Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP MPUSS low power code
0004  *
0005  * Copyright (C) 2011 Texas Instruments, Inc.
0006  *  Santosh Shilimkar <santosh.shilimkar@ti.com>
0007  *
0008  * OMAP4430 MPUSS mainly consists of dual Cortex-A9 with per-CPU
0009  * Local timer and Watchdog, GIC, SCU, PL310 L2 cache controller,
0010  * CPU0 and CPU1 LPRM modules.
0011  * CPU0, CPU1 and MPUSS each have there own power domain and
0012  * hence multiple low power combinations of MPUSS are possible.
0013  *
0014  * The CPU0 and CPU1 can't support Closed switch Retention (CSWR)
0015  * because the mode is not supported by hw constraints of dormant
0016  * mode. While waking up from the dormant mode, a reset  signal
0017  * to the Cortex-A9 processor must be asserted by the external
0018  * power controller.
0019  *
0020  * With architectural inputs and hardware recommendations, only
0021  * below modes are supported from power gain vs latency point of view.
0022  *
0023  *  CPU0        CPU1        MPUSS
0024  *  ----------------------------------------------
0025  *  ON      ON      ON
0026  *  ON(Inactive)    OFF     ON(Inactive)
0027  *  OFF     OFF     CSWR
0028  *  OFF     OFF     OSWR
0029  *  OFF     OFF     OFF(Device OFF *TBD)
0030  *  ----------------------------------------------
0031  *
0032  * Note: CPU0 is the master core and it is the last CPU to go down
0033  * and first to wake-up when MPUSS low power states are excercised
0034  */
0035 
0036 #include <linux/kernel.h>
0037 #include <linux/io.h>
0038 #include <linux/errno.h>
0039 #include <linux/linkage.h>
0040 #include <linux/smp.h>
0041 
0042 #include <asm/cacheflush.h>
0043 #include <asm/tlbflush.h>
0044 #include <asm/smp_scu.h>
0045 #include <asm/suspend.h>
0046 #include <asm/virt.h>
0047 #include <asm/hardware/cache-l2x0.h>
0048 
0049 #include "soc.h"
0050 #include "common.h"
0051 #include "omap44xx.h"
0052 #include "omap4-sar-layout.h"
0053 #include "pm.h"
0054 #include "prcm_mpu44xx.h"
0055 #include "prcm_mpu54xx.h"
0056 #include "prminst44xx.h"
0057 #include "prcm44xx.h"
0058 #include "prm44xx.h"
0059 #include "prm-regbits-44xx.h"
0060 
0061 static void __iomem *sar_base;
0062 static u32 old_cpu1_ns_pa_addr;
0063 
0064 #if defined(CONFIG_PM) && defined(CONFIG_SMP)
0065 
0066 struct omap4_cpu_pm_info {
0067     struct powerdomain *pwrdm;
0068     void __iomem *scu_sar_addr;
0069     void __iomem *wkup_sar_addr;
0070     void __iomem *l2x0_sar_addr;
0071 };
0072 
0073 /**
0074  * struct cpu_pm_ops - CPU pm operations
0075  * @finish_suspend: CPU suspend finisher function pointer
0076  * @resume:     CPU resume function pointer
0077  * @scu_prepare:    CPU Snoop Control program function pointer
0078  * @hotplug_restart:    CPU restart function pointer
0079  *
0080  * Structure holds functions pointer for CPU low power operations like
0081  * suspend, resume and scu programming.
0082  */
0083 struct cpu_pm_ops {
0084     int (*finish_suspend)(unsigned long cpu_state);
0085     void (*resume)(void);
0086     void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
0087     void (*hotplug_restart)(void);
0088 };
0089 
0090 static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
0091 static struct powerdomain *mpuss_pd;
0092 static u32 cpu_context_offset;
0093 
0094 static int default_finish_suspend(unsigned long cpu_state)
0095 {
0096     omap_do_wfi();
0097     return 0;
0098 }
0099 
0100 static void dummy_cpu_resume(void)
0101 {}
0102 
0103 static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state)
0104 {}
0105 
0106 static struct cpu_pm_ops omap_pm_ops = {
0107     .finish_suspend     = default_finish_suspend,
0108     .resume         = dummy_cpu_resume,
0109     .scu_prepare        = dummy_scu_prepare,
0110     .hotplug_restart    = dummy_cpu_resume,
0111 };
0112 
0113 /*
0114  * Program the wakeup routine address for the CPU0 and CPU1
0115  * used for OFF or DORMANT wakeup.
0116  */
0117 static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr)
0118 {
0119     struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0120 
0121     if (pm_info->wkup_sar_addr)
0122         writel_relaxed(addr, pm_info->wkup_sar_addr);
0123 }
0124 
0125 /*
0126  * Store the SCU power status value to scratchpad memory
0127  */
0128 static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
0129 {
0130     struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0131     u32 scu_pwr_st;
0132 
0133     switch (cpu_state) {
0134     case PWRDM_POWER_RET:
0135         scu_pwr_st = SCU_PM_DORMANT;
0136         break;
0137     case PWRDM_POWER_OFF:
0138         scu_pwr_st = SCU_PM_POWEROFF;
0139         break;
0140     case PWRDM_POWER_ON:
0141     case PWRDM_POWER_INACTIVE:
0142     default:
0143         scu_pwr_st = SCU_PM_NORMAL;
0144         break;
0145     }
0146 
0147     if (pm_info->scu_sar_addr)
0148         writel_relaxed(scu_pwr_st, pm_info->scu_sar_addr);
0149 }
0150 
0151 /* Helper functions for MPUSS OSWR */
0152 static inline void mpuss_clear_prev_logic_pwrst(void)
0153 {
0154     u32 reg;
0155 
0156     reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
0157         OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
0158     omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION,
0159         OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
0160 }
0161 
0162 static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id)
0163 {
0164     u32 reg;
0165 
0166     if (cpu_id) {
0167         reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST,
0168                     cpu_context_offset);
0169         omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST,
0170                     cpu_context_offset);
0171     } else {
0172         reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST,
0173                     cpu_context_offset);
0174         omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST,
0175                     cpu_context_offset);
0176     }
0177 }
0178 
0179 /*
0180  * Store the CPU cluster state for L2X0 low power operations.
0181  */
0182 static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)
0183 {
0184     struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0185 
0186     if (pm_info->l2x0_sar_addr)
0187         writel_relaxed(save_state, pm_info->l2x0_sar_addr);
0188 }
0189 
0190 /*
0191  * Save the L2X0 AUXCTRL and POR value to SAR memory. Its used to
0192  * in every restore MPUSS OFF path.
0193  */
0194 #ifdef CONFIG_CACHE_L2X0
0195 static void __init save_l2x0_context(void)
0196 {
0197     void __iomem *l2x0_base = omap4_get_l2cache_base();
0198 
0199     if (l2x0_base && sar_base) {
0200         writel_relaxed(l2x0_saved_regs.aux_ctrl,
0201                    sar_base + L2X0_AUXCTRL_OFFSET);
0202         writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
0203                    sar_base + L2X0_PREFETCH_CTRL_OFFSET);
0204     }
0205 }
0206 #else
0207 static void __init save_l2x0_context(void)
0208 {}
0209 #endif
0210 
0211 /**
0212  * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
0213  * The purpose of this function is to manage low power programming
0214  * of OMAP4 MPUSS subsystem
0215  * @cpu : CPU ID
0216  * @power_state: Low power state.
0217  *
0218  * MPUSS states for the context save:
0219  * save_state =
0220  *  0 - Nothing lost and no need to save: MPUSS INACTIVE
0221  *  1 - CPUx L1 and logic lost: MPUSS CSWR
0222  *  2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
0223  *  3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
0224  */
0225 int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
0226 {
0227     struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
0228     unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
0229 
0230     if (omap_rev() == OMAP4430_REV_ES1_0)
0231         return -ENXIO;
0232 
0233     switch (power_state) {
0234     case PWRDM_POWER_ON:
0235     case PWRDM_POWER_INACTIVE:
0236         save_state = 0;
0237         break;
0238     case PWRDM_POWER_OFF:
0239         cpu_logic_state = PWRDM_POWER_OFF;
0240         save_state = 1;
0241         break;
0242     case PWRDM_POWER_RET:
0243         if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
0244             save_state = 0;
0245         break;
0246     default:
0247         /*
0248          * CPUx CSWR is invalid hardware state. Also CPUx OSWR
0249          * doesn't make much scense, since logic is lost and $L1
0250          * needs to be cleaned because of coherency. This makes
0251          * CPUx OSWR equivalent to CPUX OFF and hence not supported
0252          */
0253         WARN_ON(1);
0254         return -ENXIO;
0255     }
0256 
0257     pwrdm_pre_transition(NULL);
0258 
0259     /*
0260      * Check MPUSS next state and save interrupt controller if needed.
0261      * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
0262      */
0263     mpuss_clear_prev_logic_pwrst();
0264     if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
0265         (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
0266         save_state = 2;
0267 
0268     cpu_clear_prev_logic_pwrst(cpu);
0269     pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
0270     pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
0271     set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.resume));
0272     omap_pm_ops.scu_prepare(cpu, power_state);
0273     l2x0_pwrst_prepare(cpu, save_state);
0274 
0275     /*
0276      * Call low level function  with targeted low power state.
0277      */
0278     if (save_state)
0279         cpu_suspend(save_state, omap_pm_ops.finish_suspend);
0280     else
0281         omap_pm_ops.finish_suspend(save_state);
0282 
0283     if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu)
0284         gic_dist_enable();
0285 
0286     /*
0287      * Restore the CPUx power state to ON otherwise CPUx
0288      * power domain can transitions to programmed low power
0289      * state while doing WFI outside the low powe code. On
0290      * secure devices, CPUx does WFI which can result in
0291      * domain transition
0292      */
0293     pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0294 
0295     pwrdm_post_transition(NULL);
0296 
0297     return 0;
0298 }
0299 
0300 /**
0301  * omap4_hotplug_cpu: OMAP4 CPU hotplug entry
0302  * @cpu : CPU ID
0303  * @power_state: CPU low power state.
0304  */
0305 int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
0306 {
0307     struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
0308     unsigned int cpu_state = 0;
0309 
0310     if (omap_rev() == OMAP4430_REV_ES1_0)
0311         return -ENXIO;
0312 
0313     /* Use the achievable power state for the domain */
0314     power_state = pwrdm_get_valid_lp_state(pm_info->pwrdm,
0315                            false, power_state);
0316 
0317     if (power_state == PWRDM_POWER_OFF)
0318         cpu_state = 1;
0319 
0320     pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0321     pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
0322     set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.hotplug_restart));
0323     omap_pm_ops.scu_prepare(cpu, power_state);
0324 
0325     /*
0326      * CPU never retuns back if targeted power state is OFF mode.
0327      * CPU ONLINE follows normal CPU ONLINE ptah via
0328      * omap4_secondary_startup().
0329      */
0330     omap_pm_ops.finish_suspend(cpu_state);
0331 
0332     pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0333     return 0;
0334 }
0335 
0336 
0337 /*
0338  * Enable Mercury Fast HG retention mode by default.
0339  */
0340 static void enable_mercury_retention_mode(void)
0341 {
0342     u32 reg;
0343 
0344     reg = omap4_prcm_mpu_read_inst_reg(OMAP54XX_PRCM_MPU_DEVICE_INST,
0345                   OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
0346     /* Enable HG_EN, HG_RAMPUP = fast mode */
0347     reg |= BIT(24) | BIT(25);
0348     omap4_prcm_mpu_write_inst_reg(reg, OMAP54XX_PRCM_MPU_DEVICE_INST,
0349                       OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
0350 }
0351 
0352 /*
0353  * Initialise OMAP4 MPUSS
0354  */
0355 int __init omap4_mpuss_init(void)
0356 {
0357     struct omap4_cpu_pm_info *pm_info;
0358 
0359     if (omap_rev() == OMAP4430_REV_ES1_0) {
0360         WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
0361         return -ENODEV;
0362     }
0363 
0364     /* Initilaise per CPU PM information */
0365     pm_info = &per_cpu(omap4_pm_info, 0x0);
0366     if (sar_base) {
0367         pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
0368         if (cpu_is_omap44xx())
0369             pm_info->wkup_sar_addr = sar_base +
0370                 CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
0371         else
0372             pm_info->wkup_sar_addr = sar_base +
0373                 OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
0374         pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
0375     }
0376     pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm");
0377     if (!pm_info->pwrdm) {
0378         pr_err("Lookup failed for CPU0 pwrdm\n");
0379         return -ENODEV;
0380     }
0381 
0382     /* Clear CPU previous power domain state */
0383     pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0384     cpu_clear_prev_logic_pwrst(0);
0385 
0386     /* Initialise CPU0 power domain state to ON */
0387     pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0388 
0389     pm_info = &per_cpu(omap4_pm_info, 0x1);
0390     if (sar_base) {
0391         pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
0392         if (cpu_is_omap44xx())
0393             pm_info->wkup_sar_addr = sar_base +
0394                 CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0395         else
0396             pm_info->wkup_sar_addr = sar_base +
0397                 OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0398         pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
0399     }
0400 
0401     pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
0402     if (!pm_info->pwrdm) {
0403         pr_err("Lookup failed for CPU1 pwrdm\n");
0404         return -ENODEV;
0405     }
0406 
0407     /* Clear CPU previous power domain state */
0408     pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0409     cpu_clear_prev_logic_pwrst(1);
0410 
0411     /* Initialise CPU1 power domain state to ON */
0412     pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0413 
0414     mpuss_pd = pwrdm_lookup("mpu_pwrdm");
0415     if (!mpuss_pd) {
0416         pr_err("Failed to lookup MPUSS power domain\n");
0417         return -ENODEV;
0418     }
0419     pwrdm_clear_all_prev_pwrst(mpuss_pd);
0420     mpuss_clear_prev_logic_pwrst();
0421 
0422     if (sar_base) {
0423         /* Save device type on scratchpad for low level code to use */
0424         writel_relaxed((omap_type() != OMAP2_DEVICE_TYPE_GP) ? 1 : 0,
0425                    sar_base + OMAP_TYPE_OFFSET);
0426         save_l2x0_context();
0427     }
0428 
0429     if (cpu_is_omap44xx()) {
0430         omap_pm_ops.finish_suspend = omap4_finish_suspend;
0431         omap_pm_ops.resume = omap4_cpu_resume;
0432         omap_pm_ops.scu_prepare = scu_pwrst_prepare;
0433         omap_pm_ops.hotplug_restart = omap4_secondary_startup;
0434         cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET;
0435     } else if (soc_is_omap54xx() || soc_is_dra7xx()) {
0436         cpu_context_offset = OMAP54XX_RM_CPU0_CPU0_CONTEXT_OFFSET;
0437         enable_mercury_retention_mode();
0438     }
0439 
0440     if (cpu_is_omap446x())
0441         omap_pm_ops.hotplug_restart = omap4460_secondary_startup;
0442 
0443     return 0;
0444 }
0445 
0446 #endif
0447 
0448 u32 omap4_get_cpu1_ns_pa_addr(void)
0449 {
0450     return old_cpu1_ns_pa_addr;
0451 }
0452 
0453 /*
0454  * For kexec, we must set CPU1_WAKEUP_NS_PA_ADDR to point to
0455  * current kernel's secondary_startup() early before
0456  * clockdomains_init(). Otherwise clockdomain_init() can
0457  * wake CPU1 and cause a hang.
0458  */
0459 void __init omap4_mpuss_early_init(void)
0460 {
0461     unsigned long startup_pa;
0462     void __iomem *ns_pa_addr;
0463 
0464     if (!(soc_is_omap44xx() || soc_is_omap54xx()))
0465         return;
0466 
0467     sar_base = omap4_get_sar_ram_base();
0468 
0469     /* Save old NS_PA_ADDR for validity checks later on */
0470     if (soc_is_omap44xx())
0471         ns_pa_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0472     else
0473         ns_pa_addr = sar_base + OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0474     old_cpu1_ns_pa_addr = readl_relaxed(ns_pa_addr);
0475 
0476     if (soc_is_omap443x())
0477         startup_pa = __pa_symbol(omap4_secondary_startup);
0478     else if (soc_is_omap446x())
0479         startup_pa = __pa_symbol(omap4460_secondary_startup);
0480     else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
0481         startup_pa = __pa_symbol(omap5_secondary_hyp_startup);
0482     else
0483         startup_pa = __pa_symbol(omap5_secondary_startup);
0484 
0485     if (soc_is_omap44xx())
0486         writel_relaxed(startup_pa, sar_base +
0487                    CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
0488     else
0489         writel_relaxed(startup_pa, sar_base +
0490                    OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
0491 }