Skip to content

Commit 7c2f970

Browse files
committed
feat: 添加时钟节点支持,扩展 NodeRef 和 NodeKind 枚举以支持时钟类型,更新相关逻辑和测试用例
1 parent 310b1ac commit 7c2f970

File tree

5 files changed

+264
-11
lines changed

5 files changed

+264
-11
lines changed

fdt-edit/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ pub use ctx::Context;
1515
// pub use encode::{FdtData, FdtEncoder, NodeEncode};
1616
pub use fdt::{Fdt, MemoryReservation};
1717
pub use node::*;
18+
pub use node::NodeKind;
1819
pub use prop::{Phandle, Property, RangesEntry, RegInfo, Status};

fdt-edit/src/node/clock.rs

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
use core::ops::Deref;
2+
3+
use alloc::{string::{String, ToString}, vec::Vec};
4+
use fdt_raw::Phandle;
5+
6+
use crate::node::gerneric::NodeRefGen;
7+
8+
/// 时钟提供者类型
9+
#[derive(Clone, Debug, PartialEq)]
10+
pub enum ClockType {
11+
/// 固定时钟
12+
Fixed(FixedClock),
13+
/// 普通时钟提供者
14+
Normal,
15+
}
16+
17+
/// 固定时钟
18+
#[derive(Clone, Debug, PartialEq)]
19+
pub struct FixedClock {
20+
pub name: Option<String>,
21+
/// 时钟频率 (Hz)
22+
pub frequency: u32,
23+
/// 时钟精度
24+
pub accuracy: Option<u32>,
25+
}
26+
27+
/// 时钟引用,用于解析 clocks 属性
28+
///
29+
/// 根据设备树规范,clocks 属性格式为:
30+
/// `clocks = <&clock_provider specifier [specifier ...]> [<&clock_provider2 ...>]`
31+
///
32+
/// 每个时钟引用由一个 phandle 和若干个 specifier cells 组成,
33+
/// specifier 的数量由目标 clock provider 的 `#clock-cells` 属性决定。
34+
#[derive(Clone, Debug)]
35+
pub struct ClockRef {
36+
/// 时钟的名称,来自 clock-names 属性
37+
pub name: Option<String>,
38+
/// 时钟提供者的 phandle
39+
pub phandle: Phandle,
40+
/// provider 的 #clock-cells 值
41+
pub cells: u32,
42+
/// 时钟选择器(specifier),通常第一个值用于选择时钟输出
43+
/// 长度由 provider 的 #clock-cells 决定
44+
pub specifier: Vec<u32>,
45+
}
46+
47+
impl ClockRef {
48+
/// 创建一个新的时钟引用
49+
pub fn new(phandle: Phandle, cells: u32, specifier: Vec<u32>) -> Self {
50+
Self {
51+
name: None,
52+
phandle,
53+
cells,
54+
specifier,
55+
}
56+
}
57+
58+
/// 创建一个带名称的时钟引用
59+
pub fn with_name(
60+
name: Option<String>,
61+
phandle: Phandle,
62+
cells: u32,
63+
specifier: Vec<u32>,
64+
) -> Self {
65+
Self {
66+
name,
67+
phandle,
68+
cells,
69+
specifier,
70+
}
71+
}
72+
73+
/// 获取选择器的第一个值(通常用于选择时钟输出)
74+
///
75+
/// 只有当 `cells > 0` 时才返回选择器值,
76+
/// 因为 `#clock-cells = 0` 的 provider 不需要选择器。
77+
pub fn select(&self) -> Option<u32> {
78+
if self.cells > 0 {
79+
self.specifier.first().copied()
80+
} else {
81+
None
82+
}
83+
}
84+
}
85+
86+
/// 时钟提供者节点引用
87+
#[derive(Clone, Debug)]
88+
pub struct NodeRefClock<'a> {
89+
pub node: NodeRefGen<'a>,
90+
pub clock_output_names: Vec<String>,
91+
pub clock_cells: u32,
92+
pub kind: ClockType,
93+
}
94+
95+
impl<'a> NodeRefClock<'a> {
96+
pub fn try_from(node: NodeRefGen<'a>) -> Result<Self, NodeRefGen<'a>> {
97+
// 检查是否有时钟提供者属性
98+
if node.find_property("#clock-cells").is_none() {
99+
return Err(node);
100+
}
101+
102+
// 获取 clock-output-names 属性
103+
let clock_output_names = if let Some(prop) = node.find_property("clock-output-names") {
104+
let iter = prop.as_str_iter();
105+
iter.map(|s| s.to_string()).collect()
106+
} else {
107+
Vec::new()
108+
};
109+
110+
// 获取 #clock-cells
111+
let clock_cells = node
112+
.find_property("#clock-cells")
113+
.and_then(|prop| prop.get_u32())
114+
.unwrap_or(0);
115+
116+
// 判断时钟类型
117+
let kind = if node.compatibles().any(|c| c == "fixed-clock") {
118+
let frequency = node
119+
.find_property("clock-frequency")
120+
.and_then(|prop| prop.get_u32())
121+
.unwrap_or(0);
122+
let accuracy = node
123+
.find_property("clock-accuracy")
124+
.and_then(|prop| prop.get_u32());
125+
let name = clock_output_names.first().cloned();
126+
127+
ClockType::Fixed(FixedClock {
128+
name,
129+
frequency,
130+
accuracy,
131+
})
132+
} else {
133+
ClockType::Normal
134+
};
135+
136+
Ok(Self {
137+
node,
138+
clock_output_names,
139+
clock_cells,
140+
kind,
141+
})
142+
}
143+
144+
/// 获取时钟输出名称(用于 provider)
145+
pub fn output_name(&self, index: usize) -> Option<&str> {
146+
self.clock_output_names.get(index).map(|s| s.as_str())
147+
}
148+
149+
/// 解析 clocks 属性,返回时钟引用列表
150+
///
151+
/// 通过查找每个 phandle 对应的 clock provider 的 #clock-cells,
152+
/// 正确解析 specifier 的长度。
153+
pub fn clocks(&self) -> Vec<ClockRef> {
154+
let Some(prop) = self.find_property("clocks") else {
155+
return Vec::new();
156+
};
157+
158+
let mut clocks = Vec::new();
159+
let mut data = prop.as_reader();
160+
let mut index = 0;
161+
162+
// 获取 clock-names 用于命名
163+
let clock_names = if let Some(prop) = self.find_property("clock-names") {
164+
let iter = prop.as_str_iter();
165+
iter.map(|s| s.to_string()).collect()
166+
} else {
167+
Vec::new()
168+
};
169+
170+
while let Some(phandle_raw) = data.read_u32() {
171+
let phandle = Phandle::from(phandle_raw);
172+
173+
// 通过 phandle 查找 provider 节点,获取其 #clock-cells
174+
let clock_cells = if let Some(provider) = self.ctx.find_by_phandle(phandle) {
175+
provider
176+
.get_property("#clock-cells")
177+
.and_then(|p| p.get_u32())
178+
.unwrap_or(1) // 默认 1 cell
179+
} else {
180+
1 // 默认 1 cell
181+
};
182+
183+
// 读取 specifier(根据 provider 的 #clock-cells)
184+
let mut specifier = Vec::with_capacity(clock_cells as usize);
185+
let mut complete = true;
186+
for _ in 0..clock_cells {
187+
if let Some(val) = data.read_u32() {
188+
specifier.push(val);
189+
} else {
190+
// 数据不足,停止解析
191+
complete = false;
192+
break;
193+
}
194+
}
195+
196+
// 只有完整的 clock reference 才添加
197+
if !complete {
198+
break;
199+
}
200+
201+
// 从 clock-names 获取对应的名称
202+
let name = clock_names.get(index).cloned();
203+
204+
clocks.push(ClockRef::with_name(
205+
name,
206+
phandle,
207+
clock_cells,
208+
specifier,
209+
));
210+
index += 1;
211+
}
212+
213+
clocks
214+
}
215+
}
216+
217+
impl<'a> Deref for NodeRefClock<'a> {
218+
type Target = NodeRefGen<'a>;
219+
220+
fn deref(&self) -> &Self::Target {
221+
&self.node
222+
}
223+
}

fdt-edit/src/node/iter.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,44 @@ use core::{
88
use alloc::vec::Vec;
99

1010
use crate::{
11-
Context, Node, NodeRefPci,
11+
Context, Node, NodeRefPci, NodeRefClock, NodeKind,
1212
node::gerneric::{NodeMutGen, NodeRefGen},
1313
};
1414

1515
#[derive(Clone, Debug)]
1616
pub enum NodeRef<'a> {
1717
Gerneric(NodeRefGen<'a>),
1818
Pci(NodeRefPci<'a>),
19+
Clock(NodeRefClock<'a>),
1920
}
2021

2122
impl<'a> NodeRef<'a> {
2223
pub fn new(node: &'a Node, ctx: Context<'a>) -> Self {
2324
let mut g = NodeRefGen { node, ctx };
2425

26+
// 先尝试 PCI
2527
g = match NodeRefPci::try_from(g) {
2628
Ok(pci) => return Self::Pci(pci),
2729
Err(v) => v,
2830
};
2931

32+
// 再尝试 Clock
33+
g = match NodeRefClock::try_from(g) {
34+
Ok(clock) => return Self::Clock(clock),
35+
Err(v) => v,
36+
};
37+
3038
Self::Gerneric(g)
3139
}
40+
41+
/// 获取节点的具体类型用于模式匹配
42+
pub fn as_ref(&self) -> NodeKind<'a> {
43+
match self {
44+
NodeRef::Clock(clock) => NodeKind::Clock(clock.clone()),
45+
NodeRef::Pci(pci) => NodeKind::Pci(pci.clone()),
46+
NodeRef::Gerneric(generic) => NodeKind::Generic(generic.clone()),
47+
}
48+
}
3249
}
3350

3451
impl<'a> Deref for NodeRef<'a> {
@@ -38,6 +55,7 @@ impl<'a> Deref for NodeRef<'a> {
3855
match self {
3956
NodeRef::Gerneric(n) => n,
4057
NodeRef::Pci(n) => &n.node,
58+
NodeRef::Clock(n) => &n.node,
4159
}
4260
}
4361
}

fdt-edit/src/node/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@ use alloc::{
77
};
88
use fdt_raw::data::StrIter;
99

10-
use crate::{Phandle, Property, RangesEntry, Status};
10+
use crate::{Phandle, Property, RangesEntry, Status, node::gerneric::NodeRefGen};
1111

12+
mod clock;
1213
mod gerneric;
1314
mod iter;
1415
mod pci;
1516

17+
pub use clock::*;
1618
pub use iter::*;
1719
pub use pci::*;
1820

21+
/// 节点类型枚举,用于模式匹配
22+
#[derive(Clone, Debug)]
23+
pub enum NodeKind<'a> {
24+
Clock(NodeRefClock<'a>),
25+
Pci(NodeRefPci<'a>),
26+
Generic(NodeRefGen<'a>),
27+
}
28+
1929
#[derive(Clone)]
2030
pub struct Node {
2131
pub name: String,

fdt-edit/tests/clock.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use dtb_file::*;
44
use fdt_edit::*;
5+
use fdt_edit::NodeKind;
56

67
#[cfg(test)]
78
mod tests {
@@ -16,7 +17,7 @@ mod tests {
1617
// 遍历查找 clock 节点(有 #clock-cells 属性的节点)
1718
let mut clock_count = 0;
1819
for node in fdt.all_nodes() {
19-
if let Node::Clock(clock) = node.as_ref() {
20+
if let NodeKind::Clock(clock) = node.as_ref() {
2021
clock_count += 1;
2122
println!(
2223
"Clock node: {} (#clock-cells={})",
@@ -34,7 +35,7 @@ mod tests {
3435
let fdt = Fdt::from_bytes(&raw_data).unwrap();
3536

3637
for node in fdt.all_nodes() {
37-
if let Node::Clock(clock) = node.as_ref() {
38+
if let NodeKind::Clock(clock) = node.as_ref() {
3839
// 获取 #clock-cells
3940
let cells = clock.clock_cells;
4041
println!("Clock: {} cells={}", clock.name(), cells);
@@ -67,7 +68,7 @@ mod tests {
6768
// 查找固定时钟
6869
let mut found_with_freq = false;
6970
for node in fdt.all_nodes() {
70-
if let Node::Clock(clock) = node.as_ref() {
71+
if let NodeKind::Clock(clock) = node.as_ref() {
7172
if let ClockType::Fixed(fixed) = &clock.kind {
7273
// 打印固定时钟信息
7374
println!(
@@ -96,7 +97,7 @@ mod tests {
9697
let fdt = Fdt::from_bytes(&raw_data).unwrap();
9798

9899
for node in fdt.all_nodes() {
99-
if let Node::Clock(clock) = node.as_ref() {
100+
if let NodeKind::Clock(clock) = node.as_ref() {
100101
let names = &clock.clock_output_names;
101102
if !names.is_empty() {
102103
// 测试 output_name 方法
@@ -119,7 +120,7 @@ mod tests {
119120
let fdt = Fdt::from_bytes(&raw_data).unwrap();
120121

121122
for node in fdt.all_nodes() {
122-
if let Node::Clock(clock) = node.as_ref() {
123+
if let NodeKind::Clock(clock) = node.as_ref() {
123124
match &clock.kind {
124125
ClockType::Fixed(fixed) => {
125126
// 打印固定时钟信息
@@ -146,10 +147,10 @@ mod tests {
146147

147148
let mut found_clocks = false;
148149
for node in fdt.all_nodes() {
149-
if let Node::Clock(clock_ref) = node.as_ref() {
150+
if let NodeKind::Clock(clock_ref) = node.as_ref() {
150151
found_clocks = true;
151152

152-
let clocks = clock_ref.clocks(&node.ctx);
153+
let clocks = clock_ref.clocks();
153154
if !clocks.is_empty() {
154155
found_clocks = true;
155156
println!(
@@ -182,8 +183,8 @@ mod tests {
182183

183184
for node in fdt.all_nodes() {
184185
// 使用 as_clock_ref 获取带上下文的 clock 引用
185-
if let Node::Clock(clock) = node.as_ref() {
186-
let clocks = clock.clocks(&node.ctx);
186+
if let NodeKind::Clock(clock) = node.as_ref() {
187+
let clocks = clock.clocks();
187188
for clk in clocks {
188189
// 测试 select() 方法
189190
if clk.cells > 0 {

0 commit comments

Comments
 (0)