ARMv8: Add basic PSCI framework
authormacro.wave.z@gmail.com <macro.wave.z@gmail.com>
Thu, 8 Dec 2016 03:58:24 +0000 (11:58 +0800)
committerYork Sun <york.sun@nxp.com>
Thu, 15 Dec 2016 19:57:44 +0000 (11:57 -0800)
This patch introduces a generic ARMv8 PSCI framework, with all functions
returning a dummy ARM_PSCI_RET_NI (Not Implemented), then it is up to each
platform to implement their own functions based on this framework.

Signed-off-by: Hongbo Zhang <hongbo.zhang@nxp.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: York Sun <york.sun@nxp.com>
arch/arm/cpu/armv8/Kconfig
arch/arm/cpu/armv8/Makefile
arch/arm/cpu/armv8/psci.S [new file with mode: 0644]
arch/arm/include/asm/psci.h

index edae43de07dbd2f82b10d2d28a9c38c4d532e85c..22dce8807650013f2fb7e0788f8adec2fd1f03d0 100644 (file)
@@ -58,6 +58,16 @@ config ARMV8_PSCI_NR_CPUS
          It is no problem to set a larger value than the number of CPUs in
          the actual hardware implementation.
 
+config ARMV8_PSCI_CPUS_PER_CLUSTER
+       int "Number of CPUs per cluster"
+       depends on ARMV8_PSCI
+       default 0
+       help
+         The number of CPUs per cluster, suppose each cluster has same number
+         of CPU cores, platforms with asymmetric clusters don't apply here.
+         A value 0 or no definition of it works for single cluster system.
+         System with multi-cluster should difine their own exact value.
+
 if SYS_HAS_ARMV8_SECURE_BASE
 
 config ARMV8_SECURE_BASE
index dea14657d9aef4ff3ef974cbceb75dd061536107..28ba7862072a2cc165c87bea0877e9422a76c520 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_FSL_LAYERSCAPE) += fsl-layerscape/
 obj-$(CONFIG_S32V234) += s32v234/
 obj-$(CONFIG_ARCH_ZYNQMP) += zynqmp/
 obj-$(CONFIG_TARGET_HIKEY) += hisilicon/
