[U-Boot] [PATCH 11/11] Exynos: Fix L2 cache timings on Exynos5420 and Exynos5800

Simon Glass sjg at chromium.org
Wed Jan 28 05:13:09 CET 2015


Hi Akshay,

On 15 January 2015 at 06:42, Akshay Saraswat <akshay.s at samsung.com> wrote:
> From: Doug Anderson <dianders at chromium.org>
>
> 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 at chromium.org>
> Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
> ---
>  arch/arm/cpu/armv7/exynos/common_setup.h  | 55 +++++++++++++++++++++++++++++++
>  arch/arm/cpu/armv7/exynos/lowlevel_init.c | 55 +++++++++----------------------
>  arch/arm/cpu/armv7/exynos/soc.c           | 51 ----------------------------
>  3 files changed, 70 insertions(+), 91 deletions(-)

This causes a compilation error on snow, so needs to be adjusted.

Tested on pit, pi
Tested-by: Simon Glass <sjg at chromium.org>

>
> diff --git a/arch/arm/cpu/armv7/exynos/common_setup.h b/arch/arm/cpu/armv7/exynos/common_setup.h
> index e6318c0..7fa9683 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,56 @@ void system_clock_init(void);
>  int do_lowlevel_init(void);
>
>  void sdelay(unsigned long);
> +
> +enum l2_cache_params {
> +       CACHE_ECC_AND_PARITY = (1 << 21),
> +       CACHE_TAG_RAM_SETUP = (1 << 9),
> +       CACHE_DATA_RAM_SETUP = (1 << 5),
> +#ifndef CONFIG_EXYNOS5420
> +       CACHE_TAG_RAM_LATENCY = (2 << 6),  /* 5250 */
> +       CACHE_DATA_RAM_LATENCY = (2 << 0),
> +#else
> +       CACHE_TAG_RAM_LATENCY = (3 << 6),  /* 5420 and 5422 */
> +       CACHE_DATA_RAM_LATENCY = (3 << 0),
> +#endif
> +};
> +
> +#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 |
> +               CACHE_DATA_RAM_LATENCY |
> +               CACHE_ECC_AND_PARITY;
> +       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)
> +{
> +#ifdef CONFIG_EXYNOS5420
> +       uint32_t val;
> +
> +       mrc_l2_aux_ctlr(val);
> +       val |= (1 << 27) |      /* Prevents stopping the L2 logic clock */
> +               (1 << 7) |      /* Enable hazard detect timeout for A15 */
> +               (1 << 3);       /* Disable clean/evict push to external */
> +       mcr_l2_aux_ctlr(val);
> +#endif
> +}
> +#endif
> diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> index a459432..40d3e3a 100644
> --- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> +++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> @@ -67,43 +67,6 @@ static void enable_smp(void)
>  }
>
>  /*
> - * 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[7] to reissue any memory transaction in the L2 that has been
> - * stalled for 1024 cycles to verify that its hazard condition still exists.
> - * Disable clean/evict push to external by setting L2ACTLR[3].
> - */
> -static void configure_l2_actlr(void)
> -{
> -       uint32_t val;
> -
> -       mrc_l2_aux_ctlr(val);
> -       val |= (1 << 27);
> -       val |= (1 << 7);
> -       val |= (1 << 3);
> -       mcr_l2_aux_ctlr(val);
> -}
> -
> -/*
>   * Power up secondary CPUs.
>   */
>  static void secondary_cpu_start(void)
> @@ -198,9 +161,6 @@ static void power_down_core(void)
>   */
>  static void secondary_cores_configure(void)
>  {
> -       /* Setup L2 cache */
> -       configure_l2_ctlr();
> -
>         /* Clear secondary boot iRAM base */
>         writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C));
>
> @@ -226,6 +186,21 @@ int do_lowlevel_init(void)
>
>         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 ea201e7..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 {
> -#ifndef CONFIG_EXYNOS5420
> -       CACHE_TAG_RAM_SETUP = (1 << 9),
> -       CACHE_DATA_RAM_SETUP = (1 << 5),
> -#endif
> -       CACHE_TAG_RAM_LATENCY = (2 << 6),
> -       CACHE_DATA_RAM_LATENCY = (2 << 0)
> -};
> -
>  void reset_cpu(ulong addr)
>  {
>         writel(0x1, samsung_get_base_swreset());
> @@ -30,45 +21,3 @@ void enable_caches(void)
>         dcache_enable();
>  }
>  #endif
> -
> -#ifndef CONFIG_SYS_L2CACHE_OFF
> -/*
> - * Set L2 cache parameters
> - */
> -static void exynos5_set_l2cache_params(void)
> -{
> -       unsigned int val = 0;
> -
> -       asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r"(val));
> -
> -#ifndef CONFIG_EXYNOS5420
> -       val |= CACHE_TAG_RAM_SETUP |
> -               CACHE_DATA_RAM_SETUP |
> -               CACHE_TAG_RAM_LATENCY |
> -               CACHE_DATA_RAM_LATENCY;
> -#else
> -       val |= CACHE_TAG_RAM_LATENCY |
> -               CACHE_DATA_RAM_LATENCY;
> -#endif
> -
> -       asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
> -
> -#ifdef CONFIG_EXYNOS5420
> -       /* Read CP15 L2ACTLR value */
> -       asm volatile("mrc       p15, 1, %0, c15, c0, 0" : "=r" (val));
> -       /* Disable clean/evict push to external */
> -       val |= (0x1 << 3);
> -       /* Write new vlaue to L2ACTLR */
> -       asm volatile("mcr       p15, 1, %0, c15, c0, 0" : : "r" (val));
> -#endif
> -}
> -
> -/*
> - * Sets L2 cache related parameters before enabling data cache
> - */
> -void v7_outer_cache_enable(void)
> -{
> -       if (cpu_is_exynos5())
> -               exynos5_set_l2cache_params();
> -}
> -#endif
> --
> 1.9.1
>

Regards,
Simon


More information about the U-Boot mailing list