axplat_aarch64_peripherals/
psci.rs1#![allow(dead_code)]
4
5use core::sync::atomic::{AtomicBool, Ordering};
6
7const PSCI_0_2_FN_BASE: u32 = 0x84000000;
8const PSCI_0_2_64BIT: u32 = 0x40000000;
9const PSCI_0_2_FN_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + 1;
10const PSCI_0_2_FN_CPU_OFF: u32 = PSCI_0_2_FN_BASE + 2;
11const PSCI_0_2_FN_CPU_ON: u32 = PSCI_0_2_FN_BASE + 3;
12const PSCI_0_2_FN_MIGRATE: u32 = PSCI_0_2_FN_BASE + 5;
13const PSCI_0_2_FN_SYSTEM_OFF: u32 = PSCI_0_2_FN_BASE + 8;
14const PSCI_0_2_FN_SYSTEM_RESET: u32 = PSCI_0_2_FN_BASE + 9;
15const PSCI_0_2_FN64_CPU_SUSPEND: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 1;
16const PSCI_0_2_FN64_CPU_ON: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 3;
17const PSCI_0_2_FN64_MIGRATE: u32 = PSCI_0_2_FN_BASE + PSCI_0_2_64BIT + 5;
18
19static PSCI_METHOD_HVC: AtomicBool = AtomicBool::new(false);
20
21#[derive(PartialEq, Debug)]
23#[repr(i32)]
24enum PsciError {
25 NotSupported = -1,
26 InvalidParams = -2,
27 Denied = -3,
28 AlreadyOn = -4,
29 OnPending = -5,
30 InternalFailure = -6,
31 NotPresent = -7,
32 Disabled = -8,
33 InvalidAddress = -9,
34}
35
36impl From<i32> for PsciError {
37 fn from(code: i32) -> PsciError {
38 use PsciError::*;
39 match code {
40 -1 => NotSupported,
41 -2 => InvalidParams,
42 -3 => Denied,
43 -4 => AlreadyOn,
44 -5 => OnPending,
45 -6 => InternalFailure,
46 -7 => NotPresent,
47 -8 => Disabled,
48 -9 => InvalidAddress,
49 _ => panic!("Unknown PSCI error code: {}", code),
50 }
51 }
52}
53
54fn arm_smccc_smc(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize {
57 let mut ret;
58 #[cfg(target_arch = "aarch64")]
59 unsafe {
60 core::arch::asm!(
61 "smc #0",
62 inlateout("x0") func as usize => ret,
63 in("x1") arg0,
64 in("x2") arg1,
65 in("x3") arg2,
66 )
67 }
68 #[cfg(target_arch = "arm")]
69 unsafe {
70 core::arch::asm!(
71 ".arch_extension sec",
72 "smc #0",
73 inlateout("r0") func => ret,
74 in("r1") arg0,
75 in("r2") arg1,
76 in("r3") arg2,
77 )
78 }
79 ret
80}
81
82fn psci_hvc_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> usize {
84 let ret;
85 #[cfg(target_arch = "aarch64")]
86 unsafe {
87 core::arch::asm!(
88 "hvc #0",
89 inlateout("x0") func as usize => ret,
90 in("x1") arg0,
91 in("x2") arg1,
92 in("x3") arg2,
93 )
94 }
95 #[cfg(target_arch = "arm")]
96 unsafe {
97 core::arch::asm!(
98 ".arch_extension virt",
99 "hvc #0",
100 inlateout("r0") func => ret,
101 in("r1") arg0,
102 in("r2") arg1,
103 in("r3") arg2,
104 )
105 }
106 ret
107}
108
109fn psci_call(func: u32, arg0: usize, arg1: usize, arg2: usize) -> Result<(), PsciError> {
110 let ret = if PSCI_METHOD_HVC.load(Ordering::Acquire) {
111 psci_hvc_call(func, arg0, arg1, arg2)
112 } else {
113 arm_smccc_smc(func, arg0, arg1, arg2)
114 };
115 if ret == 0 {
116 Ok(())
117 } else {
118 Err(PsciError::from(ret as i32))
119 }
120}
121
122pub fn init(method: &str) {
126 match method {
127 "smc" => PSCI_METHOD_HVC.store(false, Ordering::Release),
128 "hvc" => PSCI_METHOD_HVC.store(true, Ordering::Release),
129 _ => panic!("Unknown PSCI method: {}", method),
130 }
131}
132
133pub fn system_off() -> ! {
135 info!("Shutting down...");
136 psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok();
137 warn!("It should shutdown!");
138 loop {
139 axcpu::asm::halt();
140 }
141}
142
143pub fn cpu_on(target_cpu: usize, entry_point: usize, arg: usize) {
152 info!("Starting CPU {:x} ON ...", target_cpu);
153 let res = psci_call(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_point, arg);
154 if let Err(e) = res {
155 error!("failed to boot CPU {:x} ({:?})", target_cpu, e);
156 }
157}
158
159pub fn cpu_off() {
163 const PSCI_POWER_STATE_TYPE_STANDBY: u32 = 0;
164 const PSCI_POWER_STATE_TYPE_POWER_DOWN: u32 = 1;
165 const PSCI_0_2_POWER_STATE_TYPE_SHIFT: u32 = 16;
166 let state: u32 = PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT;
167 psci_call(PSCI_0_2_FN_CPU_OFF, state as usize, 0, 0).ok();
168}