diff options
| author | datdenkikniet <[email protected]> | 2025-11-12 21:51:55 +0100 |
|---|---|---|
| committer | datdenkikniet <[email protected]> | 2025-11-13 23:08:33 +0100 |
| commit | a021b4940c852f01322a20a7358bc1a549b3d3c4 (patch) | |
| tree | ca8d84867e656d7dd4d9d46beffb076b2608b240 /embassy-stm32 | |
| parent | aad63ecd597a5b12663bf12329327de6d9cd65f2 (diff) | |
Move SMA responsibility to SMA peripheral
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/build.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/mod.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/sma/mod.rs | 32 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/sma/v1.rs | 102 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/sma/v2.rs | 94 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v1/mod.rs | 89 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v2/mod.rs | 81 |
7 files changed, 249 insertions, 167 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 9dd94941c..8cbd38e10 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1404,6 +1404,11 @@ fn main() { | |||
| 1404 | } | 1404 | } |
| 1405 | } | 1405 | } |
| 1406 | 1406 | ||
| 1407 | // MDIO and MDC are special | ||
| 1408 | if pin.signal == "MDIO" || pin.signal == "MDC" { | ||
| 1409 | peri = format_ident!("{}", "ETH_SMA"); | ||
| 1410 | } | ||
| 1411 | |||
| 1407 | // XSPI NCS pin to CSSEL mapping | 1412 | // XSPI NCS pin to CSSEL mapping |
| 1408 | if pin.signal.ends_with("NCS1") { | 1413 | if pin.signal.ends_with("NCS1") { |
| 1409 | g.extend(quote! { | 1414 | g.extend(quote! { |
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index bef6a02b2..448d21f3f 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs | |||
| @@ -16,6 +16,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 16 | 16 | ||
| 17 | pub use self::_version::{InterruptHandler, *}; | 17 | pub use self::_version::{InterruptHandler, *}; |
| 18 | pub use self::generic_phy::*; | 18 | pub use self::generic_phy::*; |
| 19 | pub use self::sma::{Sma, StationManagement}; | ||
| 19 | use crate::rcc::RccPeripheral; | 20 | use crate::rcc::RccPeripheral; |
| 20 | 21 | ||
| 21 | #[allow(unused)] | 22 | #[allow(unused)] |
| @@ -158,14 +159,6 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> { | |||
| 158 | } | 159 | } |
| 159 | } | 160 | } |
| 160 | 161 | ||
| 161 | /// Station Management Interface (SMI) on an ethernet PHY | ||
| 162 | pub trait StationManagement { | ||
| 163 | /// Read a register over SMI. | ||
| 164 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16; | ||
| 165 | /// Write a register over SMI. | ||
| 166 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); | ||
| 167 | } | ||
| 168 | |||
| 169 | /// Trait for an Ethernet PHY | 162 | /// Trait for an Ethernet PHY |
| 170 | pub trait Phy { | 163 | pub trait Phy { |
| 171 | /// Reset PHY and wait for it to come out of reset. | 164 | /// Reset PHY and wait for it to come out of reset. |
| @@ -213,8 +206,8 @@ impl Instance for crate::peripherals::ETH {} | |||
| 213 | pin_trait!(RXClkPin, Instance, @A); | 206 | pin_trait!(RXClkPin, Instance, @A); |
| 214 | pin_trait!(TXClkPin, Instance, @A); | 207 | pin_trait!(TXClkPin, Instance, @A); |
| 215 | pin_trait!(RefClkPin, Instance, @A); | 208 | pin_trait!(RefClkPin, Instance, @A); |
| 216 | pin_trait!(MDIOPin, Instance, @A); | 209 | pin_trait!(MDIOPin, sma::Instance, @A); |
| 217 | pin_trait!(MDCPin, Instance, @A); | 210 | pin_trait!(MDCPin, sma::Instance, @A); |
| 218 | pin_trait!(RXDVPin, Instance, @A); | 211 | pin_trait!(RXDVPin, Instance, @A); |
| 219 | pin_trait!(CRSPin, Instance, @A); | 212 | pin_trait!(CRSPin, Instance, @A); |
| 220 | pin_trait!(RXD0Pin, Instance, @A); | 213 | pin_trait!(RXD0Pin, Instance, @A); |
diff --git a/embassy-stm32/src/eth/sma/mod.rs b/embassy-stm32/src/eth/sma/mod.rs index 106a6b2bd..558107abc 100644 --- a/embassy-stm32/src/eth/sma/mod.rs +++ b/embassy-stm32/src/eth/sma/mod.rs | |||
| @@ -2,13 +2,22 @@ | |||
| 2 | 2 | ||
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | #[cfg_attr(eth_v2, path = "v2.rs")] | ||
| 6 | #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1.rs")] | ||
| 7 | mod _version; | ||
| 8 | |||
| 5 | use embassy_hal_internal::PeripheralType; | 9 | use embassy_hal_internal::PeripheralType; |
| 6 | #[cfg(eth_v2)] | ||
| 7 | pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister}; | ||
| 8 | #[cfg(any(eth_v1a, eth_v1b, eth_v1c))] | ||
| 9 | pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister}; | ||
| 10 | use stm32_metapac::common::{RW, Reg}; | 10 | use stm32_metapac::common::{RW, Reg}; |
| 11 | use stm32_metapac::eth::regs; | 11 | |
| 12 | pub use self::_version::*; | ||
| 13 | |||
| 14 | /// Station Management Interface (SMI). | ||
| 15 | pub trait StationManagement { | ||
| 16 | /// Read a register over SMI. | ||
| 17 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16; | ||
| 18 | /// Write a register over SMI. | ||
| 19 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); | ||
| 20 | } | ||
| 12 | 21 | ||
| 13 | trait SealedInstance { | 22 | trait SealedInstance { |
| 14 | fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>); | 23 | fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>); |
| @@ -30,4 +39,17 @@ impl SealedInstance for crate::peripherals::ETH_SMA { | |||
| 30 | } | 39 | } |
| 31 | } | 40 | } |
| 32 | 41 | ||
| 42 | impl<T: crate::eth::Instance> SealedInstance for T { | ||
| 43 | fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>) { | ||
| 44 | let mac = <T as crate::eth::SealedInstance>::regs().ethernet_mac(); | ||
| 45 | |||
| 46 | #[cfg(any(eth_v1a, eth_v1b, eth_v1c))] | ||
| 47 | return (mac.macmiiar(), mac.macmiidr()); | ||
| 48 | |||
| 49 | #[cfg(eth_v2)] | ||
| 50 | return (mac.macmdioar(), mac.macmdiodr()); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 33 | impl Instance for crate::peripherals::ETH_SMA {} | 54 | impl Instance for crate::peripherals::ETH_SMA {} |
| 55 | impl<T: crate::eth::Instance> Instance for T {} | ||
diff --git a/embassy-stm32/src/eth/sma/v1.rs b/embassy-stm32/src/eth/sma/v1.rs new file mode 100644 index 000000000..db64a6c78 --- /dev/null +++ b/embassy-stm32/src/eth/sma/v1.rs | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | use embassy_hal_internal::Peri; | ||
| 2 | pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister}; | ||
| 3 | use stm32_metapac::eth::regs; | ||
| 4 | use stm32_metapac::eth::vals::{Cr, MbProgress, Mw}; | ||
| 5 | |||
| 6 | use super::{Instance, StationManagement}; | ||
| 7 | use crate::eth::{MDCPin, MDIOPin}; | ||
| 8 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | ||
| 9 | |||
| 10 | /// Station Management Agent. | ||
| 11 | /// | ||
| 12 | /// This peripheral is used for SMI reads and writes to the connected | ||
| 13 | /// ethernet PHY/device(s). | ||
| 14 | pub struct Sma<'d, T: Instance> { | ||
| 15 | _peri: Peri<'d, T>, | ||
| 16 | clock_range: Cr, | ||
| 17 | pins: [Peri<'d, AnyPin>; 2], | ||
| 18 | } | ||
| 19 | |||
| 20 | impl<'d, T: Instance> Sma<'d, T> { | ||
| 21 | /// Create a new instance of this peripheral. | ||
| 22 | pub fn new<#[cfg(afio)] A>( | ||
| 23 | peri: Peri<'d, T>, | ||
| 24 | mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>, | ||
| 25 | mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>, | ||
| 26 | ) -> Self { | ||
| 27 | set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh)); | ||
| 28 | set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh)); | ||
| 29 | |||
| 30 | // Enable necessary clocks. | ||
| 31 | critical_section::with(|_| { | ||
| 32 | #[cfg(eth_v1a)] | ||
| 33 | let reg = crate::pac::RCC.ahbenr(); | ||
| 34 | |||
| 35 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 36 | let reg = crate::pac::RCC.ahb1enr(); | ||
| 37 | |||
| 38 | reg.modify(|w| { | ||
| 39 | w.set_ethen(true); | ||
| 40 | }) | ||
| 41 | }); | ||
| 42 | |||
| 43 | let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() }; | ||
| 44 | let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not."); | ||
| 45 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 46 | |||
| 47 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 48 | let clock_range = match hclk_mhz { | ||
| 49 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||
| 50 | 25..=34 => Cr::CR_20_35, // Divide by 16 | ||
| 51 | 35..=59 => Cr::CR_35_60, // Divide by 26 | ||
| 52 | 60..=99 => Cr::CR_60_100, // Divide by 42 | ||
| 53 | 100..=149 => Cr::CR_100_150, // Divide by 62 | ||
| 54 | 150..=216 => Cr::CR_150_168, // Divide by 102 | ||
| 55 | _ => { | ||
| 56 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 57 | } | ||
| 58 | }; | ||
| 59 | |||
| 60 | Self { | ||
| 61 | _peri: peri, | ||
| 62 | clock_range, | ||
| 63 | pins: [mdio.into(), mdc.into()], | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | impl<T: Instance> StationManagement for Sma<'_, T> { | ||
| 69 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | ||
| 70 | let (macmiiar, macmiidr) = T::regs(); | ||
| 71 | |||
| 72 | macmiiar.modify(|w| { | ||
| 73 | w.set_pa(phy_addr); | ||
| 74 | w.set_mr(reg); | ||
| 75 | w.set_mw(Mw::READ); // read operation | ||
| 76 | w.set_cr(self.clock_range); | ||
| 77 | w.set_mb(MbProgress::BUSY); // indicate that operation is in progress | ||
| 78 | }); | ||
| 79 | while macmiiar.read().mb() == MbProgress::BUSY {} | ||
| 80 | macmiidr.read().md() | ||
| 81 | } | ||
| 82 | |||
| 83 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | ||
| 84 | let (macmiiar, macmiidr) = T::regs(); | ||
| 85 | |||
| 86 | macmiidr.write(|w| w.set_md(val)); | ||
| 87 | macmiiar.modify(|w| { | ||
| 88 | w.set_pa(phy_addr); | ||
| 89 | w.set_mr(reg); | ||
| 90 | w.set_mw(Mw::WRITE); // write | ||
| 91 | w.set_cr(self.clock_range); | ||
| 92 | w.set_mb(MbProgress::BUSY); | ||
| 93 | }); | ||
| 94 | while macmiiar.read().mb() == MbProgress::BUSY {} | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | impl<T: Instance> Drop for Sma<'_, T> { | ||
| 99 | fn drop(&mut self) { | ||
| 100 | self.pins.iter_mut().for_each(|p| p.set_as_disconnected()); | ||
| 101 | } | ||
| 102 | } | ||
diff --git a/embassy-stm32/src/eth/sma/v2.rs b/embassy-stm32/src/eth/sma/v2.rs new file mode 100644 index 000000000..6bc5230b5 --- /dev/null +++ b/embassy-stm32/src/eth/sma/v2.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | use embassy_hal_internal::Peri; | ||
| 2 | pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister}; | ||
| 3 | use stm32_metapac::eth::regs; | ||
| 4 | |||
| 5 | use super::{Instance, StationManagement}; | ||
| 6 | use crate::eth::{MDCPin, MDIOPin}; | ||
| 7 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | ||
| 8 | |||
| 9 | /// Station Management Agent. | ||
| 10 | /// | ||
| 11 | /// This peripheral is used for SMI reads and writes to the connected | ||
| 12 | /// ethernet PHY/device(s). | ||
| 13 | pub struct Sma<'d, T: Instance> { | ||
| 14 | _peri: Peri<'d, T>, | ||
| 15 | pins: [Peri<'d, AnyPin>; 2], | ||
| 16 | clock_range: u8, | ||
| 17 | } | ||
| 18 | |||
| 19 | impl<'d, T: Instance> Sma<'d, T> { | ||
| 20 | /// Create a new instance of this peripheral. | ||
| 21 | pub fn new(peri: Peri<'d, T>, mdio: Peri<'d, impl MDIOPin<T>>, mdc: Peri<'d, impl MDCPin<T>>) -> Self { | ||
| 22 | set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh)); | ||
| 23 | set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh)); | ||
| 24 | |||
| 25 | // Enable necessary clocks. | ||
| 26 | critical_section::with(|_| { | ||
| 27 | crate::pac::RCC.ahb1enr().modify(|w| { | ||
| 28 | w.set_ethen(true); | ||
| 29 | }) | ||
| 30 | }); | ||
| 31 | |||
| 32 | let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() }; | ||
| 33 | let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not."); | ||
| 34 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 35 | |||
| 36 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 37 | let clock_range = match hclk_mhz { | ||
| 38 | 0..=34 => 2, // Divide by 16 | ||
| 39 | 35..=59 => 3, // Divide by 26 | ||
| 40 | 60..=99 => 0, // Divide by 42 | ||
| 41 | 100..=149 => 1, // Divide by 62 | ||
| 42 | 150..=249 => 4, // Divide by 102 | ||
| 43 | 250..=310 => 5, // Divide by 124 | ||
| 44 | _ => { | ||
| 45 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | Self { | ||
| 50 | _peri: peri, | ||
| 51 | clock_range, | ||
| 52 | pins: [mdio.into(), mdc.into()], | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | impl<T: Instance> StationManagement for Sma<'_, T> { | ||
| 58 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | ||
| 59 | let (macmdioar, macmdiodr) = T::regs(); | ||
| 60 | |||
| 61 | macmdioar.modify(|w| { | ||
| 62 | w.set_pa(phy_addr); | ||
| 63 | w.set_rda(reg); | ||
| 64 | w.set_goc(0b11); // read | ||
| 65 | w.set_cr(self.clock_range); | ||
| 66 | w.set_mb(true); | ||
| 67 | }); | ||
| 68 | |||
| 69 | while macmdioar.read().mb() {} | ||
| 70 | |||
| 71 | macmdiodr.read().md() | ||
| 72 | } | ||
| 73 | |||
| 74 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | ||
| 75 | let (macmdioar, macmdiodr) = T::regs(); | ||
| 76 | |||
| 77 | macmdiodr.write(|w| w.set_md(val)); | ||
| 78 | macmdioar.modify(|w| { | ||
| 79 | w.set_pa(phy_addr); | ||
| 80 | w.set_rda(reg); | ||
| 81 | w.set_goc(0b01); // write | ||
| 82 | w.set_cr(self.clock_range); | ||
| 83 | w.set_mb(true); | ||
| 84 | }); | ||
| 85 | |||
| 86 | while macmdioar.read().mb() {} | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | impl<T: Instance> Drop for Sma<'_, T> { | ||
| 91 | fn drop(&mut self) { | ||
| 92 | self.pins.iter_mut().for_each(|p| p.set_as_disconnected()); | ||
| 93 | } | ||
| 94 | } | ||
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 91daa9d0b..d448537c8 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -3,15 +3,16 @@ | |||
| 3 | mod rx_desc; | 3 | mod rx_desc; |
| 4 | mod tx_desc; | 4 | mod tx_desc; |
| 5 | 5 | ||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::sync::atomic::{Ordering, fence}; | 6 | use core::sync::atomic::{Ordering, fence}; |
| 8 | 7 | ||
| 9 | use embassy_hal_internal::Peri; | 8 | use embassy_hal_internal::Peri; |
| 10 | use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; | 9 | use stm32_metapac::eth::vals::{Apcs, Dm, DmaomrSr, Fes, Ftf, Ifg, Pbl, Rsf, St, Tsf}; |
| 11 | 10 | ||
| 12 | pub(crate) use self::rx_desc::{RDes, RDesRing}; | 11 | pub(crate) use self::rx_desc::{RDes, RDesRing}; |
| 13 | pub(crate) use self::tx_desc::{TDes, TDesRing}; | 12 | pub(crate) use self::tx_desc::{TDes, TDesRing}; |
| 13 | use super::sma::Sma; | ||
| 14 | use super::*; | 14 | use super::*; |
| 15 | use crate::eth::{MDCPin, MDIOPin}; | ||
| 15 | #[cfg(eth_v1a)] | 16 | #[cfg(eth_v1a)] |
| 16 | use crate::gpio::Pull; | 17 | use crate::gpio::Pull; |
| 17 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; | 18 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; |
| @@ -22,7 +23,6 @@ use crate::pac::AFIO; | |||
| 22 | #[cfg(any(eth_v1b, eth_v1c))] | 23 | #[cfg(any(eth_v1b, eth_v1c))] |
| 23 | use crate::pac::SYSCFG; | 24 | use crate::pac::SYSCFG; |
| 24 | use crate::pac::{ETH, RCC}; | 25 | use crate::pac::{ETH, RCC}; |
| 25 | use crate::rcc::SealedRccPeripheral; | ||
| 26 | 26 | ||
| 27 | /// Interrupt handler. | 27 | /// Interrupt handler. |
| 28 | pub struct InterruptHandler {} | 28 | pub struct InterruptHandler {} |
| @@ -53,7 +53,7 @@ pub struct Ethernet<'d, T: Instance, P: Phy> { | |||
| 53 | 53 | ||
| 54 | pins: Pins<'d>, | 54 | pins: Pins<'d>, |
| 55 | pub(crate) phy: P, | 55 | pub(crate) phy: P, |
| 56 | pub(crate) station_management: EthernetStationManagement<'d, T>, | 56 | pub(crate) station_management: Sma<'d, T>, |
| 57 | pub(crate) mac_addr: [u8; 6], | 57 | pub(crate) mac_addr: [u8; 6], |
| 58 | } | 58 | } |
| 59 | 59 | ||
| @@ -149,11 +149,11 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 149 | #[cfg(eth_v1a)] | 149 | #[cfg(eth_v1a)] |
| 150 | { | 150 | { |
| 151 | config_in_pins!(ref_clk, rx_d0, rx_d1); | 151 | config_in_pins!(ref_clk, rx_d0, rx_d1); |
| 152 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | 152 | config_af_pins!(tx_d0, tx_d1, tx_en); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | #[cfg(any(eth_v1b, eth_v1c))] | 155 | #[cfg(any(eth_v1b, eth_v1c))] |
| 156 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 156 | config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 157 | 157 | ||
| 158 | let pins = Pins::Rmii([ | 158 | let pins = Pins::Rmii([ |
| 159 | ref_clk.into(), | 159 | ref_clk.into(), |
| @@ -168,7 +168,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 168 | Self::new_inner(queue, peri, irq, pins, mdio, mdc, phy, mac_addr) | 168 | Self::new_inner(queue, peri, irq, pins, mdio, mdc, phy, mac_addr) |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | fn new_inner<const TX: usize, const RX: usize>( | 171 | fn new_inner<const TX: usize, const RX: usize, #[cfg(afio)] A>( |
| 172 | queue: &'d mut PacketQueue<TX, RX>, | 172 | queue: &'d mut PacketQueue<TX, RX>, |
| 173 | peri: Peri<'d, T>, | 173 | peri: Peri<'d, T>, |
| 174 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, | 174 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, |
| @@ -226,31 +226,13 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 226 | 226 | ||
| 227 | // TODO MTU size setting not found for v1 ethernet, check if correct | 227 | // TODO MTU size setting not found for v1 ethernet, check if correct |
| 228 | 228 | ||
| 229 | let hclk = <T as SealedRccPeripheral>::frequency(); | 229 | let sma_peri = unsafe { peri.clone_unchecked() }; |
| 230 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 231 | |||
| 232 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 233 | let clock_range = match hclk_mhz { | ||
| 234 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||
| 235 | 25..=34 => Cr::CR_20_35, // Divide by 16 | ||
| 236 | 35..=59 => Cr::CR_35_60, // Divide by 26 | ||
| 237 | 60..=99 => Cr::CR_60_100, // Divide by 42 | ||
| 238 | 100..=149 => Cr::CR_100_150, // Divide by 62 | ||
| 239 | 150..=216 => Cr::CR_150_168, // Divide by 102 | ||
| 240 | _ => { | ||
| 241 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 242 | } | ||
| 243 | }; | ||
| 244 | 230 | ||
| 245 | let mut this = Self { | 231 | let mut this = Self { |
| 246 | _peri: peri, | 232 | _peri: peri, |
| 247 | pins, | 233 | pins, |
| 248 | phy: phy, | 234 | phy: phy, |
| 249 | station_management: EthernetStationManagement { | 235 | station_management: Sma::new(sma_peri, mdio, mdc), |
| 250 | peri: PhantomData, | ||
| 251 | clock_range: clock_range, | ||
| 252 | pins: [mdio.into(), mdc.into()], | ||
| 253 | }, | ||
| 254 | mac_addr, | 236 | mac_addr, |
| 255 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), | 237 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), |
| 256 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | 238 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), |
| @@ -347,12 +329,12 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 347 | #[cfg(eth_v1a)] | 329 | #[cfg(eth_v1a)] |
| 348 | { | 330 | { |
| 349 | config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); | 331 | config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); |
| 350 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); | 332 | config_af_pins!(tx_d0, tx_d1, tx_d2, tx_d3, tx_en); |
| 351 | } | 333 | } |
| 352 | 334 | ||
| 353 | #[cfg(any(eth_v1b, eth_v1c))] | 335 | #[cfg(any(eth_v1b, eth_v1c))] |
| 354 | config_pins!( | 336 | config_pins!( |
| 355 | rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en | 337 | rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en |
| 356 | ); | 338 | ); |
| 357 | 339 | ||
| 358 | let pins = Pins::Mii([ | 340 | let pins = Pins::Mii([ |
| @@ -374,49 +356,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 374 | } | 356 | } |
| 375 | } | 357 | } |
| 376 | 358 | ||
| 377 | /// Ethernet station management interface. | ||
| 378 | pub(crate) struct EthernetStationManagement<'d, T: Instance> { | ||
| 379 | peri: PhantomData<T>, | ||
| 380 | clock_range: Cr, | ||
| 381 | pins: [Peri<'d, AnyPin>; 2], | ||
| 382 | } | ||
| 383 | |||
| 384 | impl<T: Instance> StationManagement for EthernetStationManagement<'_, T> { | ||
| 385 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | ||
| 386 | let (macmiiar, macmiidr) = { | ||
| 387 | let regs = T::regs().ethernet_mac(); | ||
| 388 | (regs.macmiiar(), regs.macmiidr()) | ||
| 389 | }; | ||
| 390 | |||
| 391 | macmiiar.modify(|w| { | ||
| 392 | w.set_pa(phy_addr); | ||
| 393 | w.set_mr(reg); | ||
| 394 | w.set_mw(Mw::READ); // read operation | ||
| 395 | w.set_cr(self.clock_range); | ||
| 396 | w.set_mb(MbProgress::BUSY); // indicate that operation is in progress | ||
| 397 | }); | ||
| 398 | while macmiiar.read().mb() == MbProgress::BUSY {} | ||
| 399 | macmiidr.read().md() | ||
| 400 | } | ||
| 401 | |||
| 402 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | ||
| 403 | let (macmiiar, macmiidr) = { | ||
| 404 | let regs = T::regs().ethernet_mac(); | ||
| 405 | (regs.macmiiar(), regs.macmiidr()) | ||
| 406 | }; | ||
| 407 | |||
| 408 | macmiidr.write(|w| w.set_md(val)); | ||
| 409 | macmiiar.modify(|w| { | ||
| 410 | w.set_pa(phy_addr); | ||
| 411 | w.set_mr(reg); | ||
| 412 | w.set_mw(Mw::WRITE); // write | ||
| 413 | w.set_cr(self.clock_range); | ||
| 414 | w.set_mb(MbProgress::BUSY); | ||
| 415 | }); | ||
| 416 | while macmiiar.read().mb() == MbProgress::BUSY {} | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { | 359 | impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { |
| 421 | fn drop(&mut self) { | 360 | fn drop(&mut self) { |
| 422 | let dma = T::regs().ethernet_dma(); | 361 | let dma = T::regs().ethernet_dma(); |
| @@ -443,9 +382,3 @@ impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { | |||
| 443 | }) | 382 | }) |
| 444 | } | 383 | } |
| 445 | } | 384 | } |
| 446 | |||
| 447 | impl<T: Instance> Drop for EthernetStationManagement<'_, T> { | ||
| 448 | fn drop(&mut self) { | ||
| 449 | self.pins.iter_mut().for_each(|p| p.set_as_disconnected()); | ||
| 450 | } | ||
| 451 | } | ||
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 61dea6f3f..0db335a7c 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs | |||
| @@ -1,18 +1,18 @@ | |||
| 1 | mod descriptors; | 1 | mod descriptors; |
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::sync::atomic::{Ordering, fence}; | 3 | use core::sync::atomic::{Ordering, fence}; |
| 5 | 4 | ||
| 6 | use embassy_hal_internal::Peri; | 5 | use embassy_hal_internal::Peri; |
| 7 | use stm32_metapac::syscfg::vals::EthSelPhy; | 6 | use stm32_metapac::syscfg::vals::EthSelPhy; |
| 8 | 7 | ||
| 9 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; | 8 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; |
| 9 | use super::sma::Sma; | ||
| 10 | use super::*; | 10 | use super::*; |
| 11 | use crate::eth::{MDCPin, MDIOPin}; | ||
| 11 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; | 12 | use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; |
| 12 | use crate::interrupt; | 13 | use crate::interrupt; |
| 13 | use crate::interrupt::InterruptExt; | 14 | use crate::interrupt::InterruptExt; |
| 14 | use crate::pac::ETH; | 15 | use crate::pac::ETH; |
| 15 | use crate::rcc::SealedRccPeripheral; | ||
| 16 | 16 | ||
| 17 | /// Interrupt handler. | 17 | /// Interrupt handler. |
| 18 | pub struct InterruptHandler {} | 18 | pub struct InterruptHandler {} |
| @@ -42,7 +42,7 @@ pub struct Ethernet<'d, T: Instance, P: Phy> { | |||
| 42 | pub(crate) rx: RDesRing<'d>, | 42 | pub(crate) rx: RDesRing<'d>, |
| 43 | pins: Pins<'d>, | 43 | pins: Pins<'d>, |
| 44 | pub(crate) phy: P, | 44 | pub(crate) phy: P, |
| 45 | pub(crate) station_management: EthernetStationManagement<'d, T>, | 45 | pub(crate) station_management: Sma<'d, T>, |
| 46 | pub(crate) mac_addr: [u8; 6], | 46 | pub(crate) mac_addr: [u8; 6], |
| 47 | } | 47 | } |
| 48 | 48 | ||
| @@ -92,7 +92,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 92 | crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); | 92 | crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); |
| 93 | }); | 93 | }); |
| 94 | 94 | ||
| 95 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 95 | config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 96 | 96 | ||
| 97 | let pins = Pins::Rmii([ | 97 | let pins = Pins::Rmii([ |
| 98 | ref_clk.into(), | 98 | ref_clk.into(), |
| @@ -143,7 +143,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 143 | }); | 143 | }); |
| 144 | 144 | ||
| 145 | config_pins!( | 145 | config_pins!( |
| 146 | rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en | 146 | rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en |
| 147 | ); | 147 | ); |
| 148 | 148 | ||
| 149 | let pins = Pins::Mii([ | 149 | let pins = Pins::Mii([ |
| @@ -235,21 +235,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 235 | w.set_rbsz(RX_BUFFER_SIZE as u16); | 235 | w.set_rbsz(RX_BUFFER_SIZE as u16); |
| 236 | }); | 236 | }); |
| 237 | 237 | ||
| 238 | let hclk = <T as SealedRccPeripheral>::frequency(); | 238 | let sma_peri = unsafe { peri.clone_unchecked() }; |
| 239 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 240 | |||
| 241 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 242 | let clock_range = match hclk_mhz { | ||
| 243 | 0..=34 => 2, // Divide by 16 | ||
| 244 | 35..=59 => 3, // Divide by 26 | ||
| 245 | 60..=99 => 0, // Divide by 42 | ||
| 246 | 100..=149 => 1, // Divide by 62 | ||
| 247 | 150..=249 => 4, // Divide by 102 | ||
| 248 | 250..=310 => 5, // Divide by 124 | ||
| 249 | _ => { | ||
| 250 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 251 | } | ||
| 252 | }; | ||
| 253 | 239 | ||
| 254 | let mut this = Self { | 240 | let mut this = Self { |
| 255 | _peri: peri, | 241 | _peri: peri, |
| @@ -257,11 +243,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 257 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | 243 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), |
| 258 | pins, | 244 | pins, |
| 259 | phy, | 245 | phy, |
| 260 | station_management: EthernetStationManagement { | 246 | station_management: Sma::new(sma_peri, mdio, mdc), |
| 261 | peri: PhantomData, | ||
| 262 | clock_range: clock_range, | ||
| 263 | pins: [mdio.into(), mdc.into()], | ||
| 264 | }, | ||
| 265 | mac_addr, | 247 | mac_addr, |
| 266 | }; | 248 | }; |
| 267 | 249 | ||
| @@ -297,49 +279,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { | |||
| 297 | } | 279 | } |
| 298 | } | 280 | } |
| 299 | 281 | ||
| 300 | /// Ethernet SMI driver. | ||
| 301 | pub struct EthernetStationManagement<'d, T: Instance> { | ||
| 302 | peri: PhantomData<T>, | ||
| 303 | clock_range: u8, | ||
| 304 | pins: [Peri<'d, AnyPin>; 2], | ||
| 305 | } | ||
| 306 | |||
| 307 | impl<T: Instance> StationManagement for EthernetStationManagement<'_, T> { | ||
| 308 | fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { | ||
| 309 | let (macmdioar, macmdiodr) = { | ||
| 310 | let regs = T::regs().ethernet_mac(); | ||
| 311 | (regs.macmdioar(), regs.macmdiodr()) | ||
| 312 | }; | ||
| 313 | |||
| 314 | macmdioar.modify(|w| { | ||
| 315 | w.set_pa(phy_addr); | ||
| 316 | w.set_rda(reg); | ||
| 317 | w.set_goc(0b11); // read | ||
| 318 | w.set_cr(self.clock_range); | ||
| 319 | w.set_mb(true); | ||
| 320 | }); | ||
| 321 | while macmdioar.read().mb() {} | ||
| 322 | macmdiodr.read().md() | ||
| 323 | } | ||
| 324 | |||
| 325 | fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { | ||
| 326 | let (macmdioar, macmdiodr) = { | ||
| 327 | let regs = T::regs().ethernet_mac(); | ||
| 328 | (regs.macmdioar(), regs.macmdiodr()) | ||
| 329 | }; | ||
| 330 | |||
| 331 | macmdiodr.write(|w| w.set_md(val)); | ||
| 332 | macmdioar.modify(|w| { | ||
| 333 | w.set_pa(phy_addr); | ||
| 334 | w.set_rda(reg); | ||
| 335 | w.set_goc(0b01); // write | ||
| 336 | w.set_cr(self.clock_range); | ||
| 337 | w.set_mb(true); | ||
| 338 | }); | ||
| 339 | while macmdioar.read().mb() {} | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { | 282 | impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { |
| 344 | fn drop(&mut self) { | 283 | fn drop(&mut self) { |
| 345 | let dma = T::regs().ethernet_dma(); | 284 | let dma = T::regs().ethernet_dma(); |
| @@ -376,9 +315,3 @@ impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { | |||
| 376 | }) | 315 | }) |
| 377 | } | 316 | } |
| 378 | } | 317 | } |
| 379 | |||
| 380 | impl<T: Instance> Drop for EthernetStationManagement<'_, T> { | ||
| 381 | fn drop(&mut self) { | ||
| 382 | self.pins.iter_mut().for_each(|p| p.set_as_disconnected()); | ||
| 383 | } | ||
| 384 | } | ||
