--- zzzz-none-000/linux-3.10.107/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2021-02-04 17:41:59.000000000 +0000 @@ -56,6 +56,7 @@ #include "omap4-sar-layout.h" #include "pm.h" #include "prcm_mpu44xx.h" +#include "prcm_mpu54xx.h" #include "prminst44xx.h" #include "prcm44xx.h" #include "prm44xx.h" @@ -68,12 +69,48 @@ void __iomem *scu_sar_addr; void __iomem *wkup_sar_addr; void __iomem *l2x0_sar_addr; - void (*secondary_startup)(void); +}; + +/** + * struct cpu_pm_ops - CPU pm operations + * @finish_suspend: CPU suspend finisher function pointer + * @resume: CPU resume function pointer + * @scu_prepare: CPU Snoop Control program function pointer + * @hotplug_restart: CPU restart function pointer + * + * Structure holds functions pointer for CPU low power operations like + * suspend, resume and scu programming. + */ +struct cpu_pm_ops { + int (*finish_suspend)(unsigned long cpu_state); + void (*resume)(void); + void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state); + void (*hotplug_restart)(void); }; static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); static struct powerdomain *mpuss_pd; static void __iomem *sar_base; +static u32 cpu_context_offset; + +static int default_finish_suspend(unsigned long cpu_state) +{ + omap_do_wfi(); + return 0; +} + +static void dummy_cpu_resume(void) +{} + +static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state) +{} + +static struct cpu_pm_ops omap_pm_ops = { + .finish_suspend = default_finish_suspend, + .resume = dummy_cpu_resume, + .scu_prepare = dummy_scu_prepare, + .hotplug_restart = dummy_cpu_resume, +}; /* * Program the wakeup routine address for the CPU0 and CPU1 @@ -83,7 +120,8 @@ { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); - __raw_writel(addr, pm_info->wkup_sar_addr); + if (pm_info->wkup_sar_addr) + writel_relaxed(addr, pm_info->wkup_sar_addr); } /* @@ -108,7 +146,8 @@ break; } - __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); + if (pm_info->scu_sar_addr) + writel_relaxed(scu_pwr_st, pm_info->scu_sar_addr); } /* Helper functions for MPUSS OSWR */ @@ -128,14 +167,14 @@ if (cpu_id) { reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST, - OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); + cpu_context_offset); omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST, - OMAP4_RM_CPU1_CPU1_CONTEXT_OFFSET); + cpu_context_offset); } else { reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST, - OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); + cpu_context_offset); omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST, - OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET); + cpu_context_offset); } } @@ -146,7 +185,8 @@ { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); - __raw_writel(save_state, pm_info->l2x0_sar_addr); + if (pm_info->l2x0_sar_addr) + writel_relaxed(save_state, pm_info->l2x0_sar_addr); } /* @@ -154,18 +194,19 @@ * in every restore MPUSS OFF path. */ #ifdef CONFIG_CACHE_L2X0 -static void save_l2x0_context(void) +static void __init save_l2x0_context(void) { - u32 val; void __iomem *l2x0_base = omap4_get_l2cache_base(); - val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); - __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); - val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); - __raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET); + if (l2x0_base && sar_base) { + writel_relaxed(l2x0_saved_regs.aux_ctrl, + sar_base + L2X0_AUXCTRL_OFFSET); + writel_relaxed(l2x0_saved_regs.prefetch_ctrl, + sar_base + L2X0_PREFETCH_CTRL_OFFSET); + } } #else -static void save_l2x0_context(void) +static void __init save_l2x0_context(void) {} #endif @@ -186,7 +227,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); - unsigned int save_state = 0; + unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) @@ -198,9 +239,13 @@ save_state = 0; break; case PWRDM_POWER_OFF: + cpu_logic_state = PWRDM_POWER_OFF; save_state = 1; break; case PWRDM_POWER_RET: + if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE)) + save_state = 0; + break; default: /* * CPUx CSWR is invalid hardware state. Also CPUx OSWR @@ -225,14 +270,21 @@ cpu_clear_prev_logic_pwrst(cpu); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); - set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); - scu_pwrst_prepare(cpu, power_state); + pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state); + set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); + omap_pm_ops.scu_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); /* * Call low level function with targeted low power state. */ - cpu_suspend(save_state, omap4_finish_suspend); + if (save_state) + cpu_suspend(save_state, omap_pm_ops.finish_suspend); + else + omap_pm_ops.finish_suspend(save_state); + + if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu) + gic_dist_enable(); /* * Restore the CPUx power state to ON otherwise CPUx @@ -254,7 +306,7 @@ * @cpu : CPU ID * @power_state: CPU low power state. */ -int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) +int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); unsigned int cpu_state = 0; @@ -262,20 +314,24 @@ if (omap_rev() == OMAP4430_REV_ES1_0) return -ENXIO; + /* Use the achievable power state for the domain */ + power_state = pwrdm_get_valid_lp_state(pm_info->pwrdm, + false, power_state); + if (power_state == PWRDM_POWER_OFF) cpu_state = 1; pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); - set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup)); - scu_pwrst_prepare(cpu, power_state); + set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.hotplug_restart)); + omap_pm_ops.scu_prepare(cpu, power_state); /* * CPU never retuns back if targeted power state is OFF mode. * CPU ONLINE follows normal CPU ONLINE ptah via - * omap_secondary_startup(). + * omap4_secondary_startup(). */ - omap4_finish_suspend(cpu_state); + omap_pm_ops.finish_suspend(cpu_state); pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); return 0; @@ -283,6 +339,21 @@ /* + * Enable Mercury Fast HG retention mode by default. + */ +static void enable_mercury_retention_mode(void) +{ + u32 reg; + + reg = omap4_prcm_mpu_read_inst_reg(OMAP54XX_PRCM_MPU_DEVICE_INST, + OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET); + /* Enable HG_EN, HG_RAMPUP = fast mode */ + reg |= BIT(24) | BIT(25); + omap4_prcm_mpu_write_inst_reg(reg, OMAP54XX_PRCM_MPU_DEVICE_INST, + OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET); +} + +/* * Initialise OMAP4 MPUSS */ int __init omap4_mpuss_init(void) @@ -294,13 +365,17 @@ return -ENODEV; } - sar_base = omap4_get_sar_ram_base(); + if (cpu_is_omap44xx()) + sar_base = omap4_get_sar_ram_base(); /* Initilaise per CPU PM information */ pm_info = &per_cpu(omap4_pm_info, 0x0); - pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; - pm_info->wkup_sar_addr = sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET; - pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0; + if (sar_base) { + pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; + pm_info->wkup_sar_addr = sar_base + + CPU0_WAKEUP_NS_PA_ADDR_OFFSET; + pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0; + } pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); if (!pm_info->pwrdm) { pr_err("Lookup failed for CPU0 pwrdm\n"); @@ -315,13 +390,12 @@ pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); pm_info = &per_cpu(omap4_pm_info, 0x1); - pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; - pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; - pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1; - if (cpu_is_omap446x()) - pm_info->secondary_startup = omap_secondary_startup_4460; - else - pm_info->secondary_startup = omap_secondary_startup; + if (sar_base) { + pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; + pm_info->wkup_sar_addr = sar_base + + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; + pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1; + } pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); if (!pm_info->pwrdm) { @@ -344,13 +418,26 @@ pwrdm_clear_all_prev_pwrst(mpuss_pd); mpuss_clear_prev_logic_pwrst(); - /* Save device type on scratchpad for low level code to use */ - if (omap_type() != OMAP2_DEVICE_TYPE_GP) - __raw_writel(1, sar_base + OMAP_TYPE_OFFSET); - else - __raw_writel(0, sar_base + OMAP_TYPE_OFFSET); + if (sar_base) { + /* Save device type on scratchpad for low level code to use */ + writel_relaxed((omap_type() != OMAP2_DEVICE_TYPE_GP) ? 1 : 0, + sar_base + OMAP_TYPE_OFFSET); + save_l2x0_context(); + } + + if (cpu_is_omap44xx()) { + omap_pm_ops.finish_suspend = omap4_finish_suspend; + omap_pm_ops.resume = omap4_cpu_resume; + omap_pm_ops.scu_prepare = scu_pwrst_prepare; + omap_pm_ops.hotplug_restart = omap4_secondary_startup; + cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET; + } else if (soc_is_omap54xx() || soc_is_dra7xx()) { + cpu_context_offset = OMAP54XX_RM_CPU0_CPU0_CONTEXT_OFFSET; + enable_mercury_retention_mode(); + } - save_l2x0_context(); + if (cpu_is_omap446x()) + omap_pm_ops.hotplug_restart = omap4460_secondary_startup; return 0; }