From c7e5123f6604fbb9ca510f01af9b60e777bf57b4 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Sun, 22 Oct 2023 18:23:56 -0400 Subject: First commit A prototype of an i.MX RT ENET driver. There's design decisions I'm thinking of changing. Nevertheless, the smoltcp support seems to be working; an 1170EVK can act as a DHCP client and a TCP loopback server. --- src/bd/rxbd.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bd/txbd.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 src/bd/rxbd.rs create mode 100644 src/bd/txbd.rs (limited to 'src/bd') diff --git a/src/bd/rxbd.rs b/src/bd/rxbd.rs new file mode 100644 index 0000000..8523d6e --- /dev/null +++ b/src/bd/rxbd.rs @@ -0,0 +1,95 @@ +//! Enhanced receive buffer descriptor layout and fields. + +use ral_registers::{RORegister, RWRegister}; + +#[repr(C)] +pub struct RxBD { + pub data_length: RORegister, + pub flags: RWRegister, + pub data_buffer_pointer: RWRegister, + pub status: RWRegister, + pub control: RWRegister, + pub checksum: RORegister, + pub header: RORegister, + _reserved0: [u16; 1], + pub last_bdu: RWRegister, + pub timestamp_1588: RORegister, + _reserved1: [u16; 4], +} + +bdfields!(flags, u16, + empty [ offset = 15, bits = 1, ], + ro1 [ offset = 14, bits = 1, ], + wrap [ offset = 13, bits = 1, ], + ro2 [ offset = 12, bits = 1, ], + last [ offset = 11, bits = 1, ], + + miss [ offset = 8, bits = 1, ], + broadcast [ offset = 7, bits = 1, ], + multicast [ offset = 6, bits = 1, ], + length_violation [ offset = 5, bits = 1, ], + non_octet_violation [ offset = 4, bits = 1, ], + + crc_error [ offset = 2, bits = 1, ], + overrun [ offset = 1, bits = 1, ], + truncated [ offset = 0, bits = 1, ], +); + +bdfields!(status, u16, + vlan_priority [ offset = 13, bits = 3, ], + ip_checksum_error [ offset = 5, bits = 1, ], + protocol_checksum_error [ offset = 4, bits = 1, ], + vlan [ offset = 2, bits = 1, ], + ipv6 [ offset = 1, bits = 1, ], + frag [ offset = 0, bits = 1, ], +); + +bdfields!(control, u16, + mac_error [ offset = 15, bits = 1, ], + phy_error [ offset = 10, bits = 1, ], + collision [ offset = 9, bits = 1, ], + unicast [ offset = 8, bits = 1, ], + interrupt [ offset = 7, bits = 1, ], +); + +bdfields!(header, u16, + length [ offset = 11, bits = 5, ], + protocol [ offset = 0, bits = 8, ], +); + +bdfields!(last_bdu, u16, + last_bdu [ offset = 15, bits = 1, ], +); + +#[cfg(test)] +mod tests { + use core::ptr::addr_of; + + use super::RxBD; + + fn zeroed() -> RxBD { + // Safety: zero bitpattern is fine for primitive fields. + unsafe { core::mem::MaybeUninit::zeroed().assume_init() } + } + + #[test] + fn field_offsets() { + let rxbd = zeroed(); + let start = &rxbd as *const _ as *const u8; + assert_eq!(unsafe { start.add(0x0) }, addr_of!(rxbd.data_length).cast()); + assert_eq!(unsafe { start.add(0x2) }, addr_of!(rxbd.flags).cast()); + assert_eq!( + unsafe { start.add(0x4) }, + addr_of!(rxbd.data_buffer_pointer).cast() + ); + assert_eq!(unsafe { start.add(0x8) }, addr_of!(rxbd.status).cast()); + assert_eq!(unsafe { start.add(0xA) }, addr_of!(rxbd.control).cast()); + assert_eq!(unsafe { start.add(0xC) }, addr_of!(rxbd.checksum).cast()); + assert_eq!(unsafe { start.add(0xE) }, addr_of!(rxbd.header).cast()); + assert_eq!(unsafe { start.add(0x12) }, addr_of!(rxbd.last_bdu).cast()); + assert_eq!( + unsafe { start.add(0x14) }, + addr_of!(rxbd.timestamp_1588).cast() + ); + } +} diff --git a/src/bd/txbd.rs b/src/bd/txbd.rs new file mode 100644 index 0000000..9550eff --- /dev/null +++ b/src/bd/txbd.rs @@ -0,0 +1,91 @@ +//! Enhanced transmit buffer descriptor layout and fields. + +use ral_registers::RWRegister; + +#[repr(C)] +pub struct TxBD { + pub data_length: RWRegister, + pub flags: RWRegister, + pub data_buffer_pointer: RWRegister, + pub errors: RWRegister, + pub control: RWRegister, + pub launch_time: RWRegister, + _reserved0: [u16; 1], + pub last_bdu: RWRegister, + pub timestamp_1588: RWRegister, + _reserved1: [u16; 4], +} + +bdfields!(flags, u16, + ready [ offset = 15, bits = 1, ], + to1 [ offset = 14, bits = 1, ], + wrap [ offset = 13, bits = 1, ], + to2 [ offset = 12, bits = 1, ], + last_in [ offset = 11, bits = 1, ], + transmit_crc [ offset = 10, bits = 1, ], +); + +bdfields!(errors, u16, + transmit [ offset = 15, bits = 1, ], + underflow [ offset = 13, bits = 1, ], + excess_collision [ offset = 12, bits = 1, ], + frame_error [ offset = 11, bits = 1, ], + late_collision [ offset = 10, bits = 1, ], + overflow [ offset = 9, bits = 1, ], + timestamp [ offset = 8, bits = 1, ], +); + +bdfields!(control, u16, + interrupt [ offset = 14, bits = 1, ], + timestamp [ offset = 13, bits = 1, ], + pins [ offset = 12, bits = 1, ], + iins [ offset = 11, bits = 1, ], + utlt [ offset = 8, bits = 1, ], + ftype [ offset = 4, bits = 4, NON_AVB = 0, AVB_A = 1, AVB_B = 2 ], +); + +bdfields!(last_bdu, u16, + last_bdu [ offset = 15, bits = 1, ], +); + +#[cfg(test)] +mod tests { + use super::TxBD; + use std::ptr::addr_of; + + fn zeroed() -> TxBD { + // Safety: zero bitpattern is fine for primitive fields. + unsafe { core::mem::MaybeUninit::zeroed().assume_init() } + } + + #[test] + fn field_offsets() { + let txbd = zeroed(); + let start = &txbd as *const _ as *const u8; + assert_eq!(unsafe { start.add(0x0) }, addr_of!(txbd.data_length).cast()); + assert_eq!(unsafe { start.add(0x2) }, addr_of!(txbd.flags).cast()); + assert_eq!( + unsafe { start.add(0x4) }, + addr_of!(txbd.data_buffer_pointer).cast() + ); + assert_eq!(unsafe { start.add(0x8) }, addr_of!(txbd.errors).cast()); + assert_eq!(unsafe { start.add(0xA) }, addr_of!(txbd.control).cast()); + assert_eq!(unsafe { start.add(0xC) }, addr_of!(txbd.launch_time).cast()); + assert_eq!(unsafe { start.add(0x12) }, addr_of!(txbd.last_bdu).cast()); + assert_eq!( + unsafe { start.add(0x14) }, + addr_of!(txbd.timestamp_1588).cast() + ); + } + + #[test] + fn bdfields_enum() { + let txbd = zeroed(); + ral_registers::modify_reg!(super, &txbd, control, ftype: AVB_B); + assert_eq!(txbd.control.read(), 0x2 << 4); + ral_registers::modify_reg!(super, &txbd, control, interrupt: 1); + assert_eq!(txbd.control.read(), 0x2 << 4 | 1 << 14); + ral_registers::modify_reg!(super, &txbd, control, ftype: 0); + assert_eq!(txbd.control.read(), 1 << 14); + } +} -- cgit v1.2.3