u-boot/arch/arm/cpu/armv7/exynos/sec_boot.S
Akshay Saraswat 67a0652c47 Exynos542x: Add workaround for exynos iROM errata
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@samsung.com>
Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
2015-02-28 18:03:46 +09:00

128 lines
3.6 KiB
ArmAsm

/*
* Copyright (C) 2013 Samsung Electronics
* Akshay Saraswat <akshay.s@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#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