use crate::timer::Timer;
use crate::usb::control::{get_configuration_descriptor, set_configuration, vendor_in, vendor_out};
use crate::usb::descriptor::{ConfigurationDescriptor, Descriptors, EndpointDescriptor};
use crate::usb::dwc2::{Channel, ControlEndpoint, TransferError};
use crate::usb::Device;
#[cfg(feature = "async")]
mod asynch;
#[cfg(feature = "async")]
pub use asynch::{Lan7800Rx, Lan7800Tx};
pub const VENDOR_ID: u16 = 0x0424;
pub const PRODUCT_ID: u16 = 0x7800;
const READ_REGISTER: u8 = 0xA1;
const WRITE_REGISTER: u8 = 0xA0;
const REG_ID_REV: u16 = 0x000;
const REG_INT_STS: u16 = 0x00C;
const REG_HW_CFG: u16 = 0x010;
const REG_PMT_CTL: u16 = 0x014;
const REG_USB_CFG0: u16 = 0x080;
const REG_RFE_CTL: u16 = 0x0B0;
const REG_FCT_RX_CTL: u16 = 0x0C0;
const REG_FCT_TX_CTL: u16 = 0x0C4;
const REG_FCT_FLOW: u16 = 0x0D0;
const REG_MAC_CR: u16 = 0x100;
const REG_MAC_RX: u16 = 0x104;
const REG_MAC_TX: u16 = 0x108;
const REG_FLOW: u16 = 0x10C;
const REG_RX_ADDRH: u16 = 0x118;
const REG_RX_ADDRL: u16 = 0x11C;
const REG_MII_ACC: u16 = 0x120;
const REG_MII_DATA: u16 = 0x124;
const REG_MAF_HI0: u16 = 0x400;
const REG_MAF_LO0: u16 = 0x404;
const HW_CFG_LRST: u32 = 0x0000_0002;
const HW_CFG_MEF: u32 = 0x0000_0010;
const HW_CFG_CLK125_EN: u32 = 0x0200_0000;
const HW_CFG_REFCLK25_EN: u32 = 0x0100_0000;
const HW_CFG_LED0_EN: u32 = 0x0010_0000;
const HW_CFG_LED1_EN: u32 = 0x0020_0000;
const PMT_CTL_PHY_RST: u32 = 0x0000_0010;
const PMT_CTL_READY: u32 = 0x0000_0080;
const USB_CFG_BIR: u32 = 0x0000_0040;
const RFE_CTL_BCAST_EN: u32 = 0x0000_0400;
const RFE_CTL_DA_PERFECT: u32 = 0x0000_0002;
const RFE_CTL_MCAST_EN: u32 = 0x0000_0200;
const RFE_CTL_UCAST_EN: u32 = 0x0000_0100;
const FCT_RX_CTL_EN: u32 = 0x8000_0000;
const FCT_TX_CTL_EN: u32 = 0x8000_0000;
const MAC_CR_AUTO_DUPLEX: u32 = 0x0000_1000;
const MAC_CR_AUTO_SPEED: u32 = 0x0000_0800;
const MAC_CR_EEE_EN: u32 = 0x0002_0000;
const MAC_CR_GMII_EN: u32 = 0x0008_0000;
const MAC_RX_RXEN: u32 = 0x0000_0001;
const MAC_RX_MAX_SIZE_SHIFT: u32 = 16;
const MAC_RX_MAX_SIZE_MASK: u32 = 0x3FFF_0000;
const MAC_TX_TXEN: u32 = 0x0000_0001;
const MAF_HI_VALID: u32 = 0x8000_0000;
const MII_ACC_BUSY: u32 = 0x0000_0001;
const MII_ACC_PHY_ADDR_SHIFT: u32 = 11;
const MII_ACC_WRITE: u32 = 0x0000_0002;
const MII_ACC_REG_SHIFT: u32 = 6;
const PHY_ID_INTERNAL: u32 = 1;
const PHY_REG_CONTROL: u8 = 0x00;
const PHY_REG_GIGABIT_CONTROL: u8 = 0x09;
const PHY_REG_STATUS: u8 = 0x01;
const BMCR_ANEG_ENABLE: u16 = 1 << 12;
const BMCR_ANEG_RESTART: u16 = 1 << 9;
const BMCR_POWER_DOWN: u16 = 1 << 11;
const BMCR_ISOLATE: u16 = 1 << 10;
const PHY_REG_ADVERTISE: u8 = 0x04;
const PHY_REG_LINK_PARTNER: u8 = 0x05;
const BMSR_LINK_UP: u16 = 1 << 2;
const AN_100_FULL: u16 = 1 << 8;
const AN_10_FULL: u16 = 1 << 6;
const RX_COMMAND_SIZE: usize = 10;
const RX_CMD_A_LEN_MASK: u32 = 0x0000_3FFF;
const RX_CMD_A_ERRORS: u32 = 0xC03F_0000;
const RX_PADDING: usize = 2;
const TX_COMMAND_SIZE: usize = 8;
const TX_CMD_A_LEN_MASK: u32 = 0x000F_FFFF;
const TX_CMD_A_FCS: u32 = 0x0040_0000;
pub const MTU: usize = 1514;
const MAC_RX_MAX_FRAME_SIZE: u32 = (MTU + 4 + 4) as u32;
const FRAME_BUFFER_SIZE: usize = 2048;
const MII_TIMEOUT_US: u64 = 1_000_000;
const RESET_TIMEOUT_US: u64 = 1_000_000;
#[repr(C, align(64))]
struct FrameBuffer([u8; FRAME_BUFFER_SIZE]);
struct BulkEndpoint {
number: u8,
max_packet_size: u16,
toggle: bool,
}
pub use crate::usb::ethernet::IdRevision;
struct Rx {
bulk_in: BulkEndpoint,
buffer: FrameBuffer,
}
struct Tx {
bulk_out: BulkEndpoint,
buffer: FrameBuffer,
}
pub struct Lan7800 {
endpoint: ControlEndpoint,
rx: Rx,
tx: Tx,
}
fn find_bulk_endpoints(config: &[u8]) -> Option<(BulkEndpoint, BulkEndpoint)> {
let mut bulk_in = None;
let mut bulk_out = None;
for descriptor in Descriptors::new(config) {
if let Some(endpoint) = EndpointDescriptor::parse(descriptor) {
if endpoint.is_bulk() {
let info = BulkEndpoint {
number: endpoint.number(),
max_packet_size: endpoint.max_packet_size(),
toggle: false,
};
if endpoint.is_in() {
bulk_in = Some(info);
} else {
bulk_out = Some(info);
}
}
}
}
Some((bulk_in?, bulk_out?))
}
pub struct Frames<'a> {
buffer: &'a [u8],
offset: usize,
}
impl<'a> Frames<'a> {
pub fn new(buffer: &'a [u8]) -> Self {
Frames { buffer, offset: 0 }
}
pub fn as_bytes(&self) -> &'a [u8] {
self.buffer
}
}
impl<'a> Iterator for Frames<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> {
loop {
let remaining = self.buffer.len().checked_sub(self.offset)?;
if remaining < RX_COMMAND_SIZE {
return None;
}
let command = u32::from_le_bytes([
self.buffer[self.offset],
self.buffer[self.offset + 1],
self.buffer[self.offset + 2],
self.buffer[self.offset + 3],
]);
let length = (command & RX_CMD_A_LEN_MASK) as usize;
if length <= 4 || length > MTU + 4 || RX_COMMAND_SIZE + length > remaining {
self.offset = self.buffer.len();
return None;
}
let start = self.offset + RX_COMMAND_SIZE;
let end = start + length - 4;
let padding = (4 - ((length + RX_PADDING) % 4)) % 4;
self.offset = start + length + padding;
if command & RX_CMD_A_ERRORS != 0 {
continue;
}
return Some(&self.buffer[start..end]);
}
}
}
impl Rx {
fn endpoint(&self, device: ControlEndpoint) -> ControlEndpoint {
ControlEndpoint {
max_packet_size: self.bulk_in.max_packet_size,
..device
}
}
fn frames(&self, received: usize) -> Frames<'_> {
Frames::new(&self.buffer.0[..received.min(FRAME_BUFFER_SIZE)])
}
}
impl Tx {
fn endpoint(&self, device: ControlEndpoint) -> ControlEndpoint {
ControlEndpoint {
max_packet_size: self.bulk_out.max_packet_size,
..device
}
}
fn stage(&mut self, frame: &[u8]) -> usize {
debug_assert!(frame.len() <= FRAME_BUFFER_SIZE - TX_COMMAND_SIZE);
let length = frame.len();
let command_a = (length as u32 & TX_CMD_A_LEN_MASK) | TX_CMD_A_FCS;
let command_b = 0u32;
self.buffer.0[0..4].copy_from_slice(&command_a.to_le_bytes());
self.buffer.0[4..8].copy_from_slice(&command_b.to_le_bytes());
self.buffer.0[TX_COMMAND_SIZE..TX_COMMAND_SIZE + length].copy_from_slice(frame);
TX_COMMAND_SIZE + length
}
}
impl Lan7800 {
pub fn from_device(
channel: &mut Channel,
timer: &Timer,
device: Device,
) -> Result<Option<Lan7800>, TransferError> {
if device.descriptor.vendor_id != VENDOR_ID || device.descriptor.product_id != PRODUCT_ID {
return Ok(None);
}
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, device.endpoint, 0, &mut config)?;
let Some(config_value) = ConfigurationDescriptor::parse(&config[..len]).map(|c| c.value())
else {
return Ok(None);
};
let Some((bulk_in, bulk_out)) = find_bulk_endpoints(&config[..len]) else {
return Ok(None);
};
set_configuration(channel, timer, device.endpoint, config_value)?;
Ok(Some(Lan7800::new(device.endpoint, bulk_in, bulk_out)))
}
pub fn from_endpoint(
channel: &mut Channel,
timer: &Timer,
endpoint: ControlEndpoint,
) -> Result<Option<Lan7800>, TransferError> {
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, endpoint, 0, &mut config)?;
let Some((bulk_in, bulk_out)) = find_bulk_endpoints(&config[..len]) else {
return Ok(None);
};
Ok(Some(Lan7800::new(endpoint, bulk_in, bulk_out)))
}
fn new(endpoint: ControlEndpoint, bulk_in: BulkEndpoint, bulk_out: BulkEndpoint) -> Lan7800 {
Lan7800 {
endpoint,
rx: Rx {
bulk_in,
buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
},
tx: Tx {
bulk_out,
buffer: FrameBuffer([0; FRAME_BUFFER_SIZE]),
},
}
}
pub fn read_register(
&self,
channel: &mut Channel,
timer: &Timer,
register: u16,
) -> Result<u32, TransferError> {
let mut value = [0u8; 4];
vendor_in(
channel,
timer,
self.endpoint,
READ_REGISTER,
0,
register,
&mut value,
)?;
Ok(u32::from_le_bytes(value))
}
pub fn write_register(
&self,
channel: &mut Channel,
timer: &Timer,
register: u16,
value: u32,
) -> Result<(), TransferError> {
vendor_out(
channel,
timer,
self.endpoint,
WRITE_REGISTER,
0,
register,
&value.to_le_bytes(),
)
}
pub fn id_revision(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<IdRevision, TransferError> {
let id_rev = self.read_register(channel, timer, REG_ID_REV)?;
Ok(IdRevision {
id: (id_rev >> 16) as u16,
revision: id_rev as u16,
})
}
pub fn set_mac_address(
&mut self,
channel: &mut Channel,
timer: &Timer,
mac: [u8; 6],
) -> Result<(), TransferError> {
let low = u32::from_le_bytes([mac[0], mac[1], mac[2], mac[3]]);
let high = u16::from_le_bytes([mac[4], mac[5]]) as u32;
self.write_register(channel, timer, REG_RX_ADDRL, low)?;
self.write_register(channel, timer, REG_RX_ADDRH, high)?;
self.write_register(channel, timer, REG_MAF_LO0, low)?;
self.write_register(channel, timer, REG_MAF_HI0, high | MAF_HI_VALID)?;
Ok(())
}
pub fn mac_address(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<[u8; 6], TransferError> {
let low = self
.read_register(channel, timer, REG_RX_ADDRL)?
.to_le_bytes();
let high = (self.read_register(channel, timer, REG_RX_ADDRH)? as u16).to_le_bytes();
Ok([low[0], low[1], low[2], low[3], high[0], high[1]])
}
pub fn reset(&mut self, channel: &mut Channel, timer: &Timer) -> Result<(), TransferError> {
let hw_cfg = self.read_register(channel, timer, REG_HW_CFG)?;
self.write_register(channel, timer, REG_HW_CFG, hw_cfg | HW_CFG_LRST)?;
self.wait_clear(channel, timer, REG_HW_CFG, HW_CFG_LRST)?;
let usb_cfg = self.read_register(channel, timer, REG_USB_CFG0)?;
self.write_register(channel, timer, REG_USB_CFG0, usb_cfg & !USB_CFG_BIR)?;
let hw_cfg = self.read_register(channel, timer, REG_HW_CFG)?;
self.write_register(
channel,
timer,
REG_HW_CFG,
(hw_cfg | HW_CFG_CLK125_EN | HW_CFG_REFCLK25_EN | HW_CFG_LED0_EN | HW_CFG_LED1_EN)
& !HW_CFG_MEF,
)?;
self.write_register(channel, timer, REG_INT_STS, u32::MAX)?;
self.write_register(channel, timer, REG_FLOW, 0)?;
self.write_register(channel, timer, REG_FCT_FLOW, 0)?;
self.write_register(
channel,
timer,
REG_RFE_CTL,
RFE_CTL_BCAST_EN | RFE_CTL_DA_PERFECT,
)?;
let pmt_ctl = self.read_register(channel, timer, REG_PMT_CTL)?;
self.write_register(channel, timer, REG_PMT_CTL, pmt_ctl | PMT_CTL_PHY_RST)?;
self.wait_phy_ready(channel, timer)?;
let mac_cr = self.read_register(channel, timer, REG_MAC_CR)?;
self.write_register(
channel,
timer,
REG_MAC_CR,
(mac_cr | MAC_CR_AUTO_DUPLEX | MAC_CR_AUTO_SPEED | MAC_CR_GMII_EN) & !MAC_CR_EEE_EN,
)?;
let mac_rx = self.read_register(channel, timer, REG_MAC_RX)?;
self.write_register(
channel,
timer,
REG_MAC_RX,
(mac_rx & !MAC_RX_MAX_SIZE_MASK)
| ((MAC_RX_MAX_FRAME_SIZE << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE_MASK),
)?;
self.start_autonegotiation(channel, timer)?;
Ok(())
}
fn start_autonegotiation(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<(), TransferError> {
self.phy_write(channel, timer, PHY_REG_GIGABIT_CONTROL, 0)?;
let control = self.phy_read(channel, timer, PHY_REG_CONTROL)?;
let control =
(control | BMCR_ANEG_ENABLE | BMCR_ANEG_RESTART) & !(BMCR_POWER_DOWN | BMCR_ISOLATE);
self.phy_write(channel, timer, PHY_REG_CONTROL, control)
}
pub fn start(
&mut self,
channel: &mut Channel,
timer: &Timer,
mac: [u8; 6],
) -> Result<(), TransferError> {
self.reset(channel, timer)?;
self.set_mac_address(channel, timer, mac)?;
let fct_rx = self.read_register(channel, timer, REG_FCT_RX_CTL)?;
self.write_register(channel, timer, REG_FCT_RX_CTL, fct_rx | FCT_RX_CTL_EN)?;
let fct_tx = self.read_register(channel, timer, REG_FCT_TX_CTL)?;
self.write_register(channel, timer, REG_FCT_TX_CTL, fct_tx | FCT_TX_CTL_EN)?;
let mac_rx = self.read_register(channel, timer, REG_MAC_RX)?;
self.write_register(channel, timer, REG_MAC_RX, mac_rx | MAC_RX_RXEN)?;
let mac_tx = self.read_register(channel, timer, REG_MAC_TX)?;
self.write_register(channel, timer, REG_MAC_TX, mac_tx | MAC_TX_TXEN)?;
Ok(())
}
pub fn bulk_in_max_packet_size(&self) -> u16 {
self.rx.bulk_in.max_packet_size
}
pub fn bulk_out_max_packet_size(&self) -> u16 {
self.tx.bulk_out.max_packet_size
}
pub fn is_link_up(&self, channel: &mut Channel, timer: &Timer) -> Result<bool, TransferError> {
Ok(self.phy_read(channel, timer, PHY_REG_STATUS)? & BMSR_LINK_UP != 0)
}
pub fn is_full_duplex(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<bool, TransferError> {
let ours = self.phy_read(channel, timer, PHY_REG_ADVERTISE)?;
let theirs = self.phy_read(channel, timer, PHY_REG_LINK_PARTNER)?;
Ok(ours & theirs & (AN_100_FULL | AN_10_FULL) != 0)
}
pub fn set_all_multicast(
&mut self,
channel: &mut Channel,
timer: &Timer,
pass: bool,
) -> Result<(), TransferError> {
let rfe_ctl = self.read_register(channel, timer, REG_RFE_CTL)?;
let rfe_ctl = if pass {
rfe_ctl | RFE_CTL_MCAST_EN
} else {
rfe_ctl & !RFE_CTL_MCAST_EN
};
self.write_register(channel, timer, REG_RFE_CTL, rfe_ctl)
}
pub fn set_promiscuous(
&mut self,
channel: &mut Channel,
timer: &Timer,
pass: bool,
) -> Result<(), TransferError> {
let rfe_ctl = self.read_register(channel, timer, REG_RFE_CTL)?;
let rfe_ctl = if pass {
rfe_ctl | RFE_CTL_UCAST_EN
} else {
rfe_ctl & !RFE_CTL_UCAST_EN
};
self.write_register(channel, timer, REG_RFE_CTL, rfe_ctl)
}
pub fn send_frame(
&mut self,
channel: &mut Channel,
timer: &Timer,
frame: &[u8],
) -> Result<(), TransferError> {
let staged = self.tx.stage(frame);
let endpoint = self.tx.endpoint(self.endpoint);
let number = self.tx.bulk_out.number;
channel.bulk_out(
endpoint,
number,
&mut self.tx.bulk_out.toggle,
&self.tx.buffer.0[..staged],
timer,
)?;
Ok(())
}
pub fn receive_frames(
&mut self,
channel: &mut Channel,
timer: &Timer,
) -> Result<Frames<'_>, TransferError> {
let endpoint = self.rx.endpoint(self.endpoint);
let number = self.rx.bulk_in.number;
let received = match channel.bulk_in(
endpoint,
number,
&mut self.rx.bulk_in.toggle,
&mut self.rx.buffer.0,
timer,
) {
Ok(received) => received,
Err(TransferError::Nak) => 0,
Err(error) => return Err(error),
};
Ok(self.rx.frames(received))
}
pub fn phy_read(
&self,
channel: &mut Channel,
timer: &Timer,
index: u8,
) -> Result<u16, TransferError> {
self.phy_wait_not_busy(channel, timer)?;
let access = (PHY_ID_INTERNAL << MII_ACC_PHY_ADDR_SHIFT)
| ((index as u32) << MII_ACC_REG_SHIFT)
| MII_ACC_BUSY;
self.write_register(channel, timer, REG_MII_ACC, access)?;
self.phy_wait_not_busy(channel, timer)?;
Ok(self.read_register(channel, timer, REG_MII_DATA)? as u16)
}
pub fn phy_write(
&self,
channel: &mut Channel,
timer: &Timer,
index: u8,
value: u16,
) -> Result<(), TransferError> {
self.phy_wait_not_busy(channel, timer)?;
self.write_register(channel, timer, REG_MII_DATA, value as u32)?;
let access = (PHY_ID_INTERNAL << MII_ACC_PHY_ADDR_SHIFT)
| ((index as u32) << MII_ACC_REG_SHIFT)
| MII_ACC_WRITE
| MII_ACC_BUSY;
self.write_register(channel, timer, REG_MII_ACC, access)?;
self.phy_wait_not_busy(channel, timer)
}
fn phy_wait_not_busy(&self, channel: &mut Channel, timer: &Timer) -> Result<(), TransferError> {
let start = timer.now_micros();
while self.read_register(channel, timer, REG_MII_ACC)? & MII_ACC_BUSY != 0 {
if timer.now_micros() - start > MII_TIMEOUT_US {
return Err(TransferError::Timeout);
}
}
Ok(())
}
fn wait_clear(
&self,
channel: &mut Channel,
timer: &Timer,
register: u16,
bits: u32,
) -> Result<(), TransferError> {
let start = timer.now_micros();
while self.read_register(channel, timer, register)? & bits != 0 {
if timer.now_micros() - start > RESET_TIMEOUT_US {
return Err(TransferError::Timeout);
}
}
Ok(())
}
fn wait_phy_ready(&self, channel: &mut Channel, timer: &Timer) -> Result<(), TransferError> {
let start = timer.now_micros();
loop {
let pmt_ctl = self.read_register(channel, timer, REG_PMT_CTL)?;
if pmt_ctl & PMT_CTL_PHY_RST == 0 && pmt_ctl & PMT_CTL_READY != 0 {
return Ok(());
}
if timer.now_micros() - start > RESET_TIMEOUT_US {
return Err(TransferError::Timeout);
}
}
}
}
impl crate::usb::ethernet::Ethernet for Lan7800 {
type Frames<'a> = Frames<'a>;
const MTU: usize = MTU;
fn id_revision(
&self,
channel: &mut Channel,
timer: &Timer,
) -> Result<IdRevision, TransferError> {
Lan7800::id_revision(self, channel, timer)
}
fn start(
&mut self,
channel: &mut Channel,
timer: &Timer,
mac: [u8; 6],
) -> Result<(), TransferError> {
Lan7800::start(self, channel, timer, mac)
}
fn is_link_up(&self, channel: &mut Channel, timer: &Timer) -> Result<bool, TransferError> {
Lan7800::is_link_up(self, channel, timer)
}
fn is_full_duplex(&self, channel: &mut Channel, timer: &Timer) -> Result<bool, TransferError> {
Lan7800::is_full_duplex(self, channel, timer)
}
fn set_all_multicast(
&mut self,
channel: &mut Channel,
timer: &Timer,
pass: bool,
) -> Result<(), TransferError> {
Lan7800::set_all_multicast(self, channel, timer, pass)
}
fn send_frame(
&mut self,
channel: &mut Channel,
timer: &Timer,
frame: &[u8],
) -> Result<(), TransferError> {
Lan7800::send_frame(self, channel, timer, frame)
}
fn receive_frames(
&mut self,
channel: &mut Channel,
timer: &Timer,
) -> Result<Self::Frames<'_>, TransferError> {
Lan7800::receive_frames(self, channel, timer)
}
}