From 0fb096a1db5e54711154630bc4718a0aa30da8f6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 1 Jul 2025 16:17:07 +0200 Subject: [PATCH] continue phy code --- examples/zedboard/src/bin/ethernet.rs | 109 +-------------- examples/zedboard/src/lib.rs | 1 + examples/zedboard/src/phy_marvell.rs | 187 ++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 105 deletions(-) create mode 100644 examples/zedboard/src/phy_marvell.rs diff --git a/examples/zedboard/src/bin/ethernet.rs b/examples/zedboard/src/bin/ethernet.rs index 123df28..6eb22b2 100644 --- a/examples/zedboard/src/bin/ethernet.rs +++ b/examples/zedboard/src/bin/ethernet.rs @@ -63,110 +63,6 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! { main(); } -#[derive(Clone, Debug)] -pub struct PhyIdentifier { - pub oui: u32, - pub model: u8, - pub rev: u8, -} - -// Organizational Unique Identifier for Marvell 88E1518 PHY -const MARVELL_88E1518_OUI: u32 = 0x005043; -const MARVELL_88E1518_MODELL_NUMBER: u8 = 0b011101; - -#[bitbybit::bitenum(u5, exhaustive = false)] -pub enum MarvellRegistersPage0 { - CopperControl = 0x00, - CopperStatus = 0x01, - IdReg1 = 0x02, - IdReg2 = 0x03, -} - -pub struct Marvell88E1518Phy { - mdio: zynq7000_hal::eth::mdio::Mdio, - addr: u5, -} - -impl<'mdio> Marvell88E1518Phy<'mdio> { - pub fn new_autoprobe_addr( - mdio: &zynq7000_hal::eth::mdio::Mdio, - ) -> Option<(Self, u4)> { - for addr in 0..32 { - let phy_id_1 = - mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg1.raw_value()); - let phy_id_2 = - mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg2.raw_value()); - let oui = (((phy_id_2 as u32) >> 10) << 19) | ((phy_id_1 as u32) << 3); - let model_number = ((phy_id_2 >> 4) & 0b111111) as u8; - let revision_number = u4::new((phy_id_2 & 0b1111) as u8); - if oui == MARVELL_88E1518_OUI && model_number == MARVELL_88E1518_MODELL_NUMBER { - return Some(( - Self { - mdio: unsafe { mdio.clone() }, - addr: u5::new(addr), - }, - revision_number, - )); - } - } - None - } - - pub fn new(mdio: zynq7000_hal::eth::mdio::Mdio, addr: u5) -> Self { - Self { mdio, addr } - } -} - -#[bitbybit::bitfield(u16)] -pub struct CopperControlRegister { - #[bit(15, rw)] - copper_reset: bool, - #[bit(14, rw)] - loopback: bool, - #[bit(12, rw)] - auto_negotiation_enable: bool, - #[bit(11, rw)] - power_down: bool, - #[bit(10, rw)] - isolate: bool, - #[bit(9, rw)] - restart_auto_negotiation: bool, - /// 1: Full-duplex, 0: Half-duplex - #[bit(8, rw)] - copper_duplex_mode: bool, - #[bits([13, 6], rw)] - speed_selection: u2, -} - -impl Marvell88E1518Phy<'_> { - pub fn reset(&mut self) { - let mut ctrl = CopperControlRegister::new_with_raw_value( - self.mdio - .read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()), - ); - ctrl.set_copper_reset(true); - self.mdio.write_blocking( - self.addr, - MarvellRegistersPage0::CopperControl.raw_value(), - ctrl.raw_value(), - ); - } - - pub fn restart_auto_negotiation(&mut self) { - let mut ctrl = CopperControlRegister::new_with_raw_value( - self.mdio - .read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()), - ); - ctrl.set_auto_negotiation_enable(true); - ctrl.set_restart_auto_negotiation(true); - self.mdio.write_blocking( - self.addr, - MarvellRegistersPage0::CopperControl.raw_value(), - ctrl.raw_value(), - ); - } -} - #[embassy_executor::main] #[unsafe(export_name = "main")] async fn main(_spawner: Spawner) -> ! { @@ -273,7 +169,10 @@ async fn main(_spawner: Spawner) -> ! { eth.set_rx_buf_descriptor_base_address(rx_descr_ref.base_addr()); eth.set_tx_buf_descriptor_base_address(tx_descr_ref.base_addr()); let (mut phy, phy_rev) = Marvell88E1518Phy::new_autoprobe_addr(eth.mdio_mut()).unwrap(); - info!("Detected Marvell 88E1518 PHY with revision number: {:?}", phy_rev); + info!( + "Detected Marvell 88E1518 PHY with revision number: {:?}", + phy_rev + ); phy.reset(); phy.restart_auto_negotiation(); diff --git a/examples/zedboard/src/lib.rs b/examples/zedboard/src/lib.rs index 4d22d59..d712316 100644 --- a/examples/zedboard/src/lib.rs +++ b/examples/zedboard/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] use zynq7000_hal::time::Hertz; +pub mod phy_marvell; // Define the clock frequency as a constant pub const PS_CLOCK_FREQUENCY: Hertz = Hertz::from_raw(33_333_300); diff --git a/examples/zedboard/src/phy_marvell.rs b/examples/zedboard/src/phy_marvell.rs new file mode 100644 index 0000000..45905d4 --- /dev/null +++ b/examples/zedboard/src/phy_marvell.rs @@ -0,0 +1,187 @@ +#[derive(Clone, Debug)] +pub struct PhyIdentifier { + pub oui: u32, + pub model: u8, + pub rev: u8, +} + +// Organizational Unique Identifier for Marvell 88E1518 PHY +const MARVELL_88E1518_OUI: u32 = 0x005043; +const MARVELL_88E1518_MODELL_NUMBER: u8 = 0b011101; + +#[bitbybit::bitenum(u5, exhaustive = false)] +pub enum MarvellRegistersPage0 { + CopperControl = 0x00, + CopperStatus = 0x01, + IdReg1 = 0x02, + IdReg2 = 0x03, +} + +pub struct Marvell88E1518Phy { + mdio: zynq7000_hal::eth::mdio::Mdio, + addr: u5, +} + +impl<'mdio> Marvell88E1518Phy<'mdio> { + pub fn new_autoprobe_addr(mdio: &zynq7000_hal::eth::mdio::Mdio) -> Option<(Self, u4)> { + for addr in 0..32 { + let phy_id_1 = + mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg1.raw_value()); + let phy_id_2 = + mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg2.raw_value()); + let oui = (((phy_id_2 as u32) >> 10) << 19) | ((phy_id_1 as u32) << 3); + let model_number = ((phy_id_2 >> 4) & 0b111111) as u8; + let revision_number = u4::new((phy_id_2 & 0b1111) as u8); + if oui == MARVELL_88E1518_OUI && model_number == MARVELL_88E1518_MODELL_NUMBER { + return Some(( + Self { + mdio: unsafe { mdio.clone() }, + addr: u5::new(addr), + }, + revision_number, + )); + } + } + None + } + + pub fn new(mdio: zynq7000_hal::eth::mdio::Mdio, addr: u5) -> Self { + Self { mdio, addr } + } +} + +#[bitbybit::bitfield(u16)] +pub struct CopperControlRegister { + #[bit(15, rw)] + copper_reset: bool, + #[bit(14, rw)] + loopback: bool, + #[bit(12, rw)] + auto_negotiation_enable: bool, + #[bit(11, rw)] + power_down: bool, + #[bit(10, rw)] + isolate: bool, + #[bit(9, rw)] + restart_auto_negotiation: bool, + /// 1: Full-duplex, 0: Half-duplex + #[bit(8, rw)] + copper_duplex_mode: bool, + #[bits([13, 6], rw)] + speed_selection: u2, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum LatchingLinkStatus { + Up = 1, + DownSinceLastRead = 0, +} + +#[bitbybit::bitfield(u16)] +pub struct CopperStatusRegister { + /// Always 0, the 100BASE-T4 protocol is not available on Marvell 88E15XX. + #[bit(15, r)] + p_100_base_t4: bool, + /// Always 1 for Marvell 88E15XX + #[bit(14, r)] + p_100_base_x_full_duplex: bool, + /// Always 1 for Marvell 88E15XX + #[bit(13, r)] + p_100_base_x_half_duplex: bool, + /// Always 1 for Marvell 88E15XX + #[bit(12, r)] + p_10_base_t_full_duplex: bool, + /// Always 1 for Marvell 88E15XX + #[bit(11, r)] + p_10_base_t_half_duplex: bool, + /// Always 0 for Marvell 88E15XX + #[bit(10, r)] + p_100_base_t2_full_duplex: bool, + /// Always 0 for Marvell 88E15XX + #[bit(9, r)] + p_100_base_t2_half_duplex: bool, + /// Always 1 for Marvell 88E15XX + #[bit(8, r)] + extended_status: bool, + /// Always 1 for Marvell 88E15XX + #[bit(6, r)] + mf_preamble_suppression: bool, + #[bit(5, r)] + auto_negotiation_complete: bool, + // Latching high register bit. + #[bit(4, r)] + copper_remote_fault: bool, + /// Always 1 for Marvell 88E15XX + #[bit(3, r)] + auto_negotation_ability: bool, + // Latching low register bit. For the current link status, this register should be read back + // to back, or the link real time register (17_0.10) should be read + #[bit(2, r)] + copper_link_status: LatchingLinkStatus, + // Latching high register bit. + #[bit(1, r)] + jabber_detect: bool, + /// Always 1 for Marvell 88E15XX + #[bit(0, r)] + extended_capabilities: bool, +} + +#[bitbybit::bitenum(u2, exhaustive = true)] +pub enum PhySpeedBits { + Reserved = 0b11, + Mbps1000 = 0b10, + Mbps100 = 0b01, + Mbps10 = 0b00, +} + +#[bitbybit::bitenum(u1, exhaustive = true)] +pub enum PhyDuplexBit { + Full = 1, + Half = 0, +} + +#[bitbybit::bitfield(u16)] +pub struct CopperSpecificStatusRegister { + #[bits(14..=15, r)] + speed: PhySpeedBits, + #[bit(13, r)] + duplex: PhyDuplexBit, + /// Latching high register bit. + #[bit(12, r)] + page_received: bool, + /// This is 1 when auto-negotiation is not enabled. + #[bit(11, r)] + speed_and_duplex_resolved: bool, + /// This is the real-time link status. + #[bit(10, r)] + copper_link: bool +} + +impl Marvell88E1518Phy<'_> { + pub fn reset(&mut self) { + let mut ctrl = CopperControlRegister::new_with_raw_value( + self.mdio + .read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()), + ); + ctrl.set_copper_reset(true); + self.mdio.write_blocking( + self.addr, + MarvellRegistersPage0::CopperControl.raw_value(), + ctrl.raw_value(), + ); + } + + pub fn restart_auto_negotiation(&mut self) { + let mut ctrl = CopperControlRegister::new_with_raw_value( + self.mdio + .read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()), + ); + ctrl.set_auto_negotiation_enable(true); + ctrl.set_restart_auto_negotiation(true); + self.mdio.write_blocking( + self.addr, + MarvellRegistersPage0::CopperControl.raw_value(), + ctrl.raw_value(), + ); + } +}