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