+obj-$(CONFIG_ARMV8_PSCI) += psci.o
diff --git a/arch/arm/cpu/armv8/psci.S b/arch/arm/cpu/armv8/psci.S
new file mode 100644 (file)
index 0000000..43d5d6b
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Author: Hongbo Zhang <hongbo.zhang@nxp.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ * This file implements LS102X platform PSCI SYSTEM-SUSPEND function
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+#include <asm/psci.h>
+
+/* Default PSCI function, return -1, Not Implemented */
+#define PSCI_DEFAULT(__fn) \
+       ENTRY(__fn); \
+       mov     w0, #ARM_PSCI_RET_NI; \
+       ret; \
+       ENDPROC(__fn); \
+       .weak __fn
+
+/* PSCI function and ID table definition*/
+#define PSCI_TABLE(__id, __fn) \
+       .word __id; \
+       .word __fn
+
+.pushsection ._secure.text, "ax"
+
+/* 32 bits PSCI default functions */
+PSCI_DEFAULT(psci_version)
+PSCI_DEFAULT(psci_cpu_suspend)
+PSCI_DEFAULT(psci_cpu_off)
+PSCI_DEFAULT(psci_cpu_on)
+PSCI_DEFAULT(psci_affinity_info)
+PSCI_DEFAULT(psci_migrate)
+PSCI_DEFAULT(psci_migrate_info_type)
+PSCI_DEFAULT(psci_migrate_info_up_cpu)
+PSCI_DEFAULT(psci_system_off)
+PSCI_DEFAULT(psci_system_reset)
+PSCI_DEFAULT(psci_features)
+PSCI_DEFAULT(psci_cpu_freeze)
+PSCI_DEFAULT(psci_cpu_default_suspend)
+PSCI_DEFAULT(psci_node_hw_state)
+PSCI_DEFAULT(psci_system_suspend)
+PSCI_DEFAULT(psci_set_suspend_mode)
+PSCI_DEFAULT(psi_stat_residency)
+PSCI_DEFAULT(psci_stat_count)
+
+.align 3
+_psci_32_table:
+PSCI_TABLE(ARM_PSCI_FN_CPU_SUSPEND, psci_cpu_suspend)
+PSCI_TABLE(ARM_PSCI_FN_CPU_OFF, psci_cpu_off)
+PSCI_TABLE(ARM_PSCI_FN_CPU_ON, psci_cpu_on)
+PSCI_TABLE(ARM_PSCI_FN_MIGRATE, psci_migrate)
+PSCI_TABLE(ARM_PSCI_0_2_FN_PSCI_VERSION, psci_version)
+PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_SUSPEND, psci_cpu_suspend)
+PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_OFF, psci_cpu_off)
+PSCI_TABLE(ARM_PSCI_0_2_FN_CPU_ON, psci_cpu_on)
+PSCI_TABLE(ARM_PSCI_0_2_FN_AFFINITY_INFO, psci_affinity_info)
+PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE, psci_migrate)
+PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE, psci_migrate_info_type)
+PSCI_TABLE(ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu)
+PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_OFF, psci_system_off)
+PSCI_TABLE(ARM_PSCI_0_2_FN_SYSTEM_RESET, psci_system_reset)
+PSCI_TABLE(ARM_PSCI_1_0_FN_PSCI_FEATURES, psci_features)
+PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_FREEZE, psci_cpu_freeze)
+PSCI_TABLE(ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend)
+PSCI_TABLE(ARM_PSCI_1_0_FN_NODE_HW_STATE, psci_node_hw_state)
+PSCI_TABLE(ARM_PSCI_1_0_FN_SYSTEM_SUSPEND, psci_system_suspend)
+PSCI_TABLE(ARM_PSCI_1_0_FN_SET_SUSPEND_MODE, psci_set_suspend_mode)
+PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_RESIDENCY, psi_stat_residency)
+PSCI_TABLE(ARM_PSCI_1_0_FN_STAT_COUNT, psci_stat_count)
+PSCI_TABLE(0, 0)
+
+/* 64 bits PSCI default functions */
+PSCI_DEFAULT(psci_cpu_suspend_64)
+PSCI_DEFAULT(psci_cpu_on_64)
+PSCI_DEFAULT(psci_affinity_info_64)
+PSCI_DEFAULT(psci_migrate_64)
+PSCI_DEFAULT(psci_migrate_info_up_cpu_64)
+PSCI_DEFAULT(psci_cpu_default_suspend_64)
+PSCI_DEFAULT(psci_node_hw_state_64)
+PSCI_DEFAULT(psci_system_suspend_64)
+PSCI_DEFAULT(psci_stat_residency_64)
+PSCI_DEFAULT(psci_stat_count_64)
+
+.align 3
+_psci_64_table:
+PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_SUSPEND, psci_cpu_suspend_64)
+PSCI_TABLE(ARM_PSCI_0_2_FN64_CPU_ON, psci_cpu_on_64)
+PSCI_TABLE(ARM_PSCI_0_2_FN64_AFFINITY_INFO, psci_affinity_info_64)
+PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE, psci_migrate_64)
+PSCI_TABLE(ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, psci_migrate_info_up_cpu_64)
+PSCI_TABLE(ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND, psci_cpu_default_suspend_64)
+PSCI_TABLE(ARM_PSCI_1_0_FN64_NODE_HW_STATE, psci_node_hw_state_64)
+PSCI_TABLE(ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND, psci_system_suspend_64)
+PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_RESIDENCY, psci_stat_residency_64)
+PSCI_TABLE(ARM_PSCI_1_0_FN64_STAT_COUNT, psci_stat_count_64)
+PSCI_TABLE(0, 0)
+
+.macro psci_enter
+       /* PSCI call is Fast Call(atomic), so mask DAIF */
+       mrs     x15, DAIF
+       stp     x15, xzr, [sp, #-16]!
+       ldr     x15, =0x3C0
+       msr     DAIF, x15
+       /* SMC convention, x18 ~ x30 should be saved by callee */
+       stp     x29, x30, [sp, #-16]!
+       stp     x27, x28, [sp, #-16]!
+       stp     x25, x26, [sp, #-16]!
+       stp     x23, x24, [sp, #-16]!
+       stp     x21, x22, [sp, #-16]!
+       stp     x19, x20, [sp, #-16]!
+       mrs     x15, elr_el3
+       stp     x18, x15, [sp, #-16]!
+.endm
+
+.macro psci_return
+       /* restore registers */
+       ldp     x18, x15, [sp], #16
+       msr     elr_el3, x15
+       ldp     x19, x20, [sp], #16
+       ldp     x21, x22, [sp], #16
+       ldp     x23, x24, [sp], #16
+       ldp     x25, x26, [sp], #16
+       ldp     x27, x28, [sp], #16
+       ldp     x29, x30, [sp], #16
+       /* restore DAIF */
+       ldp     x15, xzr, [sp], #16
+       msr     DAIF, x15
+       eret
+.endm
+
+/* Caller must put PSCI function-ID table base in x9 */
+handle_psci:
+       psci_enter
+1:     ldr x10, [x9]                   /* Load PSCI function table */
+       ubfx x11, x10, #32, #32
+       ubfx x10, x10, #0, #32
+       cbz     x10, 3f                 /* If reach the end, bail out */
+       cmp     x10, x0
+       b.eq    2f                      /* PSCI function found */
+       add x9, x9, #8                  /* If not match, try next entry */
+       b       1b
+
+2:     blr     x11                     /* Call PSCI function */
+       psci_return
+
+3:     mov     x0, #ARM_PSCI_RET_NI
+       psci_return
+
+unknown_smc_id:
+       ldr     x0, =0xFFFFFFFF
+       eret
+
+handle_smc32:
+       /* SMC function ID  0x84000000-0x8400001F: 32 bits PSCI */
+       ldr     w9, =0x8400001F
+       cmp     w0, w9
+       b.gt    unknown_smc_id
+       ldr     w9, =0x84000000
+       cmp     w0, w9
+       b.lt    unknown_smc_id
+
+       adr     x9, _psci_32_table
+       b       handle_psci
+
+handle_smc64:
+       /* check SMC32 or SMC64 calls */
+       ubfx    x9, x0, #30, #1
+       cbz     x9, handle_smc32
+
+       /* SMC function ID 0xC4000000-0xC400001F: 64 bits PSCI */
+       ldr     x9, =0xC400001F
+       cmp     x0, x9
+       b.gt    unknown_smc_id
+       ldr     x9, =0xC4000000
+       cmp     x0, x9
+       b.lt    unknown_smc_id
+
+       adr     x9, _psci_64_table
+       b       handle_psci
+
+/*
+ * Get CPU ID from MPIDR, suppose every cluster has same number of CPU cores,
+ * Platform with asymmetric clusters should implement their own interface.
+ * In case this function being called by other platform's C code, the ARM
+ * Architecture Procedure Call Standard is considered, e.g. register X0 is
+ * used for the return value, while in this PSCI environment, X0 usually holds
+ * the SMC function identifier, so X0 should be saved by caller function.
+ */
+ENTRY(psci_get_cpu_id)
+#ifdef CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
+       mrs     x9, MPIDR_EL1
+       ubfx    x9, x9, #8, #8
+       ldr     x10, =CONFIG_ARMV8_PSCI_CPUS_PER_CLUSTER
+       mul     x9, x10, x9
+#else
+       mov     x9, xzr
+#endif
+       mrs     x10, MPIDR_EL1
+       ubfx    x10, x10, #0, #8
+       add     x0, x10, x9
+       ret
+ENDPROC(psci_get_cpu_id)
+.weak psci_get_cpu_id
+
+/* CPU ID input in x0, stack top output in x0*/
+LENTRY(psci_get_cpu_stack_top)
+       adr     x9, __secure_stack_end
+       lsl     x0, x0, #ARM_PSCI_STACK_SHIFT
+       sub     x0, x9, x0
+       ret
+ENDPROC(psci_get_cpu_stack_top)
+
+unhandled_exception:
+       b       unhandled_exception     /* simply dead loop */
+
+handle_sync:
+       mov     x15, x30
+       mov     x14, x0
+
+       bl      psci_get_cpu_id
+       bl      psci_get_cpu_stack_top
+       mov     x9, #1
+       msr     spsel, x9
+       mov     sp, x0
+
+       mov     x0, x14
+       mov     x30, x15
+
+       mrs     x9, esr_el3
+       ubfx    x9, x9, #26, #6
+       cmp     x9, #0x13
+       b.eq    handle_smc32
+       cmp     x9, #0x17
+       b.eq    handle_smc64
+
+       b       unhandled_exception
+
+       .align  11
+       .globl  el3_exception_vectors
+el3_exception_vectors:
+       b       unhandled_exception     /* Sync, Current EL using SP0 */
+       .align  7
+       b       unhandled_exception     /* IRQ, Current EL using SP0 */
+       .align  7
+       b       unhandled_exception     /* FIQ, Current EL using SP0 */
+       .align  7
+       b       unhandled_exception     /* SError, Current EL using SP0 */
+       .align  7
+       b       unhandled_exception     /* Sync, Current EL using SPx */
+       .align  7
+       b       unhandled_exception     /* IRQ, Current EL using SPx */
+       .align  7
+       b       unhandled_exception     /* FIQ, Current EL using SPx */
+       .align  7
+       b       unhandled_exception     /* SError, Current EL using SPx */
+       .align  7
+       b       handle_sync             /* Sync, Lower EL using AArch64 */
+       .align  7
+       b       unhandled_exception     /* IRQ, Lower EL using AArch64 */
+       .align  7
+       b       unhandled_exception     /* FIQ, Lower EL using AArch64 */
+       .align  7
+       b       unhandled_exception     /* SError, Lower EL using AArch64 */
+       .align  7
+       b       unhandled_exception     /* Sync, Lower EL using AArch32 */
+       .align  7
+       b       unhandled_exception     /* IRQ, Lower EL using AArch32 */
+       .align  7
+       b       unhandled_exception     /* FIQ, Lower EL using AArch32 */
+       .align  7
+       b       unhandled_exception     /* SError, Lower EL using AArch32 */
+
+ENTRY(psci_setup_vectors)
+       adr     x0, el3_exception_vectors
+       msr     vbar_el3, x0
+       ret
+ENDPROC(psci_setup_vectors)
+
+ENTRY(psci_arch_init)
+       ret
+ENDPROC(psci_arch_init)
+.weak psci_arch_init
+
+.popsection
index 9f1f779868381b91f14606b1f56c51f8d8348e96..ac8b00d6fc10971ca2662d5fc74c57b79cfbf169 100644 (file)
@@ -45,6 +45,9 @@
 #define ARM_PSCI_0_2_FN_BASE                   0x84000000
 #define ARM_PSCI_0_2_FN(n)                     (ARM_PSCI_0_2_FN_BASE + (n))
 
+#define ARM_PSCI_0_2_FN64_BASE                 0xC4000000
+#define ARM_PSCI_0_2_FN64(n)                   (ARM_PSCI_0_2_FN64_BASE + (n))
+
 #define ARM_PSCI_0_2_FN_PSCI_VERSION           ARM_PSCI_0_2_FN(0)
 #define ARM_PSCI_0_2_FN_CPU_SUSPEND            ARM_PSCI_0_2_FN(1)
 #define ARM_PSCI_0_2_FN_CPU_OFF                        ARM_PSCI_0_2_FN(2)
 #define ARM_PSCI_0_2_FN_SYSTEM_OFF             ARM_PSCI_0_2_FN(8)
 #define ARM_PSCI_0_2_FN_SYSTEM_RESET           ARM_PSCI_0_2_FN(9)
 
+#define ARM_PSCI_0_2_FN64_CPU_SUSPEND          ARM_PSCI_0_2_FN64(1)
+#define ARM_PSCI_0_2_FN64_CPU_ON               ARM_PSCI_0_2_FN64(3)
+#define ARM_PSCI_0_2_FN64_AFFINITY_INFO                ARM_PSCI_0_2_FN64(4)
+#define ARM_PSCI_0_2_FN64_MIGRATE              ARM_PSCI_0_2_FN64(5)
+#define ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU  ARM_PSCI_0_2_FN64(7)
+
 /* PSCI 1.0 interface */
 #define ARM_PSCI_1_0_FN_PSCI_FEATURES          ARM_PSCI_0_2_FN(10)
 #define ARM_PSCI_1_0_FN_CPU_FREEZE             ARM_PSCI_0_2_FN(11)
 #define ARM_PSCI_1_0_FN_STAT_RESIDENCY         ARM_PSCI_0_2_FN(16)
 #define ARM_PSCI_1_0_FN_STAT_COUNT             ARM_PSCI_0_2_FN(17)
 
+#define ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND  ARM_PSCI_0_2_FN64(12)
+#define ARM_PSCI_1_0_FN64_NODE_HW_STATE                ARM_PSCI_0_2_FN64(13)
+#define ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND       ARM_PSCI_0_2_FN64(14)
+#define ARM_PSCI_1_0_FN64_STAT_RESIDENCY       ARM_PSCI_0_2_FN64(16)
+#define ARM_PSCI_1_0_FN64_STAT_COUNT           ARM_PSCI_0_2_FN64(17)
+
 /* 1KB stack per core */
 #define ARM_PSCI_STACK_SHIFT   10
 #define ARM_PSCI_STACK_SIZE    (1 << ARM_PSCI_STACK_SHIFT)