Skip to content

Commit d37b57c

Browse files
Johannes DraaijerJohannes Draaijer
authored andcommitted
Make SMI operation more generic
Re-add StationManagement trait Implement StationManagement for `Smi` and `EthernetMAC<OwnedSmi>` Add basic driver for `LAN87XXA` based phys, based on `StationManagement` trait
1 parent b5f234b commit d37b57c

File tree

6 files changed

+432
-95
lines changed

6 files changed

+432
-95
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,17 @@ default-features = false
3232
features = ["medium-ethernet", "proto-ipv4"]
3333
optional = true
3434

35+
[dependencies.num_enum]
36+
version = "0.5"
37+
default-features = false
38+
optional = true
39+
3540
[features]
41+
default = [ "phy-lan87xxa" ]
3642
device-selected = []
3743
fence = []
44+
phy = [ "num_enum" ]
45+
phy-lan87xxa = [ "phy" ]
3846

3947
stm32f107 = ["stm32f1xx-hal/stm32f107", "device-selected"]
4048

src/lib.rs

Lines changed: 83 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! An abstraction layer for ethernet periperhals embedded in STM32 processors.
2+
//!
3+
//! For initialisation, see [`new_no_smi`], [`new_borrowed_smi`], and [`new_owned_smi`]
14
#![no_std]
25

36
/// Re-export
@@ -28,6 +31,8 @@ mod ring;
2831
pub mod smi;
2932
pub use ring::RingEntry;
3033
mod desc;
34+
mod mac;
35+
pub use mac::*;
3136
mod rx;
3237
pub use rx::{RxDescriptor, RxError, RxRingEntry};
3338
use rx::{RxPacket, RxRing};
@@ -47,6 +52,11 @@ mod smoltcp_phy;
4752
#[cfg(feature = "smoltcp-phy")]
4853
pub use smoltcp_phy::{EthRxToken, EthTxToken};
4954

55+
#[cfg(feature = "phy")]
56+
mod phy;
57+
#[cfg(feature = "phy")]
58+
pub use phy::*;
59+
5060
/// From the datasheet: *VLAN Frame maxsize = 1522*
5161
const MTU: usize = 1522;
5262

