Hi Akshay, On 15 January 2015 at 06:42, Akshay Saraswat <aksha...@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....@samsung.com> > Signed-off-by: Akshay Saraswat <aksha...@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 <s...@chromium.org> Tested on snow, pit, pi Tested-by: Simon Glass <s...@chromium.org> Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot