1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * Copyright (C) 2013 Samsung Electronics 3*4882a593Smuzhiyun * Akshay Saraswat <akshay.s@samsung.com> 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+ 6*4882a593Smuzhiyun */ 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun#include <config.h> 9*4882a593Smuzhiyun#include <asm/arch/cpu.h> 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun .globl relocate_wait_code 12*4882a593Smuzhiyunrelocate_wait_code: 13*4882a593Smuzhiyun adr r0, code_base @ r0: source address (start) 14*4882a593Smuzhiyun adr r1, code_end @ r1: source address (end) 15*4882a593Smuzhiyun ldr r2, =0x02073000 @ r2: target address 16*4882a593Smuzhiyun1: 17*4882a593Smuzhiyun ldmia r0!, {r3-r6} 18*4882a593Smuzhiyun stmia r2!, {r3-r6} 19*4882a593Smuzhiyun cmp r0, r1 20*4882a593Smuzhiyun blt 1b 21*4882a593Smuzhiyun b code_end 22*4882a593Smuzhiyun .ltorg 23*4882a593Smuzhiyun/* 24*4882a593Smuzhiyun * Secondary core waits here until Primary wake it up. 25*4882a593Smuzhiyun * Below code is copied to CONFIG_EXYNOS_RELOCATE_CODE_BASE. 26*4882a593Smuzhiyun * This is a workaround code which is supposed to act as a 27*4882a593Smuzhiyun * substitute/supplement to the iROM code. 28*4882a593Smuzhiyun * 29*4882a593Smuzhiyun * This workaround code is relocated to the address 0x02073000 30*4882a593Smuzhiyun * because that comes out to be the last 4KB of the iRAM 31*4882a593Smuzhiyun * (Base Address - 0x02020000, Limit Address - 0x020740000). 32*4882a593Smuzhiyun * 33*4882a593Smuzhiyun * U-Boot and kernel are aware of this code and flags by the simple 34*4882a593Smuzhiyun * fact that we are implementing a workaround in the last 4KB 35*4882a593Smuzhiyun * of the iRAM and we have already defined these flag and address 36*4882a593Smuzhiyun * values in both kernel and U-Boot for our use. 37*4882a593Smuzhiyun */ 38*4882a593Smuzhiyuncode_base: 39*4882a593Smuzhiyun b 1f 40*4882a593Smuzhiyun/* 41*4882a593Smuzhiyun * These addresses are being used as flags in u-boot and kernel. 42*4882a593Smuzhiyun * 43*4882a593Smuzhiyun * Jump address for resume and flag to check for resume/reset: 44*4882a593Smuzhiyun * Resume address - 0x2073008 45*4882a593Smuzhiyun * Resume flag - 0x207300C 46*4882a593Smuzhiyun * 47*4882a593Smuzhiyun * Jump address for cluster switching: 48*4882a593Smuzhiyun * Switch address - 0x2073018 49*4882a593Smuzhiyun * 50*4882a593Smuzhiyun * Jump address for core hotplug: 51*4882a593Smuzhiyun * Hotplug address - 0x207301C 52*4882a593Smuzhiyun * 53*4882a593Smuzhiyun * Jump address for C2 state (Reserved for future not being used right now): 54*4882a593Smuzhiyun * C2 address - 0x2073024 55*4882a593Smuzhiyun * 56*4882a593Smuzhiyun * Managed per core status for the active cluster: 57*4882a593Smuzhiyun * CPU0 state - 0x2073028 58*4882a593Smuzhiyun * CPU1 state - 0x207302C 59*4882a593Smuzhiyun * CPU2 state - 0x2073030 60*4882a593Smuzhiyun * CPU3 state - 0x2073034 61*4882a593Smuzhiyun * 62*4882a593Smuzhiyun * Managed per core GIC status for the active cluster: 63*4882a593Smuzhiyun * CPU0 gic state - 0x2073038 64*4882a593Smuzhiyun * CPU1 gic state - 0x207303C 65*4882a593Smuzhiyun * CPU2 gic state - 0x2073040 66*4882a593Smuzhiyun * CPU3 gic state - 0x2073044 67*4882a593Smuzhiyun * 68*4882a593Smuzhiyun * Logic of the code: 69*4882a593Smuzhiyun * Step-1: Read current CPU status. 70*4882a593Smuzhiyun * Step-2: If it's a resume then continue, else jump to step 4. 71*4882a593Smuzhiyun * Step-3: Clear inform1 PMU register and jump to inform0 value. 72*4882a593Smuzhiyun * Step-4: If it's a switch, C2 or reset, get the hotplug address. 73*4882a593Smuzhiyun * Step-5: If address is not available, enter WFE. 74*4882a593Smuzhiyun * Step-6: If address is available, jump to that address. 75*4882a593Smuzhiyun */ 76*4882a593Smuzhiyun nop @ for backward compatibility 77*4882a593Smuzhiyun .word 0x0 @ REG0: RESUME_ADDR 78*4882a593Smuzhiyun .word 0x0 @ REG1: RESUME_FLAG 79*4882a593Smuzhiyun .word 0x0 @ REG2 80*4882a593Smuzhiyun .word 0x0 @ REG3 81*4882a593Smuzhiyun_switch_addr: 82*4882a593Smuzhiyun .word 0x0 @ REG4: SWITCH_ADDR 83*4882a593Smuzhiyun_hotplug_addr: 84*4882a593Smuzhiyun .word 0x0 @ REG5: CPU1_BOOT_REG 85*4882a593Smuzhiyun .word 0x0 @ REG6 86*4882a593Smuzhiyun_c2_addr: 87*4882a593Smuzhiyun .word 0x0 @ REG7: REG_C2_ADDR 88*4882a593Smuzhiyun_cpu_state: 89*4882a593Smuzhiyun .word 0x1 @ CPU0_STATE : RESET 90*4882a593Smuzhiyun .word 0x2 @ CPU1_STATE : SECONDARY RESET 91*4882a593Smuzhiyun .word 0x2 @ CPU2_STATE : SECONDARY RESET 92*4882a593Smuzhiyun .word 0x2 @ CPU3_STATE : SECONDARY RESET 93*4882a593Smuzhiyun_gic_state: 94*4882a593Smuzhiyun .word 0x0 @ CPU0 - GICD_IGROUPR0 95*4882a593Smuzhiyun .word 0x0 @ CPU1 - GICD_IGROUPR0 96*4882a593Smuzhiyun .word 0x0 @ CPU2 - GICD_IGROUPR0 97*4882a593Smuzhiyun .word 0x0 @ CPU3 - GICD_IGROUPR0 98*4882a593Smuzhiyun1: 99*4882a593Smuzhiyun adr r0, _cpu_state 100*4882a593Smuzhiyun mrc p15, 0, r7, c0, c0, 5 @ read MPIDR 101*4882a593Smuzhiyun and r7, r7, #0xf @ r7 = cpu id 102*4882a593Smuzhiyun/* Read the current cpu state */ 103*4882a593Smuzhiyun ldr r10, [r0, r7, lsl #2] 104*4882a593Smuzhiyunsvc_entry: 105*4882a593Smuzhiyun tst r10, #(1 << 4) 106*4882a593Smuzhiyun adrne r0, _switch_addr 107*4882a593Smuzhiyun bne wait_for_addr 108*4882a593Smuzhiyun/* Clear INFORM1 */ 109*4882a593Smuzhiyun ldr r0, =(0x10040000 + 0x804) 110*4882a593Smuzhiyun ldr r1, [r0] 111*4882a593Smuzhiyun cmp r1, #0x0 112*4882a593Smuzhiyun movne r1, #0x0 113*4882a593Smuzhiyun strne r1, [r0] 114*4882a593Smuzhiyun/* Get INFORM0 */ 115*4882a593Smuzhiyun ldrne r1, =(0x10040000 + 0x800) 116*4882a593Smuzhiyun ldrne pc, [r1] 117*4882a593Smuzhiyun tst r10, #(1 << 0) 118*4882a593Smuzhiyun ldrne pc, =0x23e00000 119*4882a593Smuzhiyun adr r0, _hotplug_addr 120*4882a593Smuzhiyunwait_for_addr: 121*4882a593Smuzhiyun ldr r1, [r0] 122*4882a593Smuzhiyun cmp r1, #0x0 123*4882a593Smuzhiyun bxne r1 124*4882a593Smuzhiyun wfe 125*4882a593Smuzhiyun b wait_for_addr 126*4882a593Smuzhiyun .ltorg 127*4882a593Smuzhiyuncode_end: 128*4882a593Smuzhiyun mov pc, lr 129