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.c (8407B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
      4 * Author: Tony Xie <tony.xie@rock-chips.com>
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/io.h>
      9#include <linux/kernel.h>
     10#include <linux/of.h>
     11#include <linux/of_address.h>
     12#include <linux/regmap.h>
     13#include <linux/suspend.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/regulator/machine.h>
     16
     17#include <asm/cacheflush.h>
     18#include <asm/tlbflush.h>
     19#include <asm/suspend.h>
     20
     21#include "pm.h"
     22
     23/* These enum are option of low power mode */
     24enum {
     25	ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0,
     26	ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
     27};
     28
     29struct rockchip_pm_data {
     30	const struct platform_suspend_ops *ops;
     31	int (*init)(struct device_node *np);
     32};
     33
     34static void __iomem *rk3288_bootram_base;
     35static phys_addr_t rk3288_bootram_phy;
     36
     37static struct regmap *pmu_regmap;
     38static struct regmap *sgrf_regmap;
     39static struct regmap *grf_regmap;
     40
     41static u32 rk3288_pmu_pwr_mode_con;
     42static u32 rk3288_sgrf_soc_con0;
     43static u32 rk3288_sgrf_cpu_con0;
     44
     45static inline u32 rk3288_l2_config(void)
     46{
     47	u32 l2ctlr;
     48
     49	asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (l2ctlr));
     50	return l2ctlr;
     51}
     52
     53static void __init rk3288_config_bootdata(void)
     54{
     55	rkpm_bootdata_cpusp = rk3288_bootram_phy + (SZ_4K - 8);
     56	rkpm_bootdata_cpu_code = __pa_symbol(cpu_resume);
     57
     58	rkpm_bootdata_l2ctlr_f  = 1;
     59	rkpm_bootdata_l2ctlr = rk3288_l2_config();
     60}
     61
     62#define GRF_UOC0_CON0			0x320
     63#define GRF_UOC1_CON0			0x334
     64#define GRF_UOC2_CON0			0x348
     65#define GRF_SIDDQ			BIT(13)
     66
     67static bool rk3288_slp_disable_osc(void)
     68{
     69	static const u32 reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
     70					  GRF_UOC2_CON0 };
     71	u32 reg, i;
     72
     73	/*
     74	 * if any usb phy is still on(GRF_SIDDQ==0), that means we need the
     75	 * function of usb wakeup, so do not switch to 32khz, since the usb phy
     76	 * clk does not connect to 32khz osc
     77	 */
     78	for (i = 0; i < ARRAY_SIZE(reg_offset); i++) {
     79		regmap_read(grf_regmap, reg_offset[i], &reg);
     80		if (!(reg & GRF_SIDDQ))
     81			return false;
     82	}
     83
     84	return true;
     85}
     86
     87static void rk3288_slp_mode_set(int level)
     88{
     89	u32 mode_set, mode_set1;
     90	bool osc_disable = rk3288_slp_disable_osc();
     91
     92	regmap_read(sgrf_regmap, RK3288_SGRF_CPU_CON0, &rk3288_sgrf_cpu_con0);
     93	regmap_read(sgrf_regmap, RK3288_SGRF_SOC_CON0, &rk3288_sgrf_soc_con0);
     94
     95	regmap_read(pmu_regmap, RK3288_PMU_PWRMODE_CON,
     96		    &rk3288_pmu_pwr_mode_con);
     97
     98	/*
     99	 * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
    100	 * PCLK_WDT_GATE - disable WDT during suspend.
    101	 */
    102	regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
    103		     SGRF_PCLK_WDT_GATE | SGRF_FAST_BOOT_EN
    104		     | SGRF_PCLK_WDT_GATE_WRITE | SGRF_FAST_BOOT_EN_WRITE);
    105
    106	/*
    107	 * The dapswjdp can not auto reset before resume, that cause it may
    108	 * access some illegal address during resume. Let's disable it before
    109	 * suspend, and the MASKROM will enable it back.
    110	 */
    111	regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0, SGRF_DAPDEVICEEN_WRITE);
    112
    113	/* booting address of resuming system is from this register value */
    114	regmap_write(sgrf_regmap, RK3288_SGRF_FAST_BOOT_ADDR,
    115		     rk3288_bootram_phy);
    116
    117	mode_set = BIT(PMU_GLOBAL_INT_DISABLE) | BIT(PMU_L2FLUSH_EN) |
    118		   BIT(PMU_SREF0_ENTER_EN) | BIT(PMU_SREF1_ENTER_EN) |
    119		   BIT(PMU_DDR0_GATING_EN) | BIT(PMU_DDR1_GATING_EN) |
    120		   BIT(PMU_PWR_MODE_EN) | BIT(PMU_CHIP_PD_EN) |
    121		   BIT(PMU_SCU_EN);
    122
    123	mode_set1 = BIT(PMU_CLR_CORE) | BIT(PMU_CLR_CPUP);
    124
    125	if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
    126		/* arm off, logic deep sleep */
    127		mode_set |= BIT(PMU_BUS_PD_EN) | BIT(PMU_PMU_USE_LF) |
    128			    BIT(PMU_DDR1IO_RET_EN) | BIT(PMU_DDR0IO_RET_EN) |
    129			    BIT(PMU_ALIVE_USE_LF) | BIT(PMU_PLL_PD_EN);
    130
    131		if (osc_disable)
    132			mode_set |= BIT(PMU_OSC_24M_DIS);
    133
    134		mode_set1 |= BIT(PMU_CLR_ALIVE) | BIT(PMU_CLR_BUS) |
    135			     BIT(PMU_CLR_PERI) | BIT(PMU_CLR_DMA);
    136
    137		regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
    138			     PMU_ARMINT_WAKEUP_EN);
    139
    140		/*
    141		 * In deep suspend we use PMU_PMU_USE_LF to let the rk3288
    142		 * switch its main clock supply to the alternative 32kHz
    143		 * source. Therefore set 30ms on a 32kHz clock for pmic
    144		 * stabilization. Similar 30ms on 24MHz for the other
    145		 * mode below.
    146		 */
    147		regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, 32 * 30);
    148
    149		/* only wait for stabilization, if we turned the osc off */
    150		regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT,
    151					 osc_disable ? 32 * 30 : 0);
    152	} else {
    153		/*
    154		 * arm off, logic normal
    155		 * if pmu_clk_core_src_gate_en is not set,
    156		 * wakeup will be error
    157		 */
    158		mode_set |= BIT(PMU_CLK_CORE_SRC_GATE_EN);
    159
    160		regmap_write(pmu_regmap, RK3288_PMU_WAKEUP_CFG1,
    161			     PMU_ARMINT_WAKEUP_EN | PMU_GPIOINT_WAKEUP_EN);
    162
    163		/* 30ms on a 24MHz clock for pmic stabilization */
    164		regmap_write(pmu_regmap, RK3288_PMU_STABL_CNT, 24000 * 30);
    165
    166		/* oscillator is still running, so no need to wait */
    167		regmap_write(pmu_regmap, RK3288_PMU_OSC_CNT, 0);
    168	}
    169
    170	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON, mode_set);
    171	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON1, mode_set1);
    172}
    173
    174static void rk3288_slp_mode_set_resume(void)
    175{
    176	regmap_write(sgrf_regmap, RK3288_SGRF_CPU_CON0,
    177		     rk3288_sgrf_cpu_con0 | SGRF_DAPDEVICEEN_WRITE);
    178
    179	regmap_write(pmu_regmap, RK3288_PMU_PWRMODE_CON,
    180		     rk3288_pmu_pwr_mode_con);
    181
    182	regmap_write(sgrf_regmap, RK3288_SGRF_SOC_CON0,
    183		     rk3288_sgrf_soc_con0 | SGRF_PCLK_WDT_GATE_WRITE
    184		     | SGRF_FAST_BOOT_EN_WRITE);
    185}
    186
    187static int rockchip_lpmode_enter(unsigned long arg)
    188{
    189	flush_cache_all();
    190
    191	cpu_do_idle();
    192
    193	pr_err("%s: Failed to suspend\n", __func__);
    194
    195	return 1;
    196}
    197
    198static int rk3288_suspend_enter(suspend_state_t state)
    199{
    200	local_fiq_disable();
    201
    202	rk3288_slp_mode_set(ROCKCHIP_ARM_OFF_LOGIC_NORMAL);
    203
    204	cpu_suspend(0, rockchip_lpmode_enter);
    205
    206	rk3288_slp_mode_set_resume();
    207
    208	local_fiq_enable();
    209
    210	return 0;
    211}
    212
    213static int rk3288_suspend_prepare(void)
    214{
    215	return regulator_suspend_prepare(PM_SUSPEND_MEM);
    216}
    217
    218static void rk3288_suspend_finish(void)
    219{
    220	if (regulator_suspend_finish())
    221		pr_err("%s: Suspend finish failed\n", __func__);
    222}
    223
    224static int __init rk3288_suspend_init(struct device_node *np)
    225{
    226	struct device_node *sram_np;
    227	struct resource res;
    228	int ret;
    229
    230	pmu_regmap = syscon_node_to_regmap(np);
    231	if (IS_ERR(pmu_regmap)) {
    232		pr_err("%s: could not find pmu regmap\n", __func__);
    233		return PTR_ERR(pmu_regmap);
    234	}
    235
    236	sgrf_regmap = syscon_regmap_lookup_by_compatible(
    237				"rockchip,rk3288-sgrf");
    238	if (IS_ERR(sgrf_regmap)) {
    239		pr_err("%s: could not find sgrf regmap\n", __func__);
    240		return PTR_ERR(sgrf_regmap);
    241	}
    242
    243	grf_regmap = syscon_regmap_lookup_by_compatible(
    244				"rockchip,rk3288-grf");
    245	if (IS_ERR(grf_regmap)) {
    246		pr_err("%s: could not find grf regmap\n", __func__);
    247		return PTR_ERR(grf_regmap);
    248	}
    249
    250	sram_np = of_find_compatible_node(NULL, NULL,
    251					  "rockchip,rk3288-pmu-sram");
    252	if (!sram_np) {
    253		pr_err("%s: could not find bootram dt node\n", __func__);
    254		return -ENODEV;
    255	}
    256
    257	rk3288_bootram_base = of_iomap(sram_np, 0);
    258	if (!rk3288_bootram_base) {
    259		pr_err("%s: could not map bootram base\n", __func__);
    260		of_node_put(sram_np);
    261		return -ENOMEM;
    262	}
    263
    264	ret = of_address_to_resource(sram_np, 0, &res);
    265	if (ret) {
    266		pr_err("%s: could not get bootram phy addr\n", __func__);
    267		of_node_put(sram_np);
    268		return ret;
    269	}
    270	rk3288_bootram_phy = res.start;
    271
    272	of_node_put(sram_np);
    273
    274	rk3288_config_bootdata();
    275
    276	/* copy resume code and data to bootsram */
    277	memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
    278	       rk3288_bootram_sz);
    279
    280	return 0;
    281}
    282
    283static const struct platform_suspend_ops rk3288_suspend_ops = {
    284	.enter   = rk3288_suspend_enter,
    285	.valid   = suspend_valid_only_mem,
    286	.prepare = rk3288_suspend_prepare,
    287	.finish  = rk3288_suspend_finish,
    288};
    289
    290static const struct rockchip_pm_data rk3288_pm_data __initconst = {
    291	.ops = &rk3288_suspend_ops,
    292	.init = rk3288_suspend_init,
    293};
    294
    295static const struct of_device_id rockchip_pmu_of_device_ids[] __initconst = {
    296	{
    297		.compatible = "rockchip,rk3288-pmu",
    298		.data = &rk3288_pm_data,
    299	},
    300	{ /* sentinel */ },
    301};
    302
    303void __init rockchip_suspend_init(void)
    304{
    305	const struct rockchip_pm_data *pm_data;
    306	const struct of_device_id *match;
    307	struct device_node *np;
    308	int ret;
    309
    310	np = of_find_matching_node_and_match(NULL, rockchip_pmu_of_device_ids,
    311					     &match);
    312	if (!match) {
    313		pr_err("Failed to find PMU node\n");
    314		return;
    315	}
    316	pm_data = (struct rockchip_pm_data *) match->data;
    317
    318	if (pm_data->init) {
    319		ret = pm_data->init(np);
    320
    321		if (ret) {
    322			pr_err("%s: matches init error %d\n", __func__, ret);
    323			return;
    324		}
    325	}
    326
    327	suspend_set_ops(pm_data->ops);
    328}