cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm-imx5.c (11337B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
      4 */
      5#include <linux/suspend.h>
      6#include <linux/clk.h>
      7#include <linux/io.h>
      8#include <linux/err.h>
      9#include <linux/export.h>
     10
     11#include <linux/genalloc.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14#include <linux/of_platform.h>
     15
     16#include <asm/cacheflush.h>
     17#include <asm/fncpy.h>
     18#include <asm/system_misc.h>
     19#include <asm/tlbflush.h>
     20
     21#include "common.h"
     22#include "cpuidle.h"
     23#include "hardware.h"
     24
     25#define MXC_CCM_CLPCR			0x54
     26#define MXC_CCM_CLPCR_LPM_OFFSET	0
     27#define MXC_CCM_CLPCR_LPM_MASK		0x3
     28#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET	9
     29#define MXC_CCM_CLPCR_VSTBY		(0x1 << 8)
     30#define MXC_CCM_CLPCR_SBYOS		(0x1 << 6)
     31
     32#define MXC_CORTEXA8_PLAT_LPC		0xc
     33#define MXC_CORTEXA8_PLAT_LPC_DSM	(1 << 0)
     34#define MXC_CORTEXA8_PLAT_LPC_DBG_DSM	(1 << 1)
     35
     36#define MXC_SRPG_NEON_SRPGCR		0x280
     37#define MXC_SRPG_ARM_SRPGCR		0x2a0
     38#define MXC_SRPG_EMPGC0_SRPGCR		0x2c0
     39#define MXC_SRPG_EMPGC1_SRPGCR		0x2d0
     40
     41#define MXC_SRPGCR_PCR			1
     42
     43/*
     44 * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
     45 * This is also the lowest power state possible without affecting
     46 * non-cpu parts of the system.  For these reasons, imx5 should default
     47 * to always using this state for cpu idling.  The PM_SUSPEND_STANDBY also
     48 * uses this state and needs to take no action when registers remain configured
     49 * for this state.
     50 */
     51#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF
     52
     53struct imx5_suspend_io_state {
     54	u32	offset;
     55	u32	clear;
     56	u32	set;
     57	u32	saved_value;
     58};
     59
     60struct imx5_pm_data {
     61	phys_addr_t ccm_addr;
     62	phys_addr_t cortex_addr;
     63	phys_addr_t gpc_addr;
     64	phys_addr_t m4if_addr;
     65	phys_addr_t iomuxc_addr;
     66	void (*suspend_asm)(void __iomem *ocram_vbase);
     67	const u32 *suspend_asm_sz;
     68	const struct imx5_suspend_io_state *suspend_io_config;
     69	int suspend_io_count;
     70};
     71
     72static const struct imx5_suspend_io_state imx53_suspend_io_config[] = {
     73#define MX53_DSE_HIGHZ_MASK (0x7 << 19)
     74	{.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */
     75	{.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */
     76	{.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */
     77	{.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */
     78	{.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */
     79	{.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */
     80	{.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */
     81	{.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */
     82
     83	{.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */
     84	{.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */
     85	{.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */
     86	{.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */
     87	{.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */
     88	{.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */
     89	{.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */
     90	{.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */
     91	{.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */
     92	{.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */
     93	{.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */
     94
     95	/* Controls the CKE signal which is required to leave self refresh */
     96	{.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */
     97};
     98
     99static const struct imx5_pm_data imx51_pm_data __initconst = {
    100	.ccm_addr = 0x73fd4000,
    101	.cortex_addr = 0x83fa0000,
    102	.gpc_addr = 0x73fd8000,
    103};
    104
    105static const struct imx5_pm_data imx53_pm_data __initconst = {
    106	.ccm_addr = 0x53fd4000,
    107	.cortex_addr = 0x63fa0000,
    108	.gpc_addr = 0x53fd8000,
    109	.m4if_addr = 0x63fd8000,
    110	.iomuxc_addr = 0x53fa8000,
    111	.suspend_asm = &imx53_suspend,
    112	.suspend_asm_sz = &imx53_suspend_sz,
    113	.suspend_io_config = imx53_suspend_io_config,
    114	.suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config),
    115};
    116
    117#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config)
    118
    119/*
    120 * This structure is for passing necessary data for low level ocram
    121 * suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct
    122 * definition is changed, the offset definition in that file
    123 * must be also changed accordingly otherwise, the suspend to ocram
    124 * function will be broken!
    125 */
    126struct imx5_cpu_suspend_info {
    127	void __iomem	*m4if_base;
    128	void __iomem	*iomuxc_base;
    129	u32		io_count;
    130	struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE];
    131} __aligned(8);
    132
    133static void __iomem *ccm_base;
    134static void __iomem *cortex_base;
    135static void __iomem *gpc_base;
    136static void __iomem *suspend_ocram_base;
    137static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase);
    138
    139/*
    140 * set cpu low power mode before WFI instruction. This function is called
    141 * mx5 because it can be used for mx51, and mx53.
    142 */
    143static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
    144{
    145	u32 plat_lpc, arm_srpgcr, ccm_clpcr;
    146	u32 empgc0, empgc1;
    147	int stop_mode = 0;
    148
    149	/* always allow platform to issue a deep sleep mode request */
    150	plat_lpc = imx_readl(cortex_base + MXC_CORTEXA8_PLAT_LPC) &
    151	    ~(MXC_CORTEXA8_PLAT_LPC_DSM);
    152	ccm_clpcr = imx_readl(ccm_base + MXC_CCM_CLPCR) &
    153		    ~(MXC_CCM_CLPCR_LPM_MASK);
    154	arm_srpgcr = imx_readl(gpc_base + MXC_SRPG_ARM_SRPGCR) &
    155		     ~(MXC_SRPGCR_PCR);
    156	empgc0 = imx_readl(gpc_base + MXC_SRPG_EMPGC0_SRPGCR) &
    157		 ~(MXC_SRPGCR_PCR);
    158	empgc1 = imx_readl(gpc_base + MXC_SRPG_EMPGC1_SRPGCR) &
    159		 ~(MXC_SRPGCR_PCR);
    160
    161	switch (mode) {
    162	case WAIT_CLOCKED:
    163		break;
    164	case WAIT_UNCLOCKED:
    165		ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
    166		break;
    167	case WAIT_UNCLOCKED_POWER_OFF:
    168	case STOP_POWER_OFF:
    169		plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
    170			    | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
    171		if (mode == WAIT_UNCLOCKED_POWER_OFF) {
    172			ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
    173			ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
    174			ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
    175			stop_mode = 0;
    176		} else {
    177			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
    178			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
    179			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
    180			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
    181			stop_mode = 1;
    182		}
    183		arm_srpgcr |= MXC_SRPGCR_PCR;
    184		break;
    185	case STOP_POWER_ON:
    186		ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
    187		break;
    188	default:
    189		printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
    190		return;
    191	}
    192
    193	imx_writel(plat_lpc, cortex_base + MXC_CORTEXA8_PLAT_LPC);
    194	imx_writel(ccm_clpcr, ccm_base + MXC_CCM_CLPCR);
    195	imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_ARM_SRPGCR);
    196	imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_NEON_SRPGCR);
    197
    198	if (stop_mode) {
    199		empgc0 |= MXC_SRPGCR_PCR;
    200		empgc1 |= MXC_SRPGCR_PCR;
    201
    202		imx_writel(empgc0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
    203		imx_writel(empgc1, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
    204	}
    205}
    206
    207static int mx5_suspend_enter(suspend_state_t state)
    208{
    209	switch (state) {
    210	case PM_SUSPEND_MEM:
    211		mx5_cpu_lp_set(STOP_POWER_OFF);
    212		break;
    213	case PM_SUSPEND_STANDBY:
    214		/* DEFAULT_IDLE_STATE already configured */
    215		break;
    216	default:
    217		return -EINVAL;
    218	}
    219
    220	if (state == PM_SUSPEND_MEM) {
    221		local_flush_tlb_all();
    222		flush_cache_all();
    223
    224		/*clear the EMPGC0/1 bits */
    225		imx_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
    226		imx_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
    227
    228		if (imx5_suspend_in_ocram_fn)
    229			imx5_suspend_in_ocram_fn(suspend_ocram_base);
    230		else
    231			cpu_do_idle();
    232
    233	} else {
    234		cpu_do_idle();
    235	}
    236
    237	/* return registers to default idle state */
    238	mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
    239	return 0;
    240}
    241
    242static int mx5_pm_valid(suspend_state_t state)
    243{
    244	return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
    245}
    246
    247static const struct platform_suspend_ops mx5_suspend_ops = {
    248	.valid = mx5_pm_valid,
    249	.enter = mx5_suspend_enter,
    250};
    251
    252static inline int imx5_cpu_do_idle(void)
    253{
    254	int ret = tzic_enable_wake();
    255
    256	if (likely(!ret))
    257		cpu_do_idle();
    258
    259	return ret;
    260}
    261
    262static void imx5_pm_idle(void)
    263{
    264	imx5_cpu_do_idle();
    265}
    266
    267static int __init imx_suspend_alloc_ocram(
    268				size_t size,
    269				void __iomem **virt_out,
    270				phys_addr_t *phys_out)
    271{
    272	struct device_node *node;
    273	struct platform_device *pdev;
    274	struct gen_pool *ocram_pool;
    275	unsigned long ocram_base;
    276	void __iomem *virt;
    277	phys_addr_t phys;
    278	int ret = 0;
    279
    280	/* Copied from imx6: TODO factorize */
    281	node = of_find_compatible_node(NULL, NULL, "mmio-sram");
    282	if (!node) {
    283		pr_warn("%s: failed to find ocram node!\n", __func__);
    284		return -ENODEV;
    285	}
    286
    287	pdev = of_find_device_by_node(node);
    288	if (!pdev) {
    289		pr_warn("%s: failed to find ocram device!\n", __func__);
    290		ret = -ENODEV;
    291		goto put_node;
    292	}
    293
    294	ocram_pool = gen_pool_get(&pdev->dev, NULL);
    295	if (!ocram_pool) {
    296		pr_warn("%s: ocram pool unavailable!\n", __func__);
    297		ret = -ENODEV;
    298		goto put_device;
    299	}
    300
    301	ocram_base = gen_pool_alloc(ocram_pool, size);
    302	if (!ocram_base) {
    303		pr_warn("%s: unable to alloc ocram!\n", __func__);
    304		ret = -ENOMEM;
    305		goto put_device;
    306	}
    307
    308	phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
    309	virt = __arm_ioremap_exec(phys, size, false);
    310	if (phys_out)
    311		*phys_out = phys;
    312	if (virt_out)
    313		*virt_out = virt;
    314
    315put_device:
    316	put_device(&pdev->dev);
    317put_node:
    318	of_node_put(node);
    319
    320	return ret;
    321}
    322
    323static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data)
    324{
    325	struct imx5_cpu_suspend_info *suspend_info;
    326	int ret;
    327	/* Need this to avoid compile error due to const typeof in fncpy.h */
    328	void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm;
    329
    330	if (!suspend_asm)
    331		return 0;
    332
    333	if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz)
    334		return -EINVAL;
    335
    336	ret = imx_suspend_alloc_ocram(
    337		*soc_data->suspend_asm_sz + sizeof(*suspend_info),
    338		&suspend_ocram_base, NULL);
    339	if (ret)
    340		return ret;
    341
    342	suspend_info = suspend_ocram_base;
    343
    344	suspend_info->io_count = soc_data->suspend_io_count;
    345	memcpy(suspend_info->io_state, soc_data->suspend_io_config,
    346	       sizeof(*suspend_info->io_state) * soc_data->suspend_io_count);
    347
    348	suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K);
    349	if (!suspend_info->m4if_base) {
    350		ret = -ENOMEM;
    351		goto failed_map_m4if;
    352	}
    353
    354	suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K);
    355	if (!suspend_info->iomuxc_base) {
    356		ret = -ENOMEM;
    357		goto failed_map_iomuxc;
    358	}
    359
    360	imx5_suspend_in_ocram_fn = fncpy(
    361		suspend_ocram_base + sizeof(*suspend_info),
    362		suspend_asm,
    363		*soc_data->suspend_asm_sz);
    364
    365	return 0;
    366
    367failed_map_iomuxc:
    368	iounmap(suspend_info->m4if_base);
    369
    370failed_map_m4if:
    371	return ret;
    372}
    373
    374static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
    375{
    376	int ret;
    377	struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
    378
    379	if (IS_ERR(gpc_dvfs_clk))
    380		return PTR_ERR(gpc_dvfs_clk);
    381
    382	ret = clk_prepare_enable(gpc_dvfs_clk);
    383	if (ret)
    384		return ret;
    385
    386	arm_pm_idle = imx5_pm_idle;
    387
    388	ccm_base = ioremap(data->ccm_addr, SZ_16K);
    389	cortex_base = ioremap(data->cortex_addr, SZ_16K);
    390	gpc_base = ioremap(data->gpc_addr, SZ_16K);
    391	WARN_ON(!ccm_base || !cortex_base || !gpc_base);
    392
    393	/* Set the registers to the default cpu idle state. */
    394	mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
    395
    396	ret = imx5_cpuidle_init();
    397	if (ret)
    398		pr_warn("%s: cpuidle init failed %d\n", __func__, ret);
    399
    400	ret = imx5_suspend_init(data);
    401	if (ret)
    402		pr_warn("%s: No DDR LPM support with suspend %d!\n",
    403			__func__, ret);
    404
    405	suspend_set_ops(&mx5_suspend_ops);
    406
    407	return 0;
    408}
    409
    410void __init imx51_pm_init(void)
    411{
    412	if (IS_ENABLED(CONFIG_SOC_IMX51))
    413		imx5_pm_common_init(&imx51_pm_data);
    414}
    415
    416void __init imx53_pm_init(void)
    417{
    418	if (IS_ENABLED(CONFIG_SOC_IMX53))
    419		imx5_pm_common_init(&imx53_pm_data);
    420}