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

148 lines
3.7 KiB
Rust
Raw Normal View History

2019-06-19 06:21:17 +08:00
pub mod id;
2021-07-05 13:45:22 +08:00
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(Copy, 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);
}
pub trait PhyRegister {
fn addr() -> u8;
fn page() -> u8;
2019-06-19 06:21:17 +08:00
}
2019-06-26 03:48:47 +08:00
2021-07-05 13:45:22 +08:00
#[derive(Clone)]
pub struct Phy {
pub addr: u8,
}
2021-07-05 13:45:22 +08:00
const OUI_MARVELL: u32 = 0x005043;
const OUI_REALTEK: u32 = 0x000732;
const OUI_LANTIQ : u32 = 0x355969;
const PAGE_REGISTER: u8 = 0x16;
2021-07-05 13:45:22 +08:00
impl Phy {
/// Probe all addresses on MDIO for a known PHY
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
(0..32).find(|addr| {
match identify_phy(pa, *addr) {
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1116R
model: 36,
..
}) => true,
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1512
model: 29,
..
}) => true,
Some(PhyIdentifier {
oui: OUI_REALTEK,
// RTL 8211E
model: 0b010001,
rev: 0b0101,
}) => true,
Some(PhyIdentifier {
oui: OUI_LANTIQ,
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
model: 0,
..
}) => true,
_ => false,
}
2021-07-05 13:45:22 +08:00
}).map(|addr| Phy { addr })
}
2021-07-05 13:45:22 +08:00
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
where
PA: PhyAccess,
PR: PhyRegister + From<u16>,
{
pa.write_phy(self.addr, PAGE_REGISTER, PR::page());
2021-07-05 13:45:22 +08:00
pa.read_phy(self.addr, PR::addr()).into()
}
2021-07-05 13:45:22 +08:00
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,
{
pa.write_phy(self.addr, PAGE_REGISTER, PR::page());
2021-07-05 13:45:22 +08:00
let reg = pa.read_phy(self.addr, PR::addr()).into();
let reg = f(reg);
pa.write_phy(self.addr, PR::addr(), reg.into())
}
2021-07-05 13:45:22 +08:00
pub fn modify_control<PA, F>(&self, pa: &mut PA, f: F)
where
PA: PhyAccess,
F: FnMut(Control) -> Control,
{
self.modify_reg(pa, f)
2019-09-29 08:58:17 +08:00
}
2021-07-05 13:45:22 +08:00
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
self.read_reg(pa)
}
2021-07-05 13:45:22 +08:00
pub fn get_status<PA: PhyAccess>(&self, pa: &mut PA) -> Status {
self.read_reg(pa)
}
2021-07-05 13:45:22 +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()
}
2021-07-05 13:45:22 +08:00
}
2021-07-05 13:45:22 +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() {}
}
2021-07-05 13:45:22 +08:00
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-09-29 08:58:17 +08:00
}
2019-06-26 03:48:47 +08:00
}