aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/eth/v2/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/eth/v2/mod.rs')
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs201
1 files changed, 97 insertions, 104 deletions
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index cf7a9901b..7f92e351c 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,7 +1,6 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData; 3use core::sync::atomic::{Ordering, fence};
4use core::sync::atomic::{fence, Ordering};
5 4
6use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 6use stm32_metapac::syscfg::vals::EthSelPhy;
@@ -12,7 +11,6 @@ use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
12use crate::interrupt; 11use crate::interrupt;
13use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
14use crate::pac::ETH; 13use crate::pac::ETH;
15use crate::rcc::SealedRccPeripheral;
16 14
17/// Interrupt handler. 15/// Interrupt handler.
18pub struct InterruptHandler {} 16pub struct InterruptHandler {}
@@ -42,14 +40,13 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
42 pub(crate) rx: RDesRing<'d>, 40 pub(crate) rx: RDesRing<'d>,
43 pins: Pins<'d>, 41 pins: Pins<'d>,
44 pub(crate) phy: P, 42 pub(crate) phy: P,
45 pub(crate) station_management: EthernetStationManagement<T>,
46 pub(crate) mac_addr: [u8; 6], 43 pub(crate) mac_addr: [u8; 6],
47} 44}
48 45
49/// Pins of ethernet driver. 46/// Pins of ethernet driver.
50enum Pins<'d> { 47enum Pins<'d> {
51 Rmii([Peri<'d, AnyPin>; 9]), 48 Rmii([Peri<'d, AnyPin>; 7]),
52 Mii([Peri<'d, AnyPin>; 14]), 49 Mii([Peri<'d, AnyPin>; 12]),
53} 50}
54 51
55macro_rules! config_pins { 52macro_rules! config_pins {
@@ -63,41 +60,96 @@ macro_rules! config_pins {
63 }; 60 };
64} 61}
65 62
66impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 63impl<'d, T: Instance, SMA: sma::Instance> Ethernet<'d, T, GenericPhy<Sma<'d, SMA>>> {
67 /// Create a new RMII ethernet driver using 9 pins. 64 /// Create a new RMII ethernet driver using 7 pins.
65 ///
66 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
67 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
68 ///
69 /// See [`Ethernet::new_with_phy`] for creating an RMII ethernet
70 /// river with a non-standard PHY.
68 pub fn new<const TX: usize, const RX: usize>( 71 pub fn new<const TX: usize, const RX: usize>(
69 queue: &'d mut PacketQueue<TX, RX>, 72 queue: &'d mut PacketQueue<TX, RX>,
70 peri: Peri<'d, T>, 73 peri: Peri<'d, T>,
71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 74 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
72 ref_clk: Peri<'d, impl RefClkPin<T>>, 75 ref_clk: Peri<'d, impl RefClkPin<T>>,
73 mdio: Peri<'d, impl MDIOPin<T>>,
74 mdc: Peri<'d, impl MDCPin<T>>,
75 crs: Peri<'d, impl CRSPin<T>>, 76 crs: Peri<'d, impl CRSPin<T>>,
76 rx_d0: Peri<'d, impl RXD0Pin<T>>, 77 rx_d0: Peri<'d, impl RXD0Pin<T>>,
77 rx_d1: Peri<'d, impl RXD1Pin<T>>, 78 rx_d1: Peri<'d, impl RXD1Pin<T>>,
78 tx_d0: Peri<'d, impl TXD0Pin<T>>, 79 tx_d0: Peri<'d, impl TXD0Pin<T>>,
79 tx_d1: Peri<'d, impl TXD1Pin<T>>, 80 tx_d1: Peri<'d, impl TXD1Pin<T>>,
80 tx_en: Peri<'d, impl TXEnPin<T>>, 81 tx_en: Peri<'d, impl TXEnPin<T>>,
81 phy: P,
82 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
83 sma: Peri<'d, SMA>,
84 mdio: Peri<'d, impl MDIOPin<SMA>>,
85 mdc: Peri<'d, impl MDCPin<SMA>>,
83 ) -> Self { 86 ) -> Self {
84 // Enable the necessary clocks 87 let sma = Sma::new(sma, mdio, mdc);
85 critical_section::with(|_| { 88 let phy = GenericPhy::new_auto(sma);
86 crate::pac::RCC.ahb1enr().modify(|w| {
87 w.set_ethen(true);
88 w.set_ethtxen(true);
89 w.set_ethrxen(true);
90 });
91 89
92 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); 90 Self::new_with_phy(
93 }); 91 queue, peri, irq, ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en, mac_addr, phy,
92 )
93 }
94
95 /// Create a new MII ethernet driver using 14 pins.
96 ///
97 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
98 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
99 ///
100 /// See [`Ethernet::new_mii_with_phy`] for creating an RMII ethernet
101 /// river with a non-standard PHY.
102 pub fn new_mii<const TX: usize, const RX: usize>(
103 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 rx_clk: Peri<'d, impl RXClkPin<T>>,
107 tx_clk: Peri<'d, impl TXClkPin<T>>,
108 rxdv: Peri<'d, impl RXDVPin<T>>,
109 rx_d0: Peri<'d, impl RXD0Pin<T>>,
110 rx_d1: Peri<'d, impl RXD1Pin<T>>,
111 rx_d2: Peri<'d, impl RXD2Pin<T>>,
112 rx_d3: Peri<'d, impl RXD3Pin<T>>,
113 tx_d0: Peri<'d, impl TXD0Pin<T>>,
114 tx_d1: Peri<'d, impl TXD1Pin<T>>,
115 tx_d2: Peri<'d, impl TXD2Pin<T>>,
116 tx_d3: Peri<'d, impl TXD3Pin<T>>,
117 tx_en: Peri<'d, impl TXEnPin<T>>,
118 mac_addr: [u8; 6],
119 sma: Peri<'d, SMA>,
120 mdio: Peri<'d, impl MDIOPin<SMA>>,
121 mdc: Peri<'d, impl MDCPin<SMA>>,
122 ) -> Self {
123 let sma = Sma::new(sma, mdio, mdc);
124 let phy = GenericPhy::new_auto(sma);
125
126 Self::new_mii_with_phy(
127 queue, peri, irq, rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en,
128 mac_addr, phy,
129 )
130 }
131}
94 132
95 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 133impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
134 /// Create a new RMII ethernet driver using 7 pins.
135 pub fn new_with_phy<const TX: usize, const RX: usize>(
136 queue: &'d mut PacketQueue<TX, RX>,
137 peri: Peri<'d, T>,
138 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
139 ref_clk: Peri<'d, impl RefClkPin<T>>,
140 crs: Peri<'d, impl CRSPin<T>>,
141 rx_d0: Peri<'d, impl RXD0Pin<T>>,
142 rx_d1: Peri<'d, impl RXD1Pin<T>>,
143 tx_d0: Peri<'d, impl TXD0Pin<T>>,
144 tx_d1: Peri<'d, impl TXD1Pin<T>>,
145 tx_en: Peri<'d, impl TXEnPin<T>>,
146 mac_addr: [u8; 6],
147 phy: P,
148 ) -> Self {
149 config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
96 150
97 let pins = Pins::Rmii([ 151 let pins = Pins::Rmii([
98 ref_clk.into(), 152 ref_clk.into(),
99 mdio.into(),
100 mdc.into(),
101 crs.into(), 153 crs.into(),
102 rx_d0.into(), 154 rx_d0.into(),
103 rx_d1.into(), 155 rx_d1.into(),
@@ -106,18 +158,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
106 tx_en.into(), 158 tx_en.into(),
107 ]); 159 ]);
108 160
109 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 161 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::RMII)
110 } 162 }
111 163
112 /// Create a new MII ethernet driver using 14 pins. 164 /// Create a new MII ethernet driver using 12 pins.
113 pub fn new_mii<const TX: usize, const RX: usize>( 165 pub fn new_mii_with_phy<const TX: usize, const RX: usize>(
114 queue: &'d mut PacketQueue<TX, RX>, 166 queue: &'d mut PacketQueue<TX, RX>,
115 peri: Peri<'d, T>, 167 peri: Peri<'d, T>,
116 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 168 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
117 rx_clk: Peri<'d, impl RXClkPin<T>>, 169 rx_clk: Peri<'d, impl RXClkPin<T>>,
118 tx_clk: Peri<'d, impl TXClkPin<T>>, 170 tx_clk: Peri<'d, impl TXClkPin<T>>,
119 mdio: Peri<'d, impl MDIOPin<T>>,
120 mdc: Peri<'d, impl MDCPin<T>>,
121 rxdv: Peri<'d, impl RXDVPin<T>>, 171 rxdv: Peri<'d, impl RXDVPin<T>>,
122 rx_d0: Peri<'d, impl RXD0Pin<T>>, 172 rx_d0: Peri<'d, impl RXD0Pin<T>>,
123 rx_d1: Peri<'d, impl RXD1Pin<T>>, 173 rx_d1: Peri<'d, impl RXD1Pin<T>>,
@@ -128,29 +178,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
128 tx_d2: Peri<'d, impl TXD2Pin<T>>, 178 tx_d2: Peri<'d, impl TXD2Pin<T>>,
129 tx_d3: Peri<'d, impl TXD3Pin<T>>, 179 tx_d3: Peri<'d, impl TXD3Pin<T>>,
130 tx_en: Peri<'d, impl TXEnPin<T>>, 180 tx_en: Peri<'d, impl TXEnPin<T>>,
131 phy: P,
132 mac_addr: [u8; 6], 181 mac_addr: [u8; 6],
182 phy: P,
133 ) -> Self { 183 ) -> Self {
134 // Enable the necessary clocks 184 config_pins!(
135 critical_section::with(|_| { 185 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
136 crate::pac::RCC.ahb1enr().modify(|w| { 186 );
137 w.set_ethen(true);
138 w.set_ethtxen(true);
139 w.set_ethrxen(true);
140 });
141
142 crate::pac::SYSCFG
143 .pmcr()
144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII));
145 });
146
147 config_pins!(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);
148 187
149 let pins = Pins::Mii([ 188 let pins = Pins::Mii([
150 rx_clk.into(), 189 rx_clk.into(),
151 tx_clk.into(), 190 tx_clk.into(),
152 mdio.into(),
153 mdc.into(),
154 rxdv.into(), 191 rxdv.into(),
155 rx_d0.into(), 192 rx_d0.into(),
156 rx_d1.into(), 193 rx_d1.into(),
@@ -163,7 +200,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
163 tx_en.into(), 200 tx_en.into(),
164 ]); 201 ]);
165 202
166 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 203 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::MII_GMII)
167 } 204 }
168 205
169 fn new_inner<const TX: usize, const RX: usize>( 206 fn new_inner<const TX: usize, const RX: usize>(
@@ -173,7 +210,19 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
173 pins: Pins<'d>, 210 pins: Pins<'d>,
174 phy: P, 211 phy: P,
175 mac_addr: [u8; 6], 212 mac_addr: [u8; 6],
213 eth_sel_phy: EthSelPhy,
176 ) -> Self { 214 ) -> Self {
215 // Enable the necessary clocks
216 critical_section::with(|_| {
217 crate::pac::RCC.ahb1enr().modify(|w| {
218 w.set_ethen(true);
219 w.set_ethtxen(true);
220 w.set_ethrxen(true);
221 });
222
223 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(eth_sel_phy));
224 });
225
177 let dma = T::regs().ethernet_dma(); 226 let dma = T::regs().ethernet_dma();
178 let mac = T::regs().ethernet_mac(); 227 let mac = T::regs().ethernet_mac();
179 let mtl = T::regs().ethernet_mtl(); 228 let mtl = T::regs().ethernet_mtl();
@@ -235,32 +284,12 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
235 w.set_rbsz(RX_BUFFER_SIZE as u16); 284 w.set_rbsz(RX_BUFFER_SIZE as u16);
236 }); 285 });
237 286
238 let hclk = <T as SealedRccPeripheral>::frequency();
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
254 let mut this = Self { 287 let mut this = Self {
255 _peri: peri, 288 _peri: peri,
256 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 289 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
257 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 290 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
258 pins, 291 pins,
259 phy, 292 phy,
260 station_management: EthernetStationManagement {
261 peri: PhantomData,
262 clock_range: clock_range,
263 },
264 mac_addr, 293 mac_addr,
265 }; 294 };
266 295
@@ -286,8 +315,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
286 w.set_tie(true); 315 w.set_tie(true);
287 }); 316 });
288 317
289 this.phy.phy_reset(&mut this.station_management); 318 this.phy.phy_reset();
290 this.phy.phy_init(&mut this.station_management); 319 this.phy.phy_init();
291 320
292 interrupt::ETH.unpend(); 321 interrupt::ETH.unpend();
293 unsafe { interrupt::ETH.enable() }; 322 unsafe { interrupt::ETH.enable() };
@@ -296,42 +325,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
296 } 325 }
297} 326}
298 327
299/// Ethernet SMI driver.
300pub struct EthernetStationManagement<T: Instance> {
301 peri: PhantomData<T>,
302 clock_range: u8,
303}
304
305impl<T: Instance> StationManagement for EthernetStationManagement<T> {
306 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
307 let mac = T::regs().ethernet_mac();
308
309 mac.macmdioar().modify(|w| {
310 w.set_pa(phy_addr);
311 w.set_rda(reg);
312 w.set_goc(0b11); // read
313 w.set_cr(self.clock_range);
314 w.set_mb(true);
315 });
316 while mac.macmdioar().read().mb() {}
317 mac.macmdiodr().read().md()
318 }
319
320 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
321 let mac = T::regs().ethernet_mac();
322
323 mac.macmdiodr().write(|w| w.set_md(val));
324 mac.macmdioar().modify(|w| {
325 w.set_pa(phy_addr);
326 w.set_rda(reg);
327 w.set_goc(0b01); // write
328 w.set_cr(self.clock_range);
329 w.set_mb(true);
330 });
331 while mac.macmdioar().read().mb() {}
332 }
333}
334
335impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 328impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
336 fn drop(&mut self) { 329 fn drop(&mut self) {
337 let dma = T::regs().ethernet_dma(); 330 let dma = T::regs().ethernet_dma();