aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs5
-rw-r--r--embassy-stm32/src/eth/mod.rs13
-rw-r--r--embassy-stm32/src/eth/sma/mod.rs32
-rw-r--r--embassy-stm32/src/eth/sma/v1.rs102
-rw-r--r--embassy-stm32/src/eth/sma/v2.rs94
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs89
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs81
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
17pub use self::_version::{InterruptHandler, *}; 17pub use self::_version::{InterruptHandler, *};
18pub use self::generic_phy::*; 18pub use self::generic_phy::*;
19pub use self::sma::{Sma, StationManagement};
19use crate::rcc::RccPeripheral; 20use 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
162pub 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
170pub trait Phy { 163pub 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 {}
213pin_trait!(RXClkPin, Instance, @A); 206pin_trait!(RXClkPin, Instance, @A);
214pin_trait!(TXClkPin, Instance, @A); 207pin_trait!(TXClkPin, Instance, @A);
215pin_trait!(RefClkPin, Instance, @A); 208pin_trait!(RefClkPin, Instance, @A);
216pin_trait!(MDIOPin, Instance, @A); 209pin_trait!(MDIOPin, sma::Instance, @A);
217pin_trait!(MDCPin, Instance, @A); 210pin_trait!(MDCPin, sma::Instance, @A);
218pin_trait!(RXDVPin, Instance, @A); 211pin_trait!(RXDVPin, Instance, @A);
219pin_trait!(CRSPin, Instance, @A); 212pin_trait!(CRSPin, Instance, @A);
220pin_trait!(RXD0Pin, Instance, @A); 213pin_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")]
7mod _version;
8
5use embassy_hal_internal::PeripheralType; 9use embassy_hal_internal::PeripheralType;
6#[cfg(eth_v2)]
7pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister};
8#[cfg(any(eth_v1a, eth_v1b, eth_v1c))]
9pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister};
10use stm32_metapac::common::{RW, Reg}; 10use stm32_metapac::common::{RW, Reg};
11use stm32_metapac::eth::regs; 11
12pub use self::_version::*;
13
14/// Station Management Interface (SMI).
15pub 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
13trait SealedInstance { 22trait 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
42impl<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
33impl Instance for crate::peripherals::ETH_SMA {} 54impl Instance for crate::peripherals::ETH_SMA {}
55impl<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 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister};
3use stm32_metapac::eth::regs;
4use stm32_metapac::eth::vals::{Cr, MbProgress, Mw};
5
6use super::{Instance, StationManagement};
7use crate::eth::{MDCPin, MDIOPin};
8use 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).
14pub struct Sma<'d, T: Instance> {
15 _peri: Peri<'d, T>,
16 clock_range: Cr,
17 pins: [Peri<'d, AnyPin>; 2],
18}
19
20impl<'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
68impl<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
98impl<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 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister};
3use stm32_metapac::eth::regs;
4
5use super::{Instance, StationManagement};
6use crate::eth::{MDCPin, MDIOPin};
7use 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).
13pub struct Sma<'d, T: Instance> {
14 _peri: Peri<'d, T>,
15 pins: [Peri<'d, AnyPin>; 2],
16 clock_range: u8,
17}
18
19impl<'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
57impl<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
90impl<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 @@
3mod rx_desc; 3mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData;
7use core::sync::atomic::{Ordering, fence}; 6use core::sync::atomic::{Ordering, fence};
8 7
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 9use stm32_metapac::eth::vals::{Apcs, Dm, DmaomrSr, Fes, Ftf, Ifg, Pbl, Rsf, St, Tsf};
11 10
12pub(crate) use self::rx_desc::{RDes, RDesRing}; 11pub(crate) use self::rx_desc::{RDes, RDesRing};
13pub(crate) use self::tx_desc::{TDes, TDesRing}; 12pub(crate) use self::tx_desc::{TDes, TDesRing};
13use super::sma::Sma;
14use super::*; 14use super::*;
15use crate::eth::{MDCPin, MDIOPin};
15#[cfg(eth_v1a)] 16#[cfg(eth_v1a)]
16use crate::gpio::Pull; 17use crate::gpio::Pull;
17use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 18use 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))]
23use crate::pac::SYSCFG; 24use crate::pac::SYSCFG;
24use crate::pac::{ETH, RCC}; 25use crate::pac::{ETH, RCC};
25use crate::rcc::SealedRccPeripheral;
26 26
27/// Interrupt handler. 27/// Interrupt handler.
28pub struct InterruptHandler {} 28pub 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.
378pub(crate) struct EthernetStationManagement<'d, T: Instance> {
379 peri: PhantomData<T>,
380 clock_range: Cr,
381 pins: [Peri<'d, AnyPin>; 2],
382}
383
384impl<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
420impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 359impl<'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
447impl<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 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData;
4use core::sync::atomic::{Ordering, fence}; 3use core::sync::atomic::{Ordering, fence};
5 4
6use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 6use stm32_metapac::syscfg::vals::EthSelPhy;
8 7
9pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; 8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::sma::Sma;
10use super::*; 10use super::*;
11use crate::eth::{MDCPin, MDIOPin};
11use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; 12use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
12use crate::interrupt; 13use crate::interrupt;
13use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
14use crate::pac::ETH; 15use crate::pac::ETH;
15use crate::rcc::SealedRccPeripheral;
16 16
17/// Interrupt handler. 17/// Interrupt handler.
18pub struct InterruptHandler {} 18pub 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.
301pub struct EthernetStationManagement<'d, T: Instance> {
302 peri: PhantomData<T>,
303 clock_range: u8,
304 pins: [Peri<'d, AnyPin>; 2],
305}
306
307impl<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
343impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 282impl<'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
380impl<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}