1use crate::tree::{parse_interrupts, Compatible};
2use crate::{Error, Result};
3
4pub mod cdns_qspi_nor;
5pub mod cdns_usb3;
6pub mod cdns_xspi_nor;
7pub mod dw_apb_i2c;
8pub mod dw_apb_uart;
9pub mod dw_axi_dmac;
10pub mod dw_mmc;
11pub mod dwgmac;
12pub mod dwmac;
13pub mod jh7110_aon_pinctrl;
14pub mod jh7110_aon_syscon;
15pub mod jh7110_aoncrg;
16pub mod jh7110_crypto;
17pub mod jh7110_isp_syscon;
18pub mod jh7110_ispcrg;
19pub mod jh7110_mipitx_dphy;
20pub mod jh7110_pmu;
21pub mod jh7110_stg_syscon;
22pub mod jh7110_stgcrg;
23pub mod jh7110_sys_pinctrl;
24pub mod jh7110_sys_syscon;
25pub mod jh7110_syscrg;
26pub mod jh7110_tdm;
27pub mod jh7110_trng;
28pub mod jh7110_vout_syscon;
29pub mod jh7110_voutcrg;
30pub mod jh7110_wdt;
31pub mod oc_pwm;
32pub mod oe_omc;
33pub mod oe_ophy;
34pub mod pl022_ssp_spi;
35pub mod pl080_dmac;
36pub mod riscv_clint;
37pub mod riscv_plic;
38pub mod sifive_u74_l2pm;
39pub mod sifive_u74_sram;
40
41use cdns_qspi_nor::CdnsQspiNor;
42use cdns_usb3::{CdnsUsb3, CdnsUsb3Offsets};
43use cdns_xspi_nor::CdnsXspiNor;
44use dw_apb_i2c::DwApbI2c;
45use dw_apb_uart::DwApbUart;
46use dw_axi_dmac::DwAxiDmac;
47use dw_mmc::{DwMmc, DwMmcModel};
48use dwgmac::{DwGmac, DwGmacVersion};
49use dwmac::DwMac;
50use jh7110_aon_pinctrl::Jh7110AonPinctrl;
51use jh7110_aon_syscon::Jh7110AonSyscon;
52use jh7110_aoncrg::Jh7110AonCrg;
53use jh7110_crypto::Jh7110Crypto;
54use jh7110_isp_syscon::Jh7110IspSyscon;
55use jh7110_ispcrg::Jh7110IspCrg;
56use jh7110_mipitx_dphy::Jh7110MipiTxDphy;
57use jh7110_pmu::Jh7110Pmu;
58use jh7110_stg_syscon::Jh7110StgSyscon;
59use jh7110_stgcrg::Jh7110StgCrg;
60use jh7110_sys_pinctrl::Jh7110SysPinctrl;
61use jh7110_sys_syscon::Jh7110SysSyscon;
62use jh7110_syscrg::Jh7110SysCrg;
63use jh7110_tdm::Jh7110Tdm;
64use jh7110_trng::Jh7110Trng;
65use jh7110_vout_syscon::Jh7110VoutSyscon;
66use jh7110_voutcrg::Jh7110VoutCrg;
67use jh7110_wdt::Jh7110Wdt;
68use oc_pwm::OcPwm;
69use oe_omc::OeOmc;
70use oe_ophy::OeOphy;
71use pl022_ssp_spi::Pl022SspSpi;
72use pl080_dmac::Pl080Dmac;
73use riscv_clint::RiscvClint;
74use riscv_plic::RiscvPlic;
75use sifive_u74_l2pm::SiFiveU74L2pm;
76use sifive_u74_sram::SiFiveU74Sram;
77
78pub struct PeripheralCount {
80 pub i2c: usize,
82 pub qspi: usize,
84 pub spi: usize,
86 pub uart: usize,
88 pub mac: usize,
90 pub mmc: usize,
92 pub usb: usize,
94}
95
96impl PeripheralCount {
97 pub const fn new() -> Self {
99 Self {
100 i2c: 0,
101 qspi: 0,
102 spi: 0,
103 uart: 0,
104 mac: 0,
105 mmc: 0,
106 usb: 0,
107 }
108 }
109}
110
111impl Default for PeripheralCount {
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117pub fn create_peripheral(
119 name: &str,
120 desc: &str,
121 base_address: u64,
122 size: u32,
123 interrupt: Option<Vec<svd::Interrupt>>,
124 registers: Option<Vec<svd::RegisterCluster>>,
125 dim_element: Option<svd::DimElement>,
126) -> Result<svd::Peripheral> {
127 let info = svd::PeripheralInfo::builder()
128 .name(name.into())
129 .description(Some(desc.into()))
130 .base_address(base_address)
131 .address_block(Some(
132 [svd::AddressBlock::builder()
133 .offset(0)
134 .size(size)
135 .usage(svd::AddressBlockUsage::Registers)
136 .build(svd::ValidateLevel::Strict)?]
137 .into(),
138 ))
139 .interrupt(interrupt)
140 .registers(registers)
141 .build(svd::ValidateLevel::Strict)?;
142
143 match dim_element {
144 Some(dim) => Ok(svd::Peripheral::Array(info, dim)),
145 None => Ok(svd::Peripheral::Single(info)),
146 }
147}
148
149pub fn parse_peripherals(dt: &fdt::Fdt) -> Result<Vec<svd::Peripheral>> {
164 let mut count = PeripheralCount::new();
165
166 let harts = dt.cpus().count();
167
168 Ok(dt
169 .find_node("/soc")
170 .ok_or(Error::Svd("no `soc` node found in DeviceTree".into()))?
171 .children()
172 .filter(|n| Compatible::from(n).is_known())
173 .filter_map(|n| parse_peripheral(&n, harts, &mut count).ok())
174 .collect())
175}
176
177fn parse_peripheral(
178 node: &fdt::node::FdtNode,
179 harts: usize,
180 count: &mut PeripheralCount,
181) -> Result<svd::Peripheral> {
182 let name = node.name;
183 let comp = Compatible::from(node);
184 let comp_str = node
185 .property("compatible")
186 .ok_or(Error::DeviceTree(format!(
187 "{name} missing `compatible` property"
188 )))?
189 .as_str()
190 .unwrap_or(<&str>::from(&comp));
191
192 let reg_names = node
193 .property("reg-names")
194 .map(|p| p.as_str().unwrap_or(""))
195 .unwrap_or("");
196 let desc = format!("{name} {comp_str},{reg_names} peripheral generator");
197
198 let (address, size) = if node.property("reg").is_some() {
199 let r = node
200 .reg()
201 .next()
202 .ok_or(Error::DeviceTree("empty `reg` property".into()))?;
203
204 let size = r.size.ok_or(Error::DeviceTree(
205 "`reg` property missing `size` field".into(),
206 ))?;
207
208 (r.starting_address as u64, size as u32)
209 } else if node.property("ranges").is_some() {
210 node.ranges()
211 .next()
212 .map(|m| (m.parent_bus_address as u64, m.size as u32))
213 .ok_or(Error::DeviceTree("invalid `ranges` property".into()))?
214 } else {
215 return Err(Error::DeviceTree(
216 "no valid address, size property found".into(),
217 ));
218 };
219
220 Ok(match comp {
221 Compatible::CdnsQspiNor => {
222 let interrupt = parse_interrupts(node, "QSPI", Some(count.qspi)).ok();
223
224 CdnsQspiNor::create("qspi", address, size, interrupt, 0)?.to_inner()
225 }
226 Compatible::CdnsXspiNor => {
227 let interrupt = parse_interrupts(node, "XSPI", Some(count.qspi)).ok();
228
229 CdnsXspiNor::create("xspi", address, size, interrupt, 0)?.to_inner()
230 }
231 Compatible::DwApbI2c => {
232 let i2c_name = format!("i2c{}", count.i2c);
233
234 let interrupt = parse_interrupts(node, "I2C", Some(count.i2c)).ok();
235
236 count.i2c += 1;
237
238 DwApbI2c::create(i2c_name.as_str(), address, size, interrupt, 0)?.to_inner()
239 }
240 Compatible::DwApbUart => {
241 let uart_name = format!("uart{}", count.uart);
242
243 let interrupt = parse_interrupts(node, "UART", Some(count.uart)).ok();
244
245 count.uart += 1;
246
247 DwApbUart::create(uart_name.as_str(), address, size, interrupt, 0)?.to_inner()
248 }
249 Compatible::DwAxiDmac => {
250 let interrupt = parse_interrupts(node, "DMA", None).ok();
251 let dma_channels = node
252 .property("dma-channels")
253 .and_then(|p| p.as_usize())
254 .unwrap_or_default() as u64;
255
256 DwAxiDmac::create("dma", address, size, interrupt, dma_channels, 0)?.to_inner()
257 }
258 Compatible::DwMac => {
259 let mac_name = format!("gmac{}", count.mac);
260
261 let interrupt = parse_interrupts(node, "GMAC", Some(count.mac)).ok();
262
263 count.mac += 1;
264
265 let version = DwGmacVersion::from(comp_str);
266
267 match version {
268 DwGmacVersion::Version340 | DwGmacVersion::Version350 => {
269 if node
270 .property("phy-mode")
271 .map(|p| p.as_str().unwrap_or("").contains("rgmii"))
272 .unwrap_or(false)
273 {
274 DwGmac::create(mac_name.as_str(), address, size, interrupt, version, 0)?
275 .to_inner()
276 } else {
277 DwMac::create(mac_name.as_str(), address, size, interrupt, 0)?.to_inner()
278 }
279 }
280 _ => DwGmac::create(mac_name.as_str(), address, size, interrupt, version, 0)?
281 .to_inner(),
282 }
283 }
284 Compatible::DwMmc => {
285 let mmc_name = format!("mmc{}", count.mmc);
286
287 let interrupt = parse_interrupts(node, "MMC", Some(count.mmc)).ok();
288
289 count.mmc += 1;
290
291 let model = DwMmcModel::try_from(comp_str)?;
292
293 DwMmc::create(&mmc_name, address, size, interrupt, model)?.to_inner()
294 }
295 Compatible::Jh7110AonCrg => {
296 let interrupt = parse_interrupts(node, "AONCRG", None).ok();
297
298 Jh7110AonCrg::create("aoncrg", address, size, interrupt)?.to_inner()
299 }
300 Compatible::Jh7110AonPinctrl => {
301 let interrupt = parse_interrupts(node, "AON_IOMUX", None).ok();
302
303 Jh7110AonPinctrl::create("aon_pinctrl", address, size, interrupt)?.to_inner()
304 }
305 Compatible::Jh7110AonSyscon => {
306 let interrupt = parse_interrupts(node, "AON_SYSCON", None).ok();
307
308 Jh7110AonSyscon::create("aon_syscon", address, size, interrupt)?.to_inner()
309 }
310 Compatible::Jh7110Crypto => {
311 let interrupt = parse_interrupts(node, "CRYPTO", None).ok();
312
313 Jh7110Crypto::create("crypto", address, size, interrupt)?.to_inner()
314 }
315 Compatible::Jh7110IspCrg => {
316 let interrupt = parse_interrupts(node, "ISPCRG", None).ok();
317
318 Jh7110IspCrg::create("ispcrg", address, size, interrupt)?.to_inner()
319 }
320 Compatible::Jh7110IspSyscon => {
321 let interrupt = parse_interrupts(node, "ISP_SYSCON", None).ok();
322
323 Jh7110IspSyscon::create("isp_syscon", address, size, interrupt)?.to_inner()
324 }
325 Compatible::Jh7110MipiTxDphy => {
326 let interrupt = parse_interrupts(node, "MIPITX_DPHY", None).ok();
327
328 Jh7110MipiTxDphy::create("mipitx_dphy", address, size, interrupt)?.to_inner()
329 }
330 Compatible::Jh7110Pmu => {
331 let interrupt = parse_interrupts(node, "PMU", None).ok();
332
333 Jh7110Pmu::create("pmu", address, size, interrupt)?.to_inner()
334 }
335 Compatible::Jh7110StgCrg => {
336 let interrupt = parse_interrupts(node, "STGCRG", None).ok();
337
338 Jh7110StgCrg::create("stgcrg", address, size, interrupt)?.to_inner()
339 }
340 Compatible::Jh7110StgSyscon => {
341 let interrupt = parse_interrupts(node, "STG_SYSCON", None).ok();
342
343 Jh7110StgSyscon::create("stg_syscon", address, size, interrupt)?.to_inner()
344 }
345 Compatible::Jh7110SysCrg => {
346 let interrupt = parse_interrupts(node, "SYSCRG", None).ok();
347
348 Jh7110SysCrg::create("syscrg", address, size, interrupt)?.to_inner()
349 }
350 Compatible::Jh7110SysPinctrl => {
351 let interrupt = parse_interrupts(node, "SYS_IOMUX", None).ok();
352
353 Jh7110SysPinctrl::create("sys_pinctrl", address, size, interrupt)?.to_inner()
354 }
355 Compatible::Jh7110SysSyscon => {
356 let interrupt = parse_interrupts(node, "SYS_SYCON", None).ok();
357
358 Jh7110SysSyscon::create("sys_syscon", address, size, interrupt)?.to_inner()
359 }
360 Compatible::Jh7110Tdm => {
361 let interrupt = parse_interrupts(node, "TDM", None).ok();
362
363 Jh7110Tdm::create("tdm", address, size, interrupt)?.to_inner()
364 }
365 Compatible::Jh7110Trng => {
366 let interrupt = parse_interrupts(node, "TRNG", None).ok();
367
368 Jh7110Trng::create("trng", address, size, interrupt)?.to_inner()
369 }
370 Compatible::Jh7110Usb => {
371 let usb_name = format!("usb{}", count.usb);
372
373 let usb_node = node
374 .children()
375 .find(|n| Compatible::from(n) == Compatible::CdnsUsb3)
376 .ok_or(Error::DeviceTree(
377 "StarFive JH7110 USB does not have `cdns,usb3` child node".into(),
378 ))?;
379
380 let reg_offsets = CdnsUsb3Offsets::try_from(usb_node)?;
381
382 let interrupt = parse_interrupts(&usb_node, &usb_name, Some(count.usb)).ok();
383
384 count.usb += 1;
385
386 CdnsUsb3::create(usb_name.as_str(), address, size, interrupt, reg_offsets, 0)?
387 .to_inner()
388 }
389 Compatible::Jh7110VoutCrg => {
390 let interrupt = parse_interrupts(node, "VOUTCRG", None).ok();
391
392 Jh7110VoutCrg::create("voutcrg", address, size, interrupt)?.to_inner()
393 }
394 Compatible::Jh7110VoutSyscon => {
395 let interrupt = parse_interrupts(node, "VOUT_SYSCON", None).ok();
396
397 Jh7110VoutSyscon::create("vout_syscon", address, size, interrupt)?.to_inner()
398 }
399 Compatible::Jh7110Wdt => {
400 let interrupt = parse_interrupts(node, "WDT", None).ok();
401
402 Jh7110Wdt::create("wdt", address, size, interrupt, 0)?.to_inner()
403 }
404 Compatible::Pl022SspSpi => {
405 let spi_name = format!("spi{}", count.spi);
406
407 let interrupt = parse_interrupts(node, "SPI", Some(count.spi)).ok();
408
409 count.spi += 1;
410
411 Pl022SspSpi::create(spi_name.as_str(), address, size, interrupt, 0)?.to_inner()
412 }
413 Compatible::Pl080Dmac => {
414 let interrupt = parse_interrupts(node, "SDMA", None).ok();
415
416 Pl080Dmac::create("sdma", address, size, interrupt, 0)?.to_inner()
417 }
418 Compatible::RiscvClint => RiscvClint::create(address, size, harts)?.to_inner(),
419 Compatible::RiscvPlic => {
420 let ndev = node
421 .property("riscv,ndev")
422 .map(|p| p.as_usize().unwrap_or(1))
423 .ok_or(Error::DeviceTree(
424 "riscv,plic missing `riscv,ndev` property".into(),
425 ))?;
426
427 RiscvPlic::create(address, size, harts, ndev)?.to_inner()
428 }
429 Compatible::OcPwm => {
430 let interrupt = parse_interrupts(node, "PWM", None).ok();
431
432 OcPwm::create("pwm", address, size, interrupt, 0)?.to_inner()
433 }
434 Compatible::OeOmc => {
435 let interrupt = parse_interrupts(node, "DMC_CTRL", None).ok();
436
437 OeOmc::create("dmc_ctrl", address, size, interrupt, 0)?.to_inner()
438 }
439 Compatible::OeOphy => {
440 let interrupt = parse_interrupts(node, "DMC_PHY", None).ok();
441
442 OeOphy::create("dmc_phy", address, size, interrupt, 0)?.to_inner()
443 }
444 Compatible::SiFiveU74L2pm => {
445 let interrupt = parse_interrupts(node, "L2PM", None).ok();
446
447 SiFiveU74L2pm::create("l2pm", address, size, interrupt, 0)?.to_inner()
448 }
449 Compatible::SiFiveU74Sram => {
450 let interrupt = parse_interrupts(node, "SRAM", None).ok();
451
452 SiFiveU74Sram::create("sram", address, size, interrupt, 0)?.to_inner()
453 }
454 _ => create_peripheral(name, desc.as_str(), address, size, None, None, None)?,
455 })
456}