stm32/eth: Move phy_addr
from Ethernet
to PHY
Previously, PHY addressing was a concern of the `Ethernet` struct which limited the `PHY` implementations which very often have to manage multiple PHYs internally and thus possibly need to address many of them. This change extends `StationManagement` to allow addressing different PHY addresses via SMI.
This commit is contained in:
parent
c3ef98a73d
commit
7526b8edba
@ -41,39 +41,40 @@ mod phy_consts {
|
|||||||
}
|
}
|
||||||
use self::phy_consts::*;
|
use self::phy_consts::*;
|
||||||
|
|
||||||
/// Generic SMI Ethernet PHY
|
/// Generic SMI Ethernet PHY implementation
|
||||||
pub struct GenericSMI {
|
pub struct GenericSMI {
|
||||||
|
phy_addr: u8,
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
poll_interval: Duration,
|
poll_interval: Duration,
|
||||||
#[cfg(not(feature = "time"))]
|
|
||||||
_private: (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericSMI {
|
impl GenericSMI {
|
||||||
pub fn new() -> Self {
|
/// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
|
||||||
|
pub fn new(phy_addr: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
phy_addr,
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
poll_interval: Duration::from_millis(500),
|
poll_interval: Duration::from_millis(500),
|
||||||
#[cfg(not(feature = "time"))]
|
|
||||||
_private: (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl PHY for GenericSMI {
|
unsafe impl PHY for GenericSMI {
|
||||||
/// Reset PHY and wait for it to come out of reset.
|
|
||||||
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
|
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
|
||||||
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
|
sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
|
||||||
while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
|
while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PHY initialisation.
|
|
||||||
fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
|
fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
|
||||||
// Clear WU CSR
|
// Clear WU CSR
|
||||||
self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
|
self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
|
||||||
|
|
||||||
// Enable auto-negotiation
|
// Enable auto-negotiation
|
||||||
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
|
sm.smi_write(
|
||||||
|
self.phy_addr,
|
||||||
|
PHY_REG_BCR,
|
||||||
|
PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
|
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
|
||||||
@ -83,7 +84,7 @@ unsafe impl PHY for GenericSMI {
|
|||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
let _ = Timer::after(self.poll_interval).poll_unpin(cx);
|
let _ = Timer::after(self.poll_interval).poll_unpin(cx);
|
||||||
|
|
||||||
let bsr = sm.smi_read(PHY_REG_BSR);
|
let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR);
|
||||||
|
|
||||||
// No link without autonegotiate
|
// No link without autonegotiate
|
||||||
if bsr & PHY_REG_BSR_ANDONE == 0 {
|
if bsr & PHY_REG_BSR_ANDONE == 0 {
|
||||||
@ -108,9 +109,9 @@ impl GenericSMI {
|
|||||||
|
|
||||||
// Writes a value to an extended PHY register in MMD address space
|
// Writes a value to an extended PHY register in MMD address space
|
||||||
fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
|
fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
|
||||||
sm.smi_write(PHY_REG_CTL, 0x0003); // set address
|
sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
|
||||||
sm.smi_write(PHY_REG_ADDAR, reg_addr);
|
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
|
||||||
sm.smi_write(PHY_REG_CTL, 0x4003); // set data
|
sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
|
||||||
sm.smi_write(PHY_REG_ADDAR, reg_data);
|
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
|
|||||||
/// The methods cannot move out of self
|
/// The methods cannot move out of self
|
||||||
pub unsafe trait StationManagement {
|
pub unsafe trait StationManagement {
|
||||||
/// Read a register over SMI.
|
/// Read a register over SMI.
|
||||||
fn smi_read(&mut self, reg: u8) -> u16;
|
fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
|
||||||
/// Write a register over SMI.
|
/// Write a register over SMI.
|
||||||
fn smi_write(&mut self, reg: u8, val: u16);
|
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traits for an Ethernet PHY
|
/// Traits for an Ethernet PHY
|
||||||
|
@ -107,7 +107,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
|
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
|
||||||
phy: P,
|
phy: P,
|
||||||
mac_addr: [u8; 6],
|
mac_addr: [u8; 6],
|
||||||
phy_addr: u8,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
@ -227,7 +226,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
station_management: EthernetStationManagement {
|
station_management: EthernetStationManagement {
|
||||||
peri: PhantomData,
|
peri: PhantomData,
|
||||||
clock_range: clock_range,
|
clock_range: clock_range,
|
||||||
phy_addr: phy_addr,
|
|
||||||
},
|
},
|
||||||
mac_addr,
|
mac_addr,
|
||||||
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
|
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
|
||||||
@ -271,15 +269,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
pub struct EthernetStationManagement<T: Instance> {
|
pub struct EthernetStationManagement<T: Instance> {
|
||||||
peri: PhantomData<T>,
|
peri: PhantomData<T>,
|
||||||
clock_range: Cr,
|
clock_range: Cr,
|
||||||
phy_addr: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
||||||
fn smi_read(&mut self, reg: u8) -> u16 {
|
fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmiiar().modify(|w| {
|
mac.macmiiar().modify(|w| {
|
||||||
w.set_pa(self.phy_addr);
|
w.set_pa(phy_addr);
|
||||||
w.set_mr(reg);
|
w.set_mr(reg);
|
||||||
w.set_mw(Mw::READ); // read operation
|
w.set_mw(Mw::READ); // read operation
|
||||||
w.set_cr(self.clock_range);
|
w.set_cr(self.clock_range);
|
||||||
@ -289,12 +286,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
|||||||
mac.macmiidr().read().md()
|
mac.macmiidr().read().md()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn smi_write(&mut self, reg: u8, val: u16) {
|
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmiidr().write(|w| w.set_md(val));
|
mac.macmiidr().write(|w| w.set_md(val));
|
||||||
mac.macmiiar().modify(|w| {
|
mac.macmiiar().modify(|w| {
|
||||||
w.set_pa(self.phy_addr);
|
w.set_pa(phy_addr);
|
||||||
w.set_mr(reg);
|
w.set_mr(reg);
|
||||||
w.set_mw(Mw::WRITE); // write
|
w.set_mw(Mw::WRITE); // write
|
||||||
w.set_cr(self.clock_range);
|
w.set_cr(self.clock_range);
|
||||||
|
@ -71,7 +71,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
|
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
|
||||||
phy: P,
|
phy: P,
|
||||||
mac_addr: [u8; 6],
|
mac_addr: [u8; 6],
|
||||||
phy_addr: u8,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
|
|
||||||
@ -202,7 +201,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
station_management: EthernetStationManagement {
|
station_management: EthernetStationManagement {
|
||||||
peri: PhantomData,
|
peri: PhantomData,
|
||||||
clock_range: clock_range,
|
clock_range: clock_range,
|
||||||
phy_addr: phy_addr,
|
|
||||||
},
|
},
|
||||||
mac_addr,
|
mac_addr,
|
||||||
};
|
};
|
||||||
@ -242,15 +240,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
pub struct EthernetStationManagement<T: Instance> {
|
pub struct EthernetStationManagement<T: Instance> {
|
||||||
peri: PhantomData<T>,
|
peri: PhantomData<T>,
|
||||||
clock_range: u8,
|
clock_range: u8,
|
||||||
phy_addr: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
||||||
fn smi_read(&mut self, reg: u8) -> u16 {
|
fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmdioar().modify(|w| {
|
mac.macmdioar().modify(|w| {
|
||||||
w.set_pa(self.phy_addr);
|
w.set_pa(phy_addr);
|
||||||
w.set_rda(reg);
|
w.set_rda(reg);
|
||||||
w.set_goc(0b11); // read
|
w.set_goc(0b11); // read
|
||||||
w.set_cr(self.clock_range);
|
w.set_cr(self.clock_range);
|
||||||
@ -260,12 +257,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
|
|||||||
mac.macmdiodr().read().md()
|
mac.macmdiodr().read().md()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn smi_write(&mut self, reg: u8, val: u16) {
|
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
|
||||||
let mac = ETH.ethernet_mac();
|
let mac = ETH.ethernet_mac();
|
||||||
|
|
||||||
mac.macmdiodr().write(|w| w.set_md(val));
|
mac.macmdiodr().write(|w| w.set_md(val));
|
||||||
mac.macmdioar().modify(|w| {
|
mac.macmdioar().modify(|w| {
|
||||||
w.set_pa(self.phy_addr);
|
w.set_pa(phy_addr);
|
||||||
w.set_rda(reg);
|
w.set_rda(reg);
|
||||||
w.set_goc(0b01); // write
|
w.set_goc(0b01); // write
|
||||||
w.set_cr(self.clock_range);
|
w.set_cr(self.clock_range);
|
||||||
|
Loading…
Reference in New Issue
Block a user