Merge #733
733: Add f107 ethernet support. r=Dirbaio a=davidlenfesty The original driver works perfectly, the only required changes were only to clock and pin configuration. Bits that are also present and deserve some scrutiny: - Migrated LAN8742a driver to a generic SMI version (only *functional* difference is a couple extra status checks for the link poll, which IMO weren't great anyways (i.e. it would consider the link down if it negotiated to 10M) - Migrated f1 RCC init to "new" style. As of creating this draft PR, it is pretty much only tested on the happy path for my specific configuration, and also needs a couple things done (calculated clock speeds are hardcoded and ADC clock isn't implemented) - Support for v1b driver (f2 and f4) was added, but not tested. (Made a draft PR until f4 support is verified and I finish the clock init - adding testing and at least feature parity with how it was before) Co-authored-by: David Lenfesty <lenfesty@ualberta.ca> Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This commit is contained in:
commit
c474682ea9
@ -1,4 +1,4 @@
|
|||||||
//! SMSC LAN8742A Ethernet PHY
|
//! Generic SMI Ethernet PHY
|
||||||
|
|
||||||
use super::{StationManagement, PHY};
|
use super::{StationManagement, PHY};
|
||||||
|
|
||||||
@ -13,7 +13,6 @@ mod phy_consts {
|
|||||||
pub const PHY_REG_ANEXP: u8 = 0x06;
|
pub const PHY_REG_ANEXP: u8 = 0x06;
|
||||||
pub const PHY_REG_ANNPTX: u8 = 0x07;
|
pub const PHY_REG_ANNPTX: u8 = 0x07;
|
||||||
pub const PHY_REG_ANNPRX: u8 = 0x08;
|
pub const PHY_REG_ANNPRX: u8 = 0x08;
|
||||||
pub const PHY_REG_SSR: u8 = 0x1F; // Special Status Register
|
|
||||||
pub const PHY_REG_CTL: u8 = 0x0D; // Ethernet PHY Register Control
|
pub const PHY_REG_CTL: u8 = 0x0D; // Ethernet PHY Register Control
|
||||||
pub const PHY_REG_ADDAR: u8 = 0x0E; // Ethernet PHY Address or Data
|
pub const PHY_REG_ADDAR: u8 = 0x0E; // Ethernet PHY Address or Data
|
||||||
|
|
||||||
@ -33,20 +32,13 @@ mod phy_consts {
|
|||||||
pub const PHY_REG_BSR_UP: u16 = 1 << 2;
|
pub const PHY_REG_BSR_UP: u16 = 1 << 2;
|
||||||
pub const PHY_REG_BSR_FAULT: u16 = 1 << 4;
|
pub const PHY_REG_BSR_FAULT: u16 = 1 << 4;
|
||||||
pub const PHY_REG_BSR_ANDONE: u16 = 1 << 5;
|
pub const PHY_REG_BSR_ANDONE: u16 = 1 << 5;
|
||||||
|
|
||||||
pub const PHY_REG_SSR_ANDONE: u16 = 1 << 12;
|
|
||||||
pub const PHY_REG_SSR_SPEED: u16 = 0b111 << 2;
|
|
||||||
pub const PHY_REG_SSR_10BASE_HD: u16 = 0b001 << 2;
|
|
||||||
pub const PHY_REG_SSR_10BASE_FD: u16 = 0b101 << 2;
|
|
||||||
pub const PHY_REG_SSR_100BASE_HD: u16 = 0b010 << 2;
|
|
||||||
pub const PHY_REG_SSR_100BASE_FD: u16 = 0b110 << 2;
|
|
||||||
}
|
}
|
||||||
use self::phy_consts::*;
|
use self::phy_consts::*;
|
||||||
|
|
||||||
/// SMSC LAN8742A Ethernet PHY
|
/// Generic SMI Ethernet PHY
|
||||||
pub struct LAN8742A;
|
pub struct GenericSMI;
|
||||||
|
|
||||||
unsafe impl PHY for LAN8742A {
|
unsafe impl PHY for GenericSMI {
|
||||||
/// Reset PHY and wait for it to come out of reset.
|
/// Reset PHY and wait for it to come out of reset.
|
||||||
fn phy_reset<S: StationManagement>(sm: &mut S) {
|
fn phy_reset<S: StationManagement>(sm: &mut S) {
|
||||||
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
|
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
|
||||||
@ -67,7 +59,6 @@ unsafe impl PHY for LAN8742A {
|
|||||||
|
|
||||||
fn poll_link<S: StationManagement>(sm: &mut S) -> bool {
|
fn poll_link<S: StationManagement>(sm: &mut S) -> bool {
|
||||||
let bsr = sm.smi_read(PHY_REG_BSR);
|
let bsr = sm.smi_read(PHY_REG_BSR);
|
||||||
let ssr = sm.smi_read(PHY_REG_SSR);
|
|
||||||
|
|
||||||
// No link without autonegotiate
|
// No link without autonegotiate
|
||||||
if bsr & PHY_REG_BSR_ANDONE == 0 {
|
if bsr & PHY_REG_BSR_ANDONE == 0 {
|
||||||
@ -77,22 +68,14 @@ unsafe impl PHY for LAN8742A {
|
|||||||
if bsr & PHY_REG_BSR_UP == 0 {
|
if bsr & PHY_REG_BSR_UP == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// No link if autonegotiate incomplete
|
|
||||||
if ssr & PHY_REG_SSR_ANDONE == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// No link if other side isn't 100Mbps full duplex
|
|
||||||
if ssr & PHY_REG_SSR_SPEED != PHY_REG_SSR_100BASE_FD {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Got link
|
// Got link
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Public functions for the LAN8742A
|
/// Public functions for the PHY
|
||||||
impl LAN8742A {
|
impl GenericSMI {
|
||||||
// Writes a value to an extended PHY register in MMD address space
|
// Writes a value to an extended PHY register in MMD address space
|
||||||
fn smi_write_ext<S: StationManagement>(sm: &mut S, reg_addr: u16, reg_data: u16) {
|
fn smi_write_ext<S: StationManagement>(sm: &mut S, reg_addr: u16, reg_data: u16) {
|
||||||
sm.smi_write(PHY_REG_CTL, 0x0003); // set address
|
sm.smi_write(PHY_REG_CTL, 0x0003); // set address
|
@ -1,10 +1,9 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
#[cfg_attr(eth_v1c, path = "v1c/mod.rs")]
|
#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
|
||||||
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
|
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
|
||||||
#[cfg_attr(eth_v1, path = "v1.rs")]
|
|
||||||
mod _version;
|
mod _version;
|
||||||
pub mod lan8742a;
|
pub mod generic_smi;
|
||||||
|
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -12,7 +12,11 @@ use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
|
|||||||
|
|
||||||
use crate::gpio::sealed::Pin as __GpioPin;
|
use crate::gpio::sealed::Pin as __GpioPin;
|
||||||
use crate::gpio::{sealed::AFType, AnyPin, Speed};
|
use crate::gpio::{sealed::AFType, AnyPin, Speed};
|
||||||
use crate::pac::{ETH, RCC, SYSCFG};
|
#[cfg(eth_v1a)]
|
||||||
|
use crate::pac::AFIO;
|
||||||
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
|
use crate::pac::SYSCFG;
|
||||||
|
use crate::pac::{ETH, RCC};
|
||||||
|
|
||||||
mod descriptors;
|
mod descriptors;
|
||||||
mod rx_desc;
|
mod rx_desc;
|
||||||
@ -42,6 +46,33 @@ pub struct Ethernet<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> {
|
|||||||
mac_addr: [u8; 6],
|
mac_addr: [u8; 6],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(eth_v1a)]
|
||||||
|
macro_rules! config_in_pins {
|
||||||
|
($($pin:ident),*) => {
|
||||||
|
// NOTE(unsafe) Exclusive access to the registers
|
||||||
|
critical_section::with(|_| {
|
||||||
|
$(
|
||||||
|
// TODO properly create a set_as_input function
|
||||||
|
$pin.set_as_af($pin.af_num(), AFType::Input);
|
||||||
|
)*
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(eth_v1a)]
|
||||||
|
macro_rules! config_af_pins {
|
||||||
|
($($pin:ident),*) => {
|
||||||
|
// NOTE(unsafe) Exclusive access to the registers
|
||||||
|
critical_section::with(|_| {
|
||||||
|
$(
|
||||||
|
// We are lucky here, this configures to max speed (50MHz)
|
||||||
|
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
|
||||||
|
)*
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
macro_rules! config_pins {
|
macro_rules! config_pins {
|
||||||
($($pin:ident),*) => {
|
($($pin:ident),*) => {
|
||||||
// NOTE(unsafe) Exclusive access to the registers
|
// NOTE(unsafe) Exclusive access to the registers
|
||||||
@ -77,6 +108,22 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
|
|||||||
|
|
||||||
// Enable the necessary Clocks
|
// Enable the necessary Clocks
|
||||||
// NOTE(unsafe) We have exclusive access to the registers
|
// NOTE(unsafe) We have exclusive access to the registers
|
||||||
|
#[cfg(eth_v1a)]
|
||||||
|
critical_section::with(|_| {
|
||||||
|
RCC.apb2enr().modify(|w| w.set_afioen(true));
|
||||||
|
|
||||||
|
// Select RMII (Reduced Media Independent Interface)
|
||||||
|
// Must be done prior to enabling peripheral clock
|
||||||
|
AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
|
||||||
|
|
||||||
|
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(|_| {
|
critical_section::with(|_| {
|
||||||
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
|
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
|
||||||
RCC.ahb1enr().modify(|w| {
|
RCC.ahb1enr().modify(|w| {
|
||||||
@ -89,6 +136,13 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
|
|||||||
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
|
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(eth_v1a)]
|
||||||
|
{
|
||||||
|
config_in_pins!(ref_clk, rx_d0, rx_d1);
|
||||||
|
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
|
||||||
// NOTE(unsafe) We are ourselves not leak-safe.
|
// NOTE(unsafe) We are ourselves not leak-safe.
|
@ -11,7 +11,7 @@ use embassy::util::Forever;
|
|||||||
use embassy_net::{
|
use embassy_net::{
|
||||||
Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket,
|
Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket,
|
||||||
};
|
};
|
||||||
use embassy_stm32::eth::lan8742a::LAN8742A;
|
use embassy_stm32::eth::generic_smi::GenericSMI;
|
||||||
use embassy_stm32::eth::{Ethernet, State};
|
use embassy_stm32::eth::{Ethernet, State};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::peripherals::ETH;
|
use embassy_stm32::peripherals::ETH;
|
||||||
@ -26,7 +26,7 @@ use panic_probe as _;
|
|||||||
|
|
||||||
#[embassy::task]
|
#[embassy::task]
|
||||||
async fn main_task(
|
async fn main_task(
|
||||||
device: &'static mut Ethernet<'static, ETH, LAN8742A, 4, 4>,
|
device: &'static mut Ethernet<'static, ETH, GenericSMI, 4, 4>,
|
||||||
config: &'static mut StaticConfigurator,
|
config: &'static mut StaticConfigurator,
|
||||||
spawner: Spawner,
|
spawner: Spawner,
|
||||||
) {
|
) {
|
||||||
@ -82,7 +82,7 @@ static mut RNG_INST: Option<Rng<RNG>> = None;
|
|||||||
|
|
||||||
static EXECUTOR: Forever<Executor> = Forever::new();
|
static EXECUTOR: Forever<Executor> = Forever::new();
|
||||||
static STATE: Forever<State<'static, ETH, 4, 4>> = Forever::new();
|
static STATE: Forever<State<'static, ETH, 4, 4>> = Forever::new();
|
||||||
static ETH: Forever<Ethernet<'static, ETH, LAN8742A, 4, 4>> = Forever::new();
|
static ETH: Forever<Ethernet<'static, ETH, GenericSMI, 4, 4>> = Forever::new();
|
||||||
static CONFIG: Forever<StaticConfigurator> = Forever::new();
|
static CONFIG: Forever<StaticConfigurator> = Forever::new();
|
||||||
static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
|
static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ fn main() -> ! {
|
|||||||
let eth = unsafe {
|
let eth = unsafe {
|
||||||
ETH.put(Ethernet::new(
|
ETH.put(Ethernet::new(
|
||||||
state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PG13, p.PB13,
|
state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PG13, p.PB13,
|
||||||
p.PG11, LAN8742A, mac_addr, 0,
|
p.PG11, GenericSMI, mac_addr, 0,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ use embassy::util::Forever;
|
|||||||
use embassy_net::{
|
use embassy_net::{
|
||||||
Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket,
|
Config as NetConfig, Ipv4Address, Ipv4Cidr, StackResources, StaticConfigurator, TcpSocket,
|
||||||
};
|
};
|
||||||
use embassy_stm32::eth::lan8742a::LAN8742A;
|
use embassy_stm32::eth::generic_smi::GenericSMI;
|
||||||
use embassy_stm32::eth::{Ethernet, State};
|
use embassy_stm32::eth::{Ethernet, State};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::peripherals::ETH;
|
use embassy_stm32::peripherals::ETH;
|
||||||
@ -26,7 +26,7 @@ use heapless::Vec;
|
|||||||
|
|
||||||
#[embassy::task]
|
#[embassy::task]
|
||||||
async fn main_task(
|
async fn main_task(
|
||||||
device: &'static mut Ethernet<'static, ETH, LAN8742A, 4, 4>,
|
device: &'static mut Ethernet<'static, ETH, GenericSMI, 4, 4>,
|
||||||
config: &'static mut StaticConfigurator,
|
config: &'static mut StaticConfigurator,
|
||||||
spawner: Spawner,
|
spawner: Spawner,
|
||||||
) {
|
) {
|
||||||
@ -82,7 +82,7 @@ static mut RNG_INST: Option<Rng<RNG>> = None;
|
|||||||
|
|
||||||
static EXECUTOR: Forever<Executor> = Forever::new();
|
static EXECUTOR: Forever<Executor> = Forever::new();
|
||||||
static STATE: Forever<State<'static, ETH, 4, 4>> = Forever::new();
|
static STATE: Forever<State<'static, ETH, 4, 4>> = Forever::new();
|
||||||
static ETH: Forever<Ethernet<'static, ETH, LAN8742A, 4, 4>> = Forever::new();
|
static ETH: Forever<Ethernet<'static, ETH, GenericSMI, 4, 4>> = Forever::new();
|
||||||
static CONFIG: Forever<StaticConfigurator> = Forever::new();
|
static CONFIG: Forever<StaticConfigurator> = Forever::new();
|
||||||
static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
|
static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ fn main() -> ! {
|
|||||||
let eth = unsafe {
|
let eth = unsafe {
|
||||||
ETH.put(Ethernet::new(
|
ETH.put(Ethernet::new(
|
||||||
state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PG13, p.PB13,
|
state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PG13, p.PB13,
|
||||||
p.PG11, LAN8742A, mac_addr, 0,
|
p.PG11, GenericSMI, mac_addr, 0,
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b71707e525e336f0afb9a74f3c436d3dd540ffcf
|
Subproject commit 9abfa9d2b51e6071fdc7e680b4a171e4fa20c2fb
|
Loading…
Reference in New Issue
Block a user