diff options
| author | Raul Alimbekov <[email protected]> | 2025-12-16 09:05:22 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-16 09:05:22 +0300 |
| commit | c9a04b4b732b7a3b696eb8223664c1a7942b1875 (patch) | |
| tree | 6dbe5c02e66eed8d8762f13f95afd24f8db2b38c /embassy-stm32/src/eth/sma/v1.rs | |
| parent | cde24a3ef1117653ba5ed4184102b33f745782fb (diff) | |
| parent | 5ae6e060ec1c90561719aabdc29d5b6e7b8b0a82 (diff) | |
Merge branch 'main' into main
Diffstat (limited to 'embassy-stm32/src/eth/sma/v1.rs')
| -rw-r--r-- | embassy-stm32/src/eth/sma/v1.rs | 102 |
1 files changed, 102 insertions, 0 deletions
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 | } | ||
