msm: idle-v7.S: Change the cache flush sequence operations for 8x25
On current implementation when the core0 enter into either
idlePC/SuspendPC it follows the below sequence to flush the
caches.
1. L2 cache clean & invalidation by way
2. Disable the L2 cache
3. invalidate the L1
4. disable data caching at all levels
5. goto PC
But PL310 TRM says, to avoid any kind of data corruption we need to
follow the below sequence of operations on cache.
1. invalidate the L1
2. disable data caching at all levels
3. L2 cache clean & invalidation by way
4. Disable the L2 cache
5. goto PC
Refer the PL310 TRM Page no: 91 for more information.
Change-Id: I908fcee72dec600945396e073f03517e265656b1
Signed-off-by: Murali Nalajala <mnalajal@codeaurora.org>
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
new file mode 100644
index 0000000..1622e13
--- /dev/null
+++ b/arch/arm/mach-msm/idle-macros.S
@@ -0,0 +1,153 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/hardware/cache-l2x0.h>
+
+/* Add 300 NOPs after 'wfi' for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+ .rept \rept
+ nop
+ .endr
+#endif
+.endm
+
+/* Switch between smp_to_amp/amp_to_smp configuration */
+.macro SET_SMP_COHERENCY, on = 0
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip\@
+ mrc p15, 0, r0, c1, c0, 1 /* read ACTLR register */
+ .if \on
+ orr r0, r0, #(1 << 6) /* Set the SMP bit in ACTLR */
+ .else
+ bic r0, r0, #(1 << 6) /* Clear the SMP bit */
+ .endif
+ mcr p15, 0, r0, c1, c0, 1 /* write ACTLR register */
+ isb
+skip\@:
+.endm
+
+/*
+ * Enable the "L2" cache, not require to restore the controller registers
+ */
+.macro ENABLE_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_enable\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_enable\@
+ ldr r0, =l2x0_base_addr
+ ldr r0, [r0]
+ mov r1, #0x1
+ str r1, [r0, #L2X0_CTRL]
+ dmb
+skip_enable\@:
+.endm
+
+/*
+ * Perform the required operation
+ * operation: type of operation on l2 cache (e.g: clean&inv or inv)
+ * l2_enable: enable or disable
+ */
+.macro DO_CACHE_OPERATION, operation, l2_enable
+ ldr r2, =l2x0_base_addr
+ ldr r2, [r2]
+ ldr r0, =0xffff
+ str r0, [r2, #\operation]
+wait\@:
+ ldr r0, [r2, #\operation]
+ ldr r1, =0xffff
+ ands r0, r0, r1
+ bne wait\@
+l2x_sync\@:
+ mov r0, #0x0
+ str r0, [r2, #L2X0_CACHE_SYNC]
+sync\@:
+ ldr r0, [r2, #L2X0_CACHE_SYNC]
+ ands r0, r0, #0x1
+ bne sync\@
+ mov r1, #\l2_enable
+ str r1, [r2, #L2X0_CTRL]
+.endm
+
+/*
+ * Clean and invalidate the L2 cache.
+ * 1. Check the target type
+ * 2. Check whether we are coming from PC are not
+ * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
+ * 4. Start L2 clean & invalidation operation
+ * 5. Disable the L2 cache
+ */
+.macro SUSPEND_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_suspend\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_suspend\@
+ ldr r0, =l2x0_saved_ctrl_reg_val
+ ldr r1, =l2x0_base_addr
+ ldr r1, [r1]
+ ldr r2, [r1, #L2X0_AUX_CTRL]
+ str r2, [r0, #0x0] /* store aux_ctlr reg value */
+ ldr r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ str r2, [r0, #0x4] /* store data latency reg value */
+ ldr r2, [r1, #L2X0_PREFETCH_CTRL]
+ str r2, [r0, #0x8] /* store prefetch_ctlr reg value */
+ DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
+ dmb
+skip_suspend\@:
+.endm
+
+/*
+ * Coming back from a successful PC
+ * 1. Check the target type
+ * 2. Check whether we are going to PC are not
+ * 3. Disable the L2 cache
+ * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
+ * 5. Invalidate the cache
+ * 6. Enable the L2 cache
+ */
+.macro RESUME_8x25_L2
+ ldr r0, =target_type
+ ldr r0, [r0]
+ mov r1, #TARGET_IS_8625
+ cmp r0, r1
+ bne skip_resume\@
+ ldr r0, =apps_power_collapse
+ ldr r0, [r0]
+ cmp r0, #POWER_COLLAPSED
+ bne skip_resume\@
+ ldr r1, =l2x0_base_addr
+ ldr r1, [r1]
+ mov r0, #0x0
+ str r0, [r1, #L2X0_CTRL]
+ ldr r0, =l2x0_saved_ctrl_reg_val
+ ldr r2, [r0, #0x0]
+ str r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
+ ldr r2, [r0, #0x4]
+ str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ ldr r2, [r0, #0x8]
+ str r2, [r1, #L2X0_PREFETCH_CTRL]
+ DO_CACHE_OPERATION L2X0_INV_WAY ON
+skip_resume\@:
+.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index b73ddc8..b75f76f 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -20,39 +20,13 @@
#include <asm/assembler.h>
#include "idle.h"
+#include "idle-macros.S"
#ifdef CONFIG_ARCH_MSM_KRAIT
#define SCM_SVC_BOOT 0x1
#define SCM_CMD_TERMINATE_PC 0x2
#endif
-/* Switch between smp_to_amp/amp_to_smp configuration */
-.macro SET_SMP_COHERENCY, on = 0
-ldr r0, =target_type
-ldr r0, [r0]
-mov r1, #TARGET_IS_8625
-cmp r0, r1
-bne skip\@
-mrc p15, 0, r0, c1, c0, 1 /* read ACTLR register */
-.if \on
-orr r0, r0, #(1 << 6) /* Set the SMP bit in ACTLR */
-.else
-bic r0, r0, #(1 << 6) /* Clear the SMP bit */
-.endif
-mcr p15, 0, r0, c1, c0, 1 /* write ACTLR register */
-isb
-skip\@:
-.endm
-
-/* Add NOPs for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
- .rept \rept
- nop
- .endr
-#endif
-.endm
-
ENTRY(msm_arch_idle)
wfi
#ifdef CONFIG_ARCH_MSM8X60
@@ -135,16 +109,19 @@
bic r0, r4, #(1 << 2) /* clear dcache bit */
bic r0, r0, #(1 << 12) /* clear icache bit */
mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
- dsb
+ isb
+ SUSPEND_8x25_L2
SET_SMP_COHERENCY OFF
wfi
DELAY_8x25 300
mcr p15, 0, r4, c1, c0, 0 /* restore d/i cache */
isb
-#endif
+ ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
SET_SMP_COHERENCY ON
+#endif
+
#if defined(CONFIG_MSM_FIQ_SUPPORT)
cpsie f
#endif
@@ -237,7 +214,6 @@
dsb
isb
- SET_SMP_COHERENCY ON
#ifdef CONFIG_ARCH_MSM_KRAIT
mrc p15, 0, r1, c0, c0, 0
ldr r3, =0xff00fc00
@@ -247,7 +223,11 @@
mrceq p15, 7, r3, c15, c0, 2
biceq r3, r3, #0x400
mcreq p15, 7, r3, c15, c0, 2
+#else
+ RESUME_8x25_L2
+ SET_SMP_COHERENCY ON
#endif
+
#ifdef CONFIG_MSM_JTAG
stmfd sp!, {lr}
bl msm_jtag_restore_state
@@ -302,6 +282,14 @@
target_type:
.long 0x0
+ .globl apps_power_collapse
+apps_power_collapse:
+ .long 0x0
+
+ .globl l2x0_base_addr
+l2x0_base_addr:
+ .long 0x0
+
/*
* Default the l2 flush flag to 1 so that caches are flushed during power
* collapse unless the L2 driver decides to flush them only during L2
@@ -309,3 +297,13 @@
*/
msm_pm_flush_l2_flag:
.long 0x1
+
+/*
+ * Save & restore l2x0 registers while system is entering and resuming
+ * from Power Collapse.
+ * 1. aux_ctrl_save (0x0)
+ * 2. data_latency_ctrl (0x4)
+ * 3. prefetch control (0x8)
+ */
+l2x0_saved_ctrl_reg_val:
+ .space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index bfd632f..4abdd04 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -25,6 +25,7 @@
#define ON 1
#define OFF 0
#define TARGET_IS_8625 1
+#define POWER_COLLAPSED 1
#ifndef __ASSEMBLY__
@@ -40,6 +41,8 @@
extern unsigned long msm_pm_pc_pgd;
extern unsigned long msm_pm_boot_vector[NR_CPUS];
extern uint32_t target_type;
+extern uint32_t apps_power_collapse;
+extern uint32_t *l2x0_base_addr;
#else
static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
{
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 3b78cf5..426d6e6 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -954,7 +954,10 @@
#endif
#ifdef CONFIG_CACHE_L2X0
- l2cc_suspend();
+ if (!cpu_is_msm8625())
+ l2cc_suspend();
+ else
+ apps_power_collapse = 1;
#endif
collapsed = msm_pm_collapse();
@@ -981,7 +984,10 @@
}
#ifdef CONFIG_CACHE_L2X0
- l2cc_resume();
+ if (!cpu_is_msm8625())
+ l2cc_resume();
+ else
+ apps_power_collapse = 0;
#endif
msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1720,6 +1726,8 @@
*/
val = 0x00030002;
__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
+
+ l2x0_base_addr = MSM_L2CC_BASE;
}
#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE