diff options
Diffstat (limited to 'embassy-stm32/src/eth/generic_phy.rs')
| -rw-r--r-- | embassy-stm32/src/eth/generic_phy.rs | 64 |
1 files changed, 30 insertions, 34 deletions
diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs index 774beef80..0a5f41de0 100644 --- a/embassy-stm32/src/eth/generic_phy.rs +++ b/embassy-stm32/src/eth/generic_phy.rs | |||
| @@ -8,6 +8,7 @@ use embassy_time::{Duration, Timer}; | |||
| 8 | use futures_util::FutureExt; | 8 | use futures_util::FutureExt; |
| 9 | 9 | ||
| 10 | use super::{Phy, StationManagement}; | 10 | use super::{Phy, StationManagement}; |
| 11 | use crate::block_for_us as blocking_delay_us; | ||
| 11 | 12 | ||
| 12 | #[allow(dead_code)] | 13 | #[allow(dead_code)] |
| 13 | mod phy_consts { | 14 | mod phy_consts { |
| @@ -43,21 +44,23 @@ mod phy_consts { | |||
| 43 | use self::phy_consts::*; | 44 | use self::phy_consts::*; |
| 44 | 45 | ||
| 45 | /// Generic SMI Ethernet PHY implementation | 46 | /// Generic SMI Ethernet PHY implementation |
| 46 | pub struct GenericPhy { | 47 | pub struct GenericPhy<SM: StationManagement> { |
| 47 | phy_addr: u8, | 48 | phy_addr: u8, |
| 49 | sm: SM, | ||
| 48 | #[cfg(feature = "time")] | 50 | #[cfg(feature = "time")] |
| 49 | poll_interval: Duration, | 51 | poll_interval: Duration, |
| 50 | } | 52 | } |
| 51 | 53 | ||
| 52 | impl GenericPhy { | 54 | impl<SM: StationManagement> GenericPhy<SM> { |
| 53 | /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication | 55 | /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication |
| 54 | /// | 56 | /// |
| 55 | /// # Panics | 57 | /// # Panics |
| 56 | /// `phy_addr` must be in range `0..32` | 58 | /// `phy_addr` must be in range `0..32` |
| 57 | pub fn new(phy_addr: u8) -> Self { | 59 | pub fn new(sm: SM, phy_addr: u8) -> Self { |
| 58 | assert!(phy_addr < 32); | 60 | assert!(phy_addr < 32); |
| 59 | Self { | 61 | Self { |
| 60 | phy_addr, | 62 | phy_addr, |
| 63 | sm, | ||
| 61 | #[cfg(feature = "time")] | 64 | #[cfg(feature = "time")] |
| 62 | poll_interval: Duration::from_millis(500), | 65 | poll_interval: Duration::from_millis(500), |
| 63 | } | 66 | } |
| @@ -67,8 +70,9 @@ impl GenericPhy { | |||
| 67 | /// | 70 | /// |
| 68 | /// # Panics | 71 | /// # Panics |
| 69 | /// Initialization panics if PHY didn't respond on any address | 72 | /// Initialization panics if PHY didn't respond on any address |
| 70 | pub fn new_auto() -> Self { | 73 | pub fn new_auto(sm: SM) -> Self { |
| 71 | Self { | 74 | Self { |
| 75 | sm, | ||
| 72 | phy_addr: 0xFF, | 76 | phy_addr: 0xFF, |
| 73 | #[cfg(feature = "time")] | 77 | #[cfg(feature = "time")] |
| 74 | poll_interval: Duration::from_millis(500), | 78 | poll_interval: Duration::from_millis(500), |
| @@ -76,27 +80,14 @@ impl GenericPhy { | |||
| 76 | } | 80 | } |
| 77 | } | 81 | } |
| 78 | 82 | ||
| 79 | // TODO: Factor out to shared functionality | 83 | impl<SM: StationManagement> Phy for GenericPhy<SM> { |
| 80 | fn blocking_delay_us(us: u32) { | 84 | fn phy_reset(&mut self) { |
| 81 | #[cfg(feature = "time")] | ||
| 82 | embassy_time::block_for(Duration::from_micros(us as u64)); | ||
| 83 | #[cfg(not(feature = "time"))] | ||
| 84 | { | ||
| 85 | let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; | ||
| 86 | let us = us as u64; | ||
| 87 | let cycles = freq * us / 1_000_000; | ||
| 88 | cortex_m::asm::delay(cycles as u32); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | impl Phy for GenericPhy { | ||
| 93 | fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { | ||
| 94 | // Detect SMI address | 85 | // Detect SMI address |
| 95 | if self.phy_addr == 0xFF { | 86 | if self.phy_addr == 0xFF { |
| 96 | for addr in 0..32 { | 87 | for addr in 0..32 { |
| 97 | sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); | 88 | self.sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); |
| 98 | for _ in 0..10 { | 89 | for _ in 0..10 { |
| 99 | if sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET { | 90 | if self.sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET { |
| 100 | trace!("Found ETH PHY on address {}", addr); | 91 | trace!("Found ETH PHY on address {}", addr); |
| 101 | self.phy_addr = addr; | 92 | self.phy_addr = addr; |
| 102 | return; | 93 | return; |
| @@ -108,30 +99,30 @@ impl Phy for GenericPhy { | |||
| 108 | panic!("PHY did not respond"); | 99 | panic!("PHY did not respond"); |
| 109 | } | 100 | } |
| 110 | 101 | ||
| 111 | sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); | 102 | self.sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); |
| 112 | while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} | 103 | while self.sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} |
| 113 | } | 104 | } |
| 114 | 105 | ||
| 115 | fn phy_init<S: StationManagement>(&mut self, sm: &mut S) { | 106 | fn phy_init(&mut self) { |
| 116 | // Clear WU CSR | 107 | // Clear WU CSR |
| 117 | self.smi_write_ext(sm, PHY_REG_WUCSR, 0); | 108 | self.smi_write_ext(PHY_REG_WUCSR, 0); |
| 118 | 109 | ||
| 119 | // Enable auto-negotiation | 110 | // Enable auto-negotiation |
| 120 | sm.smi_write( | 111 | self.sm.smi_write( |
| 121 | self.phy_addr, | 112 | self.phy_addr, |
| 122 | PHY_REG_BCR, | 113 | PHY_REG_BCR, |
| 123 | PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M, | 114 | PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M, |
| 124 | ); | 115 | ); |
| 125 | } | 116 | } |
| 126 | 117 | ||
| 127 | fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool { | 118 | fn poll_link(&mut self, cx: &mut Context) -> bool { |
| 128 | #[cfg(not(feature = "time"))] | 119 | #[cfg(not(feature = "time"))] |
| 129 | cx.waker().wake_by_ref(); | 120 | cx.waker().wake_by_ref(); |
| 130 | 121 | ||
| 131 | #[cfg(feature = "time")] | 122 | #[cfg(feature = "time")] |
| 132 | let _ = Timer::after(self.poll_interval).poll_unpin(cx); | 123 | let _ = Timer::after(self.poll_interval).poll_unpin(cx); |
| 133 | 124 | ||
| 134 | let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR); | 125 | let bsr = self.sm.smi_read(self.phy_addr, PHY_REG_BSR); |
| 135 | 126 | ||
| 136 | // No link without autonegotiate | 127 | // No link without autonegotiate |
| 137 | if bsr & PHY_REG_BSR_ANDONE == 0 { | 128 | if bsr & PHY_REG_BSR_ANDONE == 0 { |
| @@ -148,7 +139,7 @@ impl Phy for GenericPhy { | |||
| 148 | } | 139 | } |
| 149 | 140 | ||
| 150 | /// Public functions for the PHY | 141 | /// Public functions for the PHY |
| 151 | impl GenericPhy { | 142 | impl<SM: StationManagement> GenericPhy<SM> { |
| 152 | /// Set the SMI polling interval. | 143 | /// Set the SMI polling interval. |
| 153 | #[cfg(feature = "time")] | 144 | #[cfg(feature = "time")] |
| 154 | pub fn set_poll_interval(&mut self, poll_interval: Duration) { | 145 | pub fn set_poll_interval(&mut self, poll_interval: Duration) { |
| @@ -156,10 +147,15 @@ impl GenericPhy { | |||
| 156 | } | 147 | } |
| 157 | 148 | ||
| 158 | // Writes a value to an extended PHY register in MMD address space | 149 | // Writes a value to an extended PHY register in MMD address space |
| 159 | fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) { | 150 | fn smi_write_ext(&mut self, reg_addr: u16, reg_data: u16) { |
| 160 | sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address | 151 | self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address |
| 161 | sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); | 152 | self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); |
| 162 | sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data | 153 | self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data |
| 163 | sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); | 154 | self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); |
| 155 | } | ||
| 156 | |||
| 157 | /// Access the underlying station management. | ||
| 158 | pub fn station_management(&mut self) -> &mut SM { | ||
| 159 | &mut self.sm | ||
| 164 | } | 160 | } |
| 165 | } | 161 | } |
