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    /// 开启指定电源域
54    pub fn power_domain_on(&mut self, domain: PowerDomain) -> NpuResult<()> {
55        self.set_power_domain(domain, true)
56    }
57
58    /// 关闭指定电源域
59    pub fn power_domain_off(&mut self, domain: PowerDomain) -> NpuResult<()> {
60        self.set_power_domain(domain, false)
61    }
62
63    /// 设置电源域状态(简化版本)
64    fn set_power_domain(&mut self, domain: PowerDomain, power_on: bool) -> NpuResult<()> {
65        let domain_info = self
66            .info
67            .domains
68            .get(&domain)
69            .ok_or(NpuError::DomainNotFound)?;
70
71        if domain_info.pwr_mask == 0 {
72            return Ok(());
73        }
74
75        // 写入电源控制寄存器
76        self.write_power_control(&domain, power_on)?;
77
78        // 等待电源域状态稳定
79        self.wait_power_domain_stable(&domain, power_on)?;
80
81        Ok(())
82    }
83
84    /// 写入电源控制寄存器
85    fn write_power_control(&mut self, domain: &PowerDomain, power_on: bool) -> NpuResult<()> {
86        let domain_info = self
87            .info
88            .domains
89            .get(domain)
90            .ok_or(NpuError::DomainNotFound)?;
91        let pwr_offset = self.info.pwr_offset + domain_info.pwr_offset;
92
93        if domain_info.pwr_w_mask != 0 {
94            // 使用写使能掩码方式
95            let value = if power_on {
96                domain_info.pwr_w_mask
97            } else {
98                domain_info.pwr_mask | domain_info.pwr_w_mask
99            };
100            self.reg.write_u32(pwr_offset as usize, value as u32);
101        } else {
102            // 使用读改写方式
103            let current = self.reg.read_u32(pwr_offset as usize);
104            let new_value = if power_on {
105                current & !(domain_info.pwr_mask as u32)
106            } else {
107                current | (domain_info.pwr_mask as u32)
108            };
109            self.reg.write_u32(pwr_offset as usize, new_value);
110        }
111
112        mb();
113
114        Ok(())
115    }
116
117    /// 等待电源域状态稳定
118    fn wait_power_domain_stable(&self, domain: &PowerDomain, expected_on: bool) -> NpuResult<()> {
119        for _ in 0..10000 {
120            if self.is_domain_on(domain)? == expected_on {
121                return Ok(());
122            }
123        }
124        Err(NpuError::Timeout)
125    }
126
127    /// 检查电源域是否开启
128    fn is_domain_on(&self, domain: &PowerDomain) -> NpuResult<bool> {
129        let domain_info = self
130            .info
131            .domains
132            .get(domain)
133            .ok_or(NpuError::DomainNotFound)?;
134
135        if domain_info.repair_status_mask != 0 {
136            // 使用修复状态寄存器
137            let val = self.reg.read_u32(self.info.repair_status_offset as usize);
138            // 1'b1: power on, 1'b0: power off
139            return Ok((val & (domain_info.repair_status_mask as u32)) != 0);
140        }
141
142        if domain_info.status_mask == 0 {
143            // 仅检查空闲状态的域
144            return Ok(!self.is_domain_idle(domain)?);
145        }
146
147        let val = self.reg.read_u32(self.info.status_offset as usize);
148        // 1'b0: power on, 1'b1: power off
149        Ok((val & (domain_info.status_mask as u32)) == 0)
150    }
151
152    /// 检查电源域是否空闲
153    fn is_domain_idle(&self, domain: &PowerDomain) -> NpuResult<bool> {
154        let domain_info = self
155            .info
156            .domains
157            .get(domain)
158            .ok_or(NpuError::DomainNotFound)?;
159
160        let val = self.reg.read_u32(self.info.idle_offset as usize);
161        Ok((val & (domain_info.idle_mask as u32)) == (domain_info.idle_mask as u32))
162    }
163}
164
165impl DriverGeneric for RockchipPM {
166    fn open(&mut self) -> Result<(), rdif_base::KError> {
167        Ok(())
168    }
169
170    fn close(&mut self) -> Result<(), rdif_base::KError> {
171        Ok(())
172    }
173}