From 7526b8edba9bbfec7831959afef7736f2d1a39b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20G=C3=B3rski?= <gabriel.gorski@mobilaris.se>
Date: Fri, 6 Oct 2023 17:45:04 +0200
Subject: [PATCH] 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.
---
 embassy-stm32/src/eth/generic_smi.rs | 33 ++++++++++++++--------------
 embassy-stm32/src/eth/mod.rs         |  4 ++--
 embassy-stm32/src/eth/v1/mod.rs      | 11 ++++------
 embassy-stm32/src/eth/v2/mod.rs      | 11 ++++------
 4 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs
index 2ed46ca2c..1e1094a1c 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_smi.rs
@@ -41,39 +41,40 @@ mod phy_consts {
 }
 use self::phy_consts::*;
 
-/// Generic SMI Ethernet PHY
+/// Generic SMI Ethernet PHY implementation
 pub struct GenericSMI {
+    phy_addr: u8,
     #[cfg(feature = "time")]
     poll_interval: Duration,
-    #[cfg(not(feature = "time"))]
-    _private: (),
 }
 
 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 {
+            phy_addr,
             #[cfg(feature = "time")]
             poll_interval: Duration::from_millis(500),
-            #[cfg(not(feature = "time"))]
-            _private: (),
         }
     }
 }
 
 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) {
-        sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
-        while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
+        sm.smi_write(self.phy_addr, PHY_REG_BCR, 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) {
         // Clear WU CSR
         self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
 
         // 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 {
@@ -83,7 +84,7 @@ unsafe impl PHY for GenericSMI {
         #[cfg(feature = "time")]
         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
         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
     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(PHY_REG_ADDAR, reg_addr);
-        sm.smi_write(PHY_REG_CTL, 0x4003); // set data
-        sm.smi_write(PHY_REG_ADDAR, reg_data);
+        sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
+        sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
+        sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
+        sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
     }
 }
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 1e057235a..556aadd73 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
 /// The methods cannot move out of self
 pub unsafe trait StationManagement {
     /// 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.
-    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
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 4d19103dd..631a9377f 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -107,7 +107,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
         tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
         phy: P,
         mac_addr: [u8; 6],
-        phy_addr: u8,
     ) -> Self {
         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 {
                 peri: PhantomData,
                 clock_range: clock_range,
-                phy_addr: phy_addr,
             },
             mac_addr,
             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> {
     peri: PhantomData<T>,
     clock_range: Cr,
-    phy_addr: u8,
 }
 
 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();
 
         mac.macmiiar().modify(|w| {
-            w.set_pa(self.phy_addr);
+            w.set_pa(phy_addr);
             w.set_mr(reg);
             w.set_mw(Mw::READ); // read operation
             w.set_cr(self.clock_range);
@@ -289,12 +286,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
         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();
 
         mac.macmiidr().write(|w| w.set_md(val));
         mac.macmiiar().modify(|w| {
-            w.set_pa(self.phy_addr);
+            w.set_pa(phy_addr);
             w.set_mr(reg);
             w.set_mw(Mw::WRITE); // write
             w.set_cr(self.clock_range);
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 6efd40e3e..12cf618aa 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -71,7 +71,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
         tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
         phy: P,
         mac_addr: [u8; 6],
-        phy_addr: u8,
     ) -> Self {
         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 {
                 peri: PhantomData,
                 clock_range: clock_range,
-                phy_addr: phy_addr,
             },
             mac_addr,
         };
@@ -242,15 +240,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
 pub struct EthernetStationManagement<T: Instance> {
     peri: PhantomData<T>,
     clock_range: u8,
-    phy_addr: u8,
 }
 
 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();
 
         mac.macmdioar().modify(|w| {
-            w.set_pa(self.phy_addr);
+            w.set_pa(phy_addr);
             w.set_rda(reg);
             w.set_goc(0b11); // read
             w.set_cr(self.clock_range);
@@ -260,12 +257,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
         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();
 
         mac.macmdiodr().write(|w| w.set_md(val));
         mac.macmdioar().modify(|w| {
-            w.set_pa(self.phy_addr);
+            w.set_pa(phy_addr);
             w.set_rda(reg);
             w.set_goc(0b01); // write
             w.set_cr(self.clock_range);