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 NpuError {
28 DomainNotFound,
30 Timeout,
32 HardwareError,
34}
35
36pub type NpuResult<T> = Result<T, NpuError>;
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
61 Self {
62 _board: board,
63 info: RockchipPmuInfo::new(board),
64 reg: PmuRegs::new(base),
65 }
66 }
67
68 pub fn get_power_dowain_by_name(&self, name: &str) -> Option<PowerDomain> {
69 for (domain, info) in &self.info.domains {
70 if info.name == name {
71 return Some(*domain);
72 }
73 }
74 None
75 }
76
77 pub fn power_domain_on(&mut self, domain: PowerDomain) -> NpuResult<()> {
79 self.set_power_domain(domain, true)
80 }
81
82 pub fn power_domain_off(&mut self, domain: PowerDomain) -> NpuResult<()> {
84 self.set_power_domain(domain, false)
85 }
86
87 fn set_power_domain(&mut self, domain: PowerDomain, power_on: bool) -> NpuResult<()> {
89 let domain_info = self
90 .info
91 .domains
92 .get(&domain)
93 .ok_or(NpuError::DomainNotFound)?;
94
95 if domain_info.pwr_mask == 0 {
96 return Ok(());
97 }
98
99 self.write_power_control(&domain, power_on)?;
101
102 self.wait_power_domain_stable(&domain, power_on)?;
104
105 Ok(())
106 }
107
108 fn write_power_control(&mut self, domain: &PowerDomain, power_on: bool) -> NpuResult<()> {
110 let domain_info = self
111 .info
112 .domains
113 .get(domain)
114 .ok_or(NpuError::DomainNotFound)?;
115 let pwr_offset = self.info.pwr_offset + domain_info.pwr_offset;
116
117 if domain_info.pwr_w_mask != 0 {
118 let value = if power_on {
120 domain_info.pwr_w_mask
121 } else {
122 domain_info.pwr_mask | domain_info.pwr_w_mask
123 };
124 self.reg.write_u32(pwr_offset as usize, value as u32);
125 } else {
126 let current = self.reg.read_u32(pwr_offset as usize);
128 let new_value = if power_on {
129 current & !(domain_info.pwr_mask as u32)
130 } else {
131 current | (domain_info.pwr_mask as u32)
132 };
133 self.reg.write_u32(pwr_offset as usize, new_value);
134 }
135
136 mb();
137
138 Ok(())
139 }
140
141 fn wait_power_domain_stable(&self, domain: &PowerDomain, expected_on: bool) -> NpuResult<()> {
143 for _ in 0..10000 {
144 if self.is_domain_on(domain)? == expected_on {
145 return Ok(());
146 }
147 }
148 Err(NpuError::Timeout)
149 }
150
151 fn is_domain_on(&self, domain: &PowerDomain) -> NpuResult<bool> {
153 let domain_info = self
154 .info
155 .domains
156 .get(domain)
157 .ok_or(NpuError::DomainNotFound)?;
158
159 if domain_info.repair_status_mask != 0 {
160 let val = self.reg.read_u32(self.info.repair_status_offset as usize);
162 return Ok((val & (domain_info.repair_status_mask as u32)) != 0);
164 }
165
166 if domain_info.status_mask == 0 {
167 return Ok(!self.is_domain_idle(domain)?);
169 }
170
171 let val = self.reg.read_u32(self.info.status_offset as usize);
172 Ok((val & (domain_info.status_mask as u32)) == 0)
174 }
175
176 fn is_domain_idle(&self, domain: &PowerDomain) -> NpuResult<bool> {
178 let domain_info = self
179 .info
180 .domains
181 .get(domain)
182 .ok_or(NpuError::DomainNotFound)?;
183
184 let val = self.reg.read_u32(self.info.idle_offset as usize);
185 Ok((val & (domain_info.idle_mask as u32)) == (domain_info.idle_mask as u32))
186 }
187}
188
189impl DriverGeneric for RockchipPM {
190 fn open(&mut self) -> Result<(), rdif_base::KError> {
191 Ok(())
192 }
193
194 fn close(&mut self) -> Result<(), rdif_base::KError> {
195 Ok(())
196 }
197}