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 NpuError {
28    /// 电源域不存在
29    DomainNotFound,
30    /// 超时错误
31    Timeout,
32    /// 硬件错误
33    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    /// 开启指定电源域
78    pub fn power_domain_on(&mut self, domain: PowerDomain) -> NpuResult<()> {
79        self.set_power_domain(domain, true)
80    }
81
82    /// 关闭指定电源域
83    pub fn power_domain_off(&mut self, domain: PowerDomain) -> NpuResult<()> {
84        self.set_power_domain(domain, false)
85    }
86
87    /// 设置电源域状态(简化版本)
88    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        // 写入电源控制寄存器
100        self.write_power_control(&domain, power_on)?;
101
102        // 等待电源域状态稳定
103        self.wait_power_domain_stable(&domain, power_on)?;
104
105        Ok(())
106    }
107
108    /// 写入电源控制寄存器
109    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            // 使用写使能掩码方式
119            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            // 使用读改写方式
127            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    /// 等待电源域状态稳定
142    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    /// 检查电源域是否开启
152    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            // 使用修复状态寄存器
161            let val = self.reg.read_u32(self.info.repair_status_offset as usize);
162            // 1'b1: power on, 1'b0: power off
163            return Ok((val & (domain_info.repair_status_mask as u32)) != 0);
164        }
165
166        if domain_info.status_mask == 0 {
167            // 仅检查空闲状态的域
168            return Ok(!self.is_domain_idle(domain)?);
169        }
170
171        let val = self.reg.read_u32(self.info.status_offset as usize);
172        // 1'b0: power on, 1'b1: power off
173        Ok((val & (domain_info.status_mask as u32)) == 0)
174    }
175
176    /// 检查电源域是否空闲
177    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}