zynq-rs/libboard_zynq/src/eth/phy/mod.rs

156 lines
3.9 KiB
Rust
Raw Normal View History

2019-06-19 06:21:17 +08:00
pub mod id;
use id::{identify_phy, PhyIdentifier};
2019-06-26 03:48:47 +08:00
mod status;
pub use status::Status;
mod control;
pub use control::Control;
mod pssr;
pub use pssr::PSSR;
2019-06-19 06:21:17 +08:00
#[derive(Clone, Debug, PartialEq)]
pub struct Link {
pub speed: LinkSpeed,
pub duplex: LinkDuplex,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LinkSpeed {
S10,
S100,
S1000,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LinkDuplex {
Half,
Full,
}
2019-05-30 08:42:42 +08:00
pub trait PhyAccess {
fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
}
2019-09-29 08:30:03 +08:00
#[derive(Clone)]
2019-06-26 03:48:47 +08:00
pub struct Phy {
pub addr: u8,
device: PhyDevice,
}
2019-09-29 08:30:03 +08:00
#[derive(Clone, Copy)]
2019-06-26 03:48:47 +08:00
pub enum PhyDevice {
2020-07-30 02:08:38 +08:00
Marvell88E1116R,
Marvell88E1512,
2019-06-19 06:21:17 +08:00
Rtl8211E,
2020-09-29 16:01:54 +08:00
PEF7071
2019-06-19 06:21:17 +08:00
}
2020-07-30 02:08:38 +08:00
const OUI_MARVELL: u32 = 0x005043;
2019-06-19 06:21:17 +08:00
const OUI_REALTEK: u32 = 0x000732;
2020-09-29 16:01:54 +08:00
const OUI_LANTIQ : u32 = 0x355969;
2019-06-19 06:21:17 +08:00
impl Phy {
/// Probe all addresses on MDIO for a known PHY
2019-06-26 03:48:47 +08:00
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
(1..32).filter_map(|addr| {
match identify_phy(pa, addr) {
2019-06-19 06:21:17 +08:00
Some(PhyIdentifier {
2020-07-30 02:08:38 +08:00
oui: OUI_MARVELL,
2019-06-19 06:21:17 +08:00
model: 36,
..
2020-07-30 02:08:38 +08:00
}) => Some(PhyDevice::Marvell88E1116R),
Some(PhyIdentifier {
oui: OUI_MARVELL,
model: 29,
..
}) => Some(PhyDevice::Marvell88E1512),
2019-06-19 06:21:17 +08:00
Some(PhyIdentifier {
oui: OUI_REALTEK,
model: 0b010001,
rev: 0b0101,
2019-06-26 03:48:47 +08:00
}) => Some(PhyDevice::Rtl8211E),
2020-09-29 16:01:54 +08:00
Some(PhyIdentifier {
oui: OUI_LANTIQ,
model: 0,
..
}) => Some(PhyDevice::PEF7071),
2019-06-26 03:48:47 +08:00
_ => None,
}.map(|device| Phy { addr, device })
}).next()
2019-06-19 06:21:17 +08:00
}
pub fn name(&self) -> &'static str {
2019-06-26 03:48:47 +08:00
match self.device {
2020-07-30 02:08:38 +08:00
PhyDevice::Marvell88E1116R => &"Marvell 88E1116R",
PhyDevice::Marvell88E1512 => &"Marvell 88E1512",
2019-06-26 03:48:47 +08:00
PhyDevice::Rtl8211E => &"RTL8211E",
2020-09-29 16:01:54 +08:00
PhyDevice::PEF7071 => &"Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6"
2019-06-19 06:21:17 +08:00
}
}
2019-06-26 03:48:47 +08:00
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)
}
2019-09-29 08:58:17 +08:00
pub fn get_link<PA: PhyAccess>(&self, pa: &mut PA) -> Option<Link> {
let status = self.get_status(pa);
if !status.link_status() {
None
} else if status.cap_1000base_t_extended_status() {
let phy_status: PSSR = self.read_reg(pa);
phy_status.get_link()
} else {
status.get_link()
}
}
2019-09-29 08:58:17 +08:00
pub fn reset<PA: PhyAccess>(&self, pa: &mut PA) {
self.modify_control(pa, |control|
control.set_reset(true)
);
while self.get_control(pa).reset() {}
}
pub fn restart_autoneg<PA: PhyAccess>(&self, pa: &mut PA) {
self.modify_control(pa, |control|
control.set_autoneg_enable(true)
.set_restart_autoneg(true)
);
}
2019-06-26 03:48:47 +08:00
}
pub trait PhyRegister {
fn addr() -> u8;
2019-05-30 08:42:42 +08:00
}