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 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 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}