From 5823d90db1cfdfa052643acc747866b7b28ffa23 Mon Sep 17 00:00:00 2001 From: Astro Date: Tue, 25 Jun 2019 21:48:47 +0200 Subject: [PATCH] phy: implement control, status, reset --- src/eth/mod.rs | 22 ++++++++++ src/eth/phy/control.rs | 97 ++++++++++++++++++++++++++++++++++++++++++ src/eth/phy/mod.rs | 71 +++++++++++++++++++++++++++---- src/eth/phy/status.rs | 66 ++++++++++++++++++++++++++++ src/main.rs | 17 +------- 5 files changed, 248 insertions(+), 25 deletions(-) create mode 100644 src/eth/phy/control.rs create mode 100644 src/eth/phy/status.rs diff --git a/src/eth/mod.rs b/src/eth/mod.rs index 12f7502..97742a6 100644 --- a/src/eth/mod.rs +++ b/src/eth/mod.rs @@ -355,6 +355,28 @@ impl Eth { fn wait_phy_idle(&self) { while !self.regs.net_status.read().phy_mgmt_idle() {} } + + pub fn reset_phy(&mut self) -> bool { + match phy::Phy::find(self) { + Some(phy) => { + phy.modify_control(self, |control| + control.set_reset(true) + ); + while phy.get_control(self).reset() { + println!("Wait for PHY reset"); + } + phy.modify_control(self, |control| + control.set_autoneg_enable(true) + .set_restart_autoneg(true) + ); + // 125 MHz for 1000base-TX + Self::setup_gem0_clock(125); + + true + } + None => false + } + } } impl<'rx, TX> Eth, TX> { diff --git a/src/eth/phy/control.rs b/src/eth/phy/control.rs new file mode 100644 index 0000000..92825f6 --- /dev/null +++ b/src/eth/phy/control.rs @@ -0,0 +1,97 @@ +use bit_field::BitField; +use super::PhyRegister; + +#[derive(Clone, Copy, Debug)] +/// Basic Mode Control Register +pub struct Control(pub u16); + +impl Control { + pub fn speed1(&self) -> bool { + self.0.get_bit(6) + } + pub fn set_speed1(mut self, value: bool) -> Self { + self.0.set_bit(6, value); + self + } + pub fn collision_test(&self) -> bool { + self.0.get_bit(7) + } + pub fn set_collision_test(mut self, value: bool) -> Self { + self.0.set_bit(7, value); + self + } + pub fn duplex(&self) -> bool { + self.0.get_bit(8) + } + pub fn set_duplex(mut self, value: bool) -> Self { + self.0.set_bit(8, value); + self + } + pub fn restart_autoneg(&self) -> bool { + self.0.get_bit(9) + } + pub fn set_restart_autoneg(mut self, value: bool) -> Self { + self.0.set_bit(9, value); + self + } + pub fn isolate(&self) -> bool { + self.0.get_bit(10) + } + pub fn set_isolate(mut self, value: bool) -> Self { + self.0.set_bit(10, value); + self + } + pub fn power_down(&self) -> bool { + self.0.get_bit(11) + } + pub fn set_power_down(mut self, value: bool) -> Self { + self.0.set_bit(11, value); + self + } + pub fn autoneg_enable(&self) -> bool { + self.0.get_bit(12) + } + pub fn set_autoneg_enable(mut self, value: bool) -> Self { + self.0.set_bit(12, value); + self + } + pub fn speed0(&self) -> bool { + self.0.get_bit(13) + } + pub fn set_speed0(mut self, value: bool) -> Self { + self.0.set_bit(13, value); + self + } + pub fn loopback(&self) -> bool { + self.0.get_bit(14) + } + pub fn set_loopback(mut self, value: bool) -> Self { + self.0.set_bit(14, value); + self + } + pub fn reset(&self) -> bool { + self.0.get_bit(15) + } + pub fn set_reset(mut self, value: bool) -> Self { + self.0.set_bit(15, value); + self + } +} + +impl PhyRegister for Control { + fn addr() -> u8 { + 0 + } +} + +impl From for Control { + fn from(value: u16) -> Self { + Control(value) + } +} + +impl Into for Control { + fn into(self) -> u16 { + self.0 + } +} diff --git a/src/eth/phy/mod.rs b/src/eth/phy/mod.rs index 1b270e5..191d8cf 100644 --- a/src/eth/phy/mod.rs +++ b/src/eth/phy/mod.rs @@ -1,12 +1,21 @@ pub mod id; use id::{identify_phy, PhyIdentifier}; +mod status; +pub use status::Status; +mod control; +pub use control::Control; pub trait PhyAccess { fn read_phy(&mut self, addr: u8, reg: u8) -> u16; fn write_phy(&mut self, addr: u8, reg: u8, data: u16); } -pub enum Phy { +pub struct Phy { + pub addr: u8, + device: PhyDevice, +} + +pub enum PhyDevice { Marvel88E1116R, Rtl8211E, } @@ -16,20 +25,25 @@ const OUI_REALTEK: u32 = 0x000732; impl Phy { /// Probe all addresses on MDIO for a known PHY - pub fn find(pa: &mut PA) -> Option<(u8, Phy)> { + pub fn find(pa: &mut PA) -> Option { for addr in 1..32 { - match identify_phy(pa, addr) { + let device = match identify_phy(pa, addr) { Some(PhyIdentifier { oui: OUI_MARVEL, model: 36, .. - }) => return Some((addr, Phy::Marvel88E1116R)), + }) => Some(PhyDevice::Marvel88E1116R), Some(PhyIdentifier { oui: OUI_REALTEK, model: 0b010001, rev: 0b0101, - }) => return Some((addr, Phy::Rtl8211E)), - _ => {} + }) => Some(PhyDevice::Rtl8211E), + _ => None, + }; + match device { + Some(device) => + return Some(Phy { addr, device }), + None => {} } } @@ -37,9 +51,48 @@ impl Phy { } pub fn name(&self) -> &'static str { - match self { - Phy::Marvel88E1116R => &"Marvel 88E1116R", - Phy::Rtl8211E => &"RTL8211E", + match self.device { + PhyDevice::Marvel88E1116R => &"Marvel 88E1116R", + PhyDevice::Rtl8211E => &"RTL8211E", } } + + pub fn read_reg(&self, pa: &mut PA) -> PR + where + PA: PhyAccess, + PR: PhyRegister + From, + { + pa.read_phy(self.addr, PR::addr()).into() + } + + pub fn modify_reg(&self, pa: &mut PA, mut f: F) + where + PA: PhyAccess, + PR: PhyRegister + From + Into, + F: FnMut(PR) -> PR, + { + let reg = pa.read_phy(self.addr, PR::addr()).into(); + let reg = f(reg); + pa.write_phy(self.addr, PR::addr(), reg.into()) + } + + pub fn modify_control(&self, pa: &mut PA, f: F) + where + PA: PhyAccess, + F: FnMut(Control) -> Control, + { + self.modify_reg(pa, f) + } + + pub fn get_control(&self, pa: &mut PA) -> Control { + self.read_reg(pa) + } + + pub fn get_status(&self, pa: &mut PA) -> Status { + self.read_reg(pa) + } +} + +pub trait PhyRegister { + fn addr() -> u8; } diff --git a/src/eth/phy/status.rs b/src/eth/phy/status.rs new file mode 100644 index 0000000..e220b34 --- /dev/null +++ b/src/eth/phy/status.rs @@ -0,0 +1,66 @@ +use bit_field::BitField; +use super::PhyRegister; + +#[derive(Clone, Copy, Debug)] +/// Basic Mode Status Register +pub struct Status(pub u16); + +impl Status { + pub fn extended_capability(&self) -> bool { + self.0.get_bit(0) + } + pub fn jabber_detect(&self) -> bool { + self.0.get_bit(1) + } + pub fn link_status(&self) -> bool { + self.0.get_bit(2) + } + pub fn autoneg_ability(&self) -> bool { + self.0.get_bit(3) + } + pub fn remote_fault(&self) -> bool { + self.0.get_bit(4) + } + pub fn autoneg_complete(&self) -> bool { + self.0.get_bit(5) + } + pub fn preamble_suppression(&self) -> bool { + self.0.get_bit(6) + } + pub fn cap_1000base_t_extended_status(&self) -> bool { + self.0.get_bit(8) + } + pub fn cap_10base_t2_half(&self) -> bool { + self.0.get_bit(9) + } + pub fn cap_10base_t2_full(&self) -> bool { + self.0.get_bit(10) + } + pub fn cap_10base_t_half(&self) -> bool { + self.0.get_bit(11) + } + pub fn cap_10base_t_full(&self) -> bool { + self.0.get_bit(12) + } + pub fn cap_100base_tx_half(&self) -> bool { + self.0.get_bit(13) + } + pub fn cap_100base_tx_full(&self) -> bool { + self.0.get_bit(14) + } + pub fn cap_100base_t4(&self) -> bool { + self.0.get_bit(15) + } +} + +impl PhyRegister for Status { + fn addr() -> u8 { + 1 + } +} + +impl From for Status { + fn from(value: u16) -> Self { + Status(value) + } +} diff --git a/src/main.rs b/src/main.rs index 2f45e8b..3e6edef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,22 +75,7 @@ fn main() { let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]); println!("Eth on"); - match eth::phy::Phy::find(&mut eth) { - Some((addr, phy)) => { - println!("Found {} PHY at addr {}", phy.name(), addr); - } - None => { - use eth::phy::PhyAccess; - for addr in 1..32 { - match eth::phy::id::identify_phy(&mut eth, addr) { - Some(identifier) => { - println!("phy {}: {:?}", addr, identifier); - } - None => {} - } - } - } - } + eth.reset_phy(); let mut rx_descs: [eth::rx::DescEntry; 8] = unsafe { uninitialized() }; let mut rx_buffers = [[0u8; 1536]; 8];