mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-15 09:27:35 +00:00
67a0652c47
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>
128 lines
3.6 KiB
ArmAsm
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
|