diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs index 774beef802..93e48674cb 100644 --- a/embassy-stm32/src/eth/generic_phy.rs +++ b/embassy-stm32/src/eth/generic_phy.rs @@ -47,6 +47,7 @@ pub struct GenericPhy { phy_addr: u8, #[cfg(feature = "time")] poll_interval: Duration, + auto_recover: bool, } impl GenericPhy { @@ -60,6 +61,7 @@ impl GenericPhy { phy_addr, #[cfg(feature = "time")] poll_interval: Duration::from_millis(500), + auto_recover: false, } } @@ -72,8 +74,17 @@ impl GenericPhy { phy_addr: 0xFF, #[cfg(feature = "time")] poll_interval: Duration::from_millis(500), + auto_recover: false, } } + + /// Enables automatic detection and recovery from spurious PHY resets. + /// + /// If your hardware works perfectly, this should not be necessary. + pub fn that_auto_recovers(mut self) -> Self { + self.auto_recover = true; + self + } } // TODO: Factor out to shared functionality @@ -133,17 +144,31 @@ impl Phy for GenericPhy { let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR); + let mut link_up = true; + // No link without autonegotiate if bsr & PHY_REG_BSR_ANDONE == 0 { - return false; + link_up = false; } // No link if link is down - if bsr & PHY_REG_BSR_UP == 0 { - return false; + if link_up && (bsr & PHY_REG_BSR_UP == 0) { + link_up = false; + } + + if !link_up && self.auto_recover { + let bcr = sm.smi_read(self.phy_addr, PHY_REG_BCR); + + if (bcr & PHY_REG_BCR_AN == 0) || (bcr & PHY_REG_BCR_100M == 0) { + #[cfg(feature = "defmt")] + defmt::error!("Spurious PHY reset detected, will automatically reconfigure."); + + self.phy_reset(sm); + self.phy_init(sm); + } } // Got link - true + link_up } }