sifive: support for cadence gemgxl ethernet

This commit is contained in:
2026-02-05 17:10:14 +02:00
parent 4f648142c8
commit 1a87bc3666
9 changed files with 780 additions and 35 deletions
+7 -7
View File
@@ -96,7 +96,7 @@ struct HartContext {
/// RISC-V Platform-Level Interrupt Controller (PLIC) device
pub struct Plic {
base: PhysicalAddress,
max_irqs: usize,
max_irq: usize,
// hart id -> context map
context_map: Vec<HartContext>,
inner: OneTimeInit<Inner>,
@@ -116,8 +116,8 @@ impl Plic {
log::error!("plic: irq cannot be zero");
return Err(Error::InvalidArgument);
}
if irq as usize >= self.max_irqs {
log::error!("plic: irq ({}) >= max_irqs ({})", irq, self.max_irqs);
if irq as usize > self.max_irq {
log::error!("plic: irq ({}) > max_irq ({})", irq, self.max_irq);
return Err(Error::InvalidArgument);
}
Ok(irq)
@@ -209,7 +209,7 @@ impl Device for Plic {
let common = DeviceMemoryIo::<CommonRegs>::map(self.base, Default::default())?;
for i in 0..self.max_irqs - 1 {
for i in 0..self.max_irq {
common.PRIORITY[i].set(3);
}
@@ -233,7 +233,7 @@ impl Device for Plic {
Default::default(),
)?;
for i in 0..self.max_irqs.div_ceil(32) {
for i in 0..self.max_irq.div_ceil(32) {
enable.ENABLE[i].set(0);
}
control.THRESHOLD.set(0);
@@ -289,7 +289,7 @@ device_tree_driver! {
let ndev = node.prop_usize("riscv,ndev")?;
let iext = node.property("interrupts-extended")?;
let max_irqs = MAX_IRQS.min(ndev);
let max_irq = MAX_IRQS.min(ndev);
// Parse the context -> hart mapping, only select S-mode external interrupts
let mut context_map = Vec::new();
@@ -322,7 +322,7 @@ device_tree_driver! {
let intc = Arc::new(Plic {
base,
max_irqs,
max_irq,
context_map,
inner: OneTimeInit::new(),
});
+2
View File
@@ -10,7 +10,9 @@ yggdrasil-abi.workspace = true
libk-mm.workspace = true
libk-util.workspace = true
libk.workspace = true
ygg_driver_net_core.path = "../../net/core"
static_assertions.workspace = true
tock-registers.workspace = true
log.workspace = true
bytemuck.workspace = true
@@ -0,0 +1,271 @@
use core::{mem::MaybeUninit, time::Duration};
use alloc::sync::Arc;
use device_api::{
clock::ClockHandle,
device::{Device, DeviceInitContext},
dma::DmaAllocator,
interrupt::{InterruptHandler, IrqHandle, IrqVector},
};
use device_tree::driver::{
InitSequence, Node, ProbeContext, device_tree_driver, util::read_mac_address,
};
use futures_util::task::AtomicWaker;
use libk::{
dma::DmaBuffer,
error::Error,
task::runtime::{self, with_timeout},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::{OneTimeInit, event::BitmapEvent, sync::IrqSafeSpinlock};
use tock_registers::{
LocalRegisterCopy,
interfaces::{ReadWriteable, Readable, Writeable},
};
use ygg_driver_net_core::{
RxPacket,
ephy::PhyAccess,
interface::{NetworkDevice, NetworkInterfaceType},
};
use yggdrasil_abi::net::{MacAddress, link::LinkState};
use crate::ethernet::{
queue::Queue,
regs::{ControlRegs, Regs},
};
const RX_BUF_SIZE_MUL: usize = 64;
mod queue;
mod regs;
// TODO multiqueue
struct Ethernet {
// Device tree info
name: &'static str,
irq: IrqHandle,
clk_pclk: ClockHandle,
clk_hclk: ClockHandle,
local_mac_address: Option<MacAddress>,
// Memory/HW
// caps: Capabilities,
dma: OneTimeInit<Arc<dyn DmaAllocator>>,
control_regs: IrqSafeSpinlock<DeviceMemoryIo<'static, ControlRegs>>,
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
// Operation
queue: OneTimeInit<Queue>,
softirq: BitmapEvent<AtomicWaker>,
iface_id: OneTimeInit<u32>,
}
// bitflags! {
// pub struct CapFlags: u32 {
// const MACB_IS_GEM: bit 0;
// }
// }
// struct Capabilities {
// flags: CapFlags,
// queue_mask: u32,
// queue_count: usize,
// }
impl Ethernet {
fn probe(node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let name = node.name().unwrap_or("gemgxl");
let irq = node.interrupt(0)?;
let clk_pclk = node.named_clock("pclk")?;
let clk_hclk = node.named_clock("hclk")?;
let base = node.map_base(context, 0)?;
let base_control = node.map_base(context, 1)?;
let local_mac_address = read_mac_address(node);
let regs = unsafe { DeviceMemoryIo::<Regs>::map(base, Default::default()) }.ok()?;
let control_regs = unsafe { DeviceMemoryIo::map(base_control, Default::default()) }.ok()?;
// let caps = regs.probe_capabilities();
let gem = Arc::new(Ethernet {
name,
clk_pclk,
clk_hclk,
irq,
local_mac_address,
// caps,
dma: OneTimeInit::new(),
regs: IrqSafeSpinlock::new(regs),
control_regs: IrqSafeSpinlock::new(control_regs),
queue: OneTimeInit::new(),
softirq: BitmapEvent::new(AtomicWaker::new()),
iface_id: OneTimeInit::new(),
});
context.sequence = Some(InitSequence::Late);
Some(gem)
}
async fn softirq(self: Arc<Self>) {
let iface = *self.iface_id.get();
let queue = self.queue.get();
loop {
let event_fut = self.softirq.wait();
let bits = match with_timeout(event_fut, Duration::from_millis(100)).await {
Ok(bits) => bits as u32,
Err(_) => {
queue.consume_tx().ok();
continue;
}
};
let status = LocalRegisterCopy::<_, regs::Interrupt::Register>::new(bits);
if status.matches_all(regs::Interrupt::RCOMP::SET) {
queue
.consume_rx(&**self.dma.get(), |packet| {
let packet = RxPacket::new(packet, 0, iface);
ygg_driver_net_core::receive_packet(packet).ok();
})
.ok();
let regs = self.regs.lock();
regs.interrupt_enable.write(regs::Interrupt::RCOMP::SET);
}
if status.matches_all(regs::Interrupt::TCOMP::SET) {
queue.consume_tx().ok();
let regs = self.regs.lock();
regs.interrupt_enable.write(regs::Interrupt::RCOMP::SET);
}
if status.matches_all(regs::Interrupt::LINK::SET) {
log::info!("Link status changed");
let regs = self.regs.lock();
regs.interrupt_enable.write(regs::Interrupt::LINK::SET);
}
}
}
fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> {
let queue = self.queue.get();
queue.push_xmit(frame)?;
let regs = self.regs.lock();
regs.network_control
.modify(regs::NetworkControl::TSTART::SET);
Ok(())
}
}
impl Device for Ethernet {
unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
let _ = (&self.clk_pclk, &self.clk_hclk, &self.control_regs);
log::info!("{}: hw address {:?}", self.name, self.local_mac_address);
// TODO enable clocks
let dma = self.dma.init(cx.dma_allocator);
let regs = self.regs.lock();
let queue = self.queue.init(Queue::with_capacity(&**dma, 256, 64)?);
let rx_queue_base = queue.rx_queue_base().try_into_u32().unwrap();
let tx_queue_base = queue.tx_queue_base().try_into_u32().unwrap();
regs.rx_buffer_queue_base.set(rx_queue_base);
regs.tx_buffer_queue_base.set(tx_queue_base);
regs.dma_config.write(
regs::DmaConfig::RX_BUF_SIZE.val((queue::RX_BUFFER_SIZE / RX_BUF_SIZE_MUL) as _),
);
regs.network_control.modify(regs::NetworkControl::MPE::SET);
{
let phy = PhyAccess::new(&**regs, 0);
let phy_id = phy.id()?;
log::info!("{}: PHY {:04x}:{:04x}", self.name, phy_id.0, phy_id.1);
phy.setup_link(false, None)?;
}
regs.network_config.write(regs::NetworkConfig::PROMISC::SET);
regs.network_control
.modify(regs::NetworkControl::TE::SET + regs::NetworkControl::RE::SET);
// if (GEM_BFEXT(DAW64, gem_readl(...)))
// hw_dma_cap |= HW_DMA_CAP_64B
regs.interrupt_disable.set(0xFFFFFFFF);
regs.interrupt_enable.write(
regs::Interrupt::LINK::SET + regs::Interrupt::RCOMP::SET + regs::Interrupt::TCOMP::SET,
);
let iface =
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
self.iface_id.init(iface.id());
runtime::spawn(self.clone().softirq())?;
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
Ok(())
}
fn display_name(&self) -> &str {
self.name
}
}
impl NetworkDevice for Ethernet {
fn allocate_transmit_buffer(&self, len: usize) -> Result<DmaBuffer<[MaybeUninit<u8>]>, Error> {
DmaBuffer::new_uninit_slice(&**self.dma.get(), len)
}
fn transmit_buffer(&self, buffer: DmaBuffer<[u8]>) -> Result<(), Error> {
self.start_xmit(buffer)
}
fn packet_prefix_size(&self) -> usize {
0
}
fn read_hardware_address(&self) -> MacAddress {
// TODO from registers
self.local_mac_address.unwrap()
}
fn link_state(&self) -> LinkState {
self.regs.lock().link_state()
}
}
impl InterruptHandler for Ethernet {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
const MASK: u32 = regs::Interrupt::RCOMP::SET.value
| regs::Interrupt::TCOMP::SET.value
| regs::Interrupt::LINK::SET.value;
let regs = self.regs.lock();
let status = regs.interrupt_status.get();
// Mask the IRQ and send it to softirq handler
regs.interrupt_disable.set(MASK & status);
self.softirq.signal(status as u64);
status != 0
}
}
device_tree_driver! {
compatible: ["sifive,fu540-c000-gem"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
Ethernet::probe(node, context)
}
}
}
@@ -0,0 +1,255 @@
use core::mem::{self, MaybeUninit};
use alloc::vec::Vec;
use device_api::dma::DmaAllocator;
use libk::{
dma::{BusAddress, DmaBuffer},
error::Error,
};
use libk_util::sync::IrqSafeSpinlock;
pub const RX_BUFFER_SIZE: usize = 4096;
static_assertions::const_assert_eq!(RX_BUFFER_SIZE % super::RX_BUF_SIZE_MUL, 0);
static_assertions::const_assert_ne!(RX_BUFFER_SIZE / super::RX_BUF_SIZE_MUL, 0);
#[derive(Clone, Copy, Debug)]
#[repr(C)]
struct Descriptor {
address: u32,
control: u32,
}
struct RxQueue {
entries: DmaBuffer<[Descriptor]>,
buffers: Vec<DmaBuffer<[MaybeUninit<u8>]>>,
rd: usize,
}
struct TxQueue {
entries: DmaBuffer<[Descriptor]>,
buffers: Vec<Option<DmaBuffer<[u8]>>>,
wr: usize,
rd: usize,
}
pub struct Queue {
rx_queue: IrqSafeSpinlock<RxQueue>,
rx_queue_base: BusAddress,
tx_queue: IrqSafeSpinlock<TxQueue>,
tx_queue_base: BusAddress,
}
impl Descriptor {
const USED: u32 = 1 << 31;
const LENGTH: u32 = 0x1FFF;
const TX_WRAP: u32 = 1 << 30;
const TX_LAST: u32 = 1 << 15;
const RX_OWNERSHIP: u32 = 1 << 0;
const RX_WRAP: u32 = 1 << 1;
const EMPTY_RX: Self = Self {
address: Self::RX_OWNERSHIP,
control: 0,
};
const EMPTY_TX: Self = Self {
address: 0,
control: Self::USED,
};
fn setup_rx(&mut self, buffer: BusAddress, wrap: bool) {
let mut address = buffer.try_into_u32().unwrap();
if wrap {
address |= Self::RX_WRAP;
}
self.address = address;
self.control = 0;
}
fn setup_tx(&mut self, buffer: BusAddress, len: usize, wrap: bool) {
assert!(len < Self::LENGTH as usize - 1);
let mut control = len as u32;
if wrap {
control |= Self::TX_WRAP;
}
// LAST
control |= Self::TX_LAST;
self.address = buffer.try_into_u32().unwrap();
self.control = control;
}
}
impl RxQueue {
fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let mut entries = DmaBuffer::new_slice(dma, Descriptor::EMPTY_RX, capacity)?;
let buffers = (0..capacity)
.map(|_| DmaBuffer::new_uninit_slice(dma, RX_BUFFER_SIZE))
.collect::<Result<Vec<_>, _>>()?;
for i in 0..capacity {
entries[i].setup_rx(buffers[i].bus_address(), i == capacity - 1);
}
Ok(Self {
buffers,
entries,
rd: 0,
})
}
pub fn consume<F: Fn(DmaBuffer<[u8]>)>(
&mut self,
dma: &dyn DmaAllocator,
packet_handler: F,
) -> Result<usize, Error> {
let mut count = 0;
let capacity = self.entries.len();
loop {
let index = self.rd % self.entries.len();
self.entries.cache_flush_element(index, false);
let entry = &mut self.entries[index];
if entry.address & Descriptor::RX_OWNERSHIP != 0 {
// if entry.rx_completed().is_some() {
// Grab the current buffer (the one just written to by the DMA), replace it
// with the newly allocated one, and mark the descriptor as DMA-owned again
let new_buffer = DmaBuffer::new_uninit_slice(dma, 4096)?;
let new_buffer_address = new_buffer.bus_address();
let buffer = mem::replace(&mut self.buffers[index], new_buffer);
let buffer = unsafe { DmaBuffer::assume_init_slice(buffer) };
// TODO packet size hint
packet_handler(buffer);
entry.setup_rx(new_buffer_address, index == capacity - 1);
// entry.setup_rx(new_buffer_address, true)?;
self.rd = self.rd.wrapping_add(1);
count += 1;
} else {
break;
}
}
Ok(count)
}
}
impl TxQueue {
pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let mut entries = DmaBuffer::new_slice(dma, Descriptor::EMPTY_TX, capacity)?;
entries[capacity - 1].control |= Descriptor::TX_WRAP;
let buffers = (0..capacity).map(|_| None).collect();
Ok(Self {
entries,
buffers,
wr: 0,
rd: 0,
})
}
pub fn can_xmit(&self) -> bool {
let capacity = self.entries.len();
self.wr.wrapping_add(1) % capacity != self.rd % capacity
}
pub fn push_xmit(&mut self, frame: DmaBuffer<[u8]>) -> Result<usize, Error> {
if !self.can_xmit() {
return Err(Error::WouldBlock);
}
let address = frame.bus_address();
let frame_len = frame.len();
if !(8..0x2000).contains(&frame_len) {
return Err(Error::InvalidArgument);
}
let capacity = self.entries.len();
let index = self.wr % capacity;
assert!(self.buffers[index].is_none());
frame.cache_flush_all(true);
self.entries[index].setup_tx(address, frame_len, index == capacity - 1);
// self.entries[index].setup_tx(address, frame_len, true)?;
self.entries.cache_flush_element(index, true);
self.buffers[index] = Some(frame);
self.wr = self.wr.wrapping_add(1);
Ok(self.wr % capacity)
}
pub fn consume(&mut self) -> Result<usize, Error> {
let mut count = 0;
loop {
let index = self.rd % self.entries.len();
self.entries.cache_flush_element(index, false);
if self.rd == self.wr {
break;
}
let entry = &self.entries[index];
if entry.control & Descriptor::USED != 0 {
let _ = self.buffers[index].take().unwrap();
self.rd = self.rd.wrapping_add(1);
count += 1;
} else {
break;
}
}
Ok(count)
}
}
impl Queue {
pub fn with_capacity(
dma: &dyn DmaAllocator,
tx_capacity: usize,
rx_capacity: usize,
) -> Result<Self, Error> {
let rx_queue = RxQueue::with_capacity(dma, rx_capacity)?;
let rx_queue_base = rx_queue.entries.bus_address();
let tx_queue = TxQueue::with_capacity(dma, tx_capacity)?;
let tx_queue_base = tx_queue.entries.bus_address();
Ok(Self {
rx_queue: IrqSafeSpinlock::new(rx_queue),
rx_queue_base,
tx_queue: IrqSafeSpinlock::new(tx_queue),
tx_queue_base,
})
}
pub fn rx_queue_base(&self) -> BusAddress {
self.rx_queue_base
}
pub fn tx_queue_base(&self) -> BusAddress {
self.tx_queue_base
}
pub fn push_xmit(&self, packet: DmaBuffer<[u8]>) -> Result<usize, Error> {
self.tx_queue.lock().push_xmit(packet)
}
pub fn consume_rx<F: Fn(DmaBuffer<[u8]>)>(
&self,
dma: &dyn DmaAllocator,
packet_handler: F,
) -> Result<usize, Error> {
self.rx_queue.lock().consume(dma, packet_handler)
}
pub fn consume_tx(&self) -> Result<usize, Error> {
self.tx_queue.lock().consume()
}
}
@@ -0,0 +1,197 @@
use core::time::Duration;
use libk::{error::Error, task::runtime::pwait};
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use ygg_driver_net_core::ephy::MdioBus;
use yggdrasil_abi::net::link::LinkState;
// use crate::ethernet::{CapFlags, Capabilities};
register_structs! {
pub ControlRegs {
(0x00 => pub tx_clk_sel: ReadWrite<u32>),
(0x04 => _0),
(0x20 => pub control_status_speed_mode: ReadWrite<u32>),
(0x24 => _1),
(0x40 => @END),
}
}
register_bitfields! {
u32,
pub NetworkControl [
// Rx enable
RE OFFSET(2) NUMBITS(1) [],
// Tx enable
TE OFFSET(3) NUMBITS(1) [],
// MDIO enable
MPE OFFSET(4) NUMBITS(1) [],
// Start Tx
TSTART OFFSET(9) NUMBITS(1) [],
// Halt Tx
THALT OFFSET(10) NUMBITS(1) [],
],
pub NetworkConfig [
// Speed
SPD OFFSET(0) NUMBITS(1) [],
// Full duplex
FD OFFSET(1) NUMBITS(1) [],
PROMISC OFFSET(4) NUMBITS(1) [],
// Gigabit mode enable
GBE OFFSET(10) NUMBITS(1) [],
],
pub NetworkStatus [
LINK OFFSET(0) NUMBITS(1) [],
MDIO_IDLE OFFSET(2) NUMBITS(1) [],
],
pub DmaConfig [
RX_BUF_SIZE OFFSET(16) NUMBITS(8) [],
],
pub Interrupt [
// Rx complete
RCOMP OFFSET(1) NUMBITS(1) [],
// Tx complete
TCOMP OFFSET(7) NUMBITS(1) [],
// Link change
LINK OFFSET(8) NUMBITS(1) [],
],
pub PhyMaintenance [
DATA OFFSET(0) NUMBITS(16) [],
CODE OFFSET(16) NUMBITS(2) [],
REGA OFFSET(18) NUMBITS(5) [],
PHYA OFFSET(23) NUMBITS(5) [],
RW OFFSET(28) NUMBITS(2) [
Read = 0b10,
Write = 0b01,
],
SOF OFFSET(30) NUMBITS(1) [],
],
pub ModuleId [
IDNUM OFFSET(16) NUMBITS(12) [],
REV OFFSET(0) NUMBITS(16) [],
]
}
register_structs! {
pub Regs {
(0x000 => pub network_control: ReadWrite<u32, NetworkControl::Register>),
(0x004 => pub network_config: ReadWrite<u32, NetworkConfig::Register>),
(0x008 => pub network_status: ReadOnly<u32, NetworkStatus::Register>),
(0x00C => pub user_io: ReadWrite<u32>),
(0x010 => pub dma_config: ReadWrite<u32, DmaConfig::Register>),
(0x014 => pub transmit_status: ReadWrite<u32>),
(0x018 => pub rx_buffer_queue_base: ReadWrite<u32>),
(0x01C => pub tx_buffer_queue_base: ReadWrite<u32>),
(0x020 => pub rx_status: ReadWrite<u32>),
(0x024 => pub interrupt_status: ReadWrite<u32, Interrupt::Register>),
(0x028 => pub interrupt_enable: WriteOnly<u32, Interrupt::Register>),
(0x02C => pub interrupt_disable: WriteOnly<u32, Interrupt::Register>),
(0x030 => pub interrupt_mask: ReadOnly<u32, Interrupt::Register>),
(0x034 => pub phy_maintenance: ReadWrite<u32, PhyMaintenance::Register>),
(0x038 => pub rx_pause_quantum: ReadOnly<u32>),
(0x03C => pub tx_pause_quantum: ReadWrite<u32>),
(0x040 => pub tx_partial_store_fwd: ReadWrite<u32>),
(0x044 => pub rx_partial_store_fwd: ReadWrite<u32>),
(0x048 => _0),
(0x080 => pub hash_register_bottom: ReadWrite<u32>),
(0x084 => pub hash_register_top: ReadWrite<u32>),
(0x088 => pub specific_address_x: [ReadWrite<u32>; 8]),
(0x0A8 => pub type_id_match: [ReadWrite<u32>; 4]),
(0x0B8 => pub wake_on_lan: ReadWrite<u32>),
(0x0BC => pub ipg_stretch: ReadWrite<u32>),
(0x0C0 => pub stacked_vlan: ReadWrite<u32>),
(0x0C4 => pub tx_pfc_pause: ReadWrite<u32>),
(0x0C8 => pub specific_address_mask: [ReadWrite<u32>; 2]),
(0x0D0 => pub rx_buffer_ahb_mask: ReadWrite<u32>),
(0x0D4 => pub ptp_rx_unicast_dst_ip: ReadWrite<u32>),
(0x0D8 => pub ptp_tx_unicast_dst_ip: ReadWrite<u32>),
(0x0DC => pub tsu_timer_cval_nanos: ReadWrite<u32>),
(0x0E0 => pub tsu_timer_cval_sec: ReadWrite<u32>),
(0x0E4 => _1),
(0x0FC => pub module_id: ReadOnly<u32, ModuleId::Register>),
(0x100 => _2),
(0x200 => pub pcs_control: ReadWrite<u32>),
(0x204 => pub pcs_status: ReadOnly<u32>),
(0x208 => pub pcs_phy_id_upper: ReadOnly<u32>),
(0x20C => pub pcs_phy_id_lower: ReadOnly<u32>),
(0x210 => pub pcs_aneg_adv: ReadWrite<u32>),
(0x214 => pub pcs_aneg_link_ability: ReadOnly<u32>),
(0x218 => pub pcs_aneg_expansion: ReadOnly<u32>),
(0x21C => pub pcs_aneg_next_page: ReadWrite<u32>),
(0x220 => pub pcs_aneg_link_next_page: ReadOnly<u32>),
(0x224 => _3),
(0x280 => pub design_config_1: ReadOnly<u32>),
(0x284 => pub design_config_2: ReadOnly<u32>),
(0x288 => pub design_config_3: ReadOnly<u32>),
(0x28C => pub design_config_4: ReadOnly<u32>),
(0x290 => pub design_config_5: ReadOnly<u32>),
(0x294 => pub design_config_6: ReadOnly<u32>),
(0x298 => pub design_config_7: ReadOnly<u32>),
(0x29C => _4),
(0x400 => @END),
}
}
impl Regs {
// pub fn probe_capabilities(&self) -> Capabilities {
// let mut flags = CapFlags::empty();
// let mut queue_mask = 0x1;
// let mut queue_count = 1;
// let module_id = self.module_id.read(ModuleId::IDNUM);
// if module_id >= 0x2 {
// flags |= CapFlags::MACB_IS_GEM;
// queue_mask |= self.design_config_6.get() & 0xFF;
// queue_count = queue_mask.count_ones() as usize;
// }
// Capabilities {
// flags,
// queue_mask,
// queue_count,
// }
// }
pub fn link_state(&self) -> LinkState {
todo!()
}
fn wait_mdio_idle(&self, timeout: Duration) -> Result<(), Error> {
pwait(timeout, Duration::from_millis(20), || {
self.network_status
.matches_all(NetworkStatus::MDIO_IDLE::SET)
})
}
}
impl MdioBus for Regs {
fn mii_read(&self, phyaddr: u8, regaddr: u8) -> Result<u16, Error> {
self.wait_mdio_idle(Duration::from_secs(1))?;
self.phy_maintenance.write(
PhyMaintenance::CODE.val(2)
+ PhyMaintenance::PHYA.val(phyaddr as _)
+ PhyMaintenance::REGA.val(regaddr as _)
+ PhyMaintenance::SOF.val(1)
+ PhyMaintenance::RW::Read,
);
self.wait_mdio_idle(Duration::from_secs(1))?;
let value = self.phy_maintenance.read(PhyMaintenance::DATA);
Ok(value as u16)
}
fn mii_write(&self, phyaddr: u8, regaddr: u8, value: u16) -> Result<(), Error> {
self.wait_mdio_idle(Duration::from_secs(1))?;
self.phy_maintenance.write(
PhyMaintenance::CODE.val(2)
+ PhyMaintenance::PHYA.val(phyaddr as _)
+ PhyMaintenance::REGA.val(regaddr as _)
+ PhyMaintenance::SOF.val(1)
+ PhyMaintenance::DATA.val(value as _)
+ PhyMaintenance::RW::Write,
);
self.wait_mdio_idle(Duration::from_secs(1))
}
}
+1
View File
@@ -3,4 +3,5 @@
extern crate alloc;
mod clock;
mod ethernet;
mod uart;