Skip to content

Commit

Permalink
Inline into EthernetDevice::new()
Browse files Browse the repository at this point in the history
  • Loading branch information
dtwood committed May 28, 2019
1 parent 060af75 commit e0af105
Showing 1 changed file with 90 additions and 167 deletions.
257 changes: 90 additions & 167 deletions tm4c129x-hal/src/ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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();

Expand All @@ -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 {
Expand Down

0 comments on commit e0af105

Please sign in to comment.