rockchip_pm/
lib.rs

1#![no_std]
2//! # RK3588 电源管理驱动
3//!
4//! 本库提供了针对 RK3588 系列 SoC 的电源管理功能,特别是 NPU 电源域的控制。
5//!
6
7extern 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    /// 电源域不存在
29    DomainNotFound,
30    /// 超时错误
31    Timeout,
32    /// 硬件错误
33    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    /// 开启指定电源域
77    pub fn power_domain_on(&mut self, domain: PowerDomain) -> PmResult<()> {
78        self.set_power_domain(domain, true)
79    }
80
81    /// 关闭指定电源域
82    pub fn power_domain_off(&mut self, domain: PowerDomain) -> PmResult<()> {
83        self.set_power_domain(domain, false)
84    }
85
86    /// 设置电源域状态(简化版本)
87    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        // 写入电源控制寄存器
99        self.write_power_control(&domain, power_on)?;
100
101        // 等待电源域状态稳定
102        self.wait_power_domain_stable(&domain, power_on)?;
103
104        Ok(())
105    }
106
107    /// 写入电源控制寄存器
108    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            // 使用写使能掩码方式
118            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            // 使用读改写方式
126            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    /// 等待电源域状态稳定
141    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    /// 检查电源域是否开启
151    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            // 使用修复状态寄存器
160            let val = self.reg.read_u32(self.info.repair_status_offset as usize);
161            // 1'b1: power on, 1'b0: power off
162            return Ok((val & (domain_info.repair_status_mask as u32)) != 0);
163        }
164
165        if domain_info.status_mask == 0 {
166            // 仅检查空闲状态的域
167            return Ok(!self.is_domain_idle(domain)?);
168        }
169
170        let val = self.reg.read_u32(self.info.status_offset as usize);
171        // 1'b0: power on, 1'b1: power off
172        Ok((val & (domain_info.status_mask as u32)) == 0)
173    }
174
175    /// 检查电源域是否空闲
176    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}