eth: prepare link change detection
This commit is contained in:
parent
378755a0ce
commit
0f6bc68d1f
@ -4,6 +4,7 @@ use crate::println;
|
|||||||
use crate::clocks::CpuClocks;
|
use crate::clocks::CpuClocks;
|
||||||
|
|
||||||
pub mod phy;
|
pub mod phy;
|
||||||
|
use phy::{Phy, PhyAccess};
|
||||||
mod regs;
|
mod regs;
|
||||||
pub mod rx;
|
pub mod rx;
|
||||||
pub mod tx;
|
pub mod tx;
|
||||||
@ -19,6 +20,9 @@ pub struct Eth<'r, RX, TX> {
|
|||||||
regs: &'r mut regs::RegisterBlock,
|
regs: &'r mut regs::RegisterBlock,
|
||||||
rx: RX,
|
rx: RX,
|
||||||
tx: TX,
|
tx: TX,
|
||||||
|
link: bool,
|
||||||
|
// TODO: no Option
|
||||||
|
phy: Option<Phy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r> Eth<'r, (), ()> {
|
impl<'r> Eth<'r, (), ()> {
|
||||||
@ -172,8 +176,13 @@ impl<'r> Eth<'r, (), ()> {
|
|||||||
regs,
|
regs,
|
||||||
rx: (),
|
rx: (),
|
||||||
tx: (),
|
tx: (),
|
||||||
}.init();
|
link: false,
|
||||||
|
phy: None,
|
||||||
|
};
|
||||||
|
eth.init();
|
||||||
eth.configure(macaddr);
|
eth.configure(macaddr);
|
||||||
|
eth.phy = Phy::find(&mut eth);
|
||||||
|
eth.reset_phy();
|
||||||
eth
|
eth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +234,7 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(self) -> Self {
|
fn init(&mut self) {
|
||||||
// Clear the Network Control register.
|
// Clear the Network Control register.
|
||||||
self.regs.net_ctrl.write(regs::NetCtrl::zeroed());
|
self.regs.net_ctrl.write(regs::NetCtrl::zeroed());
|
||||||
self.regs.net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
self.regs.net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
||||||
@ -287,8 +296,6 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
self.regs.tx_qbar.write(
|
self.regs.tx_qbar.write(
|
||||||
regs::TxQbar::zeroed()
|
regs::TxQbar::zeroed()
|
||||||
);
|
);
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure(&mut self, macaddr: [u8; 6]) {
|
fn configure(&mut self, macaddr: [u8; 6]) {
|
||||||
@ -354,6 +361,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
regs: self.regs,
|
regs: self.regs,
|
||||||
rx: rx::DescList::new(rx_list, rx_buffers),
|
rx: rx::DescList::new(rx_list, rx_buffers),
|
||||||
tx: self.tx,
|
tx: self.tx,
|
||||||
|
link: self.link,
|
||||||
|
phy: self.phy,
|
||||||
};
|
};
|
||||||
let list_addr = new_self.rx.list_addr();
|
let list_addr = new_self.rx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
@ -372,6 +381,8 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
regs: self.regs,
|
regs: self.regs,
|
||||||
rx: self.rx,
|
rx: self.rx,
|
||||||
tx: tx::DescList::new(tx_list, tx_buffers),
|
tx: tx::DescList::new(tx_list, tx_buffers),
|
||||||
|
link: self.link,
|
||||||
|
phy: self.phy,
|
||||||
};
|
};
|
||||||
let list_addr = &new_self.tx.list_addr();
|
let list_addr = &new_self.tx.list_addr();
|
||||||
assert!(list_addr & 0b11 == 0);
|
assert!(list_addr & 0b11 == 0);
|
||||||
@ -389,10 +400,9 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
while !self.regs.net_status.read().phy_mgmt_idle() {}
|
while !self.regs.net_status.read().phy_mgmt_idle() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_phy(&mut self) -> bool {
|
pub fn reset_phy(&mut self) {
|
||||||
match phy::Phy::find(self) {
|
let phy = self.phy.clone().expect("phy");
|
||||||
Some(phy) => {
|
println!("eth: Reset PHY at {}: {}", phy.addr, phy.name());
|
||||||
println!("eth: Found PHY at {}: {}", phy.addr, phy.name());
|
|
||||||
phy.modify_control(self, |control|
|
phy.modify_control(self, |control|
|
||||||
control.set_reset(true)
|
control.set_reset(true)
|
||||||
);
|
);
|
||||||
@ -403,15 +413,29 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
|
|||||||
control.set_autoneg_enable(true)
|
control.set_autoneg_enable(true)
|
||||||
.set_restart_autoneg(true)
|
.set_restart_autoneg(true)
|
||||||
);
|
);
|
||||||
println!("eth: Wait for link");
|
}
|
||||||
while !phy.get_status(self).link_status() {}
|
|
||||||
println!("eth: Got link, setting clock for gigabit");
|
|
||||||
Self::setup_gem0_clock(TX_1000);
|
|
||||||
|
|
||||||
true
|
fn check_link_change(&mut self) {
|
||||||
|
let phy = self.phy.clone().expect("phy");
|
||||||
|
let link = phy.get_status(self).link_status();
|
||||||
|
|
||||||
|
// Check link state transition
|
||||||
|
match (self.link, link) {
|
||||||
|
(false, true) => {
|
||||||
|
println!("eth: got link, setting clock for gigabit");
|
||||||
|
Self::setup_gem0_clock(TX_1000);
|
||||||
}
|
}
|
||||||
None => false
|
(true, false) => {
|
||||||
|
println!("eth: link lost");
|
||||||
|
phy.modify_control(self, |control|
|
||||||
|
control.set_autoneg_enable(true)
|
||||||
|
.set_restart_autoneg(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.link = link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,6 +481,7 @@ impl<'r, 'rx, TX> Eth<'r, rx::DescList<'rx>, TX> {
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
|
self.check_link_change();
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,7 +493,7 @@ impl<'r, 'tx, RX> Eth<'r, RX, tx::DescList<'tx>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'r, RX, TX> phy::PhyAccess for Eth<'r, RX, TX> {
|
impl<'r, RX, TX> PhyAccess for Eth<'r, RX, TX> {
|
||||||
fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
|
fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
|
||||||
self.wait_phy_idle();
|
self.wait_phy_idle();
|
||||||
self.regs.phy_maint.write(
|
self.regs.phy_maint.write(
|
||||||
@ -517,8 +542,10 @@ impl<'r, 'rx, 'tx: 'a, 'a> smoltcp::phy::Device<'a> for &mut Eth<'r, rx::DescLis
|
|||||||
};
|
};
|
||||||
Some((pktref, tx_token))
|
Some((pktref, tx_token))
|
||||||
}
|
}
|
||||||
Ok(None) =>
|
Ok(None) => {
|
||||||
None,
|
// TODO: self.check_link_change();
|
||||||
|
None
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("eth recv error: {:?}", e);
|
println!("eth recv error: {:?}", e);
|
||||||
None
|
None
|
||||||
|
@ -10,11 +10,13 @@ pub trait PhyAccess {
|
|||||||
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
|
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Phy {
|
pub struct Phy {
|
||||||
pub addr: u8,
|
pub addr: u8,
|
||||||
device: PhyDevice,
|
device: PhyDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum PhyDevice {
|
pub enum PhyDevice {
|
||||||
Marvel88E1116R,
|
Marvel88E1116R,
|
||||||
Rtl8211E,
|
Rtl8211E,
|
||||||
|
@ -90,7 +90,6 @@ fn main() {
|
|||||||
|
|
||||||
let mut eth = eth::Eth::default(HWADDR.clone());
|
let mut eth = eth::Eth::default(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
eth.reset_phy();
|
|
||||||
|
|
||||||
const RX_LEN: usize = 2;
|
const RX_LEN: usize = 2;
|
||||||
let mut rx_descs: [eth::rx::DescEntry; RX_LEN] = unsafe { uninitialized() };
|
let mut rx_descs: [eth::rx::DescEntry; RX_LEN] = unsafe { uninitialized() };
|
||||||
|
Loading…
Reference in New Issue
Block a user