From e0af105285ba4a3785632ae0a100a23830186d9f Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 28 May 2019 20:17:22 +0100 Subject: [PATCH] Inline into EthernetDevice::new() --- tm4c129x-hal/src/ethernet.rs | 257 ++++++++++++----------------------- 1 file changed, 90 insertions(+), 167 deletions(-) diff --git a/tm4c129x-hal/src/ethernet.rs b/tm4c129x-hal/src/ethernet.rs index da4b2bc..087b6a2 100644 --- a/tm4c129x-hal/src/ethernet.rs +++ b/tm4c129x-hal/src/ethernet.rs @@ -85,159 +85,6 @@ static mut RX_BUFFERS: [[u8; ETHERNET_MTU]; NUM_RX_DESCRIPTORS] = static mut TX_BUFFERS: [[u8; ETHERNET_MTU]; NUM_TX_DESCRIPTORS] = [[0; ETHERNET_MTU]; NUM_TX_DESCRIPTORS]; -fn emac_reset(emac0: &EMAC0) { - emac0.dmabusmod.modify(|_, w| w.swr().set_bit()); - - while emac0.dmabusmod.read().swr().bit_is_set() {} -} - -fn emac_phy_config_set( - emac0: &EMAC0, - lock: &sysctl::PowerControl, - config: impl for<'r, 'w> FnOnce( - &'r tm4c129x::emac0::pc::R, - &'w mut tm4c129x::emac0::pc::W, - ) -> &'w mut tm4c129x::emac0::pc::W, -) { - emac0.pc.modify(config); - - let pc = emac0.pc.read(); - if pc.phyext().bit_is_clear() { - sysctl::reset(lock, sysctl::Domain::Ephy0); - for _ in 0..10000 { - cortex_m::asm::nop(); - } - } - - // TI's register definitions seem to disagree with the datasheet here - this - // register should be RW, and also doesn't seem to have the CLKEN field we need. - // For now just assert that the bit is already set to the value we expect. - if pc.pintfs().is_rmii() { - // emac0.cc.modify(|_, w| w.clken().set_bit()); - assert!(emac0.cc.read().bits() & 0x00010000 == 0x00010000); - } else { - // emac0.cc.modify(|_, w| w.clken().clear_bit()); - assert!(emac0.cc.read().bits() & 0x00010000 == 0); - } - - sysctl::reset(lock, sysctl::Domain::Emac0); - - for _ in 0..1000 { - cortex_m::asm::nop(); - } -} - -fn emac_init( - emac0: &EMAC0, - sysclk: u32, - mut rx_burst: u32, - mut tx_burst: u32, - desc_skip_size: u32, -) { - // Parameter sanity checks. - assert!(desc_skip_size < 32); - assert!(tx_burst < 32 * 8); - assert!(rx_burst < 32 * 8); - - // Make sure that the DMA software reset is clear before continuing. - while emac0.dmabusmod.read().swr().bit_is_set() {} - - emac0.dmabusmod.modify(|_, w| { - // Set common flags. Note that this driver assumes we are always using 8 word - // descriptors so we need to OR in EMAC_DMABUSMOD_ATDS here. - - // Do we need to use the 8X burst length multiplier? - if tx_burst > 32 || rx_burst > 32 { - // Divide both burst lengths by 8 and set the 8X burst length multiplier. - w._8xpbl().set_bit(); - tx_burst >>= 3; - rx_burst >>= 3; - - // Sanity check - neither burst length should have become zero. If they did, - // this indicates that the values passed are invalid. - assert!(tx_burst > 0); - assert!(rx_burst > 0); - } else { - w._8xpbl().clear_bit(); - } - - // Are the receive and transmit burst lengths the same? - unsafe { - w.pbl().bits(tx_burst as u8); - } - if rx_burst == tx_burst { - // Yes - set up to use a single burst length. - w.usp().clear_bit(); - } else { - // No - we need to use separate burst lengths for each. - w.usp().set_bit(); - unsafe { - w.rpbl().bits(rx_burst as u8); - } - } - - // Finally, write the bus mode register. - w - }); - - unsafe { - emac0.miiaddr.modify(|_, w| { - w.cr().bits(if sysclk < 20_000_000 { - panic!() - } else if sysclk < 35_000_000 { - 0x8 - } else if sysclk < 60_000_000 { - 0xc - } else if sysclk < 100_000_000 { - 0x0 - } else if sysclk < 150_000_000 { - 0x4 - } else { - panic!() - }) - }); - } - - // Disable all the MMC interrupts as these are enabled by default at reset. - unsafe { - emac0.mmcrxim.write(|w| w.bits(0xffffffff)); - emac0.mmctxim.write(|w| w.bits(0xffffffff)); - } -} - -fn emac_primary_addr_set(emac0: &EMAC0, mac_addr: [u8; 6]) { - unsafe { - emac0.addr0h.write(|w| { - w.addrhi() - .bits(byteorder::LittleEndian::read_u16(&mac_addr[4..])) - }); - emac0.addr0l.write(|w| { - w.addrlo() - .bits(byteorder::LittleEndian::read_u32(&mac_addr[..4])) - }); - } -} - -fn emac_frame_filter_set( - emac0: &EMAC0, - filter_opts: impl for<'r, 'w> FnOnce( - &'r tm4c129x::emac0::framefltr::R, - &'w mut tm4c129x::emac0::framefltr::W, - ) -> &'w mut tm4c129x::emac0::framefltr::W, -) { - emac0.framefltr.modify(filter_opts) -} - -fn emac_tx_enable(emac0: &EMAC0) { - emac0.dmaopmode.modify(|_, w| w.st().set_bit()); - emac0.cfg.modify(|_, w| w.te().set_bit()); -} - -fn emac_rx_enable(emac0: &EMAC0) { - emac0.dmaopmode.modify(|_, w| w.sr().set_bit()); - emac0.cfg.modify(|_, w| w.re().set_bit()); -} - pub struct EthernetDevice { emac0: EMAC0, next_rx_descriptor: &'static RDES, @@ -265,9 +112,11 @@ impl EthernetDevice { sysctl::PowerState::On, ); - emac_reset(&emac0); + emac0.dmabusmod.modify(|_, w| w.swr().set_bit()); - emac_phy_config_set(&emac0, lock, |_, w| { + while emac0.dmabusmod.read().swr().bit_is_set() {} + + emac0.pc.modify(|_, w| { // EMAC_PHY_TYPE_INTERNAL w.phyext().clear_bit(); w.pintfs().imii(); @@ -281,24 +130,74 @@ impl EthernetDevice { w }); - emac_init(&emac0, clocks.sysclk.0, 4, 4, 1); + let pc = emac0.pc.read(); + if pc.phyext().bit_is_clear() { + sysctl::reset(lock, sysctl::Domain::Ephy0); + for _ in 0..10000 { + cortex_m::asm::nop(); + } + } + + // TI's register definitions seem to disagree with the datasheet here - this + // register should be RW, and also doesn't seem to have the CLKEN field we need. + // For now just assert that the bit is already set to the value we expect. + if pc.pintfs().is_rmii() { + // emac0.cc.modify(|_, w| w.clken().set_bit()); + assert!(emac0.cc.read().bits() & 0x00010000 == 0x00010000); + } else { + // emac0.cc.modify(|_, w| w.clken().clear_bit()); + assert!(emac0.cc.read().bits() & 0x00010000 == 0); + } + + sysctl::reset(lock, sysctl::Domain::Emac0); + + for _ in 0..1000 { + cortex_m::asm::nop(); + } + + // Make sure that the DMA software reset is clear before continuing. + while emac0.dmabusmod.read().swr().bit_is_set() {} + + emac0.dmabusmod.reset(); + + unsafe { + emac0.miiaddr.modify(|_, w| { + w.cr().bits(if clocks.sysclk.0 < 20_000_000 { + panic!() + } else if clocks.sysclk.0 < 35_000_000 { + 0x8 + } else if clocks.sysclk.0 < 60_000_000 { + 0xc + } else if clocks.sysclk.0 < 100_000_000 { + 0x0 + } else if clocks.sysclk.0 < 150_000_000 { + 0x4 + } else { + panic!() + }) + }); + } + + // Disable all the MMC interrupts as these are enabled by default at reset. + unsafe { + emac0.mmcrxim.write(|w| w.bits(0xffffffff)); + emac0.mmctxim.write(|w| w.bits(0xffffffff)); + } - // Set the configuration flags as specified. Note that we unconditionally - // OR in the EMAC_CFG_PS bit here since this implementation supports only - // MII and RMII interfaces to the PHYs. emac0.cfg.modify(|_, w| { + // w.saddr().bits(0x02); + w.cst().set_bit(); + w.ifg()._96(); w.dupm().set_bit(); + w.fes().set_bit(); w.ipc().set_bit(); - w.ifg()._96(); - w.cst().set_bit(); w.acs().set_bit(); - // w.saddr().bits(0x02); w.bl()._1024(); w }); - emac0.wdogto.write(|w| w.pwe().clear_bit()); + emac0.wdogto.reset(); emac0.dmaopmode.write(|w| { w.rsf().set_bit(); @@ -361,11 +260,24 @@ impl EthernetDevice { .write(|w| w.bits(&TX_DESCRIPTORS as *const _ as u32)); } - emac_primary_addr_set(&emac0, [0x00u8, 0x1A, 0xB6, 0x00, 0x02, 0x74]); + { + unsafe { + let mac_addr = [0x00u8, 0x1A, 0xB6, 0x00, 0x02, 0x74]; + + emac0.addr0h.write(|w| { + w.addrhi() + .bits(byteorder::LittleEndian::read_u16(&mac_addr[4..])) + }); + emac0.addr0l.write(|w| { + w.addrlo() + .bits(byteorder::LittleEndian::read_u32(&mac_addr[..4])) + }); + } + } while ephy.bmsr.read(&mut emac0).linkstat().bit_is_clear() {} - emac_frame_filter_set(&emac0, |_, w| { + emac0.framefltr.modify(|_, w| { w.ra().set_bit(); w.pr().set_bit(); @@ -377,8 +289,19 @@ impl EthernetDevice { emac0.ephyim.write(|w| w.bits(0xffff_ffff)); } - emac_tx_enable(&emac0); - emac_rx_enable(&emac0); + emac0.dmaopmode.modify(|_, w| { + w.sr().set_bit(); + w.st().set_bit(); + + w + }); + emac0.cfg.modify(|_, w| { + w.re().set_bit(); + w.te().set_bit(); + + w + }); + nvic.enable(tm4c129x::Interrupt::EMAC0); EthernetDevice {