fdt_edit/node/
clock.rs

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