Implement MII for STM32 V1 ethernet peripheral

This commit is contained in:
Andreas Galauner 2025-04-15 04:05:52 +02:00
parent dd787c3727
commit d9f708ca6d

View File

@ -51,12 +51,18 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
pub(crate) tx: TDesRing<'d>, pub(crate) tx: TDesRing<'d>,
pub(crate) rx: RDesRing<'d>, pub(crate) rx: RDesRing<'d>,
pins: [Peri<'d, AnyPin>; 9], pins: Pins<'d>,
pub(crate) phy: P, pub(crate) phy: P,
pub(crate) station_management: EthernetStationManagement<T>, pub(crate) station_management: EthernetStationManagement<T>,
pub(crate) mac_addr: [u8; 6], pub(crate) mac_addr: [u8; 6],
} }
/// Pins of ethernet driver.
enum Pins<'d> {
Rmii([Peri<'d, AnyPin>; 9]),
Mii([Peri<'d, AnyPin>; 14]),
}
#[cfg(eth_v1a)] #[cfg(eth_v1a)]
macro_rules! config_in_pins { macro_rules! config_in_pins {
($($pin:ident),*) => { ($($pin:ident),*) => {
@ -96,7 +102,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
pub fn new<const TX: usize, const RX: usize>( pub fn new<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>, queue: &'d mut PacketQueue<TX, RX>,
peri: Peri<'d, T>, peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
ref_clk: Peri<'d, impl RefClkPin<T>>, ref_clk: Peri<'d, impl RefClkPin<T>>,
mdio: Peri<'d, impl MDIOPin<T>>, mdio: Peri<'d, impl MDIOPin<T>>,
mdc: Peri<'d, impl MDCPin<T>>, mdc: Peri<'d, impl MDCPin<T>>,
@ -146,6 +152,29 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
#[cfg(any(eth_v1b, eth_v1c))] #[cfg(any(eth_v1b, eth_v1c))]
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
let pins = Pins::Rmii([
ref_clk.into(),
mdio.into(),
mdc.into(),
crs.into(),
rx_d0.into(),
rx_d1.into(),
tx_d0.into(),
tx_d1.into(),
tx_en.into(),
]);
Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
}
fn new_inner<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>,
peri: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
pins: Pins<'d>,
phy: P,
mac_addr: [u8; 6],
) -> Self {
let dma = T::regs().ethernet_dma(); let dma = T::regs().ethernet_dma();
let mac = T::regs().ethernet_mac(); let mac = T::regs().ethernet_mac();
@ -210,18 +239,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
} }
}; };
let pins = [
ref_clk.into(),
mdio.into(),
mdc.into(),
crs.into(),
rx_d0.into(),
rx_d1.into(),
tx_d0.into(),
tx_d1.into(),
tx_en.into(),
];
let mut this = Self { let mut this = Self {
_peri: peri, _peri: peri,
pins, pins,
@ -267,6 +284,87 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
this this
} }
/// Create a new MII ethernet driver using 14 pins.
pub fn new_mii<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>,
peri: Peri<'d, T>,
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
rx_clk: Peri<'d, impl RXClkPin<T>>,
tx_clk: Peri<'d, impl TXClkPin<T>>,
mdio: Peri<'d, impl MDIOPin<T>>,
mdc: Peri<'d, impl MDCPin<T>>,
rxdv: Peri<'d, impl RXDVPin<T>>,
rx_d0: Peri<'d, impl RXD0Pin<T>>,
rx_d1: Peri<'d, impl RXD1Pin<T>>,
rx_d2: Peri<'d, impl RXD2Pin<T>>,
rx_d3: Peri<'d, impl RXD3Pin<T>>,
tx_d0: Peri<'d, impl TXD0Pin<T>>,
tx_d1: Peri<'d, impl TXD1Pin<T>>,
tx_d2: Peri<'d, impl TXD2Pin<T>>,
tx_d3: Peri<'d, impl TXD3Pin<T>>,
tx_en: Peri<'d, impl TXEnPin<T>>,
phy: P,
mac_addr: [u8; 6],
) -> Self {
// TODO: Handle optional signals like CRS, MII_COL, RX_ER?
// Enable the necessary Clocks
#[cfg(eth_v1a)]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_afioen(true));
// Select MII (Media Independent Interface)
// Must be done prior to enabling peripheral clock
AFIO.mapr().modify(|w| w.set_mii_rmii_sel(false));
RCC.ahbenr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
});
#[cfg(any(eth_v1b, eth_v1c))]
critical_section::with(|_| {
RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
// MII (Media Independent Interface)
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false));
});
#[cfg(eth_v1a)]
{
config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv);
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
}
#[cfg(any(eth_v1b, eth_v1c))]
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);
let pins = Pins::Mii([
rx_clk.into(),
tx_clk.into(),
mdio.into(),
mdc.into(),
rxdv.into(),
rx_d0.into(),
rx_d1.into(),
rx_d2.into(),
rx_d3.into(),
tx_d0.into(),
tx_d1.into(),
tx_d2.into(),
tx_d3.into(),
tx_en.into(),
]);
Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
}
} }
/// Ethernet station management interface. /// Ethernet station management interface.
@ -322,7 +420,10 @@ impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
critical_section::with(|_| { critical_section::with(|_| {
for pin in self.pins.iter_mut() { for pin in match self.pins {
Pins::Rmii(ref mut pins) => pins.iter_mut(),
Pins::Mii(ref mut pins) => pins.iter_mut(),
} {
pin.set_as_disconnected(); pin.set_as_disconnected();
} }
}) })