[U-Boot] [PATCH 05/11] Exynos542x: Add workaround for exynos iROM errata
Simon Glass
sjg at chromium.org
Wed Jan 28 05:10:08 CET 2015
Hi Akshay,
On 15 January 2015 at 06:42, Akshay Saraswat <akshay.s at samsung.com> wrote:
> iROM logic provides undesired jump address for CPU2.
> This patch adds a programmable susbstitute for a part of
> iROM logic which wakes up cores and provides jump addresses.
> This patch creates a logic to make all secondary cores jump
> to a particular address which evades the possibility of CPU2
> jumping to wrong address and create undesired results.
>
> Logic of the workaround:
>
> Step-1: iROM code checks value at address 0x2020028.
> Step-2: If value is 0xc9cfcfcf, it jumps to the address (0x202000+CPUid*4),
> else, it continues executing normally.
> Step-3: Primary core puts secondary cores in WFE and store 0xc9cfcfcf in
> 0x2020028 and jump address (pointer to function low_power_start)
> in (0x202000+CPUid*4).
> Step-4: When secondary cores recieve event signal they jump to this address
> and continue execution.
>
> Signed-off-by: Kimoon Kim <kimoon.kim at samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
> ---
> arch/arm/cpu/armv7/exynos/Makefile | 2 +
> arch/arm/cpu/armv7/exynos/lowlevel_init.c | 90 +++++++++++++++----
> arch/arm/cpu/armv7/exynos/sec_boot.S | 145 ++++++++++++++++++++++++++++++
> 3 files changed, 219 insertions(+), 18 deletions(-)
> create mode 100644 arch/arm/cpu/armv7/exynos/sec_boot.S
>
> diff --git a/arch/arm/cpu/armv7/exynos/Makefile b/arch/arm/cpu/armv7/exynos/Makefile
> index e207bd6..8542f89 100644
> --- a/arch/arm/cpu/armv7/exynos/Makefile
> +++ b/arch/arm/cpu/armv7/exynos/Makefile
> @@ -7,6 +7,8 @@
>
> obj-y += clock.o power.o soc.o system.o pinmux.o tzpc.o
>
> +obj-$(CONFIG_EXYNOS5420) += sec_boot.o
> +
> ifdef CONFIG_SPL_BUILD
> obj-$(CONFIG_EXYNOS5) += clock_init_exynos5.o
> obj-$(CONFIG_EXYNOS5) += dmc_common.o dmc_init_ddr3.o
> diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> index 3097382..d3c466e 100644
> --- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> +++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c
> @@ -49,7 +49,7 @@ enum {
> * before modifying the ACTLR.SMP bit. This is required during boot before
> * MMU has been enabled, or during a specified reset or power down sequence.
> */
> -void enable_smp(void)
> +static void enable_smp(void)
> {
> uint32_t temp, val;
>
> @@ -70,7 +70,7 @@ void enable_smp(void)
> * 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.
> */
> -void set_l2cache(void)
> +static void set_l2cache(void)
> {
> uint32_t val;
>
> @@ -89,6 +89,62 @@ void set_l2cache(void)
> }
>
> /*
> + * Power up secondary CPUs.
> + */
> +static void secondary_cpu_start(void)
> +{
> + enable_smp();
> + svc32_mode_en();
> + set_pc(CONFIG_EXYNOS_RELOCATE_CODE_BASE);
> +}
> +
> +/*
> + * This is the entry point of hotplug-in and
> + * cluster switching.
> + */
> +static void low_power_start(void)
> +{
> + uint32_t val, reg_val;
> +
> + reg_val = readl(RST_FLAG_REG);
> + if (reg_val != RST_FLAG_VAL) {
> + writel(0x0, CONFIG_LOWPOWER_FLAG);
> + set_pc(0x0);
> + }
> +
> + reg_val = readl(CONFIG_PHY_IRAM_BASE + 0x4);
> + if (reg_val != (uint32_t)&low_power_start) {
> + /* Store jump address as low_power_start if not present */
> + writel((uint32_t)&low_power_start, CONFIG_PHY_IRAM_BASE + 0x4);
> + dsb();
> + sev();
> + }
> +
> + /* Set the CPU to SVC32 mode */
> + svc32_mode_en();
> + set_l2cache();
> +
> + /* Invalidate L1 & TLB */
> + val = 0x0;
> + mcr_tlb(val);
> + mcr_icache(val);
> +
> + /* Disable MMU stuff and caches */
> + mrc_sctlr(val);
> +
> + val &= ~((0x2 << 12) | 0x7);
> + val |= ((0x1 << 12) | (0x8 << 8) | 0x2);
> + mcr_sctlr(val);
> +
> + /* CPU state is hotplug or reset */
> + secondary_cpu_start();
> +
> + /* Core should not enter into WFI here */
> + wfi();
> +
> +}
> +
> +/*
> * Pointer to this function is stored in iRam which is used
> * for jump and power down of a specific core.
> */
> @@ -118,29 +174,25 @@ static void power_down_core(void)
> */
> static void secondary_cores_configure(void)
> {
> - uint32_t core_id;
> + /* Setup L2 cache */
> + set_l2cache();
> +
> + /* Clear secondary boot iRAM base */
> + writel(0x0, (CONFIG_EXYNOS_RELOCATE_CODE_BASE + 0x1C));
>
> - /* Store jump address for power down of secondary cores */
> + /* set lowpower flag and address */
> + writel(RST_FLAG_VAL, CONFIG_LOWPOWER_FLAG);
> + writel((uint32_t)&low_power_start, CONFIG_LOWPOWER_ADDR);
> + writel(RST_FLAG_VAL, RST_FLAG_REG);
> + /* Store jump address for power down */
> writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4);
>
> /* Need all core power down check */
> dsb();
> sev();
> -
> - /*
> - * Power down all cores(secondary) while primary core must
> - * wait for all cores to go down.
> - */
> - for (core_id = 1; core_id != CORE_COUNT; core_id++) {
> - while ((readl(ARM_CORE0_STATUS
> - + (core_id * CORE_CONFIG_OFFSET))
> - & 0xff) != 0x0) {
> - isb();
> - sev();
> - }
> - isb();
> - }
> }
> +
> +extern void relocate_wait_code(void);
> #endif
>
> int do_lowlevel_init(void)
> @@ -151,6 +203,8 @@ int do_lowlevel_init(void)
> arch_cpu_init();
>
> #ifdef CONFIG_EXYNOS5420
> + relocate_wait_code();
> +
> /* Reconfigure secondary cores */
> secondary_cores_configure();
> #endif
> diff --git a/arch/arm/cpu/armv7/exynos/sec_boot.S b/arch/arm/cpu/armv7/exynos/sec_boot.S
> new file mode 100644
> index 0000000..e818cf1
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/exynos/sec_boot.S
> @@ -0,0 +1,145 @@
> +/*
> + * Lowlevel setup for EXYNOS5
> + *
> + * Copyright (C) 2013 Samsung Electronics
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
Can we please use SPDX header here?
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <config.h>
> +#include <asm/arch/cpu.h>
> +
> + .globl relocate_wait_code
> +relocate_wait_code:
> + adr r0, code_base @ r0: source address (start)
> + adr r1, code_end @ r1: source address (end)
> + ldr r2, =0x02073000 @ r2: target address
> +1:
> + ldmia r0!, {r3-r6}
> + stmia r2!, {r3-r6}
> + cmp r0, r1
> + blt 1b
> + b code_end
> + .ltorg
> +/*
> + * Secondary core waits here until Primary wake it up.
> + * Below code is copied to CONFIG_EXYNOS_RELOCATE_CODE_BASE.
> + * This is a workaround code which is supposed to act as a
> + * substitute/supplement to the iROM code.
> + *
> + * This workaround code is relocated to the address 0x02073000
> + * because that comes out to be the last 4KB of the iRAM
> + * (Base Address - 0x02020000, Limit Address - 0x020740000).
> + *
> + * U-boot and kernel are aware of this code and flags by the simple
> + * fact that we are implementing a workaround in the last 4KB
> + * of the iRAM and we have already defined these flag and address
> + * values in both kernel and U-boot for our use.
> + */
> +code_base:
> + b 1f
> +/*
> + * These addresses are being used as flags in u-boot and kernel.
> + *
> + * Jump address for resume and flag to check for resume/reset:
> + * Resume address - 0x2073008
> + * Resume flag - 0x207300C
> + *
> + * Jump address for cluster switching:
> + * Switch address - 0x2073018
> + *
> + * Jump address for core hotplug:
> + * Hotplug address - 0x207301C
> + *
> + * Jump address for C2 state (Reserved for future not being used right now):
> + * C2 address - 0x2073024
> + *
> + * Managed per core status for the active cluster:
> + * CPU0 state - 0x2073028
> + * CPU1 state - 0x207302C
> + * CPU2 state - 0x2073030
> + * CPU3 state - 0x2073034
> + *
> + * Managed per core GIC status for the active cluster:
> + * CPU0 gic state - 0x2073038
> + * CPU1 gic state - 0x207303C
> + * CPU2 gic state - 0x2073040
> + * CPU3 gic state - 0x2073044
> + *
> + * Logic of the code:
> + * Step-1: Read current CPU status.
> + * Step-2: If it's a resume then continue, else jump to step 4.
> + * Step-3: Clear inform1 PMU register and jump to inform0 value.
> + * Step-4: If it's a switch, C2 or reset, get the hotplug address.
> + * Step-5: If address is not available, enter WFE.
> + * Step-6: If address is available, jump to that address.
> + */
> + nop @ for backward compatibility
> + .word 0x0 @ REG0: RESUME_ADDR
> + .word 0x0 @ REG1: RESUME_FLAG
> + .word 0x0 @ REG2
> + .word 0x0 @ REG3
> +_switch_addr:
> + .word 0x0 @ REG4: SWITCH_ADDR
> +_hotplug_addr:
> + .word 0x0 @ REG5: CPU1_BOOT_REG
> + .word 0x0 @ REG6
> +_c2_addr:
> + .word 0x0 @ REG7: REG_C2_ADDR
> +_cpu_state:
> + .word 0x1 @ CPU0_STATE : RESET
> + .word 0x2 @ CPU1_STATE : SECONDARY RESET
> + .word 0x2 @ CPU2_STATE : SECONDARY RESET
> + .word 0x2 @ CPU3_STATE : SECONDARY RESET
> +_gic_state:
> + .word 0x0 @ CPU0 - GICD_IGROUPR0
> + .word 0x0 @ CPU1 - GICD_IGROUPR0
> + .word 0x0 @ CPU2 - GICD_IGROUPR0
> + .word 0x0 @ CPU3 - GICD_IGROUPR0
> +1:
> + adr r0, _cpu_state
> + mrc p15, 0, r7, c0, c0, 5 @ read MPIDR
> + and r7, r7, #0xf @ r7 = cpu id
> +/* Read the current cpu state */
> + ldr r10, [r0, r7, lsl #2]
> +svc_entry:
> + tst r10, #(1 << 4)
> + adrne r0, _switch_addr
> + bne wait_for_addr
> +/* Clear INFORM1 */
> + ldr r0, =(0x10040000 + 0x804)
> + ldr r1, [r0]
> + cmp r1, #0x0
> + movne r1, #0x0
> + strne r1, [r0]
> +/* Get INFORM0 */
> + ldrne r1, =(0x10040000 + 0x800)
> + ldrne pc, [r1]
> + tst r10, #(1 << 0)
> + ldrne pc, =0x23e00000
> + adr r0, _hotplug_addr
> +wait_for_addr:
> + ldr r1, [r0]
> + cmp r1, #0x0
> + bxne r1
> + wfe
> + b wait_for_addr
> + .ltorg
> +code_end:
> + mov pc, lr
> --
> 1.9.1
>
Reviewed-by: Simon Glass <sjg at chromium.org>
Tested on snow, pit, pi
Tested-by: Simon Glass <sjg at chromium.org>
Regards,
Simon
More information about the U-Boot
mailing list