1use alloc::{
2 collections::{BTreeMap, btree_set::BTreeSet},
3 vec::Vec,
4};
5use core::ptr::NonNull;
6use spin::{Mutex, Once};
7
8pub use fdt_parser::*;
9
10use crate::{
11 Descriptor, DeviceId, PlatformDevice,
12 error::DriverError,
13 probe::OnProbeError,
14 register::{DriverRegister, ProbeKind},
15};
16
17use super::ProbeError;
18
19static SYSTEM: Once<System> = Once::new();
20
21pub fn init(fdt_addr: NonNull<u8>) -> Result<(), DriverError> {
22 let sys = System::new(fdt_addr)?;
23 SYSTEM.call_once(|| sys);
24 Ok(())
25}
26
27pub fn probe_register(
28 register: &DriverRegister,
29) -> Result<Vec<Result<(), OnProbeError>>, ProbeError> {
30 let sys = system();
31 sys.probe_register(register)
32}
33
34pub(crate) fn system() -> &'static System {
35 SYSTEM.get().expect("rdrive not init")
36}
37
38#[derive(Clone)]
39pub struct FdtInfo<'a> {
40 pub node: Node<'a>,
41 phandle_2_device_id: BTreeMap<Phandle, DeviceId>,
42}
43
44impl<'a> FdtInfo<'a> {
45 pub fn phandle_to_device_id(&self, phandle: Phandle) -> Option<DeviceId> {
46 self.phandle_2_device_id.get(&phandle).copied()
47 }
48
49 pub fn find_clk_by_name(&'a self, name: &str) -> Option<ClockRef<'a>> {
50 self.node.clocks().find(|clock| clock.name == Some(name))
51 }
52
53 pub fn interrupts(&self) -> Vec<Vec<u32>> {
54 let mut out = Vec::new();
55 if let Some(raws) = self.node.interrupts() {
56 for raw in raws {
57 out.push(raw.collect());
58 }
59 }
60 out
61 }
62}
63
64pub type FnOnProbe = fn(fdt: FdtInfo<'_>, plat_dev: PlatformDevice) -> Result<(), OnProbeError>;
65
66pub struct System {
67 phandle_2_device_id: BTreeMap<Phandle, DeviceId>,
68 fdt_addr: usize,
69 probed_names: Mutex<BTreeSet<&'static str>>,
71}
72
73unsafe impl Send for System {}
74
75impl System {
76 pub fn fdt_addr(&self) -> NonNull<u8> {
77 unsafe { NonNull::new_unchecked(self.fdt_addr as *mut u8) }
78 }
79
80 pub fn phandle_to_device_id(&self, phandle: Phandle) -> Option<DeviceId> {
81 self.phandle_2_device_id.get(&phandle).copied()
82 }
83}
84
85impl System {
86 pub fn new(fdt_addr: NonNull<u8>) -> Result<Self, DriverError> {
87 let fdt = Fdt::from_ptr(fdt_addr)?;
88 let mut phandle_2_device_id = BTreeMap::new();
89 for node in fdt.all_nodes() {
90 if let Some(phandle) = node.phandle() {
91 phandle_2_device_id.insert(phandle, DeviceId::new());
92 }
93 }
94 Ok(Self {
95 phandle_2_device_id,
96 fdt_addr: fdt_addr.as_ptr() as usize,
97 probed_names: Mutex::new(BTreeSet::new()),
98 })
99 }
100
101 fn new_device_id(&self, phandle: Option<Phandle>) -> DeviceId {
102 if let Some(phandle) = phandle {
103 self.phandle_2_device_id[&phandle]
104 } else {
105 DeviceId::new()
106 }
107 }
108
109 fn get_fdt_match_nodes(
110 &self,
111 register: &DriverRegister,
112 fdt: &Fdt<'static>,
113 ) -> Vec<ProbeFdtInfo> {
114 let mut out = Vec::new();
115 for node in fdt.all_nodes() {
116 if matches!(node.status(), Some(Status::Disabled)) {
117 continue;
118 }
119
120 let node_compatibles = node.compatibles().collect::<Vec<_>>();
121
122 for probe in register.probe_kinds {
123 let &ProbeKind::Fdt {
124 compatibles,
125 on_probe,
126 } = probe
127 else {
128 continue;
129 };
130
131 for campatible in &node_compatibles {
132 if compatibles.contains(campatible) {
133 out.push(ProbeFdtInfo {
134 name: register.name,
135 node: node.clone(),
136 on_probe,
137 });
138 }
139 }
140 }
141 }
142 out
143 }
144
145 fn probe_register(
146 &self,
147 register: &DriverRegister,
148 ) -> Result<Vec<Result<(), OnProbeError>>, ProbeError> {
149 let fdt: Fdt<'static> = Fdt::from_ptr(self.fdt_addr())?;
150 let node_ls = self.get_fdt_match_nodes(register, &fdt);
151 let mut out = Vec::new();
152 for node_info in node_ls {
153 if self.probed_names.lock().contains(node_info.name) {
154 continue;
156 }
157 let id = self.new_device_id(node_info.node.phandle());
158
159 let irq_parent = node_info
160 .node
161 .interrupt_parent()
162 .filter(|p| p.node.phandle() != node_info.node.phandle())
163 .and_then(|n| n.node.phandle())
164 .and_then(|p| self.phandle_2_device_id.get(&p).copied());
165
166 let phandle_map = self.phandle_2_device_id.clone();
167
168 debug!("Probe [{}]->[{}]", node_info.node.name, node_info.name);
169
170 let descriptor = Descriptor {
171 name: node_info.name,
172 device_id: id,
173 irq_parent,
174 };
175
176 let res = (node_info.on_probe)(
177 FdtInfo {
178 node: node_info.node.clone(),
179 phandle_2_device_id: phandle_map,
180 },
181 PlatformDevice::new(descriptor),
182 );
183
184 if res.is_ok() {
185 self.probed_names.lock().insert(node_info.name);
186 }
187
188 out.push(res);
189 }
190
191 Ok(out)
192 }
193}
194
195struct ProbeFdtInfo {
196 name: &'static str,
197 node: Node<'static>,
198 on_probe: FnOnProbe,
199}