zynq::eth: implement phy::extended_status, set clock for link speed
This commit is contained in:
parent
961e2e1dd0
commit
99a00e019b
@ -13,6 +13,8 @@ pub mod tx;
|
||||
pub const MTU: usize = 1536;
|
||||
/// Maximum MDC clock
|
||||
const MAX_MDC: u32 = 2_500_000;
|
||||
const TX_10: u32 = 10_000_000;
|
||||
const TX_100: u32 = 25_000_000;
|
||||
/// Clock for GbE
|
||||
const TX_1000: u32 = 125_000_000;
|
||||
|
||||
@ -171,7 +173,7 @@ impl<'r> Eth<'r, (), ()> {
|
||||
fn from_regs(regs: &'r mut regs::RegisterBlock, macaddr: [u8; 6]) -> Self {
|
||||
let mut inner = EthInner {
|
||||
regs,
|
||||
link: false,
|
||||
link: None,
|
||||
};
|
||||
inner.init();
|
||||
inner.configure(macaddr);
|
||||
@ -369,7 +371,7 @@ impl<'r, 'rx, 'tx: 'a, 'a> smoltcp::phy::Device<'a> for &mut Eth<'r, rx::DescLis
|
||||
|
||||
struct EthInner<'r> {
|
||||
regs: &'r mut regs::RegisterBlock,
|
||||
link: bool,
|
||||
link: Option<phy::Link>,
|
||||
}
|
||||
|
||||
impl<'r> EthInner<'r> {
|
||||
@ -502,26 +504,40 @@ impl<'r> EthInner<'r> {
|
||||
|
||||
|
||||
fn check_link_change(&mut self, phy: &Phy) {
|
||||
let link = phy.get_status(self).link_status();
|
||||
let link = phy.get_link(self);
|
||||
|
||||
// Check link state transition
|
||||
match (self.link, link) {
|
||||
(false, true) => {
|
||||
println!("eth: got link, setting clock for gigabit");
|
||||
// TODO: should derive gem0/gem107
|
||||
Eth::<(), ()>::setup_gem0_clock(TX_1000);
|
||||
}
|
||||
(true, false) => {
|
||||
println!("eth: link lost");
|
||||
phy.modify_control(self, |control|
|
||||
control.set_autoneg_enable(true)
|
||||
.set_restart_autoneg(true)
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if self.link != link {
|
||||
match &link {
|
||||
Some(link) => {
|
||||
println!("eth: got {:?}", link);
|
||||
|
||||
self.link = link;
|
||||
use phy::LinkSpeed::*;
|
||||
let txclock = match link.speed {
|
||||
S10 => TX_10,
|
||||
S100 => TX_100,
|
||||
S1000 => TX_1000,
|
||||
};
|
||||
Eth::<(), ()>::setup_gem0_clock(txclock);
|
||||
/* .full_duplex(false) doesn't work even if
|
||||
half duplex has been negotiated. */
|
||||
self.regs.net_cfg.modify(|_, w| w
|
||||
.full_duplex(true)
|
||||
.gige_en(link.speed == S1000)
|
||||
.speed(link.speed != S10)
|
||||
);
|
||||
}
|
||||
None => {
|
||||
println!("eth: link lost");
|
||||
phy.modify_control(self, |control|
|
||||
control.set_autoneg_enable(true)
|
||||
.set_restart_autoneg(true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.link = link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
59
src/zynq/eth/phy/extended_status.rs
Normal file
59
src/zynq/eth/phy/extended_status.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use bit_field::BitField;
|
||||
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// 1000Base-T Extended Status Register
|
||||
pub struct ExtendedStatus(pub u16);
|
||||
|
||||
impl ExtendedStatus {
|
||||
pub fn cap_1000base_t_half(&self) -> bool {
|
||||
self.0.get_bit(12)
|
||||
}
|
||||
pub fn cap_1000base_t_full(&self) -> bool {
|
||||
self.0.get_bit(13)
|
||||
}
|
||||
pub fn cap_1000base_x_half(&self) -> bool {
|
||||
self.0.get_bit(14)
|
||||
}
|
||||
pub fn cap_1000base_x_full(&self) -> bool {
|
||||
self.0.get_bit(12)
|
||||
}
|
||||
|
||||
pub fn get_link(&self) -> Option<Link> {
|
||||
if self.cap_1000base_t_half() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S1000,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_1000base_t_full() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S1000,
|
||||
duplex: LinkDuplex::Full,
|
||||
})
|
||||
} else if self.cap_1000base_x_half() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S1000,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_1000base_x_full() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S1000,
|
||||
duplex: LinkDuplex::Full,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PhyRegister for ExtendedStatus {
|
||||
fn addr() -> u8 {
|
||||
0xF
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for ExtendedStatus {
|
||||
fn from(value: u16) -> Self {
|
||||
ExtendedStatus(value)
|
||||
}
|
||||
}
|
@ -2,9 +2,30 @@ pub mod id;
|
||||
use id::{identify_phy, PhyIdentifier};
|
||||
mod status;
|
||||
pub use status::Status;
|
||||
mod extended_status;
|
||||
pub use extended_status::ExtendedStatus;
|
||||
mod control;
|
||||
pub use control::Control;
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
pub trait PhyAccess {
|
||||
fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
|
||||
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
|
||||
@ -94,6 +115,22 @@ impl Phy {
|
||||
self.read_reg(pa)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||
self.modify_control(pa, |control|
|
||||
control.set_reset(true)
|
||||
|
@ -1,5 +1,5 @@
|
||||
use bit_field::BitField;
|
||||
use super::PhyRegister;
|
||||
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// Basic Mode Status Register
|
||||
@ -51,6 +51,49 @@ impl Status {
|
||||
pub fn cap_100base_t4(&self) -> bool {
|
||||
self.0.get_bit(15)
|
||||
}
|
||||
|
||||
pub fn get_link(&self) -> Option<Link> {
|
||||
if ! self.link_status() {
|
||||
None
|
||||
} else if self.cap_10base_t_half() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S10,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_10base_t_full() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S10,
|
||||
duplex: LinkDuplex::Full,
|
||||
})
|
||||
} else if self.cap_10base_t2_half() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S10,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_10base_t2_full() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S10,
|
||||
duplex: LinkDuplex::Full,
|
||||
})
|
||||
} else if self.cap_100base_t4() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S100,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_100base_tx_half() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S100,
|
||||
duplex: LinkDuplex::Half,
|
||||
})
|
||||
} else if self.cap_100base_tx_full() {
|
||||
Some(Link {
|
||||
speed: LinkSpeed::S100,
|
||||
duplex: LinkDuplex::Full,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PhyRegister for Status {
|
||||
|
Loading…
Reference in New Issue
Block a user