diff options
-rw-r--r-- | arch/arm/mach-omap2/include/mach/omap-secure.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-mpuss-lowpower.c | 41 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap4-sar-layout.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/sleep44xx.S | 95 |
4 files changed, 144 insertions, 1 deletions
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 @@ | |||
37 | 37 | ||
38 | /* Secure Monitor mode APIs */ | 38 | /* Secure Monitor mode APIs */ |
39 | #define OMAP4_MON_SCU_PWR_INDEX 0x108 | 39 | #define OMAP4_MON_SCU_PWR_INDEX 0x108 |
40 | #define OMAP4_MON_L2X0_DBG_CTRL_INDEX 0x100 | ||
41 | #define OMAP4_MON_L2X0_CTRL_INDEX 0x102 | ||
42 | #define OMAP4_MON_L2X0_AUXCTRL_INDEX 0x109 | ||
43 | #define OMAP4_MON_L2X0_PREFETCH_INDEX 0x113 | ||
40 | 44 | ||
41 | /* Secure PPA(Primary Protected Application) APIs */ | 45 | /* Secure PPA(Primary Protected Application) APIs */ |
46 | #define OMAP4_PPA_L2_POR_INDEX 0x23 | ||
42 | #define OMAP4_PPA_CPU_ACTRL_SMP_INDEX 0x25 | 47 | #define OMAP4_PPA_CPU_ACTRL_SMP_INDEX 0x25 |
43 | 48 | ||
44 | #ifndef __ASSEMBLER__ | 49 | #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 @@ | |||
49 | #include <asm/system.h> | 49 | #include <asm/system.h> |
50 | #include <asm/pgalloc.h> | 50 | #include <asm/pgalloc.h> |
51 | #include <asm/suspend.h> | 51 | #include <asm/suspend.h> |
52 | #include <asm/hardware/cache-l2x0.h> | ||
52 | 53 | ||
53 | #include <plat/omap44xx.h> | 54 | #include <plat/omap44xx.h> |
54 | 55 | ||
@@ -63,10 +64,12 @@ struct omap4_cpu_pm_info { | |||
63 | struct powerdomain *pwrdm; | 64 | struct powerdomain *pwrdm; |
64 | void __iomem *scu_sar_addr; | 65 | void __iomem *scu_sar_addr; |
65 | void __iomem *wkup_sar_addr; | 66 | void __iomem *wkup_sar_addr; |
67 | void __iomem *l2x0_sar_addr; | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); | 70 | static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info); |
69 | static struct powerdomain *mpuss_pd; | 71 | static struct powerdomain *mpuss_pd; |
72 | static void __iomem *sar_base; | ||
70 | 73 | ||
71 | /* | 74 | /* |
72 | * Program the wakeup routine address for the CPU0 and CPU1 | 75 | * 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) | |||
135 | __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); | 138 | __raw_writel(scu_pwr_st, pm_info->scu_sar_addr); |
136 | } | 139 | } |
137 | 140 | ||
141 | /* | ||
142 | * Store the CPU cluster state for L2X0 low power operations. | ||
143 | */ | ||
144 | static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state) | ||
145 | { | ||
146 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); | ||
147 | |||
148 | __raw_writel(save_state, pm_info->l2x0_sar_addr); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Save the L2X0 AUXCTRL and POR value to SAR memory. Its used to | ||
153 | * in every restore MPUSS OFF path. | ||
154 | */ | ||
155 | #ifdef CONFIG_CACHE_L2X0 | ||
156 | static void save_l2x0_context(void) | ||
157 | { | ||
158 | u32 val; | ||
159 | void __iomem *l2x0_base = omap4_get_l2cache_base(); | ||
160 | |||
161 | val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); | ||
162 | __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); | ||
163 | val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); | ||
164 | __raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET); | ||
165 | } | ||
166 | #else | ||
167 | static void save_l2x0_context(void) | ||
168 | {} | ||
169 | #endif | ||
170 | |||
138 | /** | 171 | /** |
139 | * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function | 172 | * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function |
140 | * The purpose of this function is to manage low power programming | 173 | * 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) | |||
182 | set_cpu_next_pwrst(cpu, power_state); | 215 | set_cpu_next_pwrst(cpu, power_state); |
183 | set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); | 216 | set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); |
184 | scu_pwrst_prepare(cpu, power_state); | 217 | scu_pwrst_prepare(cpu, power_state); |
218 | l2x0_pwrst_prepare(cpu, save_state); | ||
185 | 219 | ||
186 | /* | 220 | /* |
187 | * Call low level function with targeted low power state. | 221 | * Call low level function with targeted low power state. |
@@ -239,17 +273,19 @@ int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) | |||
239 | int __init omap4_mpuss_init(void) | 273 | int __init omap4_mpuss_init(void) |
240 | { | 274 | { |
241 | struct omap4_cpu_pm_info *pm_info; | 275 | struct omap4_cpu_pm_info *pm_info; |
242 | void __iomem *sar_base = omap4_get_sar_ram_base(); | ||
243 | 276 | ||
244 | if (omap_rev() == OMAP4430_REV_ES1_0) { | 277 | if (omap_rev() == OMAP4430_REV_ES1_0) { |
245 | WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); | 278 | WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); |
246 | return -ENODEV; | 279 | return -ENODEV; |
247 | } | 280 | } |
248 | 281 | ||
282 | sar_base = omap4_get_sar_ram_base(); | ||
283 | |||
249 | /* Initilaise per CPU PM information */ | 284 | /* Initilaise per CPU PM information */ |
250 | pm_info = &per_cpu(omap4_pm_info, 0x0); | 285 | pm_info = &per_cpu(omap4_pm_info, 0x0); |
251 | pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; | 286 | pm_info->scu_sar_addr = sar_base + SCU_OFFSET0; |
252 | pm_info->wkup_sar_addr = sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET; | 287 | pm_info->wkup_sar_addr = sar_base + CPU0_WAKEUP_NS_PA_ADDR_OFFSET; |
288 | pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0; | ||
253 | pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); | 289 | pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm"); |
254 | if (!pm_info->pwrdm) { | 290 | if (!pm_info->pwrdm) { |
255 | pr_err("Lookup failed for CPU0 pwrdm\n"); | 291 | pr_err("Lookup failed for CPU0 pwrdm\n"); |
@@ -265,6 +301,7 @@ int __init omap4_mpuss_init(void) | |||
265 | pm_info = &per_cpu(omap4_pm_info, 0x1); | 301 | pm_info = &per_cpu(omap4_pm_info, 0x1); |
266 | pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; | 302 | pm_info->scu_sar_addr = sar_base + SCU_OFFSET1; |
267 | pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; | 303 | pm_info->wkup_sar_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; |
304 | pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1; | ||
268 | pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); | 305 | pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm"); |
269 | if (!pm_info->pwrdm) { | 306 | if (!pm_info->pwrdm) { |
270 | pr_err("Lookup failed for CPU1 pwrdm\n"); | 307 | pr_err("Lookup failed for CPU1 pwrdm\n"); |
@@ -290,6 +327,8 @@ int __init omap4_mpuss_init(void) | |||
290 | else | 327 | else |
291 | __raw_writel(0, sar_base + OMAP_TYPE_OFFSET); | 328 | __raw_writel(0, sar_base + OMAP_TYPE_OFFSET); |
292 | 329 | ||
330 | save_l2x0_context(); | ||
331 | |||
293 | return 0; | 332 | return 0; |
294 | } | 333 | } |
295 | 334 | ||
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 @@ | |||
23 | #define SCU_OFFSET0 0xd00 | 23 | #define SCU_OFFSET0 0xd00 |
24 | #define SCU_OFFSET1 0xd04 | 24 | #define SCU_OFFSET1 0xd04 |
25 | #define OMAP_TYPE_OFFSET 0xd10 | 25 | #define OMAP_TYPE_OFFSET 0xd10 |
26 | #define L2X0_SAVE_OFFSET0 0xd14 | ||
27 | #define L2X0_SAVE_OFFSET1 0xd18 | ||
28 | #define L2X0_AUXCTRL_OFFSET 0xd1c | ||
29 | #define L2X0_PREFETCH_CTRL_OFFSET 0xd20 | ||
26 | 30 | ||
27 | /* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */ | 31 | /* CPUx Wakeup Non-Secure Physical Address offsets in SAR_BANK3 */ |
28 | #define CPU0_WAKEUP_NS_PA_ADDR_OFFSET 0xa04 | 32 | #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 @@ | |||
32 | ppa_zero_params: | 32 | ppa_zero_params: |
33 | .word 0x0 | 33 | .word 0x0 |
34 | 34 | ||
35 | ppa_por_params: | ||
36 | .word 1, 0 | ||
37 | |||
35 | /* | 38 | /* |
36 | * ============================= | 39 | * ============================= |
37 | * == CPU suspend finisher == | 40 | * == CPU suspend finisher == |
@@ -132,6 +135,54 @@ skip_scu_gp_set: | |||
132 | mcrne p15, 0, r0, c1, c0, 1 | 135 | mcrne p15, 0, r0, c1, c0, 1 |
133 | isb | 136 | isb |
134 | dsb | 137 | dsb |
138 | #ifdef CONFIG_CACHE_L2X0 | ||
139 | /* | ||
140 | * Clean and invalidate the L2 cache. | ||
141 | * Common cache-l2x0.c functions can't be used here since it | ||
142 | * uses spinlocks. We are out of coherency here with data cache | ||
143 | * disabled. The spinlock implementation uses exclusive load/store | ||
144 | * instruction which can fail without data cache being enabled. | ||
145 | * OMAP4 hardware doesn't support exclusive monitor which can | ||
146 | * overcome exclusive access issue. Because of this, CPU can | ||
147 | * lead to deadlock. | ||
148 | */ | ||
149 | bl omap4_get_sar_ram_base | ||
150 | mov r8, r0 | ||
151 | mrc p15, 0, r5, c0, c0, 5 @ Read MPIDR | ||
152 | ands r5, r5, #0x0f | ||
153 | ldreq r0, [r8, #L2X0_SAVE_OFFSET0] @ Retrieve L2 state from SAR | ||
154 | ldrne r0, [r8, #L2X0_SAVE_OFFSET1] @ memory. | ||
155 | cmp r0, #3 | ||
156 | bne do_WFI | ||
157 | #ifdef CONFIG_PL310_ERRATA_727915 | ||
158 | mov r0, #0x03 | ||
159 | mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX | ||
160 | DO_SMC | ||
161 | #endif | ||
162 | bl omap4_get_l2cache_base | ||
163 | mov r2, r0 | ||
164 | ldr r0, =0xffff | ||
165 | str r0, [r2, #L2X0_CLEAN_INV_WAY] | ||
166 | wait: | ||
167 | ldr r0, [r2, #L2X0_CLEAN_INV_WAY] | ||
168 | ldr r1, =0xffff | ||
169 | ands r0, r0, r1 | ||
170 | bne wait | ||
171 | #ifdef CONFIG_PL310_ERRATA_727915 | ||
172 | mov r0, #0x00 | ||
173 | mov r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX | ||
174 | DO_SMC | ||
175 | #endif | ||
176 | l2x_sync: | ||
177 | bl omap4_get_l2cache_base | ||
178 | mov r2, r0 | ||
179 | mov r0, #0x0 | ||
180 | str r0, [r2, #L2X0_CACHE_SYNC] | ||
181 | sync: | ||
182 | ldr r0, [r2, #L2X0_CACHE_SYNC] | ||
183 | ands r0, r0, #0x1 | ||
184 | bne sync | ||
185 | #endif | ||
135 | 186 | ||
136 | do_WFI: | 187 | do_WFI: |
137 | bl omap_do_wfi | 188 | bl omap_do_wfi |
@@ -225,6 +276,50 @@ enable_smp_bit: | |||
225 | mcreq p15, 0, r0, c1, c0, 1 | 276 | mcreq p15, 0, r0, c1, c0, 1 |
226 | isb | 277 | isb |
227 | skip_ns_smp_enable: | 278 | skip_ns_smp_enable: |
279 | #ifdef CONFIG_CACHE_L2X0 | ||
280 | /* | ||
281 | * Restore the L2 AUXCTRL and enable the L2 cache. | ||
282 | * OMAP4_MON_L2X0_AUXCTRL_INDEX = Program the L2X0 AUXCTRL | ||
283 | * OMAP4_MON_L2X0_CTRL_INDEX = Enable the L2 using L2X0 CTRL | ||
284 | * register r0 contains value to be programmed. | ||
285 | * L2 cache is already invalidate by ROM code as part | ||
286 | * of MPUSS OFF wakeup path. | ||
287 | */ | ||
288 | ldr r2, =OMAP44XX_L2CACHE_BASE | ||
289 | ldr r0, [r2, #L2X0_CTRL] | ||
290 | and r0, #0x0f | ||
291 | cmp r0, #1 | ||
292 | beq skip_l2en @ Skip if already enabled | ||
293 | ldr r3, =OMAP44XX_SAR_RAM_BASE | ||
294 | ldr r1, [r3, #OMAP_TYPE_OFFSET] | ||
295 | cmp r1, #0x1 @ Check for HS device | ||
296 | bne set_gp_por | ||
297 | ldr r0, =OMAP4_PPA_L2_POR_INDEX | ||
298 | ldr r1, =OMAP44XX_SAR_RAM_BASE | ||
299 | ldr r4, [r1, #L2X0_PREFETCH_CTRL_OFFSET] | ||
300 | adr r3, ppa_por_params | ||
301 | str r4, [r3, #0x04] | ||
302 | mov r1, #0x0 @ Process ID | ||
303 | mov r2, #0x4 @ Flag | ||
304 | mov r6, #0xff | ||
305 | mov r12, #0x00 @ Secure Service ID | ||
306 | DO_SMC | ||
307 | b set_aux_ctrl | ||
308 | set_gp_por: | ||
309 | ldr r1, =OMAP44XX_SAR_RAM_BASE | ||
310 | ldr r0, [r1, #L2X0_PREFETCH_CTRL_OFFSET] | ||
311 | ldr r12, =OMAP4_MON_L2X0_PREFETCH_INDEX @ Setup L2 PREFETCH | ||
312 | DO_SMC | ||
313 | set_aux_ctrl: | ||
314 | ldr r1, =OMAP44XX_SAR_RAM_BASE | ||
315 | ldr r0, [r1, #L2X0_AUXCTRL_OFFSET] | ||
316 | ldr r12, =OMAP4_MON_L2X0_AUXCTRL_INDEX @ Setup L2 AUXCTRL | ||
317 | DO_SMC | ||
318 | mov r0, #0x1 | ||
319 | ldr r12, =OMAP4_MON_L2X0_CTRL_INDEX @ Enable L2 cache | ||
320 | DO_SMC | ||
321 | skip_l2en: | ||
322 | #endif | ||
228 | 323 | ||
229 | b cpu_resume @ Jump to generic resume | 324 | b cpu_resume @ Jump to generic resume |
230 | ENDPROC(omap4_cpu_resume) | 325 | ENDPROC(omap4_cpu_resume) |