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

omap-mpuss-lowpower.c (13659B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * OMAP MPUSS low power code
      4 *
      5 * Copyright (C) 2011 Texas Instruments, Inc.
      6 *	Santosh Shilimkar <santosh.shilimkar@ti.com>
      7 *
      8 * OMAP4430 MPUSS mainly consists of dual Cortex-A9 with per-CPU
      9 * Local timer and Watchdog, GIC, SCU, PL310 L2 cache controller,
     10 * CPU0 and CPU1 LPRM modules.
     11 * CPU0, CPU1 and MPUSS each have there own power domain and
     12 * hence multiple low power combinations of MPUSS are possible.
     13 *
     14 * The CPU0 and CPU1 can't support Closed switch Retention (CSWR)
     15 * because the mode is not supported by hw constraints of dormant
     16 * mode. While waking up from the dormant mode, a reset  signal
     17 * to the Cortex-A9 processor must be asserted by the external
     18 * power controller.
     19 *
     20 * With architectural inputs and hardware recommendations, only
     21 * below modes are supported from power gain vs latency point of view.
     22 *
     23 *	CPU0		CPU1		MPUSS
     24 *	----------------------------------------------
     25 *	ON		ON		ON
     26 *	ON(Inactive)	OFF		ON(Inactive)
     27 *	OFF		OFF		CSWR
     28 *	OFF		OFF		OSWR
     29 *	OFF		OFF		OFF(Device OFF *TBD)
     30 *	----------------------------------------------
     31 *
     32 * Note: CPU0 is the master core and it is the last CPU to go down
     33 * and first to wake-up when MPUSS low power states are excercised
     34 */
     35
     36#include <linux/kernel.h>
     37#include <linux/io.h>
     38#include <linux/errno.h>
     39#include <linux/linkage.h>
     40#include <linux/smp.h>
     41
     42#include <asm/cacheflush.h>
     43#include <asm/tlbflush.h>
     44#include <asm/smp_scu.h>
     45#include <asm/suspend.h>
     46#include <asm/virt.h>
     47#include <asm/hardware/cache-l2x0.h>
     48
     49#include "soc.h"
     50#include "common.h"
     51#include "omap44xx.h"
     52#include "omap4-sar-layout.h"
     53#include "pm.h"
     54#include "prcm_mpu44xx.h"
     55#include "prcm_mpu54xx.h"
     56#include "prminst44xx.h"
     57#include "prcm44xx.h"
     58#include "prm44xx.h"
     59#include "prm-regbits-44xx.h"
     60
     61static void __iomem *sar_base;
     62static u32 old_cpu1_ns_pa_addr;
     63
     64#if defined(CONFIG_PM) && defined(CONFIG_SMP)
     65
     66struct omap4_cpu_pm_info {
     67	struct powerdomain *pwrdm;
     68	void __iomem *scu_sar_addr;
     69	void __iomem *wkup_sar_addr;
     70	void __iomem *l2x0_sar_addr;
     71};
     72
     73/**
     74 * struct cpu_pm_ops - CPU pm operations
     75 * @finish_suspend:	CPU suspend finisher function pointer
     76 * @resume:		CPU resume function pointer
     77 * @scu_prepare:	CPU Snoop Control program function pointer
     78 * @hotplug_restart:	CPU restart function pointer
     79 *
     80 * Structure holds functions pointer for CPU low power operations like
     81 * suspend, resume and scu programming.
     82 */
     83struct cpu_pm_ops {
     84	int (*finish_suspend)(unsigned long cpu_state);
     85	void (*resume)(void);
     86	void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
     87	void (*hotplug_restart)(void);
     88};
     89
     90static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
     91static struct powerdomain *mpuss_pd;
     92static u32 cpu_context_offset;
     93
     94static int default_finish_suspend(unsigned long cpu_state)
     95{
     96	omap_do_wfi();
     97	return 0;
     98}
     99
    100static void dummy_cpu_resume(void)
    101{}
    102
    103static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state)
    104{}
    105
    106static struct cpu_pm_ops omap_pm_ops = {
    107	.finish_suspend		= default_finish_suspend,
    108	.resume			= dummy_cpu_resume,
    109	.scu_prepare		= dummy_scu_prepare,
    110	.hotplug_restart	= dummy_cpu_resume,
    111};
    112
    113/*
    114 * Program the wakeup routine address for the CPU0 and CPU1
    115 * used for OFF or DORMANT wakeup.
    116 */
    117static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr)
    118{
    119	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
    120
    121	if (pm_info->wkup_sar_addr)
    122		writel_relaxed(addr, pm_info->wkup_sar_addr);
    123}
    124
    125/*
    126 * Store the SCU power status value to scratchpad memory
    127 */
    128static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
    129{
    130	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
    131	u32 scu_pwr_st;
    132
    133	switch (cpu_state) {
    134	case PWRDM_POWER_RET:
    135		scu_pwr_st = SCU_PM_DORMANT;
    136		break;
    137	case PWRDM_POWER_OFF:
    138		scu_pwr_st = SCU_PM_POWEROFF;
    139		break;
    140	case PWRDM_POWER_ON:
    141	case PWRDM_POWER_INACTIVE:
    142	default:
    143		scu_pwr_st = SCU_PM_NORMAL;
    144		break;
    145	}
    146
    147	if (pm_info->scu_sar_addr)
    148		writel_relaxed(scu_pwr_st, pm_info->scu_sar_addr);
    149}
    150
    151/* Helper functions for MPUSS OSWR */
    152static inline void mpuss_clear_prev_logic_pwrst(void)
    153{
    154	u32 reg;
    155
    156	reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
    157		OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
    158	omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION,
    159		OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
    160}
    161
    162static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id)
    163{
    164	u32 reg;
    165
    166	if (cpu_id) {
    167		reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST,
    168					cpu_context_offset);
    169		omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST,
    170					cpu_context_offset);
    171	} else {
    172		reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST,
    173					cpu_context_offset);
    174		omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST,
    175					cpu_context_offset);
    176	}
    177}
    178
    179/*
    180 * Store the CPU cluster state for L2X0 low power operations.
    181 */
    182static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)
    183{
    184	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
    185
    186	if (pm_info->l2x0_sar_addr)
    187		writel_relaxed(save_state, pm_info->l2x0_sar_addr);
    188}
    189
    190/*
    191 * Save the L2X0 AUXCTRL and POR value to SAR memory. Its used to
    192 * in every restore MPUSS OFF path.
    193 */
    194#ifdef CONFIG_CACHE_L2X0
    195static void __init save_l2x0_context(void)
    196{
    197	void __iomem *l2x0_base = omap4_get_l2cache_base();
    198
    199	if (l2x0_base && sar_base) {
    200		writel_relaxed(l2x0_saved_regs.aux_ctrl,
    201			       sar_base + L2X0_AUXCTRL_OFFSET);
    202		writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
    203			       sar_base + L2X0_PREFETCH_CTRL_OFFSET);
    204	}
    205}
    206#else
    207static void __init save_l2x0_context(void)
    208{}
    209#endif
    210
    211/**
    212 * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
    213 * The purpose of this function is to manage low power programming
    214 * of OMAP4 MPUSS subsystem
    215 * @cpu : CPU ID
    216 * @power_state: Low power state.
    217 *
    218 * MPUSS states for the context save:
    219 * save_state =
    220 *	0 - Nothing lost and no need to save: MPUSS INACTIVE
    221 *	1 - CPUx L1 and logic lost: MPUSS CSWR
    222 *	2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
    223 *	3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
    224 */
    225int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
    226{
    227	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
    228	unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
    229
    230	if (omap_rev() == OMAP4430_REV_ES1_0)
    231		return -ENXIO;
    232
    233	switch (power_state) {
    234	case PWRDM_POWER_ON:
    235	case PWRDM_POWER_INACTIVE:
    236		save_state = 0;
    237		break;
    238	case PWRDM_POWER_OFF:
    239		cpu_logic_state = PWRDM_POWER_OFF;
    240		save_state = 1;
    241		break;
    242	case PWRDM_POWER_RET:
    243		if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
    244			save_state = 0;
    245		break;
    246	default:
    247		/*
    248		 * CPUx CSWR is invalid hardware state. Also CPUx OSWR
    249		 * doesn't make much scense, since logic is lost and $L1
    250		 * needs to be cleaned because of coherency. This makes
    251		 * CPUx OSWR equivalent to CPUX OFF and hence not supported
    252		 */
    253		WARN_ON(1);
    254		return -ENXIO;
    255	}
    256
    257	pwrdm_pre_transition(NULL);
    258
    259	/*
    260	 * Check MPUSS next state and save interrupt controller if needed.
    261	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
    262	 */
    263	mpuss_clear_prev_logic_pwrst();
    264	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
    265		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
    266		save_state = 2;
    267
    268	cpu_clear_prev_logic_pwrst(cpu);
    269	pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
    270	pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
    271	set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.resume));
    272	omap_pm_ops.scu_prepare(cpu, power_state);
    273	l2x0_pwrst_prepare(cpu, save_state);
    274
    275	/*
    276	 * Call low level function  with targeted low power state.
    277	 */
    278	if (save_state)
    279		cpu_suspend(save_state, omap_pm_ops.finish_suspend);
    280	else
    281		omap_pm_ops.finish_suspend(save_state);
    282
    283	if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu)
    284		gic_dist_enable();
    285
    286	/*
    287	 * Restore the CPUx power state to ON otherwise CPUx
    288	 * power domain can transitions to programmed low power
    289	 * state while doing WFI outside the low powe code. On
    290	 * secure devices, CPUx does WFI which can result in
    291	 * domain transition
    292	 */
    293	pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
    294
    295	pwrdm_post_transition(NULL);
    296
    297	return 0;
    298}
    299
    300/**
    301 * omap4_hotplug_cpu: OMAP4 CPU hotplug entry
    302 * @cpu : CPU ID
    303 * @power_state: CPU low power state.
    304 */
    305int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
    306{
    307	struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
    308	unsigned int cpu_state = 0;
    309
    310	if (omap_rev() == OMAP4430_REV_ES1_0)
    311		return -ENXIO;
    312
    313	/* Use the achievable power state for the domain */
    314	power_state = pwrdm_get_valid_lp_state(pm_info->pwrdm,
    315					       false, power_state);
    316
    317	if (power_state == PWRDM_POWER_OFF)
    318		cpu_state = 1;
    319
    320	pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
    321	pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
    322	set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.hotplug_restart));
    323	omap_pm_ops.scu_prepare(cpu, power_state);
    324
    325	/*
    326	 * CPU never retuns back if targeted power state is OFF mode.
    327	 * CPU ONLINE follows normal CPU ONLINE ptah via
    328	 * omap4_secondary_startup().
    329	 */
    330	omap_pm_ops.finish_suspend(cpu_state);
    331
    332	pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
    333	return 0;
    334}
    335
    336
    337/*
    338 * Enable Mercury Fast HG retention mode by default.
    339 */
    340static void enable_mercury_retention_mode(void)
    341{
    342	u32 reg;
    343
    344	reg = omap4_prcm_mpu_read_inst_reg(OMAP54XX_PRCM_MPU_DEVICE_INST,
    345				  OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
    346	/* Enable HG_EN, HG_RAMPUP = fast mode */
    347	reg |= BIT(24) | BIT(25);
    348	omap4_prcm_mpu_write_inst_reg(reg, OMAP54XX_PRCM_MPU_DEVICE_INST,
    349				      OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
    350}
    351
    352/*
    353 * Initialise OMAP4 MPUSS
    354 */
    355int __init omap4_mpuss_init(void)
    356{
    357	struct omap4_cpu_pm_info *pm_info;
    358
    359	if (omap_rev() == OMAP4430_REV_ES1_0) {
    360		WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
    361		return -ENODEV;
    362	}
    363
    364	/* Initilaise per CPU PM information */
    365	pm_info = &per_cpu(omap4_pm_info, 0x0);
    366	if (sar_base) {
    367		pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
    368		if (cpu_is_omap44xx())
    369			pm_info->wkup_sar_addr = sar_base +
    370				CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
    371		else
    372			pm_info->wkup_sar_addr = sar_base +
    373				OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
    374		pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
    375	}
    376	pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm");
    377	if (!pm_info->pwrdm) {
    378		pr_err("Lookup failed for CPU0 pwrdm\n");
    379		return -ENODEV;
    380	}
    381
    382	/* Clear CPU previous power domain state */
    383	pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
    384	cpu_clear_prev_logic_pwrst(0);
    385
    386	/* Initialise CPU0 power domain state to ON */
    387	pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
    388
    389	pm_info = &per_cpu(omap4_pm_info, 0x1);
    390	if (sar_base) {
    391		pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
    392		if (cpu_is_omap44xx())
    393			pm_info->wkup_sar_addr = sar_base +
    394				CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
    395		else
    396			pm_info->wkup_sar_addr = sar_base +
    397				OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
    398		pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
    399	}
    400
    401	pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
    402	if (!pm_info->pwrdm) {
    403		pr_err("Lookup failed for CPU1 pwrdm\n");
    404		return -ENODEV;
    405	}
    406
    407	/* Clear CPU previous power domain state */
    408	pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
    409	cpu_clear_prev_logic_pwrst(1);
    410
    411	/* Initialise CPU1 power domain state to ON */
    412	pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
    413
    414	mpuss_pd = pwrdm_lookup("mpu_pwrdm");
    415	if (!mpuss_pd) {
    416		pr_err("Failed to lookup MPUSS power domain\n");
    417		return -ENODEV;
    418	}
    419	pwrdm_clear_all_prev_pwrst(mpuss_pd);
    420	mpuss_clear_prev_logic_pwrst();
    421
    422	if (sar_base) {
    423		/* Save device type on scratchpad for low level code to use */
    424		writel_relaxed((omap_type() != OMAP2_DEVICE_TYPE_GP) ? 1 : 0,
    425			       sar_base + OMAP_TYPE_OFFSET);
    426		save_l2x0_context();
    427	}
    428
    429	if (cpu_is_omap44xx()) {
    430		omap_pm_ops.finish_suspend = omap4_finish_suspend;
    431		omap_pm_ops.resume = omap4_cpu_resume;
    432		omap_pm_ops.scu_prepare = scu_pwrst_prepare;
    433		omap_pm_ops.hotplug_restart = omap4_secondary_startup;
    434		cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET;
    435	} else if (soc_is_omap54xx() || soc_is_dra7xx()) {
    436		cpu_context_offset = OMAP54XX_RM_CPU0_CPU0_CONTEXT_OFFSET;
    437		enable_mercury_retention_mode();
    438	}
    439
    440	if (cpu_is_omap446x())
    441		omap_pm_ops.hotplug_restart = omap4460_secondary_startup;
    442
    443	return 0;
    444}
    445
    446#endif
    447
    448u32 omap4_get_cpu1_ns_pa_addr(void)
    449{
    450	return old_cpu1_ns_pa_addr;
    451}
    452
    453/*
    454 * For kexec, we must set CPU1_WAKEUP_NS_PA_ADDR to point to
    455 * current kernel's secondary_startup() early before
    456 * clockdomains_init(). Otherwise clockdomain_init() can
    457 * wake CPU1 and cause a hang.
    458 */
    459void __init omap4_mpuss_early_init(void)
    460{
    461	unsigned long startup_pa;
    462	void __iomem *ns_pa_addr;
    463
    464	if (!(soc_is_omap44xx() || soc_is_omap54xx()))
    465		return;
    466
    467	sar_base = omap4_get_sar_ram_base();
    468
    469	/* Save old NS_PA_ADDR for validity checks later on */
    470	if (soc_is_omap44xx())
    471		ns_pa_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
    472	else
    473		ns_pa_addr = sar_base + OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
    474	old_cpu1_ns_pa_addr = readl_relaxed(ns_pa_addr);
    475
    476	if (soc_is_omap443x())
    477		startup_pa = __pa_symbol(omap4_secondary_startup);
    478	else if (soc_is_omap446x())
    479		startup_pa = __pa_symbol(omap4460_secondary_startup);
    480	else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
    481		startup_pa = __pa_symbol(omap5_secondary_hyp_startup);
    482	else
    483		startup_pa = __pa_symbol(omap5_secondary_startup);
    484
    485	if (soc_is_omap44xx())
    486		writel_relaxed(startup_pa, sar_base +
    487			       CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
    488	else
    489		writel_relaxed(startup_pa, sar_base +
    490			       OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
    491}