eth: rx/tx desc list, start_rx
This commit is contained in:
parent
2d7fed6c59
commit
824e91e6cb
@ -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(
|
||||
|
@ -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
62
src/eth/rx.rs
Normal 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
23
src/eth/tx.rs
Normal 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);
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user