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:
Gabriel Górski 2023-10-06 17:45:04 +02:00
parent c3ef98a73d
commit 7526b8edba
4 changed files with 27 additions and 32 deletions

View File

@ -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);
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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);