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