forked from M-Labs/zynq-rs
phy: implement control, status, reset
This commit is contained in:
parent
e6827a81f3
commit
5823d90db1
@ -355,6 +355,28 @@ impl<RX, TX> Eth<RX, TX> {
|
||||
fn wait_phy_idle(&self) {
|
||||
while !self.regs.net_status.read().phy_mgmt_idle() {}
|
||||
}
|
||||
|
||||
pub fn reset_phy(&mut self) -> bool {
|
||||
match phy::Phy::find(self) {
|
||||
Some(phy) => {
|
||||
phy.modify_control(self, |control|
|
||||
control.set_reset(true)
|
||||
);
|
||||
while phy.get_control(self).reset() {
|
||||
println!("Wait for PHY reset");
|
||||
}
|
||||
phy.modify_control(self, |control|
|
||||
control.set_autoneg_enable(true)
|
||||
.set_restart_autoneg(true)
|
||||
);
|
||||
// 125 MHz for 1000base-TX
|
||||
Self::setup_gem0_clock(125);
|
||||
|
||||
true
|
||||
}
|
||||
None => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'rx, TX> Eth<rx::DescList<'rx>, TX> {
|
||||
|
97
src/eth/phy/control.rs
Normal file
97
src/eth/phy/control.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use bit_field::BitField;
|
||||
use super::PhyRegister;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// Basic Mode Control Register
|
||||
pub struct Control(pub u16);
|
||||
|
||||
impl Control {
|
||||
pub fn speed1(&self) -> bool {
|
||||
self.0.get_bit(6)
|
||||
}
|
||||
pub fn set_speed1(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(6, value);
|
||||
self
|
||||
}
|
||||
pub fn collision_test(&self) -> bool {
|
||||
self.0.get_bit(7)
|
||||
}
|
||||
pub fn set_collision_test(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(7, value);
|
||||
self
|
||||
}
|
||||
pub fn duplex(&self) -> bool {
|
||||
self.0.get_bit(8)
|
||||
}
|
||||
pub fn set_duplex(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(8, value);
|
||||
self
|
||||
}
|
||||
pub fn restart_autoneg(&self) -> bool {
|
||||
self.0.get_bit(9)
|
||||
}
|
||||
pub fn set_restart_autoneg(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(9, value);
|
||||
self
|
||||
}
|
||||
pub fn isolate(&self) -> bool {
|
||||
self.0.get_bit(10)
|
||||
}
|
||||
pub fn set_isolate(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(10, value);
|
||||
self
|
||||
}
|
||||
pub fn power_down(&self) -> bool {
|
||||
self.0.get_bit(11)
|
||||
}
|
||||
pub fn set_power_down(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(11, value);
|
||||
self
|
||||
}
|
||||
pub fn autoneg_enable(&self) -> bool {
|
||||
self.0.get_bit(12)
|
||||
}
|
||||
pub fn set_autoneg_enable(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(12, value);
|
||||
self
|
||||
}
|
||||
pub fn speed0(&self) -> bool {
|
||||
self.0.get_bit(13)
|
||||
}
|
||||
pub fn set_speed0(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(13, value);
|
||||
self
|
||||
}
|
||||
pub fn loopback(&self) -> bool {
|
||||
self.0.get_bit(14)
|
||||
}
|
||||
pub fn set_loopback(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(14, value);
|
||||
self
|
||||
}
|
||||
pub fn reset(&self) -> bool {
|
||||
self.0.get_bit(15)
|
||||
}
|
||||
pub fn set_reset(mut self, value: bool) -> Self {
|
||||
self.0.set_bit(15, value);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PhyRegister for Control {
|
||||
fn addr() -> u8 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Control {
|
||||
fn from(value: u16) -> Self {
|
||||
Control(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u16> for Control {
|
||||
fn into(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
@ -1,12 +1,21 @@
|
||||
pub mod id;
|
||||
use id::{identify_phy, PhyIdentifier};
|
||||
mod status;
|
||||
pub use status::Status;
|
||||
mod control;
|
||||
pub use control::Control;
|
||||
|
||||
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 enum Phy {
|
||||
pub struct Phy {
|
||||
pub addr: u8,
|
||||
device: PhyDevice,
|
||||
}
|
||||
|
||||
pub enum PhyDevice {
|
||||
Marvel88E1116R,
|
||||
Rtl8211E,
|
||||
}
|
||||
@ -16,20 +25,25 @@ const OUI_REALTEK: u32 = 0x000732;
|
||||
|
||||
impl Phy {
|
||||
/// Probe all addresses on MDIO for a known PHY
|
||||
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<(u8, Phy)> {
|
||||
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
||||
for addr in 1..32 {
|
||||
match identify_phy(pa, addr) {
|
||||
let device = match identify_phy(pa, addr) {
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_MARVEL,
|
||||
model: 36,
|
||||
..
|
||||
}) => return Some((addr, Phy::Marvel88E1116R)),
|
||||
}) => Some(PhyDevice::Marvel88E1116R),
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_REALTEK,
|
||||
model: 0b010001,
|
||||
rev: 0b0101,
|
||||
}) => return Some((addr, Phy::Rtl8211E)),
|
||||
_ => {}
|
||||
}) => Some(PhyDevice::Rtl8211E),
|
||||
_ => None,
|
||||
};
|
||||
match device {
|
||||
Some(device) =>
|
||||
return Some(Phy { addr, device }),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,9 +51,48 @@ impl Phy {
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Phy::Marvel88E1116R => &"Marvel 88E1116R",
|
||||
Phy::Rtl8211E => &"RTL8211E",
|
||||
match self.device {
|
||||
PhyDevice::Marvel88E1116R => &"Marvel 88E1116R",
|
||||
PhyDevice::Rtl8211E => &"RTL8211E",
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PhyRegister {
|
||||
fn addr() -> u8;
|
||||
}
|
||||
|
66
src/eth/phy/status.rs
Normal file
66
src/eth/phy/status.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use bit_field::BitField;
|
||||
use super::PhyRegister;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// Basic Mode Status Register
|
||||
pub struct Status(pub u16);
|
||||
|
||||
impl Status {
|
||||
pub fn extended_capability(&self) -> bool {
|
||||
self.0.get_bit(0)
|
||||
}
|
||||
pub fn jabber_detect(&self) -> bool {
|
||||
self.0.get_bit(1)
|
||||
}
|
||||
pub fn link_status(&self) -> bool {
|
||||
self.0.get_bit(2)
|
||||
}
|
||||
pub fn autoneg_ability(&self) -> bool {
|
||||
self.0.get_bit(3)
|
||||
}
|
||||
pub fn remote_fault(&self) -> bool {
|
||||
self.0.get_bit(4)
|
||||
}
|
||||
pub fn autoneg_complete(&self) -> bool {
|
||||
self.0.get_bit(5)
|
||||
}
|
||||
pub fn preamble_suppression(&self) -> bool {
|
||||
self.0.get_bit(6)
|
||||
}
|
||||
pub fn cap_1000base_t_extended_status(&self) -> bool {
|
||||
self.0.get_bit(8)
|
||||
}
|
||||
pub fn cap_10base_t2_half(&self) -> bool {
|
||||
self.0.get_bit(9)
|
||||
}
|
||||
pub fn cap_10base_t2_full(&self) -> bool {
|
||||
self.0.get_bit(10)
|
||||
}
|
||||
pub fn cap_10base_t_half(&self) -> bool {
|
||||
self.0.get_bit(11)
|
||||
}
|
||||
pub fn cap_10base_t_full(&self) -> bool {
|
||||
self.0.get_bit(12)
|
||||
}
|
||||
pub fn cap_100base_tx_half(&self) -> bool {
|
||||
self.0.get_bit(13)
|
||||
}
|
||||
pub fn cap_100base_tx_full(&self) -> bool {
|
||||
self.0.get_bit(14)
|
||||
}
|
||||
pub fn cap_100base_t4(&self) -> bool {
|
||||
self.0.get_bit(15)
|
||||
}
|
||||
}
|
||||
|
||||
impl PhyRegister for Status {
|
||||
fn addr() -> u8 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Status {
|
||||
fn from(value: u16) -> Self {
|
||||
Status(value)
|
||||
}
|
||||
}
|
17
src/main.rs
17
src/main.rs
@ -75,22 +75,7 @@ fn main() {
|
||||
|
||||
let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]);
|
||||
println!("Eth on");
|
||||
match eth::phy::Phy::find(&mut eth) {
|
||||
Some((addr, phy)) => {
|
||||
println!("Found {} PHY at addr {}", phy.name(), addr);
|
||||
}
|
||||
None => {
|
||||
use eth::phy::PhyAccess;
|
||||
for addr in 1..32 {
|
||||
match eth::phy::id::identify_phy(&mut eth, addr) {
|
||||
Some(identifier) => {
|
||||
println!("phy {}: {:?}", addr, identifier);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eth.reset_phy();
|
||||
|
||||
let mut rx_descs: [eth::rx::DescEntry; 8] = unsafe { uninitialized() };
|
||||
let mut rx_buffers = [[0u8; 1536]; 8];
|
||||
|
Loading…
Reference in New Issue
Block a user