eth: rx/tx desc list, start_rx

smoltcp
Astro 2019-06-09 01:02:10 +02:00
parent 2d7fed6c59
commit 824e91e6cb
5 changed files with 174 additions and 23 deletions

View File

@ -3,13 +3,16 @@ use crate::slcr;
pub mod phy;
mod regs;
mod rx;
mod tx;
pub struct Eth {
pub struct Eth<'rx> {
regs: &'static mut regs::RegisterBlock,
rx: Option<rx::DescList<'rx>>,
}
impl Eth {
pub fn default() -> Self {
impl<'rx> Eth<'rx> {
pub fn default(macaddr: [u8; 6]) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// MDIO
slcr.mio_pin_53.write(
@ -116,10 +119,10 @@ impl Eth {
);
});
Self::gem0()
Self::gem0(macaddr)
}
pub fn gem0() -> Self {
pub fn gem0(macaddr: [u8; 6]) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Enable gem0 ref clock
slcr.gem0_rclk_ctrl.write(
@ -137,12 +140,18 @@ impl Eth {
});
let regs = regs::RegisterBlock::gem0();
Eth { regs }.init()
let rx = None;
let mut eth = Eth { regs, rx }.init();
eth.configure(macaddr);
eth
}
pub fn gem1() -> Self {
pub fn gem1(macaddr: [u8; 6]) -> Self {
let regs = regs::RegisterBlock::gem1();
Eth { regs }.init()
let rx = None;
let mut eth = Eth { regs, rx }.init();
eth.configure(macaddr);
eth
}
fn init(mut self) -> Self {
@ -208,11 +217,10 @@ impl Eth {
regs::TxQbar::zeroed()
);
self.configure();
self
}
fn configure(&mut self) {
fn configure(&mut self, macaddr: [u8; 6]) {
self.regs.net_cfg.write(
regs::NetCfg::zeroed()
.full_duplex(true)
@ -224,8 +232,39 @@ impl Eth {
.copy_all(true)
.mdc_clk_div(0b111)
);
// TODO: mac addr
// TODO: Program the DMA Configuration register (gem.dma_cfg).
let macaddr_msbs =
(u16::from(macaddr[0]) << 8) |
u16::from(macaddr[1]);
let macaddr_lsbs =
(u32::from(macaddr[2]) << 24) |
(u32::from(macaddr[3]) << 16) |
(u32::from(macaddr[4]) << 8) |
u32::from(macaddr[5]);
self.regs.spec_addr1_top.write(
regs::SpecAddrTop::zeroed()
.addr_msbs(macaddr_msbs)
);
self.regs.spec_addr1_bot.write(
regs::SpecAddrBot::zeroed()
.addr_lsbs(macaddr_lsbs)
);
self.regs.dma_cfg.write(
regs::DmaCfg::zeroed()
// 1600 bytes
.ahb_mem_rx_buf_size(0x19)
// 8 KB
.rx_pktbuf_memsz_sel(0x3)
// 4 KB
.tx_pktbuf_memsz_sel(true)
// .csum_gen_offload_en(true)
// Little-endian
.ahb_endian_swp_mgmt_en(false)
// INCR16 AHB burst
.ahb_fixed_burst_len(0x10)
);
self.regs.net_ctrl.write(
regs::NetCtrl::zeroed()
@ -235,12 +274,21 @@ impl Eth {
);
}
pub fn start_rx(&mut self, rx_buffers: [&'rx mut [u8]; rx::DESCS]) {
self.rx = Some(rx::DescList::new(rx_buffers));
let list_addr = self.rx.as_ref().unwrap() as *const _ as u32;
self.regs.rx_qbar.write(
regs::RxQbar::zeroed()
.rx_q_baseaddr(list_addr >> 2)
);
}
fn wait_phy_idle(&self) {
while !self.regs.net_status.read().phy_mgmt_idle() {}
}
}
impl phy::PhyAccess for Eth {
impl<'rx> phy::PhyAccess for Eth<'rx> {
fn read_phy(&mut self, addr: u8, reg: u8) -> u16 {
self.wait_phy_idle();
self.regs.phy_maint.write(

View File

@ -8,7 +8,7 @@ pub struct RegisterBlock {
pub net_cfg: NetCfg,
pub net_status: NetStatus,
pub unused0: RO<u32>,
pub dma_cfg: RW<u32>,
pub dma_cfg: DmaCfg,
pub tx_status: TxStatus,
pub rx_qbar: RxQbar,
pub tx_qbar: TxQbar,
@ -23,14 +23,14 @@ pub struct RegisterBlock {
pub unused1: [RO<u32>; 16],
pub hash_bot: RW<u32>,
pub hash_top: RW<u32>,
pub spec_addr1_bot: RW<u32>,
pub spec_addr1_top: RW<u32>,
pub spec_addr2_bot: RW<u32>,
pub spec_addr2_top: RW<u32>,
pub spec_addr3_bot: RW<u32>,
pub spec_addr3_top: RW<u32>,
pub spec_addr4_bot: RW<u32>,
pub spec_addr4_top: RW<u32>,
pub spec_addr1_bot: SpecAddrBot,
pub spec_addr1_top: SpecAddrTop,
pub spec_addr2_bot: SpecAddrBot,
pub spec_addr2_top: SpecAddrTop,
pub spec_addr3_bot: SpecAddrBot,
pub spec_addr3_top: SpecAddrTop,
pub spec_addr4_bot: SpecAddrBot,
pub spec_addr4_top: SpecAddrTop,
pub type_id_match1: RW<u32>,
pub type_id_match2: RW<u32>,
pub type_id_match3: RW<u32>,
@ -233,6 +233,16 @@ register_bit!(net_status, pcs_autoneg_pause_rx_res, 4);
register_bit!(net_status, pcs_autoneg_pause_tx_res, 5);
register_bit!(net_status, pfc_pri_pause_neg, 6);
register!(dma_cfg, DmaCfg, RW, u32);
register_bits!(dma_cfg, ahb_fixed_burst_len, u8, 0, 4);
register_bit!(dma_cfg, ahb_endian_swp_mgmt_en, 6);
register_bit!(dma_cfg, ahb_endian_swp_pkt_en, 7);
register_bits!(dma_cfg, rx_pktbuf_memsz_sel, u8, 8, 9);
register_bit!(dma_cfg, tx_pktbuf_memsz_sel, 10);
register_bit!(dma_cfg, csum_gen_offload_en, 11);
register_bits!(dma_cfg, ahb_mem_rx_buf_size, u8, 16, 23);
register_bit!(dma_cfg, disc_when_no_ahb, 24);
register!(tx_status, TxStatus, RW, u32);
register_bit!(tx_status, used_bit_read, 0);
register_bit!(tx_status, collision, 1);
@ -305,3 +315,11 @@ register_bits!(phy_maint,
register_bits_typed!(phy_maint, operation, u8, PhyOperation, 28, 29);
// PHY clause 22 compliant (not clause 45)?
register_bit!(phy_maint, clause_22, 30);
register!(spec_addr_top, SpecAddrTop, RW, u32);
register_bits!(spec_addr_top,
addr_msbs, u16, 0, 15);
register!(spec_addr_bot, SpecAddrBot, RW, u32);
register_bits!(spec_addr_bot,
addr_lsbs, u32, 0, 31);

62
src/eth/rx.rs Normal file
View File

@ -0,0 +1,62 @@
use core::mem::uninitialized;
use crate::{register, register_bit, register_bits, register_bits_typed, regs::*};
/// Descriptor entry
#[repr(C)]
struct DescEntry {
word0: DescWord0,
word1: DescWord1,
}
register!(desc_word0, DescWord0, RW, u32);
/// true if owned by software, false if owned by hardware
register_bit!(desc_word0, used, 0);
/// mark last desc in list
register_bit!(desc_word0, wrap, 1);
register_bits!(desc_word0, address, u32, 2, 31);
register!(desc_word1, DescWord1, RW, u32);
register_bits!(desc_word1, frame_length_lsbs, u16, 0, 12);
register_bit!(desc_word1, bad_fcs, 13);
register_bit!(desc_word1, start_of_frame, 14);
register_bit!(desc_word1, end_of_frame, 15);
register_bit!(desc_word1, cfi, 16);
register_bits!(desc_word1, vlan_priority, u8, 17, 19);
register_bit!(desc_word1, priority_tag, 20);
register_bit!(desc_word1, vlan_tag, 21);
register_bits!(desc_word1, bits_22_23, u8, 22, 23);
register_bit!(desc_word1, bit_24, 24);
register_bits!(desc_word1, spec_addr_which, u8, 25, 26);
register_bit!(desc_word1, spec_addr_match, 27);
register_bit!(desc_word1, uni_hash_match, 29);
register_bit!(desc_word1, multi_hash_match, 30);
register_bit!(desc_word1, global_broadcast, 31);
/// Number of descriptors
pub const DESCS: usize = 8;
#[repr(C)]
pub struct DescList<'a> {
list: [DescEntry; DESCS],
buffers: [&'a mut [u8]; DESCS],
}
impl<'a> DescList<'a> {
pub fn new(buffers: [&'a mut [u8]; DESCS]) -> Self {
let mut list: [DescEntry; DESCS] = unsafe { uninitialized() };
for i in 0..DESCS {
let buffer_addr = &mut buffers[i][0] as *mut _ as u32;
list[i].word0.write(
DescWord0::zeroed()
.used(false)
.wrap(i == DESCS - 1)
.address(buffer_addr >> 2)
);
list[i].word1.write(
DescWord1::zeroed()
);
}
DescList { list, buffers }
}
}

23
src/eth/tx.rs Normal file
View File

@ -0,0 +1,23 @@
use crate::{register, register_bit, register_bits, register_bits_typed, regs::*};
/// Descriptor entry
struct DescEntry {
word0: DescWord0,
word1: DescWord1,
}
register!(desc_word0, DescWord0, RW, u32);
register_bits!(desc_word0, address, u32, 0, 31);
register!(desc_word1, DescWord1, RW, u32);
register_bits!(desc_word1, length, u16, 0, 13);
register_bit!(desc_word1, last_buffer, 15);
register_bit!(desc_word1, no_crc_append, 16);
register_bits!(desc_word1, csum_offload_errors, u8, 20, 22);
register_bit!(desc_word1, late_collision_tx_error, 26);
register_bit!(desc_word1, ahb_frame_corruption, 27);
register_bit!(desc_word1, retry_limit_exceeded, 29);
/// marks last descriptor in list
register_bit!(desc_word1, wrap, 30);
/// true if owned by software, false if owned by hardware
register_bit!(desc_word1, used, 31);

View File

@ -81,7 +81,7 @@ fn main() {
let mut uart = Uart::serial(UART_RATE);
writeln!(uart, "\r\nHello World!\r");
let mut eth = eth::Eth::default();
let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]);
writeln!(uart, "Eth on\r");
use eth::phy::PhyAccess;
for addr in 1..=31 {