1/* SPDX-License-Identifier: GPL-2.0+ */ 2/* 3 * Copyright 2016 Freescale Semiconductor, Inc. 4 * Author: Hongbo Zhang <hongbo.zhang@nxp.com> 5 * This file implements LS102X platform PSCI SYSTEM-SUSPEND function 6 */ 7 8#include <config.h> 9#include <linux/linkage.h> 10#include <asm/psci.h> 11 12/* Default PSCI function, return -1, Not Implemented */ 13#define PSCI_DEFAULT(__fn) \ 14 ENTRY(__fn); \ 15 mov w0, #ARM_PSCI_RET_NI; \ 16 ret; \ 17 ENDPROC(__fn); \ 18 .weak __fn 19 20/* PSCI function and ID table definition*/ 21#define PSCI_TABLE(__id, __fn) \ 22 .word __id; \ 23 .word __fn 24 25.pushsection ._secure.text, "ax" 26 27/* 32 bits PSCI default functions */ 28PSCI_DEFAULT(psci_version) 29PSCI_DEFAULT(psci_cpu_suspend) 30PSCI_DEFAULT(psci_cpu_off) 31PSCI_DEFAULT(psci_cpu_on) 32PSCI_DEFAULT(psci_affinity_info) 33PSCI_DEFAULT(psci_migrate) 34PSCI_DEFAULT(psci_migrate_info_type) 35PSCI_DEFAULT(psci_migrate_info_up_cpu) 36PSCI_DEFAULT(psci_system_off) 37PSCI_DEFAULT(psci_system_reset) 38PSCI_DEFAULT(psci_features) 39PSCI_DEFAULT(psci_cpu_freeze) 40PSCI_DEFAULT(psci_cpu_default_suspend) 41PSCI_DEFAULT(psci_node_hw_state) 42PSCI_DEFAULT(psci_system_suspend) 43PSCI_DEFAULT(psci_set_suspend_mode) 44PSCI_DEFAULT(psi_stat_residency) 45PSCI_DEFAULT(psci_stat_count) 46 47.align 3 48_psci_32_table: 49PSCI_TABLE(ARM_PSCI_FN_CPU_SUSPEND, psci_cpu_suspend) 50PSCI_TABLE(ARM_PSCI_FN_CPU_OFF, psci_cpu_off) 51PSCI_TABLE(ARM_PSCI_FN_CPU_ON, psci_cpu_on) 52PSCI_TABLE(ARM_PSCI_FN_MIGRATE, psci_migrate) 53PSCI_TABLE(ARM_PSCI_0_2_FN_PSCI_VERSION, psci_version) 54PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_SUSPEND, psci_cpu_suspend) 55PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_OFF, psci_cpu_off) 56PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_ON, psci_cpu_on) 57PSCI_TABLE(ARM_PSCI_0_2_FN_AFFINITY_INFO, psci_affinity_info) 58PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE, psci_migrate) 59PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE, psci_migrate_info_type) 60PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu) 61PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_OFF, psci_system_off) 62PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_RESET, psci_system_reset) 63PSCI_TABLE(ARM_PSCI_1_0_FN_PSCI_FEATURES, psci_features) 64PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_FREEZE, psci_cpu_freeze) 65PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend) 66PSCI_TABLE(ARM_PSCI_1_0_FN_NODE_HW_STATE, psci_node_hw_state) 67PSCI_TABLE(ARM_PSCI_1_0_FN_SYSTEM_SUSPEND, psci_system_suspend) 68PSCI_TABLE(ARM_PSCI_1_0_FN_SET_SUSPEND_MODE, psci_set_suspend_mode) 69PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_RESIDENCY, psi_stat_residency) 70PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_COUNT, psci_stat_count) 71PSCI_TABLE(0, 0) 72 73/* 64 bits PSCI default functions */ 74PSCI_DEFAULT(psci_cpu_suspend_64) 75PSCI_DEFAULT(psci_cpu_on_64) 76PSCI_DEFAULT(psci_affinity_info_64) 77PSCI_DEFAULT(psci_migrate_64) 78PSCI_DEFAULT(psci_migrate_info_up_cpu_64) 79PSCI_DEFAULT(psci_cpu_default_suspend_64) 80PSCI_DEFAULT(psci_node_hw_state_64) 81PSCI_DEFAULT(psci_system_suspend_64) 82PSCI_DEFAULT(psci_stat_residency_64) 83PSCI_DEFAULT(psci_stat_count_64) 84 85.align 3 86_psci_64_table: 87PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_SUSPEND, psci_cpu_suspend_64) 88PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_ON, psci_cpu_on_64) 89PSCI_TABLE(ARM_PSCI_0_2_FN64_AFFINITY_INFO, psci_affinity_info_64) 90PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE, psci_migrate_64) 91PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu_64) 92PSCI_TABLE(ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend_64) 93PSCI_TABLE(ARM_PSCI_1_0_FN64_NODE_HW_STATE, psci_node_hw_state_64) 94PSCI_TABLE(ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND, psci_system_suspend_64) 95PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_RESIDENCY, psci_stat_residency_64) 96PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_COUNT, psci_stat_count_64) 97PSCI_TABLE(0, 0) 98 99.macro psci_enter 100 /* PSCI call is Fast Call(atomic), so mask DAIF */ 101 mrs x15, DAIF 102 stp x15, xzr, [sp, #-16]! 103 ldr x15, =0x3C0 104 msr DAIF, x15 105 /* SMC convention, x18 ~ x30 should be saved by callee */ 106 stp x29, x30, [sp, #-16]! 107 stp x27, x28, [sp, #-16]! 108 stp x25, x26, [sp, #-16]! 109 stp x23, x24, [sp, #-16]! 110 stp x21, x22, [sp, #-16]! 111 stp x19, x20, [sp, #-16]! 112 mrs x15, elr_el3 113 stp x18, x15, [sp, #-16]! 114.endm 115 116.macro psci_return 117 /* restore registers */ 118 ldp x18, x15, [sp], #16 119 msr elr_el3, x15 120 ldp x19, x20, [sp], #16 121 ldp x21, x22, [sp], #16 122 ldp x23, x24, [sp], #16 123 ldp x25, x26, [sp], #16 124 ldp x27, x28, [sp], #16 125 ldp x29, x30, [sp], #16 126 /* restore DAIF */ 127 ldp x15, xzr, [sp], #16 128 msr DAIF, x15 129 eret 130.endm 131 132/* Caller must put PSCI function-ID table base in x9 */ 133handle_psci: 134 psci_enter 1351: ldr x10, [x9] /* Load PSCI function table */ 136 ubfx x11, x10, #32, #32 137 ubfx x10, x10, #0, #32 138 cbz x10, 3f /* If reach the end, bail out */ 139 cmp x10, x0 140 b.eq 2f /* PSCI function found */ 141 add x9, x9, #8 /* If not match, try next entry */ 142 b 1b 143 1442: blr x11 /* Call PSCI function */ 145 psci_return 146 1473: mov x0, #ARM_PSCI_RET_NI 148 psci_return 149 150unknown_smc_id: 151 ldr x0, =0xFFFFFFFF 152 eret 153 154handle_smc32: 155 /* SMC function ID 0x84000000-0x8400001F: 32 bits PSCI */ 156 ldr w9, =0x8400001F 157 cmp w0, w9 158 b.gt unknown_smc_id 159 ldr w9, =0x84000000 160 cmp w0, w9 161 b.lt unknown_smc_id 162 163 adr x9, _psci_32_table 164 b handle_psci 165 166handle_smc64: 167 /* check SMC32 or SMC64 calls */ 168 ubfx x9, x0, #30, #1 169 cbz x9, handle_smc32 170 171 /* SMC function ID 0xC4000000-0xC400001F: 64 bits PSCI */ 172 ldr x9, =0xC400001F 173 cmp x0, x9 174 b.gt unknown_smc_id 175 ldr x9, =0xC4000000 176 cmp x0, x9 177 b.lt unknown_smc_id 178 179 adr x9, _psci_64_table 180 b handle_psci 181 182/* 183 * Get CPU ID from MPIDR, suppose every cluster has same number of CPU cores, 184 * Platform with asymmetric clusters should implement their own interface. 185 * In case this function being called by other platform's C code, the ARM 186 * Architecture Procedure Call Standard is considered, e.g. register X0 is 187 * used for the return value, while in this PSCI environment, X0 usually holds 188 * the SMC function identifier, so X0 should be saved by caller function. 189 */ 190ENTRY(psci_get_cpu_id) 191#ifdef CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER 192 mrs x9, MPIDR_EL1 193 ubfx x9, x9, #8, #8 194 ldr x10, =CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER 195 mul x9, x10, x9 196#else 197 mov x9, xzr 198#endif 199 mrs x10, MPIDR_EL1 200 ubfx x10, x10, #0, #8 201 add x0, x10, x9 202 ret 203ENDPROC(psci_get_cpu_id) 204.weak psci_get_cpu_id 205 206/* CPU ID input in x0, stack top output in x0*/ 207LENTRY(psci_get_cpu_stack_top) 208 adr x9, __secure_stack_end 209 lsl x0, x0, #ARM_PSCI_STACK_SHIFT 210 sub x0, x9, x0 211 ret 212ENDPROC(psci_get_cpu_stack_top) 213 214unhandled_exception: 215 b unhandled_exception /* simply dead loop */ 216 217handle_sync: 218 mov x15, x30 219 mov x14, x0 220 221 bl psci_get_cpu_id 222 bl psci_get_cpu_stack_top 223 mov x9, #1 224 msr spsel, x9 225 mov sp, x0 226 227 mov x0, x14 228 mov x30, x15 229 230 mrs x9, esr_el3 231 ubfx x9, x9, #26, #6 232 cmp x9, #0x13 233 b.eq handle_smc32 234 cmp x9, #0x17 235 b.eq handle_smc64 236 237 b unhandled_exception 238 239#ifdef CONFIG_ARMV8_EA_EL3_FIRST 240/* 241 * Override this function if custom error handling is 242 * needed for asynchronous aborts 243 */ 244ENTRY(plat_error_handler) 245 ret 246ENDPROC(plat_error_handler) 247.weak plat_error_handler 248 249handle_error: 250 bl psci_get_cpu_id 251 bl psci_get_cpu_stack_top 252 mov x9, #1 253 msr spsel, x9 254 mov sp, x0 255 256 bl plat_error_handler /* Platform specific error handling */ 257deadloop: 258 b deadloop /* Never return */ 259#endif 260 261 .align 11 262 .globl el3_exception_vectors 263el3_exception_vectors: 264 b unhandled_exception /* Sync, Current EL using SP0 */ 265 .align 7 266 b unhandled_exception /* IRQ, Current EL using SP0 */ 267 .align 7 268 b unhandled_exception /* FIQ, Current EL using SP0 */ 269 .align 7 270 b unhandled_exception /* SError, Current EL using SP0 */ 271 .align 7 272 b unhandled_exception /* Sync, Current EL using SPx */ 273 .align 7 274 b unhandled_exception /* IRQ, Current EL using SPx */ 275 .align 7 276 b unhandled_exception /* FIQ, Current EL using SPx */ 277 .align 7 278 b unhandled_exception /* SError, Current EL using SPx */ 279 .align 7 280 b handle_sync /* Sync, Lower EL using AArch64 */ 281 .align 7 282 b unhandled_exception /* IRQ, Lower EL using AArch64 */ 283 .align 7 284 b unhandled_exception /* FIQ, Lower EL using AArch64 */ 285 .align 7 286#ifdef CONFIG_ARMV8_EA_EL3_FIRST 287 b handle_error /* SError, Lower EL using AArch64 */ 288#else 289 b unhandled_exception /* SError, Lower EL using AArch64 */ 290#endif 291 .align 7 292 b unhandled_exception /* Sync, Lower EL using AArch32 */ 293 .align 7 294 b unhandled_exception /* IRQ, Lower EL using AArch32 */ 295 .align 7 296 b unhandled_exception /* FIQ, Lower EL using AArch32 */ 297 .align 7 298 b unhandled_exception /* SError, Lower EL using AArch32 */ 299 300ENTRY(psci_setup_vectors) 301 adr x0, el3_exception_vectors 302 msr vbar_el3, x0 303 ret 304ENDPROC(psci_setup_vectors) 305 306ENTRY(psci_arch_init) 307 ret 308ENDPROC(psci_arch_init) 309.weak psci_arch_init 310 311.popsection 312