1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! MII Management (MIIM) Interface.
//!
//! The IEEE 802.3 MII Management Interface. Allows for upper-layer devices to monitor and control
//! the state of one or more PHYs.
//!
//! Each of the 8 16-bit registers are indexed via a 5-bit address, preceded by a 5-bit PHY address.
//!
//! A blanket implementation of the `mdio::miim::{Read, Write}` traits is provided for types
//! implementing the `mdio::{Read, Write}` traits.

/// A trait for reading the standard MIIM protocol.
///
/// A blanket implementation is provided for types implementing the lower-level `mdio::Read` trait.
pub trait Read {
    /// Errors that might occur on the MIIM interface.
    type Error;
    /// Read the data from the given register address associated with the specified PHY.
    fn read(&mut self, phy_addr: u8, reg_addr: u8) -> Result<u16, Self::Error>;
}

/// A trait for writing the standard MIIM protocol.
///
/// A blanket implementation is provided for types implementing the lower-level `mdio::Write` trait.
pub trait Write {
    /// Errors that might occur on the MIIM interface.
    type Error;
    /// Write to the register at the given address associated with the specified PHY.
    fn write(&mut self, phy_addr: u8, reg_addr: u8, data: u16) -> Result<(), Self::Error>;
}

impl<T> Read for T
where
    T: crate::Read,
{
    type Error = T::Error;
    fn read(&mut self, phy_addr: u8, reg_addr: u8) -> Result<u16, Self::Error> {
        let ctrl_bits = read_ctrl_bits(phy_addr, reg_addr);
        let data_bits = crate::Read::read(self, ctrl_bits)?;
        Ok(data_bits)
    }
}

impl<T> Write for T
where
    T: crate::Write,
{
    type Error = T::Error;
    fn write(&mut self, phy_addr: u8, reg_addr: u8, data: u16) -> Result<(), Self::Error> {
        let ctrl_bits = write_ctrl_bits(phy_addr, reg_addr);
        crate::Write::write(self, ctrl_bits, data)
    }
}

fn phy_addr_ctrl_bits(phy_addr: u8) -> u16 {
    const PHY_ADDR_OFFSET: u16 = 7;
    ((phy_addr & 0b00011111) as u16) << PHY_ADDR_OFFSET
}

fn reg_addr_ctrl_bits(reg_addr: u8) -> u16 {
    const REG_ADDR_OFFSET: u16 = 2;
    ((reg_addr & 0b00011111) as u16) << REG_ADDR_OFFSET
}

/// Given the PHY and register addresses, produce the control bits for an MDIO read operation.
pub fn read_ctrl_bits(phy_addr: u8, reg_addr: u8) -> u16 {
    const READ_CTRL_BITS: u16 = 0b0110_00000_00000_00;
    READ_CTRL_BITS | phy_addr_ctrl_bits(phy_addr) | reg_addr_ctrl_bits(reg_addr)
}

/// Given the PHY and register addresses, produce the control bits for an MDIO write operation.
pub fn write_ctrl_bits(phy_addr: u8, reg_addr: u8) -> u16 {
    const WRITE_CTRL_BITS: u16 = 0b0101_00000_00000_10;
    WRITE_CTRL_BITS | phy_addr_ctrl_bits(phy_addr) | reg_addr_ctrl_bits(reg_addr)
}