svd-generator 0.6.0

Converts device information from flattened device tree into an SVD description
Documentation
use crate::svd::create_peripheral;
use crate::{Error, Result};

pub mod registers;

/// Represents the offsets of Cadence USB3 register cluster groups.
pub struct CdnsUsb3Offsets {
    /// Dual-role OTG (on-the-go) registers.
    pub otg: u32,
    /// XHCI registers.
    pub xhci: u32,
    /// Device registers.
    pub dev: u32,
}

impl<'b, 'a: 'b> TryFrom<&fdt::node::FdtNode<'b, 'a>> for CdnsUsb3Offsets {
    type Error = Error;

    fn try_from(val: &fdt::node::FdtNode<'b, 'a>) -> Result<Self> {
        let regs = val
            .reg()
            .map(|c| c.starting_address as u32)
            .collect::<Vec<u32>>();

        let reg_names = val.property("reg-names").ok_or(Error::DeviceTree(
            "CdnsUsb3 missing `reg-names` property".into(),
        ))?;

        let mut otg = None;
        let mut xhci = None;
        let mut dev = None;

        reg_names
            .as_str_list()
            .enumerate()
            .for_each(|(i, r)| {
                if r.contains("otg") {
                    otg = regs.get(i).map(|&s| s);
                } else if r.contains("xhci") {
                    xhci = regs.get(i).map(|&s| s);
                } else if r.contains("dev") {
                    dev = regs.get(i).map(|&s| s);
                }
            });

        match (otg, xhci, dev) {
            (Some(otg), Some(xhci), Some(dev)) => Ok(Self { otg, xhci, dev }),
            _ => Err(Error::DeviceTree(format!("CdnsUsb3 missing a register offset, OTG: {otg:#x?}, XHCI: {xhci:#x?}, DEV: {dev:#x?}"))), 
        }
    }
}

impl<'b, 'a: 'b> TryFrom<fdt::node::FdtNode<'b, 'a>> for CdnsUsb3Offsets {
    type Error = Error;

    fn try_from(val: fdt::node::FdtNode<'b, 'a>) -> Result<Self> {
        (&val).try_into()
    }
}

/// Represents a Cadence USB3 compatible peripheral definition.
pub struct CdnsUsb3 {
    peripheral: svd::Peripheral,
}

impl CdnsUsb3 {
    /// Creates a new [CdnsUsb3] peripheral.
    pub fn create(
        name: &str,
        base_address: u64,
        size: u32,
        interrupt: Option<Vec<svd::Interrupt>>,
        offsets: CdnsUsb3Offsets,
        dim: u32,
    ) -> Result<Self> {
        let dim_element = if dim > 0 {
            Some(
                svd::DimElement::builder()
                    .dim(dim)
                    .dim_increment(size)
                    .build(svd::ValidateLevel::Strict)?,
            )
        } else {
            None
        };

        let peripheral = create_peripheral(
            name,
            format!("Cadence USB3: {name}").as_str(),
            base_address,
            size,
            interrupt,
            Some(registers::create(offsets)?),
            dim_element,
        )?;

        Ok(Self { peripheral })
    }

    /// Gets a reference to the SVD [`Peripheral`](svd::Peripheral).
    pub const fn peripheral(&self) -> &svd::Peripheral {
        &self.peripheral
    }

    /// Gets a mutable reference to the SVD [`Peripheral`](svd::Peripheral).
    pub fn peripheral_mut(&mut self) -> &mut svd::Peripheral {
        &mut self.peripheral
    }

    /// Converts the [CdnsUsb3] into the inner SVD [`Peripheral`](svd::Peripheral).
    pub fn to_inner(self) -> svd::Peripheral {
        self.peripheral
    }
}