Exynos: Fix L2 cache timings on Exynos5420 and Exynos5800
It was found that the L2 cache timings that we had before could cause
freezes and hangs. We should make things more robust with better
timings. Currently the production ChromeOS kernel applies these
timings, but it's nice to fixup firmware too (and upstream probably
won't take our kernel hacks).
This also provides a big cleanup of the L2 cache init code avoiding
some duplication. The way things used to work:
* low_power_start() was installed by the SPL (both at boot and resume
time) and left resident in iRAM for the kernel to use when bringing
up additional CPUs. It used configure_l2_ctlr() and
configure_l2_actlr() when it detected it was on an A15. This was
needed (despite the L2 cache registers being shared among all A15s)
because we might have been the first man in after the whole A15
cluster was shutdown.
* secondary_cores_configure() was called on at boot time and at resume
time. Strangely this called configure_l2_ctlr() but not
configure_l2_actlr() which was almost certainly wrong. Given that
we'll call both (see next bullet) later in the boot process it
didn't matter for normal boot, but I guess this is how L2 cache
settings got set on 5420/5800 (but not 5250?) at resume time.
* exynos5_set_l2cache_params() was called as part of cache enablement.
This should happen at boot time (normally in the SPL except for USB
boot where it happens in main U-Boot).
Note that the old code wasn't setting ECC/parity in the cache
enablement code but we happened to get it anyway because we'd call
secondary_cores_configure() at boot time. For resume time we'd get it
anyway when the 2nd A15 core came up.
Let's make this a whole lot simpler. Now we always set these
parameters in the same place for all boots and use the same code for
setting up secondary CPUs.
Intended net effects of this change (other than cleanup):
* Timings go from before:
data: 0 cycle setup, 3 cycles (0x2) latency
tag: 0 cycle setup, 3 cycles (0x2) latency
after:
data: 1 cycle setup, 4 cycles (0x3) latency
tag: 1 cycle setup, 4 cycles (0x3) latency
* L2ACTLR is properly initted on 5420/5800 in all cases.
One note is that we're still relying on luck to keep low_power_start()
working. The compiler is being nice and not storing anything on the
stack.
Another note is that on its own this patch won't help to fix cache
settings in an RW U-Boot update where we still have the RO SPL. The
plan for that is:
* Have RW U-Boot re-init the cache right before calling the kernel
(after it has turned the L2 cache off). This is why the functions
are in a header file instead of lowlevel_init.c.
* Have the kernel save the L2 cache settings of the boot CPU and apply
them to all other CPUs. We get a little lucky here because the old
code was using "|=" to modify the registers and all of the bits that
it's setting are also present in the new settings (!). That means
that when the 2nd CPU in the A15 cluster comes up it doesn't
actually mess up the settings of the 1st CPU in the A15 cluster. An
alternative option is to have the kernel write its own
low_power_start() code.
Signed-off-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
diff --git a/arch/arm/cpu/armv7/exynos/common_setup.h b/arch/arm/cpu/armv7/exynos/common_setup.h
index e6318c0..5235abb 100644
--- a/arch/arm/cpu/armv7/exynos/common_setup.h
+++ b/arch/arm/cpu/armv7/exynos/common_setup.h
@@ -23,6 +23,8 @@
* MA 02111-1307 USA
*/
+#include <asm/arch/system.h>
+
#define DMC_OFFSET 0x10000
/*
@@ -43,3 +45,63 @@
int do_lowlevel_init(void);
void sdelay(unsigned long);
+
+enum l2_cache_params {
+ CACHE_DATA_RAM_LATENCY_2_CYCLES = (2 << 0),
+ CACHE_DATA_RAM_LATENCY_3_CYCLES = (3 << 0),
+ CACHE_DISABLE_CLEAN_EVICT = (1 << 3),
+ CACHE_DATA_RAM_SETUP = (1 << 5),
+ CACHE_TAG_RAM_LATENCY_2_CYCLES = (2 << 6),
+ CACHE_TAG_RAM_LATENCY_3_CYCLES = (3 << 6),
+ CACHE_ENABLE_HAZARD_DETECT = (1 << 7),
+ CACHE_TAG_RAM_SETUP = (1 << 9),
+ CACHE_ECC_AND_PARITY = (1 << 21),
+ CACHE_ENABLE_FORCE_L2_LOGIC = (1 << 27)
+};
+
+
+#ifndef CONFIG_SYS_L2CACHE_OFF
+/*
+ * Configure L2CTLR to get timings that keep us from hanging/crashing.
+ *
+ * Must be inline here since low_power_start() is called without a
+ * stack (!).
+ */
+static inline void configure_l2_ctlr(void)
+{
+ uint32_t val;
+
+ mrc_l2_ctlr(val);
+
+ val |= CACHE_TAG_RAM_SETUP |
+ CACHE_DATA_RAM_SETUP |
+ CACHE_TAG_RAM_LATENCY_2_CYCLES |
+ CACHE_DATA_RAM_LATENCY_2_CYCLES;
+
+ if (proid_is_exynos5420() || proid_is_exynos5800()) {
+ val |= CACHE_ECC_AND_PARITY |
+ CACHE_TAG_RAM_LATENCY_3_CYCLES |
+ CACHE_DATA_RAM_LATENCY_3_CYCLES;
+ }
+
+ mcr_l2_ctlr(val);
+}
+
+/*
+ * Configure L2ACTLR.
+ *
+ * Must be inline here since low_power_start() is called without a
+ * stack (!).
+ */
+static inline void configure_l2_actlr(void)
+{
+ uint32_t val;
+
+ if (proid_is_exynos5420() || proid_is_exynos5800()) {
+ mrc_l2_aux_ctlr(val);
+ val |= CACHE_ENABLE_FORCE_L2_LOGIC |
+ CACHE_DISABLE_CLEAN_EVICT;
+ mcr_l2_aux_ctlr(val);
+ }
+}
+#endif
diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
index 329ab0c..120aaf8 100644
--- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c
+++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
@@ -47,42 +47,6 @@
#ifdef CONFIG_EXYNOS5420
/*
- * Enable ECC by setting L2CTLR[21].
- * Set L2CTLR[7] to make tag ram latency 3 cycles and
- * set L2CTLR[1] to make data ram latency 3 cycles.
- * We need to make RAM latency of 3 cycles here because cores
- * power ON and OFF while switching. And everytime a core powers
- * ON, iROM provides it a default L2CTLR value 0x400 which stands
- * for TAG RAM setup of 1 cycle. Hence, we face a need of
- * restoring data and tag latency values.
- */
-static void configure_l2_ctlr(void)
-{
- uint32_t val;
-
- mrc_l2_ctlr(val);
- val |= (1 << 21);
- val |= (1 << 7);
- val |= (1 << 1);
- mcr_l2_ctlr(val);
-}
-
-/*
- * Set L2ACTLR[27] to prevent the clock generator from stopping
- * the L2 logic clock.
- * Set L2ACTLR[3] to disable clean/evict push to external.
- */
-static void configure_l2_actlr(void)
-{
- uint32_t val;
-
- mrc_l2_aux_ctlr(val);
- val |= (1 << 27);
- val |= (1 << 3);
- mcr_l2_aux_ctlr(val);
-}
-
-/*
* Power up secondary CPUs.
*/
static void secondary_cpu_start(void)
@@ -185,10 +149,6 @@
*/
static void secondary_cores_configure(void)
{
- /* Setup L2 cache */
- configure_l2_ctlr();
- v7_enable_l2_hazard_detect();
-
/* Clear secondary boot iRAM base */
writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C));
@@ -214,6 +174,21 @@
arch_cpu_init();
+#ifndef CONFIG_SYS_L2CACHE_OFF
+ /*
+ * Init L2 cache parameters here for use by boot and resume
+ *
+ * These are here instead of in v7_outer_cache_enable() so that the
+ * L2 cache settings get properly set even at resume time or if we're
+ * running U-Boot with the cache off. The kernel still needs us to
+ * set these for it.
+ */
+ configure_l2_ctlr();
+ configure_l2_actlr();
+ dsb();
+ isb();
+#endif
+
#ifdef CONFIG_EXYNOS5420
relocate_wait_code();
diff --git a/arch/arm/cpu/armv7/exynos/soc.c b/arch/arm/cpu/armv7/exynos/soc.c
index 68eb8e7..0f116b1 100644
--- a/arch/arm/cpu/armv7/exynos/soc.c
+++ b/arch/arm/cpu/armv7/exynos/soc.c
@@ -9,15 +9,6 @@
#include <asm/io.h>
#include <asm/system.h>
-enum l2_cache_params {
- CACHE_TAG_RAM_SETUP = (1 << 9),
- CACHE_DATA_RAM_SETUP = (1 << 5),
- CACHE_TAG_RAM_LATENCY = (2 << 6),
- CACHE_DATA_RAM_LATENCY = (2 << 0),
- CACHE_ENABLE_CLEAN_EVICT = (0 << 3),
- CACHE_DISABLE_CLEAN_EVICT = (1 << 3)
-};
-
void reset_cpu(ulong addr)
{
writel(0x1, samsung_get_base_swreset());
@@ -30,47 +21,3 @@
dcache_enable();
}
#endif
-
-#ifndef CONFIG_SYS_L2CACHE_OFF
-/*
- * Set L2 cache parameters
- */
-static void exynos5_set_l2cache_params(void)
-{
- unsigned int l2ctlr = 0, l2actlr = 0;
-
- /* Read L2CTLR value */
- asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r"(l2ctlr));
-
- /* Set cache latency cycles */
- l2ctlr |= CACHE_TAG_RAM_LATENCY |
- CACHE_DATA_RAM_LATENCY;
-
- if (proid_is_exynos5420() || proid_is_exynos5800()) {
- /* Read L2ACTLR value */
- asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (l2actlr));
-
- /* Disable clean/evict push to external */
- l2actlr |= CACHE_DISABLE_CLEAN_EVICT;
-
- /* Write new vlaue to L2ACTLR */
- asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (l2actlr));
- } else {
- /* Set cache setup cycles */
- l2ctlr |= CACHE_TAG_RAM_SETUP |
- CACHE_DATA_RAM_SETUP;
- }
-
- /* Write new vlaue to L2CTLR */
- asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(l2ctlr));
-}
-
-/*
- * Sets L2 cache related parameters before enabling data cache
- */
-void v7_outer_cache_enable(void)
-{
- if (cpu_is_exynos5())
- exynos5_set_l2cache_params();
-}
-#endif
diff --git a/arch/arm/include/asm/arch-exynos/system.h b/arch/arm/include/asm/arch-exynos/system.h
index a9fd5e6..3ffb296 100644
--- a/arch/arm/include/asm/arch-exynos/system.h
+++ b/arch/arm/include/asm/arch-exynos/system.h
@@ -37,7 +37,6 @@
#define USB20_PHY_CFG_HOST_LINK_EN (1 << 0)
-#ifdef CONFIG_EXYNOS5420
/*
* Data Synchronization Barrier acts as a special kind of memory barrier.
* No instruction in program order after this instruction executes until
@@ -125,7 +124,6 @@
/* Write L2 Auxilliary Control register */
#define mcr_l2_aux_ctlr(x) __asm__ __volatile__ \
("mcr p15, 1, %0, c15, c0, 0\n\t" : : "r"(x))
-#endif
void set_usbhost_mode(unsigned int mode);
void set_system_display_ctrl(void);