zynq7000_hal/eth/
mdio.rs

1use arbitrary_int::{u2, u5};
2use zynq7000::eth::{MdcClockDivisor, PhyMaintenance};
3
4use super::{EthernetId, ll::EthernetLowLevel};
5
6pub struct Mdio {
7    regs: zynq7000::eth::MmioEthernet<'static>,
8    clause22: bool,
9}
10
11impl Mdio {
12    pub fn new(ll: &EthernetLowLevel, clause22: bool) -> Self {
13        Self {
14            regs: unsafe { ll.regs.clone() },
15            clause22,
16        }
17    }
18
19    /// # Safety
20    ///
21    /// Circumvents ownership and safety guarantees of the HAL.
22    pub unsafe fn steal(eth_id: EthernetId, clause22: bool) -> Self {
23        Self {
24            regs: unsafe { eth_id.steal_regs() },
25            clause22,
26        }
27    }
28
29    /// Steals the MDIO handle from the given Ethernet low-level interface.
30    ///
31    /// # Safety
32    ///
33    /// Circumvents ownership and safety guarantees of the HAL.
34    pub unsafe fn clone(&self) -> Self {
35        Self {
36            regs: unsafe { self.regs.clone() },
37            clause22: self.clause22,
38        }
39    }
40
41    #[inline]
42    pub fn configure_clock_div(&mut self, clk_div: MdcClockDivisor) {
43        self.regs.modify_net_cfg(|mut val| {
44            val.set_mdc_clk_div(clk_div);
45            val
46        });
47    }
48
49    pub fn read_blocking(&mut self, phy_addr: u5, reg_addr: u5) -> u16 {
50        while !self.regs.read_net_status().phy_mgmt_idle() {}
51        self.regs.write_phy_maintenance(
52            PhyMaintenance::builder()
53                .with_clause_22(self.clause22)
54                .with_op(zynq7000::eth::PhyOperation::Read)
55                .with_phy_addr(phy_addr)
56                .with_reg_addr(reg_addr)
57                .with_must_be_0b10(u2::new(0b10))
58                .with_data(0x0000)
59                .build(),
60        );
61        while !self.regs.read_net_status().phy_mgmt_idle() {}
62        self.regs.read_phy_maintenance().data()
63    }
64
65    pub fn write_blocking(&mut self, phy_addr: u5, reg_addr: u5, data: u16) {
66        while !self.regs.read_net_status().phy_mgmt_idle() {}
67        self.regs.write_phy_maintenance(
68            PhyMaintenance::builder()
69                .with_clause_22(self.clause22)
70                .with_op(zynq7000::eth::PhyOperation::Write)
71                .with_phy_addr(phy_addr)
72                .with_reg_addr(reg_addr)
73                .with_must_be_0b10(u2::new(0b10))
74                .with_data(data)
75                .build(),
76        );
77        while !self.regs.read_net_status().phy_mgmt_idle() {}
78    }
79}