forked from M-Labs/zynq-rs
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;
|
pub const MTU: usize = 1536;
|
||||||
/// Maximum MDC clock
|
/// Maximum MDC clock
|
||||||
const MAX_MDC: u32 = 2_500_000;
|
const MAX_MDC: u32 = 2_500_000;
|
||||||
|
const TX_10: u32 = 10_000_000;
|
||||||
|
const TX_100: u32 = 25_000_000;
|
||||||
/// Clock for GbE
|
/// Clock for GbE
|
||||||
const TX_1000: u32 = 125_000_000;
|
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 {
|
fn from_regs(regs: &'r mut regs::RegisterBlock, macaddr: [u8; 6]) -> Self {
|
||||||
let mut inner = EthInner {
|
let mut inner = EthInner {
|
||||||
regs,
|
regs,
|
||||||
link: false,
|
link: None,
|
||||||
};
|
};
|
||||||
inner.init();
|
inner.init();
|
||||||
inner.configure(macaddr);
|
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> {
|
struct EthInner<'r> {
|
||||||
regs: &'r mut regs::RegisterBlock,
|
regs: &'r mut regs::RegisterBlock,
|
||||||
link: bool,
|
link: Option<phy::Link>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> EthInner<'r> {
|
impl<'r> EthInner<'r> {
|
||||||
@ -502,27 +504,41 @@ impl<'r> EthInner<'r> {
|
|||||||
|
|
||||||
|
|
||||||
fn check_link_change(&mut self, phy: &Phy) {
|
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
|
// Check link state transition
|
||||||
match (self.link, link) {
|
if self.link != link {
|
||||||
(false, true) => {
|
match &link {
|
||||||
println!("eth: got link, setting clock for gigabit");
|
Some(link) => {
|
||||||
// TODO: should derive gem0/gem107
|
println!("eth: got {:?}", link);
|
||||||
Eth::<(), ()>::setup_gem0_clock(TX_1000);
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(true, false) => {
|
None => {
|
||||||
println!("eth: link lost");
|
println!("eth: link lost");
|
||||||
phy.modify_control(self, |control|
|
phy.modify_control(self, |control|
|
||||||
control.set_autoneg_enable(true)
|
control.set_autoneg_enable(true)
|
||||||
.set_restart_autoneg(true)
|
.set_restart_autoneg(true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.link = link;
|
self.link = link;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> PhyAccess for EthInner<'r> {
|
impl<'r> PhyAccess for EthInner<'r> {
|
||||||
|
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};
|
use id::{identify_phy, PhyIdentifier};
|
||||||
mod status;
|
mod status;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
|
mod extended_status;
|
||||||
|
pub use extended_status::ExtendedStatus;
|
||||||
mod control;
|
mod control;
|
||||||
pub use control::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 {
|
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);
|
||||||
@ -94,6 +115,22 @@ impl Phy {
|
|||||||
self.read_reg(pa)
|
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) {
|
pub fn reset<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||||
self.modify_control(pa, |control|
|
self.modify_control(pa, |control|
|
||||||
control.set_reset(true)
|
control.set_reset(true)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use super::PhyRegister;
|
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
/// Basic Mode Status Register
|
/// Basic Mode Status Register
|
||||||
@ -51,6 +51,49 @@ impl Status {
|
|||||||
pub fn cap_100base_t4(&self) -> bool {
|
pub fn cap_100base_t4(&self) -> bool {
|
||||||
self.0.get_bit(15)
|
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 {
|
impl PhyRegister for Status {
|
||||||
|
Loading…
Reference in New Issue
Block a user