phy: implement control, status, reset

This commit is contained in:
Astro 2019-06-25 21:48:47 +02:00
parent e6827a81f3
commit 5823d90db1
5 changed files with 248 additions and 25 deletions

View File

@ -355,6 +355,28 @@ impl<RX, TX> Eth<RX, TX> {
fn wait_phy_idle(&self) { fn wait_phy_idle(&self) {
while !self.regs.net_status.read().phy_mgmt_idle() {} 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<rx::DescList<'rx>, TX> { impl<'rx, TX> Eth<rx::DescList<'rx>, TX> {

97
src/eth/phy/control.rs Normal file
View File

@ -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<u16> for Control {
fn from(value: u16) -> Self {
Control(value)
}
}
impl Into<u16> for Control {
fn into(self) -> u16 {
self.0
}
}

View File

@ -1,12 +1,21 @@
pub mod id; pub mod id;
use id::{identify_phy, PhyIdentifier}; use id::{identify_phy, PhyIdentifier};
mod status;
pub use status::Status;
mod control;
pub use control::Control;
pub trait PhyAccess { pub trait PhyAccess {
fn read_phy(&mut self, addr: u8, reg: u8) -> u16; fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
fn write_phy(&mut self, addr: u8, reg: u8, data: 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, Marvel88E1116R,
Rtl8211E, Rtl8211E,
} }
@ -16,20 +25,25 @@ const OUI_REALTEK: u32 = 0x000732;
impl Phy { impl Phy {
/// Probe all addresses on MDIO for a known PHY /// Probe all addresses on MDIO for a known PHY
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<(u8, Phy)> { pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
for addr in 1..32 { for addr in 1..32 {
match identify_phy(pa, addr) { let device = match identify_phy(pa, addr) {
Some(PhyIdentifier { Some(PhyIdentifier {
oui: OUI_MARVEL, oui: OUI_MARVEL,
model: 36, model: 36,
.. ..
}) => return Some((addr, Phy::Marvel88E1116R)), }) => Some(PhyDevice::Marvel88E1116R),
Some(PhyIdentifier { Some(PhyIdentifier {
oui: OUI_REALTEK, oui: OUI_REALTEK,
model: 0b010001, model: 0b010001,
rev: 0b0101, 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 { pub fn name(&self) -> &'static str {
match self { match self.device {
Phy::Marvel88E1116R => &"Marvel 88E1116R", PhyDevice::Marvel88E1116R => &"Marvel 88E1116R",
Phy::Rtl8211E => &"RTL8211E", PhyDevice::Rtl8211E => &"RTL8211E",
} }
} }
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
where
PA: PhyAccess,
PR: PhyRegister + From<u16>,
{
pa.read_phy(self.addr, PR::addr()).into()
}
pub fn modify_reg<PA, PR, F>(&self, pa: &mut PA, mut f: F)
where
PA: PhyAccess,
PR: PhyRegister + From<u16> + Into<u16>,
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<PA, F>(&self, pa: &mut PA, f: F)
where
PA: PhyAccess,
F: FnMut(Control) -> Control,
{
self.modify_reg(pa, f)
}
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
self.read_reg(pa)
}
pub fn get_status<PA: PhyAccess>(&self, pa: &mut PA) -> Status {
self.read_reg(pa)
}
}
pub trait PhyRegister {
fn addr() -> u8;
} }

66
src/eth/phy/status.rs Normal file
View File

@ -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<u16> for Status {
fn from(value: u16) -> Self {
Status(value)
}
}

View File

@ -75,22 +75,7 @@ fn main() {
let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]); let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]);
println!("Eth on"); println!("Eth on");
match eth::phy::Phy::find(&mut eth) { eth.reset_phy();
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 => {}
}
}
}
}
let mut rx_descs: [eth::rx::DescEntry; 8] = unsafe { uninitialized() }; let mut rx_descs: [eth::rx::DescEntry; 8] = unsafe { uninitialized() };
let mut rx_buffers = [[0u8; 1536]; 8]; let mut rx_buffers = [[0u8; 1536]; 8];