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;
|
2019-11-04 09:23:27 +08:00
|
|
|
mod extended_status;
|
|
|
|
pub use extended_status::ExtendedStatus;
|
2019-06-26 03:48:47 +08:00
|
|
|
mod control;
|
|
|
|
pub use control::Control;
|
2019-06-19 06:21:17 +08:00
|
|
|
|
2019-11-04 09:23:27 +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 {
|
2019-06-19 06:21:17 +08:00
|
|
|
Marvel88E1116R,
|
|
|
|
Rtl8211E,
|
|
|
|
}
|
|
|
|
|
|
|
|
const OUI_MARVEL: u32 = 0x005043;
|
|
|
|
const OUI_REALTEK: u32 = 0x000732;
|
|
|
|
|
|
|
|
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> {
|
2019-06-19 06:21:17 +08:00
|
|
|
for addr in 1..32 {
|
2019-06-26 03:48:47 +08:00
|
|
|
let device = match identify_phy(pa, addr) {
|
2019-06-19 06:21:17 +08:00
|
|
|
Some(PhyIdentifier {
|
|
|
|
oui: OUI_MARVEL,
|
|
|
|
model: 36,
|
|
|
|
..
|
2019-06-26 03:48:47 +08:00
|
|
|
}) => Some(PhyDevice::Marvel88E1116R),
|
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),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
match device {
|
|
|
|
Some(device) =>
|
|
|
|
return Some(Phy { addr, device }),
|
|
|
|
None => {}
|
2019-06-19 06:21:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn name(&self) -> &'static str {
|
2019-06-26 03:48:47 +08:00
|
|
|
match self.device {
|
|
|
|
PhyDevice::Marvel88E1116R => &"Marvel 88E1116R",
|
|
|
|
PhyDevice::Rtl8211E => &"RTL8211E",
|
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
|
|
|
|
2019-11-04 09:23:27 +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 ext_status: ExtendedStatus = self.read_reg(pa);
|
|
|
|
if let Some(link) = ext_status.get_link() {
|
|
|
|
Some(link)
|
|
|
|
} else {
|
|
|
|
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
|
|
|
}
|