From 501f0c751de06d8484b4279131c26f58bd49a69d Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Sat, 1 Jan 2011 19:56:04 +0530 Subject: ARM: OMAP4: PM: Add SAR RAM support This patch adds SAR RAM support on OMAP4430. SAR RAM used to save and restore the HW context in low power modes. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap4-sar-layout.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 arch/arm/mach-omap2/omap4-sar-layout.h (limited to 'arch/arm/mach-omap2/omap4-sar-layout.h') diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h new file mode 100644 index 000000000000..7781ea4dacbc --- /dev/null +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -0,0 +1,22 @@ +/* + * omap4-sar-layout.h: OMAP4 SAR RAM layout header file + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef OMAP_ARCH_OMAP4_SAR_LAYOUT_H +#define OMAP_ARCH_OMAP4_SAR_LAYOUT_H + +/* + * SAR BANK offsets from base address OMAP44XX_SAR_RAM_BASE + */ +#define SAR_BANK1_OFFSET 0x0000 +#define SAR_BANK2_OFFSET 0x1000 +#define SAR_BANK3_OFFSET 0x2000 +#define SAR_BANK4_OFFSET 0x3000 + +#endif -- cgit v1.2.3 From b2b9762f76981c16a8768255284efeae7f27e4f1 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 16 Jun 2010 22:19:48 +0530 Subject: ARM: OMAP4: PM: Add CPUX OFF mode support This patch adds the CPU0 and CPU1 off mode support. CPUX close switch retention (CSWR) is not supported by hardware design. The CPUx OFF mode isn't supported on OMAP4430 ES1.0 CPUx sleep code is common for hotplug, suspend and CPUilde. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/Makefile | 6 +- arch/arm/mach-omap2/common.h | 30 +++ arch/arm/mach-omap2/include/mach/omap-secure.h | 9 + arch/arm/mach-omap2/omap-mpuss-lowpower.c | 248 ++++++++++++++++++++++ arch/arm/mach-omap2/omap-smp.c | 13 ++ arch/arm/mach-omap2/omap4-sar-layout.h | 9 + arch/arm/mach-omap2/pm44xx.c | 6 + arch/arm/mach-omap2/sleep44xx.S | 276 +++++++++++++++++++++++++ 8 files changed, 595 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-omap2/omap-mpuss-lowpower.c create mode 100644 arch/arm/mach-omap2/sleep44xx.S (limited to 'arch/arm/mach-omap2/omap4-sar-layout.h') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 19c29d569d82..58de1f6df27c 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -25,11 +25,13 @@ obj-$(CONFIG_TWL4030_CORE) += omap_twl.o obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o -obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o +obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o \ + sleep44xx.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) AFLAGS_omap-smc.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep44xx.o :=-Wa,-march=armv7-a$(plus_sec) # Functions loaded to SRAM obj-$(CONFIG_SOC_OMAP2420) += sram242x.o @@ -63,7 +65,7 @@ obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ cpuidle34xx.o -obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 7ebcb6a9b73e..36cdba7727f2 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -24,9 +24,11 @@ #ifndef __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H #define __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H +#ifndef __ASSEMBLER__ #include #include +#include #ifdef CONFIG_SOC_OMAP2420 extern void omap242x_map_common_io(void); @@ -183,6 +185,7 @@ static inline void __iomem *omap4_get_scu_base(void) extern void __init gic_init_irq(void); extern void omap_smc1(u32 fn, u32 arg); extern void __iomem *omap4_get_sar_ram_base(void); +extern void omap_do_wfi(void); #ifdef CONFIG_SMP /* Needed for secondary core boot */ @@ -192,4 +195,31 @@ extern void omap_auxcoreboot_addr(u32 cpu_addr); extern u32 omap_read_auxcoreboot0(void); #endif +#if defined(CONFIG_SMP) && defined(CONFIG_PM) +extern int omap4_mpuss_init(void); +extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); +extern int omap4_finish_suspend(unsigned long cpu_state); +extern void omap4_cpu_resume(void); +#else +static inline int omap4_enter_lowpower(unsigned int cpu, + unsigned int power_state) +{ + cpu_do_idle(); + return 0; +} + +static inline int omap4_mpuss_init(void) +{ + return 0; +} + +static inline int omap4_finish_suspend(unsigned long cpu_state) +{ + return 0; +} + +static inline void omap4_cpu_resume(void) +{} +#endif +#endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/include/mach/omap-secure.h b/arch/arm/mach-omap2/include/mach/omap-secure.h index 29f60cae45e9..5f0763dd5664 100644 --- a/arch/arm/mach-omap2/include/mach/omap-secure.h +++ b/arch/arm/mach-omap2/include/mach/omap-secure.h @@ -35,9 +35,18 @@ #define OMAP4_HAL_SAVEALL_INDEX 0x1c #define OMAP4_HAL_SAVEGIC_INDEX 0x1d +/* Secure Monitor mode APIs */ +#define OMAP4_MON_SCU_PWR_INDEX 0x108 + +/* Secure PPA(Primary Protected Application) APIs */ +#define OMAP4_PPA_CPU_ACTRL_SMP_INDEX 0x25 + +#ifndef __ASSEMBLER__ + extern u32 omap_secure_dispatcher(u32 idx, u32 flag, u32 nargs, u32 arg1, u32 arg2, u32 arg3, u32 arg4); extern u32 omap_smc2(u32 id, u32 falg, u32 pargs); extern phys_addr_t omap_secure_ram_mempool_base(void); +#endif /* __ASSEMBLER__ */ #endif /* OMAP_ARCH_OMAP_SECURE_H */ diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c new file mode 100644 index 000000000000..867fee51e42c --- /dev/null +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -0,0 +1,248 @@ +/* + * OMAP MPUSS low power code + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar + * + * OMAP4430 MPUSS mainly consists of dual Cortex-A9 with per-CPU + * Local timer and Watchdog, GIC, SCU, PL310 L2 cache controller, + * CPU0 and CPU1 LPRM modules. + * CPU0, CPU1 and MPUSS each have there own power domain and + * hence multiple low power combinations of MPUSS are possible. + * + * The CPU0 and CPU1 can't support Closed switch Retention (CSWR) + * because the mode is not supported by hw constraints of dormant + * mode. While waking up from the dormant mode, a reset signal + * to the Cortex-A9 processor must be asserted by the external + * power controller. + * + * With architectural inputs and hardware recommendations, only + * below modes are supported from power gain vs latency point of view. + * + * CPU0 CPU1 MPUSS + * ---------------------------------------------- + * ON ON ON + * ON(Inactive) OFF ON(Inactive) + * OFF OFF CSWR + * OFF OFF OSWR (*TBD) + * OFF OFF OFF* (*TBD) + * ---------------------------------------------- + * + * Note: CPU0 is the master core and it is the last CPU to go down + * and first to wake-up when MPUSS low power states are excercised + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "omap4-sar-layout.h" +#include "pm.h" +#include "powerdomain.h" + +#ifdef CONFIG_SMP + +struct omap4_cpu_pm_info { + struct powerdomain *pwrdm; + void __iomem *scu_sar_addr; + void __iomem *wkup_sar_addr; +}; + +static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); + +/* + * Program the wakeup routine address for the CPU0 and CPU1 + * used for OFF or DORMANT wakeup. + */ +static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + __raw_writel(addr, pm_info->wkup_sar_addr); +} + +/* + * Set the CPUx powerdomain's previous power state + */ +static inline void set_cpu_next_pwrst(unsigned int cpu_id, + unsigned int power_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); +} + +/* + * Read CPU's previous power state + */ +static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + return pwrdm_read_prev_pwrst(pm_info->pwrdm); +} + +/* + * Clear the CPUx powerdomain's previous power state + */ +static inline void clear_cpu_prev_pwrst(unsigned int cpu_id) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); +} + +/* + * Store the SCU power status value to scratchpad memory + */ +static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + u32 scu_pwr_st; + + switch (cpu_state) { + case PWRDM_POWER_RET: + scu_pwr_st = SCU_PM_DORMANT; + break; + case PWRDM_POWER_OFF: + scu_pwr_st = SCU_PM_POWEROFF; + break; + case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: + default: + scu_pwr_st = SCU_PM_NORMAL; + break; + } + + __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); +} + +/** + * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function + * The purpose of this function is to manage low power programming + * of OMAP4 MPUSS subsystem + * @cpu : CPU ID + * @power_state: Low power state. + */ +int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) +{ + unsigned int save_state = 0; + unsigned int wakeup_cpu; + + if (omap_rev() == OMAP4430_REV_ES1_0) + return -ENXIO; + + switch (power_state) { + case PWRDM_POWER_ON: + case PWRDM_POWER_INACTIVE: + save_state = 0; + break; + case PWRDM_POWER_OFF: + save_state = 1; + break; + case PWRDM_POWER_RET: + default: + /* + * CPUx CSWR is invalid hardware state. Also CPUx OSWR + * doesn't make much scense, since logic is lost and $L1 + * needs to be cleaned because of coherency. This makes + * CPUx OSWR equivalent to CPUX OFF and hence not supported + */ + WARN_ON(1); + return -ENXIO; + } + + clear_cpu_prev_pwrst(cpu); + set_cpu_next_pwrst(cpu, power_state); + set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); + scu_pwrst_prepare(cpu, power_state); + + /* + * Call low level function with targeted low power state. + */ + cpu_suspend(save_state, omap4_finish_suspend); + + /* + * Restore the CPUx power state to ON otherwise CPUx + * power domain can transitions to programmed low power + * state while doing WFI outside the low powe code. On + * secure devices, CPUx does WFI which can result in + * domain transition + */ + wakeup_cpu = smp_processor_id(); + set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); + + return 0; +} + +/* + * Initialise OMAP4 MPUSS + */ +int __init omap4_mpuss_init(void) +{ + struct omap4_cpu_pm_info *pm_info; + void __iomem *sar_base = omap4_get_sar_ram_base(); + + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); + return -ENODEV; + } + + /* 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->pwrdm = pwrdm_lookup("cpu0_pwrdm"); + if (!pm_info->pwrdm) { + pr_err("Lookup failed for CPU0 pwrdm\n"); + return -ENODEV; + } + + /* Clear CPU previous power domain state */ + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); + + /* Initialise CPU0 power domain state to ON */ + 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->pwrdm = pwrdm_lookup("cpu1_pwrdm"); + if (!pm_info->pwrdm) { + pr_err("Lookup failed for CPU1 pwrdm\n"); + return -ENODEV; + } + + /* Clear CPU previous power domain state */ + pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); + + /* Initialise CPU1 power domain state to ON */ + pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); + + /* 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); + + return 0; +} + +#endif diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 74e90b40a0c7..ee83808de0ff 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "common.h" @@ -39,6 +40,18 @@ void __iomem *omap4_get_scu_base(void) void __cpuinit platform_secondary_init(unsigned int cpu) { + /* + * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. + * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA + * init and for CPU1, a secure PPA API provided. CPU0 must be ON + * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+. + * OMAP443X GP devices- SMP bit isn't accessible. + * OMAP446X GP devices - SMP bit access is enabled on both CPUs. + */ + if (cpu_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) + omap_secure_dispatcher(OMAP4_PPA_CPU_ACTRL_SMP_INDEX, + 4, 0, 0, 0, 0, 0); + /* * If any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h index 7781ea4dacbc..970a2eef3ab9 100644 --- a/arch/arm/mach-omap2/omap4-sar-layout.h +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -19,4 +19,13 @@ #define SAR_BANK3_OFFSET 0x2000 #define SAR_BANK4_OFFSET 0x3000 +/* Scratch pad memory offsets from SAR_BANK1 */ +#define SCU_OFFSET0 0xd00 +#define SCU_OFFSET1 0xd04 +#define OMAP_TYPE_OFFSET 0xd10 + +/* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */ +#define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04 +#define CPU1_WAKEUP_NS_PA_ADDR_OFFSET 0xa08 + #endif diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index c34139dc8d8c..781aadf98e32 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -163,6 +163,12 @@ static int __init omap4_pm_init(void) goto err2; } + ret = omap4_mpuss_init(); + if (ret) { + pr_err("Failed to initialise OMAP4 MPUSS\n"); + goto err2; + } + (void) clkdm_for_each(clkdms_setup, NULL); #ifdef CONFIG_SUSPEND diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S new file mode 100644 index 000000000000..e5521945ba8e --- /dev/null +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -0,0 +1,276 @@ +/* + * OMAP44xx sleep code. + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar + * + * This program is free software,you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" +#include "omap4-sar-layout.h" + +#if defined(CONFIG_SMP) && defined(CONFIG_PM) + +.macro DO_SMC + dsb + smc #0 + dsb +.endm + +ppa_zero_params: + .word 0x0 + +/* + * ============================= + * == CPU suspend finisher == + * ============================= + * + * void omap4_finish_suspend(unsigned long cpu_state) + * + * This function code saves the CPU context and performs the CPU + * power down sequence. Calling WFI effectively changes the CPU + * power domains states to the desired target power state. + * + * @cpu_state : contains context save state (r0) + * 0 - No context lost + * 1 - CPUx L1 and logic lost: MPUSS CSWR + * 2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR + * 3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF + * @return: This function never returns for CPU OFF and DORMANT power states. + * Post WFI, CPU transitions to DORMANT or OFF power state and on wake-up + * from this follows a full CPU reset path via ROM code to CPU restore code. + * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET. + * It returns to the caller for CPU INACTIVE and ON power states or in case + * CPU failed to transition to targeted OFF/DORMANT state. + */ +ENTRY(omap4_finish_suspend) + stmfd sp!, {lr} + cmp r0, #0x0 + beq do_WFI @ No lowpower state, jump to WFI + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + bl omap4_get_sar_ram_base + ldr r9, [r0, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne skip_secure_l1_clean + mov r0, #SCU_PM_NORMAL + mov r1, #0xFF @ clean seucre L1 + stmfd r13!, {r4-r12, r14} + ldr r12, =OMAP4_MON_SCU_PWR_INDEX + DO_SMC + ldmfd r13!, {r4-r12, r14} +skip_secure_l1_clean: + bl v7_flush_dcache_all + + /* + * Clear the SCTLR.C bit to prevent further data cache + * allocation. Clearing SCTLR.C would make all the data accesses + * strongly ordered and would not hit the cache. + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #(1 << 2) @ Disable the C bit + mcr p15, 0, r0, c1, c0, 0 + isb + + /* + * Invalidate L1 data cache. Even though only invalidate is + * necessary exported flush API is used here. Doing clean + * on already clean cache would be almost NOP. + */ + bl v7_flush_dcache_all + + /* + * Switch the CPU from Symmetric Multiprocessing (SMP) mode + * to AsymmetricMultiprocessing (AMP) mode by programming + * the SCU power status to DORMANT or OFF mode. + * This enables the CPU to be taken out of coherency by + * preventing the CPU from receiving cache, TLB, or BTB + * maintenance operations broadcast by other CPUs in the cluster. + */ + bl omap4_get_sar_ram_base + mov r8, r0 + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne scu_gp_set + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + ldreq r0, [r8, #SCU_OFFSET0] + ldrne r0, [r8, #SCU_OFFSET1] + mov r1, #0x00 + stmfd r13!, {r4-r12, r14} + ldr r12, =OMAP4_MON_SCU_PWR_INDEX + DO_SMC + ldmfd r13!, {r4-r12, r14} + b skip_scu_gp_set +scu_gp_set: + mrc p15, 0, r0, c0, c0, 5 @ Read MPIDR + ands r0, r0, #0x0f + ldreq r1, [r8, #SCU_OFFSET0] + ldrne r1, [r8, #SCU_OFFSET1] + bl omap4_get_scu_base + bl scu_power_mode +skip_scu_gp_set: + mrc p15, 0, r0, c1, c1, 2 @ Read NSACR data + tst r0, #(1 << 18) + mrcne p15, 0, r0, c1, c0, 1 + bicne r0, r0, #(1 << 6) @ Disable SMP bit + mcrne p15, 0, r0, c1, c0, 1 + isb + dsb + +do_WFI: + bl omap_do_wfi + + /* + * CPU is here when it failed to enter OFF/DORMANT or + * no low power state was attempted. + */ + mrc p15, 0, r0, c1, c0, 0 + tst r0, #(1 << 2) @ Check C bit enabled? + orreq r0, r0, #(1 << 2) @ Enable the C bit + mcreq p15, 0, r0, c1, c0, 0 + isb + + /* + * Ensure the CPU power state is set to NORMAL in + * SCU power state so that CPU is back in coherency. + * In non-coherent mode CPU can lock-up and lead to + * system deadlock. + */ + mrc p15, 0, r0, c1, c0, 1 + tst r0, #(1 << 6) @ Check SMP bit enabled? + orreq r0, r0, #(1 << 6) + mcreq p15, 0, r0, c1, c0, 1 + isb + bl omap4_get_sar_ram_base + mov r8, r0 + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Check for HS device + bne scu_gp_clear + mov r0, #SCU_PM_NORMAL + mov r1, #0x00 + stmfd r13!, {r4-r12, r14} + ldr r12, =OMAP4_MON_SCU_PWR_INDEX + DO_SMC + ldmfd r13!, {r4-r12, r14} + b skip_scu_gp_clear +scu_gp_clear: + bl omap4_get_scu_base + mov r1, #SCU_PM_NORMAL + bl scu_power_mode +skip_scu_gp_clear: + isb + dsb + ldmfd sp!, {pc} +ENDPROC(omap4_finish_suspend) + +/* + * ============================ + * == CPU resume entry point == + * ============================ + * + * void omap4_cpu_resume(void) + * + * ROM code jumps to this function while waking up from CPU + * OFF or DORMANT state. Physical address of the function is + * stored in the SAR RAM while entering to OFF or DORMANT mode. + * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET. + */ +ENTRY(omap4_cpu_resume) + /* + * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. + * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA + * init and for CPU1, a secure PPA API provided. CPU0 must be ON + * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+. + * OMAP443X GP devices- SMP bit isn't accessible. + * OMAP446X GP devices - SMP bit access is enabled on both CPUs. + */ + ldr r8, =OMAP44XX_SAR_RAM_BASE + ldr r9, [r8, #OMAP_TYPE_OFFSET] + cmp r9, #0x1 @ Skip if GP device + bne skip_ns_smp_enable + mrc p15, 0, r0, c0, c0, 5 + ands r0, r0, #0x0f + beq skip_ns_smp_enable +ppa_actrl_retry: + mov r0, #OMAP4_PPA_CPU_ACTRL_SMP_INDEX + adr r3, ppa_zero_params @ Pointer to parameters + mov r1, #0x0 @ Process ID + mov r2, #0x4 @ Flag + mov r6, #0xff + mov r12, #0x00 @ Secure Service ID + DO_SMC + cmp r0, #0x0 @ API returns 0 on success. + beq enable_smp_bit + b ppa_actrl_retry +enable_smp_bit: + mrc p15, 0, r0, c1, c0, 1 + tst r0, #(1 << 6) @ Check SMP bit enabled? + orreq r0, r0, #(1 << 6) + mcreq p15, 0, r0, c1, c0, 1 + isb +skip_ns_smp_enable: + + b cpu_resume @ Jump to generic resume +ENDPROC(omap4_cpu_resume) +#endif + +ENTRY(omap_do_wfi) + stmfd sp!, {lr} + + /* + * Execute an ISB instruction to ensure that all of the + * CP15 register changes have been committed. + */ + isb + + /* + * Execute a barrier instruction to ensure that all cache, + * TLB and branch predictor maintenance operations issued + * by any CPU in the cluster have completed. + */ + dsb + dmb + + /* + * Execute a WFI instruction and wait until the + * STANDBYWFI output is asserted to indicate that the + * CPU is in idle and low power state. CPU can specualatively + * prefetch the instructions so add NOPs after WFI. Sixteen + * NOPs as per Cortex-A9 pipeline. + */ + wfi @ Wait For Interrupt + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + ldmfd sp!, {pc} +ENDPROC(omap_do_wfi) -- cgit v1.2.3 From 0f3cf2ec81aeb4747624954bae2cc8decc48e12f Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 16 Jun 2010 23:29:31 +0530 Subject: ARM: OMAP4: PM: Add WakeupGen and secure GIC low power support Add WakeupGen and secure GIC low power support to save and restore it's registers. WakeupGen Registers are saved to pre-defined SAR RAM layout and the restore is automatically done by hardware(ROM code) while coming out of MPUSS OSWR or Device off state. Secure GIC is saved using secure API and restored by hardware like WakeupGen. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap-wakeupgen.c | 131 +++++++++++++++++++++++++++++++++ arch/arm/mach-omap2/omap4-sar-layout.h | 15 ++++ 2 files changed, 146 insertions(+) (limited to 'arch/arm/mach-omap2/omap4-sar-layout.h') diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 701dfecad64b..d3d8971d7f30 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -22,10 +22,16 @@ #include #include #include +#include +#include #include #include +#include + +#include "omap4-sar-layout.h" +#include "common.h" #define NR_REG_BANKS 4 #define MAX_IRQS 128 @@ -36,6 +42,7 @@ #define CPU1_ID 0x1 static void __iomem *wakeupgen_base; +static void __iomem *sar_base; static DEFINE_PER_CPU(u32 [NR_REG_BANKS], irqmasks); static DEFINE_SPINLOCK(wakeupgen_lock); static unsigned int irq_target_cpu[NR_IRQS]; @@ -55,6 +62,11 @@ static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu) (cpu * CPU_ENA_OFFSET) + (idx * 4)); } +static inline void sar_writel(u32 val, u32 offset, u8 idx) +{ + __raw_writel(val, sar_base + offset + (idx * 4)); +} + static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg) { u8 i; @@ -180,6 +192,93 @@ static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set) spin_unlock_irqrestore(&wakeupgen_lock, flags); } +#ifdef CONFIG_CPU_PM +/* + * Save WakeupGen interrupt context in SAR BANK3. Restore is done by + * ROM code. WakeupGen IP is integrated along with GIC to manage the + * interrupt wakeups from CPU low power states. It manages + * masking/unmasking of Shared peripheral interrupts(SPI). So the + * interrupt enable/disable control should be in sync and consistent + * at WakeupGen and GIC so that interrupts are not lost. + */ +static void irq_save_context(void) +{ + u32 i, val; + + if (omap_rev() == OMAP4430_REV_ES1_0) + return; + + if (!sar_base) + sar_base = omap4_get_sar_ram_base(); + + for (i = 0; i < NR_REG_BANKS; i++) { + /* Save the CPUx interrupt mask for IRQ 0 to 127 */ + val = wakeupgen_readl(i, 0); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i); + val = wakeupgen_readl(i, 1); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i); + + /* + * Disable the secure interrupts for CPUx. The restore + * code blindly restores secure and non-secure interrupt + * masks from SAR RAM. Secure interrupts are not suppose + * to be enabled from HLOS. So overwrite the SAR location + * so that the secure interrupt remains disabled. + */ + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i); + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i); + } + + /* Save AuxBoot* registers */ + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + + /* Save SyncReq generation logic */ + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT0_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + __raw_writel(val, sar_base + AUXCOREBOOT1_OFFSET); + + /* Save SyncReq generation logic */ + val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_MASK); + __raw_writel(val, sar_base + PTMSYNCREQ_MASK_OFFSET); + val = __raw_readl(wakeupgen_base + OMAP_PTMSYNCREQ_EN); + __raw_writel(val, sar_base + PTMSYNCREQ_EN_OFFSET); + + /* Set the Backup Bit Mask status */ + val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + val |= SAR_BACKUP_STATUS_WAKEUPGEN; + __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); +} + +/* + * Clear WakeupGen SAR backup status. + */ +void irq_sar_clear(void) +{ + u32 val; + val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET); + val &= ~SAR_BACKUP_STATUS_WAKEUPGEN; + __raw_writel(val, sar_base + SAR_BACKUP_STATUS_OFFSET); +} + +/* + * Save GIC and Wakeupgen interrupt context using secure API + * for HS/EMU devices. + */ +static void irq_save_secure_context(void) +{ + u32 ret; + ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX, + FLAG_START_CRITICAL, + 0, 0, 0, 0, 0); + if (ret != API_HAL_RET_VALUE_OK) + pr_err("GIC and Wakeupgen context save failed\n"); +} +#endif + #ifdef CONFIG_HOTPLUG_CPU static int __cpuinit irq_cpu_hotplug_notify(struct notifier_block *self, unsigned long action, void *hcpu) @@ -210,6 +309,37 @@ static void __init irq_hotplug_init(void) {} #endif +#ifdef CONFIG_CPU_PM +static int irq_notifier(struct notifier_block *self, unsigned long cmd, void *v) +{ + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + irq_save_context(); + else + irq_save_secure_context(); + break; + case CPU_CLUSTER_PM_EXIT: + if (omap_type() == OMAP2_DEVICE_TYPE_GP) + irq_sar_clear(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block irq_notifier_block = { + .notifier_call = irq_notifier, +}; + +static void __init irq_pm_init(void) +{ + cpu_pm_register_notifier(&irq_notifier_block); +} +#else +static void __init irq_pm_init(void) +{} +#endif + /* * Initialise the wakeupgen module. */ @@ -253,6 +383,7 @@ int __init omap_wakeupgen_init(void) irq_target_cpu[i] = boot_cpu; irq_hotplug_init(); + irq_pm_init(); return 0; } diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h index 970a2eef3ab9..aa14a8dd2505 100644 --- a/arch/arm/mach-omap2/omap4-sar-layout.h +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -28,4 +28,19 @@ #define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04 #define CPU1_WAKEUP_NS_PA_ADDR_OFFSET 0xa08 +#define SAR_BACKUP_STATUS_OFFSET (SAR_BANK3_OFFSET + 0x500) +#define SAR_SECURE_RAM_SIZE_OFFSET (SAR_BANK3_OFFSET + 0x504) +#define SAR_SECRAM_SAVED_AT_OFFSET (SAR_BANK3_OFFSET + 0x508) + +/* WakeUpGen save restore offset from OMAP44XX_SAR_RAM_BASE */ +#define WAKEUPGENENB_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x684) +#define WAKEUPGENENB_SECURE_OFFSET_CPU0 (SAR_BANK3_OFFSET + 0x694) +#define WAKEUPGENENB_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x6a4) +#define WAKEUPGENENB_SECURE_OFFSET_CPU1 (SAR_BANK3_OFFSET + 0x6b4) +#define AUXCOREBOOT0_OFFSET (SAR_BANK3_OFFSET + 0x6c4) +#define AUXCOREBOOT1_OFFSET (SAR_BANK3_OFFSET + 0x6c8) +#define PTMSYNCREQ_MASK_OFFSET (SAR_BANK3_OFFSET + 0x6cc) +#define PTMSYNCREQ_EN_OFFSET (SAR_BANK3_OFFSET + 0x6d0) +#define SAR_BACKUP_STATUS_WAKEUPGEN 0x10 + #endif -- cgit v1.2.3 From 5e94c6e33e7c4726ef09f46c267e9ca232c5148a Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Sun, 9 Jan 2011 02:59:09 +0530 Subject: ARM: OMAP4: PM: Add L2X0 cache lowpower support When MPUSS hits off-mode, L2 cache is lost. This patch adds L2X0 necessary maintenance operations and context restoration in the low power code. Signed-off-by: Santosh Shilimkar Acked-by: Jean Pihet Reviewed-by: Kevin Hilman Tested-by: Vishwanath BS Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/include/mach/omap-secure.h | 5 ++ arch/arm/mach-omap2/omap-mpuss-lowpower.c | 41 ++++++++++- arch/arm/mach-omap2/omap4-sar-layout.h | 4 ++ arch/arm/mach-omap2/sleep44xx.S | 95 ++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/omap4-sar-layout.h') diff --git a/arch/arm/mach-omap2/include/mach/omap-secure.h b/arch/arm/mach-omap2/include/mach/omap-secure.h index 5f0763dd5664..c90a43589abe 100644 --- a/arch/arm/mach-omap2/include/mach/omap-secure.h +++ b/arch/arm/mach-omap2/include/mach/omap-secure.h @@ -37,8 +37,13 @@ /* Secure Monitor mode APIs */ #define OMAP4_MON_SCU_PWR_INDEX 0x108 +#define OMAP4_MON_L2X0_DBG_CTRL_INDEX 0x100 +#define OMAP4_MON_L2X0_CTRL_INDEX 0x102 +#define OMAP4_MON_L2X0_AUXCTRL_INDEX 0x109 +#define OMAP4_MON_L2X0_PREFETCH_INDEX 0x113 /* Secure PPA(Primary Protected Application) APIs */ +#define OMAP4_PPA_L2_POR_INDEX 0x23 #define OMAP4_PPA_CPU_ACTRL_SMP_INDEX 0x25 #ifndef __ASSEMBLER__ diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index f9bb2b3d977b..907a048fe5e9 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -63,10 +64,12 @@ struct omap4_cpu_pm_info { struct powerdomain *pwrdm; void __iomem *scu_sar_addr; void __iomem *wkup_sar_addr; + void __iomem *l2x0_sar_addr; }; static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); static struct powerdomain *mpuss_pd; +static void __iomem *sar_base; /* * Program the wakeup routine address for the CPU0 and CPU1 @@ -135,6 +138,36 @@ static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); } +/* + * Store the CPU cluster state for L2X0 low power operations. + */ +static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state) +{ + struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); + + __raw_writel(save_state, pm_info->l2x0_sar_addr); +} + +/* + * Save the L2X0 AUXCTRL and POR value to SAR memory. Its used to + * in every restore MPUSS OFF path. + */ +#ifdef CONFIG_CACHE_L2X0 +static void 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); +} +#else +static void save_l2x0_context(void) +{} +#endif + /** * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function * The purpose of this function is to manage low power programming @@ -182,6 +215,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) set_cpu_next_pwrst(cpu, power_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); scu_pwrst_prepare(cpu, power_state); + l2x0_pwrst_prepare(cpu, save_state); /* * Call low level function with targeted low power state. @@ -239,17 +273,19 @@ int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) int __init omap4_mpuss_init(void) { struct omap4_cpu_pm_info *pm_info; - void __iomem *sar_base = omap4_get_sar_ram_base(); if (omap_rev() == OMAP4430_REV_ES1_0) { WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); return -ENODEV; } + 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; pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); if (!pm_info->pwrdm) { pr_err("Lookup failed for CPU0 pwrdm\n"); @@ -265,6 +301,7 @@ int __init omap4_mpuss_init(void) 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; pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); if (!pm_info->pwrdm) { pr_err("Lookup failed for CPU1 pwrdm\n"); @@ -290,6 +327,8 @@ int __init omap4_mpuss_init(void) else __raw_writel(0, sar_base + OMAP_TYPE_OFFSET); + save_l2x0_context(); + return 0; } diff --git a/arch/arm/mach-omap2/omap4-sar-layout.h b/arch/arm/mach-omap2/omap4-sar-layout.h index aa14a8dd2505..fe5b545ad443 100644 --- a/arch/arm/mach-omap2/omap4-sar-layout.h +++ b/arch/arm/mach-omap2/omap4-sar-layout.h @@ -23,6 +23,10 @@ #define SCU_OFFSET0 0xd00 #define SCU_OFFSET1 0xd04 #define OMAP_TYPE_OFFSET 0xd10 +#define L2X0_SAVE_OFFSET0 0xd14 +#define L2X0_SAVE_OFFSET1 0xd18 +#define L2X0_AUXCTRL_OFFSET 0xd1c +#define L2X0_PREFETCH_CTRL_OFFSET 0xd20 /* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */ #define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04 diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S index e5521945ba8e..3154b63def35 100644 --- a/arch/arm/mach-omap2/sleep44xx.S +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -32,6 +32,9 @@ ppa_zero_params: .word 0x0 +ppa_por_params: + .word 1, 0 + /* * ============================= * == CPU suspend finisher == @@ -132,6 +135,54 @@ skip_scu_gp_set: mcrne p15, 0, r0, c1, c0, 1 isb dsb +#ifdef CONFIG_CACHE_L2X0 + /* + * Clean and invalidate the L2 cache. + * Common cache-l2x0.c functions can't be used here since it + * uses spinlocks. We are out of coherency here with data cache + * disabled. The spinlock implementation uses exclusive load/store + * instruction which can fail without data cache being enabled. + * OMAP4 hardware doesn't support exclusive monitor which can + * overcome exclusive access issue. Because of this, CPU can + * lead to deadlock. + */ + bl omap4_get_sar_ram_base + mov r8, r0 + mrc p15, 0, r5, c0, c0, 5 @ Read MPIDR + ands r5, r5, #0x0f + ldreq r0, [r8, #L2X0_SAVE_OFFSET0] @ Retrieve L2 state from SAR + ldrne r0, [r8, #L2X0_SAVE_OFFSET1] @ memory. + cmp r0, #3 + bne do_WFI +#ifdef CONFIG_PL310_ERRATA_727915 + mov r0, #0x03 + mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX + DO_SMC +#endif + bl omap4_get_l2cache_base + mov r2, r0 + ldr r0, =0xffff + str r0, [r2, #L2X0_CLEAN_INV_WAY] +wait: + ldr r0, [r2, #L2X0_CLEAN_INV_WAY] + ldr r1, =0xffff + ands r0, r0, r1 + bne wait +#ifdef CONFIG_PL310_ERRATA_727915 + mov r0, #0x00 + mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX + DO_SMC +#endif +l2x_sync: + bl omap4_get_l2cache_base + mov r2, r0 + mov r0, #0x0 + str r0, [r2, #L2X0_CACHE_SYNC] +sync: + ldr r0, [r2, #L2X0_CACHE_SYNC] + ands r0, r0, #0x1 + bne sync +#endif do_WFI: bl omap_do_wfi @@ -225,6 +276,50 @@ enable_smp_bit: mcreq p15, 0, r0, c1, c0, 1 isb skip_ns_smp_enable: +#ifdef CONFIG_CACHE_L2X0 + /* + * Restore the L2 AUXCTRL and enable the L2 cache. + * OMAP4_MON_L2X0_AUXCTRL_INDEX = Program the L2X0 AUXCTRL + * OMAP4_MON_L2X0_CTRL_INDEX = Enable the L2 using L2X0 CTRL + * register r0 contains value to be programmed. + * L2 cache is already invalidate by ROM code as part + * of MPUSS OFF wakeup path. + */ + ldr r2, =OMAP44XX_L2CACHE_BASE + ldr r0, [r2, #L2X0_CTRL] + and r0, #0x0f + cmp r0, #1 + beq skip_l2en @ Skip if already enabled + ldr r3, =OMAP44XX_SAR_RAM_BASE + ldr r1, [r3, #OMAP_TYPE_OFFSET] + cmp r1, #0x1 @ Check for HS device + bne set_gp_por + ldr r0, =OMAP4_PPA_L2_POR_INDEX + ldr r1, =OMAP44XX_SAR_RAM_BASE + ldr r4, [r1, #L2X0_PREFETCH_CTRL_OFFSET] + adr r3, ppa_por_params + str r4, [r3, #0x04] + mov r1, #0x0 @ Process ID + mov r2, #0x4 @ Flag + mov r6, #0xff + mov r12, #0x00 @ Secure Service ID + DO_SMC + b set_aux_ctrl +set_gp_por: + ldr r1, =OMAP44XX_SAR_RAM_BASE + ldr r0, [r1, #L2X0_PREFETCH_CTRL_OFFSET] + ldr r12, =OMAP4_MON_L2X0_PREFETCH_INDEX @ Setup L2 PREFETCH + DO_SMC +set_aux_ctrl: + ldr r1, =OMAP44XX_SAR_RAM_BASE + ldr r0, [r1, #L2X0_AUXCTRL_OFFSET] + ldr r12, =OMAP4_MON_L2X0_AUXCTRL_INDEX @ Setup L2 AUXCTRL + DO_SMC + mov r0, #0x1 + ldr r12, =OMAP4_MON_L2X0_CTRL_INDEX @ Enable L2 cache + DO_SMC +skip_l2en: +#endif b cpu_resume @ Jump to generic resume ENDPROC(omap4_cpu_resume) -- cgit v1.2.3