@@ -74,11 +84,57 @@ pub struct EthernetDMA<'rx, 'tx> {
7484
rx_ring: RxRing<'rx>,
7585
tx_ring: TxRing<'tx>,
7686
}
77-
/// Ethernet media access control (MAC).
78-
pub struct EthernetMAC {
79-
eth_mac: ETHERNET_MAC,
87+
88+
macro_rules! new {
89+
($name:ident, $smi_ty:ty) => {
90+
/// Create and initialise the ethernet driver.
91+
///
92+
/// Initialize and start tx and rx DMA engines.
93+
/// Sets up the peripheral clocks and GPIO configuration,
94+
/// and configures the ETH MAC and DMA peripherals.
95+
/// Automatically sets slew rate to VeryHigh.
96+
/// If you wish to use another configuration, please see
97+
/// [new_unchecked](new_unchecked).
98+
///
99+
/// This method does not initialise the external PHY.
100+
///
101+
/// Interacting with a PHY can be done through a struct that implementes the
102+
/// [`smi::StationManagement`] trait.
103+
///
104+
/// In the case of `new_borrowed_smi` you may access SMI through the [`EthernetMAC::smi`] function.
105+
///
106+
/// In the case of `new_no_smi`, the SMI may be accessed by constructing a new [`smi::Smi`] before passing
107+
/// the `ETHERNET_MAC` to the `new_no_smi` function.
108+
pub fn $name<'rx, 'tx, REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>(
109+
eth_mac: ETHERNET_MAC,
110+
eth_mmc: ETHERNET_MMC,
111+
eth_dma: ETHERNET_DMA,
112+
rx_buffer: &'rx mut [RxRingEntry],
113+
tx_buffer: &'tx mut [TxRingEntry],
114+
clocks: Clocks,
115+
pins: EthPins<REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>,
116+
) -> Result<(EthernetDMA<'rx, 'tx>, EthernetMAC<$smi_ty>), WrongClock>
117+
where
118+
REFCLK: RmiiRefClk + AlternateVeryHighSpeed,
119+
CRS: RmiiCrsDv + AlternateVeryHighSpeed,
120+
TXEN: RmiiTxEN + AlternateVeryHighSpeed,
121+
TXD0: RmiiTxD0 + AlternateVeryHighSpeed,
122+
TXD1: RmiiTxD1 + AlternateVeryHighSpeed,
123+
RXD0: RmiiRxD0 + AlternateVeryHighSpeed,
124+
RXD1: RmiiRxD1 + AlternateVeryHighSpeed,
125+
{
126+
pins.setup_pins();
127+
128+
let eth_mac = EthernetMAC::<$smi_ty>::new(eth_mac);
129+
130+
unsafe { new_unchecked(eth_mac, eth_mmc, eth_dma, rx_buffer, tx_buffer, clocks) }
131+
}
132+
};
80133
}
81134

135+
new!(new_no_smi, NoSmi);
136+
new!(new_borrowed_smi, BorrowedSmi);
137+
82138
/// Create and initialise the ethernet driver.
83139
///
84140
/// Initialize and start tx and rx DMA engines.
@@ -88,25 +144,32 @@ pub struct EthernetMAC {
88144
/// If you wish to use another configuration, please see
89145
/// [new_unchecked](new_unchecked).
90146
///
91-
/// This method does not initialise the external PHY. However it does return an
92-
/// [EthernetMAC](EthernetMAC) which implements the
93-
/// [StationManagement](smi::StationManagement) trait. This can be used to
94-
/// communicate with the external PHY.
147+
/// This method does not initialise the external PHY. The SMI for the external PHY
148+
/// can be accessed through a struct that implements the [`smi::StationManagement`] trait,
149+
/// which [`EthernetMAC<OwnedSmi>`] does.
95150
///
96151
/// # Note
97152
/// - Make sure that the buffers reside in a memory region that is
98153
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
99154
/// usually not accessible.
100155
/// - HCLK must be at least 25 MHz.
101-
pub fn new<'rx, 'tx, REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>(
156+
pub fn new_owned_smi<'rx, 'tx, REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1, MDIO, MDC>(
102157
eth_mac: ETHERNET_MAC,
103158
eth_mmc: ETHERNET_MMC,
104159
eth_dma: ETHERNET_DMA,
105160
rx_buffer: &'rx mut [RxRingEntry],
106161
tx_buffer: &'tx mut [TxRingEntry],
107162
clocks: Clocks,
108163
pins: EthPins<REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>,
109-
) -> Result<(EthernetDMA<'rx, 'tx>, EthernetMAC), WrongClock>
164+
mdio: MDIO,
165+
mdc: MDC,
166+
) -> Result<
167+
(
168+
EthernetDMA<'rx, 'tx>,
169+
EthernetMAC<crate::mac::OwnedSmi<MDIO, MDC>>,
170+
),
171+
WrongClock,
172+
>
110173
where
111174
REFCLK: RmiiRefClk + AlternateVeryHighSpeed,
112175
CRS: RmiiCrsDv + AlternateVeryHighSpeed,
@@ -115,8 +178,13 @@ where
115178
TXD1: RmiiTxD1 + AlternateVeryHighSpeed,
116179
RXD0: RmiiRxD0 + AlternateVeryHighSpeed,
117180
RXD1: RmiiRxD1 + AlternateVeryHighSpeed,
181+
MDIO: smi::MdioPin,
182+
MDC: smi::MdcPin,
118183
{
119184
pins.setup_pins();
185+
186+
let eth_mac = EthernetMAC::new_owned(eth_mac, mdio, mdc);
187+
120188
unsafe { new_unchecked(eth_mac, eth_mmc, eth_dma, rx_buffer, tx_buffer, clocks) }
121189
}
122190

@@ -132,16 +200,18 @@ where
132200
/// accessible by the peripheral. Core-Coupled Memory (CCM) is
133201
/// usually not accessible.
134202
/// - HCLK must be at least 25MHz.
135-
pub unsafe fn new_unchecked<'rx, 'tx>(
136-
eth_mac: ETHERNET_MAC,
203+
pub unsafe fn new_unchecked<'rx, 'tx, Smi>(
204+
eth_mac_in: EthernetMAC<Smi>,
137205
eth_mmc: ETHERNET_MMC,
138206
eth_dma: ETHERNET_DMA,
139207
rx_buffer: &'rx mut [RxRingEntry],
140208
tx_buffer: &'tx mut [TxRingEntry],
141209
clocks: Clocks,
142-
) -> Result<(EthernetDMA<'rx, 'tx>, EthernetMAC), WrongClock> {
210+
) -> Result<(EthernetDMA<'rx, 'tx>, EthernetMAC<Smi>), WrongClock> {
143211
setup::setup();
144212

213+
let eth_mac = &eth_mac_in.eth_mac;
214+
145215
let clock_frequency = clocks.hclk().to_Hz();
146216

147217
let clock_range = match clock_frequency {
@@ -270,12 +340,11 @@ pub unsafe fn new_unchecked<'rx, 'tx>(
270340
rx_ring: RxRing::new(rx_buffer),
271341
tx_ring: TxRing::new(tx_buffer),
272342
};
273-
let mac = EthernetMAC { eth_mac };
274343

275344
dma.rx_ring.start(&dma.eth_dma);
276345
dma.tx_ring.start(&dma.eth_dma);
277346

278-
Ok((dma, mac))
347+
Ok((dma, eth_mac_in))
279348
}
280349

281350
impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
@@ -343,28 +412,6 @@ impl<'rx, 'tx> EthernetDMA<'rx, 'tx> {
343412
}
344413
}
345414

346-
#[cfg(feature = "smi")]
347-
impl EthernetMAC {
348-
/// Borrow access to the MAC's SMI.
349-
///
350-
/// Allows for controlling and monitoring any PHYs that may be accessible via the MDIO/MDC
351-
/// pins.
352-
///
353-
/// Exclusive access to the `MDIO` and `MDC` is required to ensure that are not used elsewhere
354-
/// for the duration of SMI communication.
355-
pub fn smi<'eth, 'pins, Mdio, Mdc>(
356-
&'eth mut self,
357-
mdio: &'pins mut Mdio,
358-
mdc: &'pins mut Mdc,
359-
) -> smi::Smi<'eth, 'pins, Mdio, Mdc>
360-
where
361-
Mdio: smi::MdioPin,
362-
Mdc: smi::MdcPin,
363-
{
364-
smi::Smi::new(&self.eth_mac.macmiiar, &self.eth_mac.macmiidr, mdio, mdc)
365-
}
366-
}
367-
368415
/// A summary of the reasons for the interrupt
369416
/// that occured
370417
pub struct InterruptReasonSummary {

src/mac.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use crate::smi::{self, read, write, StationManagement};
2+
use crate::stm32::ETHERNET_MAC;
3+
4+
pub struct NoSmi;
5+
6+
/// Ethernet media access control (MAC).
7+
pub struct EthernetMAC<SMI> {
8+
pub(crate) eth_mac: ETHERNET_MAC,
9+
_state: SMI,
10+
}
11+
12+
impl EthernetMAC<NoSmi> {
13+
pub fn new(eth_mac: ETHERNET_MAC) -> Self {
14+
Self {
15+
eth_mac,
16+
_state: NoSmi {},
17+
}
18+
}
19+
}
20+
21+
pub struct BorrowedSmi;
22+
23+
pub struct OwnedSmi<MDIO, MDC>
24+
where
25+
MDIO: smi::MdioPin,
26+
MDC: smi::MdcPin,
27+
{
28+
_mdio: MDIO,
29+
_mdc: MDC,
30+
}
31+
32+
impl EthernetMAC<BorrowedSmi> {
33+
pub fn new(eth_mac: ETHERNET_MAC) -> Self {
34+
Self {
35+
eth_mac,
36+
_state: BorrowedSmi {},
37+
}
38+
}
39+
40+
/// Borrow access to the MAC's SMI.
41+
///
42+
/// Allows for controlling and monitoring any PHYs that may be accessible via the MDIO/MDC
43+
/// pins.
44+
///
45+
/// Exclusive access to the `MDIO` and `MDC` is required to ensure that are not used elsewhere
46+
/// for the duration of SMI communication.
47+
pub fn smi<'eth, 'pins, Mdio, Mdc>(
48+
&'eth mut self,
49+
mdio: &'pins mut Mdio,
50+
mdc: &'pins mut Mdc,
51+
) -> smi::Smi<'eth, 'pins, Mdio, Mdc>
52+
where
53+
Mdio: smi::MdioPin,
54+
Mdc: smi::MdcPin,
55+
{
56+
smi::Smi::new(&self.eth_mac.macmiiar, &self.eth_mac.macmiidr, mdio, mdc)
57+
}
58+
}
59+
60+
impl<MDIO, MDC> EthernetMAC<OwnedSmi<MDIO, MDC>>
61+
where
62+
MDIO: smi::MdioPin,
63+
MDC: smi::MdcPin,
64+
{
65+
pub fn new_owned(eth_mac: ETHERNET_MAC, mdio: MDIO, mdc: MDC) -> Self {
66+
Self {
67+
eth_mac,
68+
_state: OwnedSmi {
69+
_mdio: mdio,
70+
_mdc: mdc,
71+
},
72+
}
73+
}
74+
}
75+
76+
impl<MDIO, MDC> StationManagement for EthernetMAC<OwnedSmi<MDIO, MDC>>
77+
where
78+
MDIO: smi::MdioPin,
79+
MDC: smi::MdcPin,
80+
{
81+
fn read(&self, phy: u8, reg: u8) -> u16 {
82+
read(&self.eth_mac.macmiiar, &self.eth_mac.macmiidr, phy, reg)
83+
}
84+
85+
fn write(&mut self, phy: u8, reg: u8, data: u16) {
86+
write(
87+
&self.eth_mac.macmiiar,
88+
&self.eth_mac.macmiidr,
89+
phy,
90+
reg,
91+
data,
92+
)
93+
}
94+
}

0 commit comments

Comments
 (0)