pounder_test/src/eth.rs

612 lines
20 KiB
Rust

use core::{slice, cmp};
use cortex_m;
use stm32h7::stm32h7x3 as stm32;
use smoltcp::Result;
use smoltcp::time::Instant;
use smoltcp::wire::EthernetAddress;
use smoltcp::phy;
#[allow(dead_code)]
mod phy_consts {
pub const PHY_REG_BCR: u8 = 0x00;
pub const PHY_REG_BSR: u8 = 0x01;
pub const PHY_REG_ID1: u8 = 0x02;
pub const PHY_REG_ID2: u8 = 0x03;
pub const PHY_REG_ANTX: u8 = 0x04;
pub const PHY_REG_ANRX: u8 = 0x05;
pub const PHY_REG_ANEXP: u8 = 0x06;
pub const PHY_REG_ANNPTX: u8 = 0x07;
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_ADDAR: u8 = 0x0E; // Ethernet PHY Address or Data
pub const PHY_REG_WUCSR: u16 = 08010;
pub const PHY_REG_BCR_COLTEST: u16 = 1 << 7;
pub const PHY_REG_BCR_FD: u16 = 1 << 8;
pub const PHY_REG_BCR_ANRST: u16 = 1 << 9;
pub const PHY_REG_BCR_ISOLATE: u16 = 1 << 10;
pub const PHY_REG_BCR_POWERDN: u16 = 1 << 11;
pub const PHY_REG_BCR_AN: u16 = 1 << 12;
pub const PHY_REG_BCR_100M: u16 = 1 << 13;
pub const PHY_REG_BCR_LOOPBACK: u16 = 1 << 14;
pub const PHY_REG_BCR_RESET: u16 = 1 << 15;
pub const PHY_REG_BSR_JABBER: u16 = 1 << 1;
pub const PHY_REG_BSR_UP: u16 = 1 << 2;
pub const PHY_REG_BSR_FAULT: u16 = 1 << 4;
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::*;
pub const MTU: usize = 1522;
const EMAC_DES3_OWN: u32 = 0x80000000;
const EMAC_DES3_CTXT: u32 = 0x40000000;
const EMAC_DES3_FD: u32 = 0x20000000;
const EMAC_DES3_LD: u32 = 0x10000000;
const EMAC_DES3_ES: u32 = 0x00008000;
const EMAC_TDES2_IOC: u32 = 0x80000000;
const EMAC_RDES3_IOC: u32 = 0x40000000;
const EMAC_RDES3_PL: u32 = 0x00007FFF;
const EMAC_RDES3_BUF1V: u32 = 0x01000000;
const EMAC_TDES2_B1L: u32 = 0x00003FFF;
const EMAC_DES0_BUF1AP: u32 = 0xFFFFFFFF;
const ETH_DESC_U32_SIZE: usize = 4;
const ETH_TX_BUFFER_COUNT: usize = 4;
const ETH_TX_BUFFER_SIZE: usize = 1536;
const ETH_RX_BUFFER_COUNT: usize = 4;
const ETH_RX_BUFFER_SIZE: usize = 1536;
#[allow(dead_code)]
mod cr_consts {
/* For HCLK 60-100 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_42: u8 = 0;
/* For HCLK 100-150 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_62: u8 = 1;
/* For HCLK 20-35 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_16: u8 = 2;
/* For HCLK 35-60 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_26: u8 = 3;
/* For HCLK 150-250 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_102: u8 = 4;
/* For HCLK 250-300 MHz */
pub const ETH_MACMIIAR_CR_HCLK_DIV_124: u8 = 5;
}
use self::cr_consts::*;
// set clock range in MAC MII address register
// 200 MHz AHB clock = eth_hclk
const CLOCK_RANGE: u8 = ETH_MACMIIAR_CR_HCLK_DIV_102;
pub fn setup(rcc: &stm32::RCC, syscfg: &stm32::SYSCFG) {
rcc.apb4enr.modify(|_, w| w.syscfgen().set_bit());
rcc.ahb1enr.modify(|_, w| {
w.eth1macen().set_bit()
.eth1txen().set_bit()
.eth1rxen().set_bit()
});
syscfg.pmcr.modify(|_, w| unsafe { w.epis().bits(0b100) }); // RMII
//rcc.ahb1rstr.modify(|_, w| w.eth1macrst().set_bit());
//rcc.ahb1rstr.modify(|_, w| w.eth1macrst().clear_bit());
}
pub fn setup_pins(gpioa: &stm32::GPIOA, gpiob: &stm32::GPIOB,
gpioc: &stm32::GPIOC, gpiog: &stm32::GPIOG) {
// PA1 RMII_REF_CLK
gpioa.moder.modify(|_, w| w.moder1().alternate());
gpioa.afrl.modify(|_, w| w.afr1().af11());
gpioa.ospeedr.modify(|_, w| w.ospeedr1().very_high_speed());
// PA2 RMII_MDIO
gpioa.moder.modify(|_, w| w.moder2().alternate());
gpioa.afrl.modify(|_, w| w.afr2().af11());
gpioa.ospeedr.modify(|_, w| w.ospeedr2().very_high_speed());
// PC1 RMII_MDC
gpioc.moder.modify(|_, w| w.moder1().alternate());
gpioc.afrl.modify(|_, w| w.afr1().af11());
gpioc.ospeedr.modify(|_, w| w.ospeedr1().very_high_speed());
// PA7 RMII_CRS_DV
gpioa.moder.modify(|_, w| w.moder7().alternate());
gpioa.afrl.modify(|_, w| w.afr7().af11());
gpioa.ospeedr.modify(|_, w| w.ospeedr7().very_high_speed());
// PC4 RMII_RXD0
gpioc.moder.modify(|_, w| w.moder4().alternate());
gpioc.afrl.modify(|_, w| w.afr4().af11());
gpioc.ospeedr.modify(|_, w| w.ospeedr4().very_high_speed());
// PC5 RMII_RXD1
gpioc.moder.modify(|_, w| w.moder5().alternate());
gpioc.afrl.modify(|_, w| w.afr5().af11());
gpioc.ospeedr.modify(|_, w| w.ospeedr5().very_high_speed());
// PB11 RMII_TX_EN
gpiob.moder.modify(|_, w| w.moder11().alternate());
gpiob.afrh.modify(|_, w| w.afr11().af11());
gpiob.ospeedr.modify(|_, w| w.ospeedr11().very_high_speed());
// PB12 RXII_TXD0
gpiob.moder.modify(|_, w| w.moder12().alternate());
gpiob.afrh.modify(|_, w| w.afr12().af11());
gpiob.ospeedr.modify(|_, w| w.ospeedr12().very_high_speed());
// PG14 RMII TXD1
gpiog.moder.modify(|_, w| w.moder14().alternate());
gpiog.afrh.modify(|_, w| w.afr14().af11());
gpiog.ospeedr.modify(|_, w| w.ospeedr14().very_high_speed());
}
const PHY_ADDR: u8 = 0;
fn phy_read(reg_addr: u8) -> u16 {
cortex_m::interrupt::free(|_cs| {
let mac = unsafe { &*stm32::ETHERNET_MAC::ptr() };
while mac.macmdioar.read().mb().bit_is_set() {}
mac.macmdioar.modify(|_, w| unsafe {
w
.pa().bits(PHY_ADDR)
.rda().bits(reg_addr)
.goc().bits(0b11) // read
.cr().bits(CLOCK_RANGE)
.mb().set_bit()
});
while mac.macmdioar.read().mb().bit_is_set() {}
mac.macmdiodr.read().md().bits()
})
}
fn phy_write(reg_addr: u8, reg_data: u16) {
cortex_m::interrupt::free(|_cs| {
let mac = unsafe { &*stm32::ETHERNET_MAC::ptr() };
while mac.macmdioar.read().mb().bit_is_set() {}
mac.macmdiodr.write(|w| unsafe { w.md().bits(reg_data) });
mac.macmdioar.modify(|_, w| unsafe {
w
.pa().bits(PHY_ADDR)
.rda().bits(reg_addr)
.goc().bits(0b01) // read
.cr().bits(CLOCK_RANGE)
.mb().set_bit()
});
while mac.macmdioar.read().mb().bit_is_set() {}
})
}
// Writes a value to an extended PHY register in MMD address space
fn phy_write_ext(reg_addr: u16, reg_data: u16) {
phy_write(PHY_REG_CTL, 0x0003); // set address
phy_write(PHY_REG_ADDAR, reg_addr);
phy_write(PHY_REG_CTL, 0x4003); // set data
phy_write(PHY_REG_ADDAR, reg_data);
}
#[repr(align(4))]
struct RxRing {
desc_buf: [[u32; ETH_DESC_U32_SIZE]; ETH_RX_BUFFER_COUNT],
pkt_buf: [[u8; ETH_RX_BUFFER_SIZE]; ETH_RX_BUFFER_COUNT],
cur_desc: usize,
counter: u32,
}
impl RxRing {
const fn new() -> Self {
Self {
desc_buf: [[0; ETH_DESC_U32_SIZE]; ETH_RX_BUFFER_COUNT],
pkt_buf: [[0; ETH_RX_BUFFER_SIZE]; ETH_RX_BUFFER_COUNT],
cur_desc: 0,
counter: 0,
}
}
fn init(&mut self) {
for i in 0..self.desc_buf.len() {
for j in 0..self.desc_buf[0].len() {
self.desc_buf[i][j] = 0;
}
for j in 0..self.pkt_buf[0].len() {
self.pkt_buf[i][j] = 0;
}
}
cortex_m::interrupt::free(|_cs| unsafe {
let dma = &*stm32::ETHERNET_DMA::ptr();
dma.dmacrx_dlar.write(|w| {
w.bits(&self.desc_buf as *const _ as u32)
});
dma.dmacrx_rlr.write(|w| {
w.rdrl().bits(self.desc_buf.len() as u16 - 1) // FIXME: unclear
});
});
self.cur_desc = 0;
for _ in 0..self.desc_buf.len() {
self.buf_release()
}
self.counter = 0;
}
fn next_desc(&self) -> usize {
(self.cur_desc + 1) % self.desc_buf.len()
}
// not owned by DMA
fn buf_owned(&self) -> bool {
self.desc_buf[self.cur_desc][3] & EMAC_DES3_OWN == 0
}
fn buf_valid(&self) -> bool {
self.desc_buf[self.cur_desc][3] &
(EMAC_DES3_FD | EMAC_DES3_LD | EMAC_DES3_ES | EMAC_DES3_CTXT) ==
(EMAC_DES3_FD | EMAC_DES3_LD)
}
unsafe fn buf_as_slice<'a>(&self) -> &'a [u8] {
let len = (self.desc_buf[self.cur_desc][3] & EMAC_RDES3_PL) as usize;
let len = cmp::min(len, ETH_RX_BUFFER_SIZE);
let addr = &self.pkt_buf[self.cur_desc] as *const u8;
slice::from_raw_parts(addr, len)
}
fn buf_release(&mut self) {
let addr = &self.pkt_buf[self.cur_desc] as *const _;
self.desc_buf[self.cur_desc][0] = addr as u32 & EMAC_DES0_BUF1AP;
self.desc_buf[self.cur_desc][3] = EMAC_RDES3_BUF1V | EMAC_RDES3_IOC | EMAC_DES3_OWN;
let addr = &self.desc_buf[self.cur_desc] as *const _;
cortex_m::interrupt::free(|_cs| {
let dma = unsafe { &*stm32::ETHERNET_DMA::ptr() };
dma.dmacrx_dtpr.write(|w| unsafe { w.bits(addr as u32) });
});
self.cur_desc = self.next_desc();
self.counter += 1;
}
}
#[repr(align(4))]
struct TxRing {
desc_buf: [[u32; ETH_DESC_U32_SIZE]; ETH_TX_BUFFER_COUNT],
pkt_buf: [[u8; ETH_TX_BUFFER_SIZE]; ETH_TX_BUFFER_COUNT],
cur_desc: usize,
counter: u32,
}
impl TxRing {
const fn new() -> Self {
Self {
desc_buf: [[0; ETH_DESC_U32_SIZE]; ETH_TX_BUFFER_COUNT],
pkt_buf: [[0; ETH_TX_BUFFER_SIZE]; ETH_TX_BUFFER_COUNT],
cur_desc: 0,
counter: 0,
}
}
fn init(&mut self) {
for i in 0..self.desc_buf.len() {
for j in 0..self.desc_buf[0].len() {
self.desc_buf[i][j] = 0;
}
for j in 0..self.pkt_buf[0].len() {
self.pkt_buf[i][j] = 0;
}
}
self.cur_desc = 0;
self.counter = 0;
cortex_m::interrupt::free(|_cs| unsafe {
let dma = &*stm32::ETHERNET_DMA::ptr();
dma.dmactx_dlar.write(|w| {
w.bits(&self.desc_buf as *const _ as u32)
});
dma.dmactx_rlr.write(|w| {
w.tdrl().bits(self.desc_buf.len() as u16 - 1) // FIXME: unclear
});
dma.dmactx_dtpr.write(|w| {
w.bits(&self.desc_buf[0] as *const _ as u32)
});
});
}
fn next_desc(&self) -> usize {
(self.cur_desc + 1) % self.desc_buf.len()
}
// not owned by DMA
fn buf_owned(&self) -> bool {
self.desc_buf[self.cur_desc][3] & EMAC_DES3_OWN == 0
}
unsafe fn buf_as_slice_mut<'a>(&mut self, len: usize) -> &'a mut [u8] {
let len = cmp::min(len, ETH_TX_BUFFER_SIZE);
self.desc_buf[self.cur_desc][2] = EMAC_TDES2_IOC | (len as u32 & EMAC_TDES2_B1L);
let addr = &self.pkt_buf[self.cur_desc] as *const _ as *mut u8;
self.desc_buf[self.cur_desc][0] = addr as u32 & EMAC_DES0_BUF1AP;
slice::from_raw_parts_mut(addr, len)
}
fn buf_release(&mut self) {
self.desc_buf[self.cur_desc][3] = EMAC_DES3_OWN | EMAC_DES3_FD | EMAC_DES3_LD;
self.cur_desc = self.next_desc();
self.counter += 1;
let addr = &self.desc_buf[self.cur_desc] as *const _;
cortex_m::interrupt::free(|_cs| {
let dma = unsafe { &*stm32::ETHERNET_DMA::ptr() };
dma.dmactx_dtpr.write(|w| unsafe { w.bits(addr as u32) });
});
}
}
pub struct Device {
rx: RxRing,
tx: TxRing,
}
impl Device {
pub const fn new() -> Self {
Self{ rx: RxRing::new(), tx: TxRing::new() }
}
// After `init` is called, `Device` shall not be moved.
pub unsafe fn init(&mut self, mac: EthernetAddress) {
cortex_m::interrupt::free(|_cs| {
let eth_mac = &*stm32::ETHERNET_MAC::ptr();
let eth_dma = &*stm32::ETHERNET_DMA::ptr();
let _eth_mmc = &*stm32::ETHERNET_MMC::ptr();
let eth_mtl = &*stm32::ETHERNET_MTL::ptr();
eth_dma.dmamr.modify(|_, w| w.swr().set_bit());
while eth_dma.dmamr.read().swr().bit_is_set() {}
// 200 MHz
eth_mac.mac1ustcr.modify(|_, w| w.tic_1us_cntr().bits(200 - 1));
// Configuration Register
eth_mac.maccr.modify(|_, w| {
w
.arpen().clear_bit()
.ipc().set_bit()
.ipg().bits(0b000) // 96 bit
.ecrsfd().clear_bit()
.dcrs().clear_bit()
.bl().bits(0b00) // 19
.prelen().bits(0b00) // 7
// CRC stripping for Type frames
.cst().set_bit()
// Fast Ethernet speed
.fes().set_bit()
// Duplex mode
.dm().set_bit()
// Automatic pad/CRC stripping
.acs().set_bit()
// Retry disable in half-duplex mode
.dr().set_bit()
});
eth_mac.macecr.modify(|_, w| {
w
.eipgen().clear_bit()
.usp().clear_bit()
.spen().clear_bit()
.dcrcc().clear_bit()
});
// Set the MAC address
eth_mac.maca0lr.write(|w|
w.addrlo().bits( mac.0[0] as u32 |
((mac.0[1] as u32) << 8) |
((mac.0[2] as u32) << 16) |
((mac.0[3] as u32) << 24))
);
eth_mac.maca0hr.write(|w|
w.addrhi().bits( mac.0[4] as u16 |
((mac.0[5] as u16) << 8))
//.ae().set_bit()
//.sa().clear_bit()
//.mbc().bits(0b000000)
);
// frame filter register
eth_mac.macpfr.modify(|_, w| {
w
.dntu().clear_bit()
.ipfe().clear_bit()
.vtfe().clear_bit()
.hpf().clear_bit()
.saf().clear_bit()
.saif().clear_bit()
.pcf().bits(0b00)
.dbf().clear_bit()
.pm().clear_bit()
.daif().clear_bit()
.hmc().clear_bit()
.huc().clear_bit()
// Receive All
.ra().clear_bit()
// Promiscuous mode
.pr().clear_bit()
});
eth_mac.macwtr.write(|w| w.pwe().clear_bit());
// Flow Control Register
eth_mac.macqtxfcr.modify(|_, w| {
// Pause time
w.pt().bits(0x100)
});
eth_mac.macrxfcr.modify(|_, w| w);
eth_mtl.mtlrxqomr.modify(|_, w|
w
// Receive store and forward
.rsf().set_bit()
// Dropping of TCP/IP checksum error frames disable
.dis_tcp_ef().clear_bit()
// Forward error frames
.fep().clear_bit()
// Forward undersized good packets
.fup().clear_bit()
);
eth_mtl.mtltxqomr.modify(|_, w| {
w
// Transmit store and forward
.tsf().set_bit()
});
if (phy_read(PHY_REG_ID1) != 0x0007) | (phy_read(PHY_REG_ID2) != 0xC131) {
error!("PHY ID error!");
}
phy_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
while phy_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {};
phy_write_ext(PHY_REG_WUCSR, 0);
phy_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
/*
while phy_read(PHY_REG_BSR) & PHY_REG_BSR_UP == 0 {};
while phy_read(PHY_REG_BSR) & PHY_REG_BSR_ANDONE == 0 {};
while phy_read(PHY_REG_SSR) & (PHY_REG_SSR_ANDONE | PHY_REG_SSR_SPEED)
!= PHY_REG_SSR_ANDONE | PHY_REG_SSR_100BASE_FD {};
*/
// operation mode register
eth_dma.dmamr.modify(|_, w| {
w
.intm().clear_bit() // FIXME: bits(0b00)
// Rx Tx priority ratio 1:1
.pr().bits(0b000)
.txpr().clear_bit()
.da().clear_bit()
});
// bus mode register
eth_dma.dmasbmr.modify(|_, w| {
// Address-aligned beats
w.aal().set_bit()
// Fixed burst
.fb().set_bit()
});
eth_dma.dmaccr.modify(|_, w| {
w
.dsl().bits(0)
.pblx8().clear_bit()
.mss().bits(536)
});
eth_dma.dmactx_cr.modify(|_, w| {
w
// Tx DMA PBL
.txpbl().bits(32)
.tse().clear_bit()
// Operate on second frame
.osf().clear_bit()
});
eth_dma.dmacrx_cr.modify(|_, w| {
w
// receive buffer size
.rbsz().bits(MTU as u16)
// Rx DMA PBL
.rxpbl().bits(32)
// Disable flushing of received frames
.rpf().clear_bit()
});
self.rx.init();
self.tx.init();
// Manage MAC transmission and reception
eth_mac.maccr.modify(|_, w| {
w.re().bit(true) // Receiver Enable
.te().bit(true) // Transmiter Enable
});
eth_mtl.mtltxqomr.modify(|_, w| w.ftq().set_bit());
// Manage DMA transmission and reception
eth_dma.dmactx_cr.modify(|_, w| w.st().set_bit());
eth_dma.dmacrx_cr.modify(|_, w| w.sr().set_bit());
eth_dma.dmacsr.modify(|_, w|
w.tps().set_bit()
.rps().set_bit()
);
});
}
}
impl<'a, 'b> phy::Device<'a> for &'b mut Device {
type RxToken = RxToken<'a>;
type TxToken = TxToken<'a>;
fn capabilities(&self) -> phy::DeviceCapabilities {
let mut capabilities = phy::DeviceCapabilities::default();
capabilities.max_transmission_unit = 1500;
capabilities.max_burst_size = Some(self.tx.desc_buf.len());
capabilities
}
fn receive(&mut self) -> Option<(RxToken, TxToken)> {
// Skip all queued packets with errors.
while self.rx.buf_owned() && !self.rx.buf_valid() {
self.rx.buf_release()
}
if !(self.rx.buf_owned() && self.tx.buf_owned()) {
return None
}
Some((RxToken(&mut self.rx), TxToken(&mut self.tx)))
}
fn transmit(&mut self) -> Option<TxToken> {
if !self.tx.buf_owned() {
return None
}
Some(TxToken(&mut self.tx))
}
}
pub struct RxToken<'a>(&'a mut RxRing);
impl<'a> phy::RxToken for RxToken<'a> {
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
where F: FnOnce(&[u8]) -> Result<R> {
let result = f(unsafe { self.0.buf_as_slice() });
self.0.buf_release();
result
}
}
pub struct TxToken<'a>(&'a mut TxRing);
impl<'a> phy::TxToken for TxToken<'a> {
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where F: FnOnce(&mut [u8]) -> Result<R> {
let result = f(unsafe { self.0.buf_as_slice_mut(len) });
self.0.buf_release();
result
}
}
pub fn eth_interrupt_handler(eth_dma: &stm32::ETHERNET_DMA) {
eth_dma.dmacsr.write(|w|
w
.nis().set_bit()
.ri().set_bit()
.ti().set_bit()
);
}
pub fn enable_interrupt(dma: &stm32::ETHERNET_DMA) {
dma.dmacier.modify(|_, w|
w
.nie().set_bit()
.rie().set_bit()
.tie().set_bit()
);
}