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