embassy-stm32/eth: convert LAN8742 driver to generic SMI driver

SMI Ethernet PHYs all share a common base set of registers that can do
90% of all tasks. The LAN8742 driver used some vendor-specific
registers to check link negotiation status, but the need for that was
debatable, so I migrated it to a generic driver instead, anybody who
wants extra functionality can copy it and impl their own on top of it.
This commit is contained in:
David Lenfesty 2022-04-25 19:57:09 -06:00 committed by Dario Nieuwenhuis
parent 905b40e212
commit 2e7b42fc5b
4 changed files with 15 additions and 32 deletions

View file

@ -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

View file

@ -5,7 +5,7 @@
#[cfg_attr(eth_v2, path = "v2/mod.rs")] #[cfg_attr(eth_v2, path = "v2/mod.rs")]
#[cfg_attr(eth_v1, path = "v1.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::*;

View file

@ -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,
)) ))
}; };

View file

@ -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,
)) ))
}; };