1 /* SPDX-License-Identifier: GPL-2.0+ */ 2 /* 3 * Copyright 2015 Freescale Semiconductor, Inc. 4 * Author: Wang Dongsheng <dongsheng.wang (at) freescale.com> 5 */ 6 7 #include <config.h> 8 #include <linux/linkage.h> 9 10 #include <asm/armv7.h> 11 #include <asm/arch-armv7/generictimer.h> 12 #include <asm/psci.h> 13 14 #define RCPM_TWAITSR 0x04C 15 16 #define SCFG_CORE0_SFT_RST 0x130 17 #define SCFG_CORESRENCR 0x204 18 19 #define DCFG_CCSR_RSTCR 0x0B0 20 #define DCFG_CCSR_RSTCR_RESET_REQ 0x2 21 #define DCFG_CCSR_BRR 0x0E4 22 #define DCFG_CCSR_SCRATCHRW1 0x200 23 24 #define PSCI_FN_PSCI_VERSION_FEATURE_MASK 0x0 25 #define PSCI_FN_CPU_SUSPEND_FEATURE_MASK 0x0 26 #define PSCI_FN_CPU_OFF_FEATURE_MASK 0x0 27 #define PSCI_FN_CPU_ON_FEATURE_MASK 0x0 28 #define PSCI_FN_AFFINITY_INFO_FEATURE_MASK 0x0 29 #define PSCI_FN_SYSTEM_OFF_FEATURE_MASK 0x0 30 #define PSCI_FN_SYSTEM_RESET_FEATURE_MASK 0x0 31 #define PSCI_FN_SYSTEM_SUSPEND_FEATURE_MASK 0x0 32 33 .pushsection ._secure.text, "ax" 34 35 .arch_extension sec 36 37 .align 5 38 39 #define ONE_MS (COUNTER_FREQUENCY / 1000) 40 #define RESET_WAIT (30 * ONE_MS) 41 42 .globl psci_version 43 psci_version: 44 movw r0, #0 45 movt r0, #1 46 47 bx lr 48 49 _ls102x_psci_supported_table: 50 .word ARM_PSCI_0_2_FN_PSCI_VERSION 51 .word PSCI_FN_PSCI_VERSION_FEATURE_MASK 52 .word ARM_PSCI_0_2_FN_CPU_SUSPEND 53 .word PSCI_FN_CPU_SUSPEND_FEATURE_MASK 54 .word ARM_PSCI_0_2_FN_CPU_OFF 55 .word PSCI_FN_CPU_OFF_FEATURE_MASK 56 .word ARM_PSCI_0_2_FN_CPU_ON 57 .word PSCI_FN_CPU_ON_FEATURE_MASK 58 .word ARM_PSCI_0_2_FN_AFFINITY_INFO 59 .word PSCI_FN_AFFINITY_INFO_FEATURE_MASK 60 .word ARM_PSCI_0_2_FN_SYSTEM_OFF 61 .word PSCI_FN_SYSTEM_OFF_FEATURE_MASK 62 .word ARM_PSCI_0_2_FN_SYSTEM_RESET 63 .word PSCI_FN_SYSTEM_RESET_FEATURE_MASK 64 .word ARM_PSCI_1_0_FN_SYSTEM_SUSPEND 65 .word PSCI_FN_SYSTEM_SUSPEND_FEATURE_MASK 66 .word 0 67 .word ARM_PSCI_RET_NI 68 69 .globl psci_features 70 psci_features: 71 adr r2, _ls102x_psci_supported_table 72 1: ldr r3, [r2] 73 cmp r3, #0 74 beq out_psci_features 75 cmp r1, r3 76 addne r2, r2, #8 77 bne 1b 78 79 out_psci_features: 80 ldr r0, [r2, #4] 81 bx lr 82 83 @ r0: return value ARM_PSCI_RET_SUCCESS or ARM_PSCI_RET_INVAL 84 @ r1: input target CPU ID in MPIDR format, original value in r1 may be dropped 85 @ r4: output validated CPU ID if ARM_PSCI_RET_SUCCESS returns, meaningless for 86 @ ARM_PSCI_RET_INVAL,suppose caller saves r4 before calling 87 LENTRY(psci_check_target_cpu_id) 88 @ Get the real CPU number 89 and r4, r1, #0xff 90 mov r0, #ARM_PSCI_RET_INVAL 91 92 @ Bit[31:24], bits must be zero. 93 tst r1, #0xff000000 94 bxne lr 95 96 @ Affinity level 2 - Cluster: only one cluster in LS1021xa. 97 tst r1, #0xff0000 98 bxne lr 99 100 @ Affinity level 1 - Processors: should be in 0xf00 format. 101 lsr r1, r1, #8 102 teq r1, #0xf 103 bxne lr 104 105 @ Affinity level 0 - CPU: only 0, 1 are valid in LS1021xa. 106 cmp r4, #2 107 bxge lr 108 109 mov r0, #ARM_PSCI_RET_SUCCESS 110 bx lr 111 ENDPROC(psci_check_target_cpu_id) 112 113 @ r1 = target CPU 114 @ r2 = target PC 115 .globl psci_cpu_on 116 psci_cpu_on: 117 push {r4, r5, r6, lr} 118 119 @ Clear and Get the correct CPU number 120 @ r1 = 0xf01 121 bl psci_check_target_cpu_id 122 cmp r0, #ARM_PSCI_RET_INVAL 123 beq out_psci_cpu_on 124 125 mov r0, r4 126 mov r1, r2 127 mov r2, r3 128 bl psci_save 129 mov r1, r4 130 131 @ Get DCFG base address 132 movw r4, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff) 133 movt r4, #(CONFIG_SYS_FSL_GUTS_ADDR >> 16) 134 135 @ Detect target CPU state 136 ldr r2, [r4, #DCFG_CCSR_BRR] 137 rev r2, r2 138 lsr r2, r2, r1 139 ands r2, r2, #1 140 beq holdoff_release 141 142 @ Reset target CPU 143 @ Get SCFG base address 144 movw r0, #(CONFIG_SYS_FSL_SCFG_ADDR & 0xffff) 145 movt r0, #(CONFIG_SYS_FSL_SCFG_ADDR >> 16) 146 147 @ Enable CORE Soft Reset 148 movw r5, #0 149 movt r5, #(1 << 15) 150 rev r5, r5 151 str r5, [r0, #SCFG_CORESRENCR] 152 153 @ Get CPUx offset register 154 mov r6, #0x4 155 mul r6, r6, r1 156 add r2, r0, r6 157 158 @ Do reset on target CPU 159 movw r5, #0 160 movt r5, #(1 << 15) 161 rev r5, r5 162 str r5, [r2, #SCFG_CORE0_SFT_RST] 163 164 @ Wait target CPU up 165 timer_wait r2, RESET_WAIT 166 167 @ Disable CORE soft reset 168 mov r5, #0 169 str r5, [r0, #SCFG_CORESRENCR] 170 171 holdoff_release: 172 @ Release on target CPU 173 ldr r2, [r4, #DCFG_CCSR_BRR] 174 mov r6, #1 175 lsl r6, r6, r1 @ 32 bytes per CPU 176 177 rev r6, r6 178 orr r2, r2, r6 179 str r2, [r4, #DCFG_CCSR_BRR] 180 181 @ Set secondary boot entry 182 ldr r6, =psci_cpu_entry 183 rev r6, r6 184 str r6, [r4, #DCFG_CCSR_SCRATCHRW1] 185 186 isb 187 dsb 188 189 @ Return 190 mov r0, #ARM_PSCI_RET_SUCCESS 191 192 out_psci_cpu_on: 193 pop {r4, r5, r6, lr} 194 bx lr 195 196 .globl psci_cpu_off 197 psci_cpu_off: 198 bl psci_cpu_off_common 199 200 1: wfi 201 b 1b 202 203 .globl psci_affinity_info 204 psci_affinity_info: 205 push {lr} 206 207 mov r0, #ARM_PSCI_RET_INVAL 208 209 @ Verify Affinity level 210 cmp r2, #0 211 bne out_affinity_info 212 213 bl psci_check_target_cpu_id 214 cmp r0, #ARM_PSCI_RET_INVAL 215 beq out_affinity_info 216 mov r1, r4 217 218 @ Get RCPM base address 219 movw r4, #(CONFIG_SYS_FSL_RCPM_ADDR & 0xffff) 220 movt r4, #(CONFIG_SYS_FSL_RCPM_ADDR >> 16) 221 222 mov r0, #PSCI_AFFINITY_LEVEL_ON 223 224 @ Detect target CPU state 225 ldr r2, [r4, #RCPM_TWAITSR] 226 rev r2, r2 227 lsr r2, r2, r1 228 ands r2, r2, #1 229 beq out_affinity_info 230 231 mov r0, #PSCI_AFFINITY_LEVEL_OFF 232 233 out_affinity_info: 234 pop {pc} 235 236 .globl psci_system_reset 237 psci_system_reset: 238 @ Get DCFG base address 239 movw r1, #(CONFIG_SYS_FSL_GUTS_ADDR & 0xffff) 240 movt r1, #(CONFIG_SYS_FSL_GUTS_ADDR >> 16) 241 242 mov r2, #DCFG_CCSR_RSTCR_RESET_REQ 243 rev r2, r2 244 str r2, [r1, #DCFG_CCSR_RSTCR] 245 246 1: wfi 247 b 1b 248 249 .globl psci_system_suspend 250 psci_system_suspend: 251 push {lr} 252 253 bl ls1_system_suspend 254 255 pop {pc} 256 257 .popsection 258