Bladeren bron

[libcpu/aarch64] adding PSCI system ops;
adding shutdown operation support;

wangxiaoyao 3 jaren geleden
bovenliggende
commit
60ff07a863

+ 9 - 1
libcpu/aarch64/common/cpu.c

@@ -19,6 +19,9 @@
 #include <rtdbg.h>
 #include <string.h>
 #include "cpu.h"
+#include "psci_api.h"
+
+void (*system_off)(void);
 
 #ifdef RT_USING_SMP
 void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
@@ -325,17 +328,22 @@ RT_WEAK void rt_hw_secondary_cpu_idle_exec(void)
  */
 /*@{*/
 
-/** shutdown CPU */
+/** shutdown CPU is used as system shutdown currently */
 void rt_hw_cpu_shutdown()
 {
     rt_uint32_t level;
     rt_kprintf("shutdown...\n");
 
+    if (system_off)
+        system_off();
+    LOG_E("system shutdown failed");
+
     level = rt_hw_interrupt_disable();
     while (level)
     {
         RT_ASSERT(0);
     }
 }
+MSH_CMD_EXPORT_ALIAS(rt_hw_cpu_shutdown, shutdown, shutdown machine);
 
 /*@}*/

+ 6 - 0
libcpu/aarch64/common/cpu.h

@@ -13,6 +13,10 @@
 #include <rtthread.h>
 #include <stdbool.h>
 
+#ifndef RT_CPUS_NR
+#define RT_CPUS_NR 1
+#endif /* RT_CPUS_NR */
+
 #ifdef RT_USING_SMP
 struct cpu_ops_t
 {
@@ -54,4 +58,6 @@ extern struct cpu_ops_t cpu_ops_spin_tbl;
 
 extern void rt_hw_cpu_shutdown(void);
 
+extern void (*system_off)(void);
+
 #endif /* __RT_HW_CPU_H__ */

+ 6 - 1
libcpu/aarch64/common/cpu_psci.c

@@ -55,11 +55,16 @@ static int cpu_psci_cpu_boot(rt_uint32_t cpuid)
     return psci_ops.cpu_on(cpuid_to_hwid(cpuid), secondary_entry_pa);
 }
 
+static void cpu_psci_cpu_shutdown()
+{
+    psci_ops.cpu_off(cpuid_to_hwid(rt_hw_cpu_id()));
+}
+
 struct cpu_ops_t cpu_ops_psci = {
     .method = "psci",
     .cpu_boot = cpu_psci_cpu_boot,
     .cpu_init = cpu_psci_cpu_init,
-    .cpu_shutdown = RT_NULL
+    .cpu_shutdown = cpu_psci_cpu_shutdown,
 };
 
 #endif /* RT_USING_SMP */

+ 40 - 2
libcpu/aarch64/common/psci.c

@@ -11,6 +11,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include "cpu.h"
 #include "psci.h"
 #include "psci_api.h"
 #include "smccc.h"
@@ -86,11 +87,12 @@ int psci_init()
     psci_node = dtb_node_get_dtb_node_by_path(root, "/psci");
     if (!psci_node)
     {
+        LOG_E("No PSCI node found");
         return -1;
     }
     char *compatible = dtb_node_get_dtb_node_property_value(psci_node, "compatible", NULL);
     char *method = dtb_node_get_dtb_node_property_value(psci_node, "method", NULL);
-    
+
     int retval = 0;
 
     // setup psci-method
@@ -107,6 +109,7 @@ int psci_init()
         LOG_E("Unknown PSCI method: %s", method);
         return -1;
     }
+    LOG_D("Using psci method %s", method);
 
     retval = _psci_probe_version(compatible, &psci_ver_major, &psci_ver_minor);
     if (retval != 0)
@@ -166,7 +169,7 @@ static rt_uint32_t psci_0_2_get_version(void)
 static void psci_0_2_set_basic_ops()
 {
     psci_ops = (struct psci_ops_t){
-        .get_version = psci_0_2_get_version, 
+        .get_version = psci_0_2_get_version,
 
         // followings API are v0.1 compatible
         .cpu_suspend = psci_0_2_cpu_suspend,
@@ -176,19 +179,54 @@ static void psci_0_2_set_basic_ops()
     };
 }
 
+static void psci_0_2_system_off(void)
+{
+    psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
+}
+
+static void psci_0_2_system_reset(void)
+{
+    psci_call(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
+}
+
 static int psci_0_2_init()
 {
     psci_0_2_set_basic_ops();
 
     // TODO init other version 0.2 features...
+    // psci system off and reset which controlling machine
+    psci_ops.system_off = psci_0_2_system_off;
+    psci_ops.system_reset = psci_0_2_system_reset;
+
+    system_off = psci_0_2_system_off;
     return 0;
 }
 
+/* PSCI v1.0 & after */
+static int psci_1_0_features(uint32_t psci_func_id)
+{
+    return psci_call(PSCI_1_0_FN_PSCI_FEATURES,
+                     psci_func_id, 0, 0);
+}
+
 static int psci_1_0_init()
 {
     psci_0_2_init();
 
     // TODO init other version 1.0 features...
+    // remove unsupported features
+    if (psci_1_0_features(PSCI_0_2_FN_SYSTEM_OFF) == PSCI_RET_NOT_SUPPORTED)
+    {
+        psci_ops.system_off = RT_NULL;
+        system_off = RT_NULL;
+    }
+    else
+        LOG_D("Using SYSTEM OFF feature");
+    if (psci_1_0_features(PSCI_0_2_FN_SYSTEM_RESET) == PSCI_RET_NOT_SUPPORTED)
+        psci_ops.system_reset = RT_NULL;
+    else
+        LOG_D("Using SYSTEM RESET feature");
+
     return 0;
 }
 

+ 3 - 0
libcpu/aarch64/common/psci_api.h

@@ -22,6 +22,9 @@ struct psci_ops_t
     int32_t (*cpu_off)(uint32_t state);
     int32_t (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
     int32_t (*migrate)(unsigned long cpuid);
+
+    void (*system_off)(void);
+    void (*system_reset)(void);
 };
 
 extern struct psci_ops_t psci_ops;