1#![no_std]
2extern crate alloc;
8
9use mbarrier::mb;
10use rdif_base::DriverGeneric;
11
12use crate::{registers::PmuRegs, variants::RockchipPmuInfo};
13use core::ptr::NonNull;
14
15mod registers;
16mod variants;
17
18pub use variants::PowerDomain;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub enum RkBoard {
22 Rk3588,
23 Rk3568,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum PmError {
28 DomainNotFound,
30 Timeout,
32 HardwareError,
34}
35
36pub type PmResult<T> = Result<T, PmError>;
37
38pub struct RockchipPM {
39 _board: RkBoard,
40 reg: PmuRegs,
41 info: RockchipPmuInfo,
42}
43
44impl RockchipPM {
45 pub fn new(base: NonNull<u8>, board: RkBoard) -> Self {
46 Self {
47 _board: board,
48 info: RockchipPmuInfo::new(board),
49 reg: PmuRegs::new(base),
50 }
51 }
52
53 pub fn new_with_compatible(base: NonNull<u8>, compatible: &str) -> Self {
54 let board = match compatible {
55 "rockchip,rk3568-power-controller" => RkBoard::Rk3568,
56 "rockchip,rk3588-power-controller" => RkBoard::Rk3588,
57 _ => panic!("Unsupported compatible string: {compatible}"),
58 };
59
60 Self {
61 _board: board,
62 info: RockchipPmuInfo::new(board),
63 reg: PmuRegs::new(base),
64 }
65 }
66
67 pub fn get_power_dowain_by_name(&self, name: &str) -> Option<PowerDomain> {
68 for (domain, info) in &self.info.domains {
69 if info.name == name {
70 return Some(*domain);
71 }
72 }
73 None
74 }
75
76 pub fn power_domain_on(&mut self, domain: PowerDomain) -> PmResult<()> {
78 self.set_power_domain(domain, true)
79 }
80
81 pub fn power_domain_off(&mut self, domain: PowerDomain) -> PmResult<()> {
83 self.set_power_domain(domain, false)
84 }
85
86 fn set_power_domain(&mut self, domain: PowerDomain, power_on: bool) -> PmResult<()> {
88 let domain_info = self
89 .info
90 .domains
91 .get(&domain)
92 .ok_or(PmError::DomainNotFound)?;
93
94 if domain_info.pwr_mask == 0 {
95 return Ok(());
96 }
97
98 self.write_power_control(&domain, power_on)?;
100
101 self.wait_power_domain_stable(&domain, power_on)?;
103
104 Ok(())
105 }
106
107 fn write_power_control(&mut self, domain: &PowerDomain, power_on: bool) -> PmResult<()> {
109 let domain_info = self
110 .info
111 .domains
112 .get(domain)
113 .ok_or(PmError::DomainNotFound)?;
114 let pwr_offset = self.info.pwr_offset + domain_info.pwr_offset;
115
116 if domain_info.pwr_w_mask != 0 {
117 let value = if power_on {
119 domain_info.pwr_w_mask
120 } else {
121 domain_info.pwr_mask | domain_info.pwr_w_mask
122 };
123 self.reg.write_u32(pwr_offset as usize, value as u32);
124 } else {
125 let current = self.reg.read_u32(pwr_offset as usize);
127 let new_value = if power_on {
128 current & !(domain_info.pwr_mask as u32)
129 } else {
130 current | (domain_info.pwr_mask as u32)
131 };
132 self.reg.write_u32(pwr_offset as usize, new_value);
133 }
134
135 mb();
136
137 Ok(())
138 }
139
140 fn wait_power_domain_stable(&self, domain: &PowerDomain, expected_on: bool) -> PmResult<()> {
142 for _ in 0..10000 {
143 if self.is_domain_on(domain)? == expected_on {
144 return Ok(());
145 }
146 }
147 Err(PmError::Timeout)
148 }
149
150 fn is_domain_on(&self, domain: &PowerDomain) -> PmResult<bool> {
152 let domain_info = self
153 .info
154 .domains
155 .get(domain)
156 .ok_or(PmError::DomainNotFound)?;
157
158 if domain_info.repair_status_mask != 0 {
159 let val = self.reg.read_u32(self.info.repair_status_offset as usize);
161 return Ok((val & (domain_info.repair_status_mask as u32)) != 0);
163 }
164
165 if domain_info.status_mask == 0 {
166 return Ok(!self.is_domain_idle(domain)?);
168 }
169
170 let val = self.reg.read_u32(self.info.status_offset as usize);
171 Ok((val & (domain_info.status_mask as u32)) == 0)
173 }
174
175 fn is_domain_idle(&self, domain: &PowerDomain) -> PmResult<bool> {
177 let domain_info = self
178 .info
179 .domains
180 .get(domain)
181 .ok_or(PmError::DomainNotFound)?;
182
183 let val = self.reg.read_u32(self.info.idle_offset as usize);
184 Ok((val & (domain_info.idle_mask as u32)) == (domain_info.idle_mask as u32))
185 }
186}
187
188impl DriverGeneric for RockchipPM {
189 fn open(&mut self) -> Result<(), rdif_base::KError> {
190 Ok(())
191 }
192
193 fn close(&mut self) -> Result<(), rdif_base::KError> {
194 Ok(())
195 }
196}