Compare commits
2 Commits
8d2df7f6f7
...
fbd963d26c
Author | SHA1 | Date | |
---|---|---|---|
fbd963d26c | |||
93ab72d4a0 |
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -2520,6 +2520,22 @@ dependencies = [
|
|||||||
"yggdrasil-abi",
|
"yggdrasil-abi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ygg_driver_net_stmmac"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"device-api",
|
||||||
|
"device-tree",
|
||||||
|
"libk",
|
||||||
|
"libk-mm",
|
||||||
|
"libk-util",
|
||||||
|
"log",
|
||||||
|
"tock-registers 0.9.0",
|
||||||
|
"ygg_driver_net_core",
|
||||||
|
"yggdrasil-abi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ygg_driver_nvme"
|
name = "ygg_driver_nvme"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2694,6 +2710,7 @@ dependencies = [
|
|||||||
"ygg_driver_input",
|
"ygg_driver_input",
|
||||||
"ygg_driver_net_core",
|
"ygg_driver_net_core",
|
||||||
"ygg_driver_net_loopback",
|
"ygg_driver_net_loopback",
|
||||||
|
"ygg_driver_net_stmmac",
|
||||||
"ygg_driver_nvme",
|
"ygg_driver_nvme",
|
||||||
"ygg_driver_pci",
|
"ygg_driver_pci",
|
||||||
"ygg_driver_usb",
|
"ygg_driver_usb",
|
||||||
|
@ -56,6 +56,7 @@ kernel-arch-aarch64.workspace = true
|
|||||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||||
device-tree.workspace = true
|
device-tree.workspace = true
|
||||||
kernel-arch-riscv64.workspace = true
|
kernel-arch-riscv64.workspace = true
|
||||||
|
ygg_driver_net_stmmac.path = "driver/net/stmmac"
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
yboot-proto.workspace = true
|
yboot-proto.workspace = true
|
||||||
@ -87,6 +88,8 @@ kernel-arch-x86.workspace = true
|
|||||||
kernel-arch-aarch64.workspace = true
|
kernel-arch-aarch64.workspace = true
|
||||||
kernel-arch-riscv64.workspace = true
|
kernel-arch-riscv64.workspace = true
|
||||||
|
|
||||||
|
ygg_driver_net_stmmac.path = "driver/net/stmmac"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fb_console"]
|
default = ["fb_console"]
|
||||||
fb_console = []
|
fb_console = []
|
||||||
|
@ -70,6 +70,7 @@ pub fn handle(packet: L2Packet) {
|
|||||||
match ty {
|
match ty {
|
||||||
EtherType::ARP => l3::arp::handle_packet(packet),
|
EtherType::ARP => l3::arp::handle_packet(packet),
|
||||||
EtherType::IPV4 => l3::ip::handle_v4_packet(packet),
|
EtherType::IPV4 => l3::ip::handle_v4_packet(packet),
|
||||||
|
EtherType(0x0027) => (),
|
||||||
p => {
|
p => {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Unrecognized L2 protocol: {:#06x}",
|
"Unrecognized L2 protocol: {:#06x}",
|
||||||
|
17
kernel/driver/net/stmmac/Cargo.toml
Normal file
17
kernel/driver/net/stmmac/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "ygg_driver_net_stmmac"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
device-tree.workspace = true
|
||||||
|
device-api.workspace = true
|
||||||
|
yggdrasil-abi.workspace = true
|
||||||
|
libk-mm.workspace = true
|
||||||
|
libk-util.workspace = true
|
||||||
|
libk.workspace = true
|
||||||
|
ygg_driver_net_core.path = "../core"
|
||||||
|
|
||||||
|
tock-registers.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
bytemuck.workspace = true
|
319
kernel/driver/net/stmmac/src/lib.rs
Normal file
319
kernel/driver/net/stmmac/src/lib.rs
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
use device_api::{
|
||||||
|
clock::{ClockHandle, ResetHandle},
|
||||||
|
device::Device,
|
||||||
|
interrupt::{FullIrq, InterruptHandler},
|
||||||
|
};
|
||||||
|
use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext};
|
||||||
|
use libk::{device::external_interrupt_controller, error::Error};
|
||||||
|
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, PageBox};
|
||||||
|
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||||
|
use regs::{
|
||||||
|
dma::{DMACiCR, DMACiIER, DMACiSR, DMACiTXCR, DMAC0RXCR, DMAMR, DMASBMR},
|
||||||
|
mac::{
|
||||||
|
MACAiHR, MACAiLR, MACCR, MACIER, MACISR, MACPFR, MACPHYCSR, MACQ0TXFCR, MACRXFCR, MACRXQC0R,
|
||||||
|
},
|
||||||
|
mtl::{MTLRXQiOMR, MTLTXQiOMR, MTLOMR},
|
||||||
|
Regs,
|
||||||
|
};
|
||||||
|
use ring::{RxDescriptor, RxRing, TxDescriptor, TxRing};
|
||||||
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
use ygg_driver_net_core::{
|
||||||
|
interface::{NetworkDevice, NetworkInterfaceType},
|
||||||
|
Packet,
|
||||||
|
};
|
||||||
|
use yggdrasil_abi::net::MacAddress;
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub mod regs;
|
||||||
|
pub mod ring;
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||||
|
|
||||||
|
tx_ring: IrqSafeSpinlock<TxRing>,
|
||||||
|
rx_ring: IrqSafeSpinlock<RxRing>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Stmmac {
|
||||||
|
base: PhysicalAddress,
|
||||||
|
mac: MacAddress,
|
||||||
|
resets: Vec<ResetHandle>,
|
||||||
|
clocks: Vec<ClockHandle>,
|
||||||
|
irq: FullIrq,
|
||||||
|
|
||||||
|
inner: OneTimeInit<Inner>,
|
||||||
|
iface_id: OneTimeInit<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stmmac {
|
||||||
|
pub fn start_xmit(&self, frame: PageBox<[u8]>) -> Result<(), Error> {
|
||||||
|
let inner = self.inner.get();
|
||||||
|
let regs = inner.regs.lock();
|
||||||
|
|
||||||
|
let mut tx_ring = inner.tx_ring.lock();
|
||||||
|
let index = tx_ring.push_xmit(frame)?;
|
||||||
|
let ring_pos = tx_ring
|
||||||
|
.physical_base()
|
||||||
|
.add(size_of::<TxDescriptor>() * index)
|
||||||
|
.try_into_u32()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
regs.DMA.DMAC0TXDTPR.set(ring_pos);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterruptHandler for Stmmac {
|
||||||
|
fn handle_irq(self: Arc<Self>, _vector: Option<usize>) -> bool {
|
||||||
|
let inner = self.inner.get();
|
||||||
|
let regs = inner.regs.lock();
|
||||||
|
let mac_isr = regs.MAC.MACISR.extract();
|
||||||
|
let dma0_sr = regs.DMA.DMAC0SR.extract();
|
||||||
|
|
||||||
|
if mac_isr.matches_all(MACISR::RGSMIIIS::SET) {
|
||||||
|
let macphycsr = regs.MAC.MACPHYCSR.extract();
|
||||||
|
let state = if macphycsr.matches_all(MACPHYCSR::LNKSTS::Up) {
|
||||||
|
"up"
|
||||||
|
} else {
|
||||||
|
"down"
|
||||||
|
};
|
||||||
|
let mode = if macphycsr.matches_all(MACPHYCSR::LNKMOD::FullDuplex) {
|
||||||
|
"full-duplex"
|
||||||
|
} else {
|
||||||
|
"half-duplex"
|
||||||
|
};
|
||||||
|
log::info!("RGMII link status update");
|
||||||
|
log::info!("Link state: link={state}, mode={mode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if dma0_sr.matches_all(DMACiSR::TI::SET) {
|
||||||
|
regs.DMA.DMAC0SR.modify(DMACiSR::TI::SET);
|
||||||
|
inner.tx_ring.lock().consume().ok();
|
||||||
|
}
|
||||||
|
if dma0_sr.matches_all(DMACiSR::RI::SET) {
|
||||||
|
regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET);
|
||||||
|
let iface = *self.iface_id.get();
|
||||||
|
let mut rx_ring = inner.rx_ring.lock();
|
||||||
|
rx_ring
|
||||||
|
.consume(|packet| {
|
||||||
|
let packet = Packet::new(packet, 0, iface);
|
||||||
|
ygg_driver_net_core::receive_packet(packet).ok();
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Stmmac {
|
||||||
|
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
|
||||||
|
let intc = external_interrupt_controller()?;
|
||||||
|
|
||||||
|
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||||
|
|
||||||
|
let tx_ring_capacity = 32;
|
||||||
|
let rx_ring_capacity = 32;
|
||||||
|
|
||||||
|
log::info!("dwmac: setup {:#x}, mac={}", self.base, self.mac);
|
||||||
|
|
||||||
|
for clock in self.clocks.iter() {
|
||||||
|
clock.enable()?;
|
||||||
|
}
|
||||||
|
for reset in self.resets.iter() {
|
||||||
|
reset.deassert()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let regs = unsafe { DeviceMemoryIo::<Regs>::map(self.base, Default::default()) }?;
|
||||||
|
|
||||||
|
// DMA initialization
|
||||||
|
|
||||||
|
// Perform a software reset
|
||||||
|
regs.DMA.DMAMR.modify(DMAMR::SWR::SET);
|
||||||
|
|
||||||
|
let mut timeout = 100000;
|
||||||
|
while timeout > 0 && regs.DMA.DMAMR.matches_all(DMAMR::SWR::SET) {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
timeout -= 1;
|
||||||
|
}
|
||||||
|
if timeout == 0 {
|
||||||
|
log::warn!("dwmac: reset timeout");
|
||||||
|
return Err(Error::TimedOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup DMA parameters
|
||||||
|
// TODO get these params from device tree
|
||||||
|
regs.DMA.DMASBMR.write(
|
||||||
|
DMASBMR::FB::SET
|
||||||
|
+ DMASBMR::BLEN256::SET
|
||||||
|
+ DMASBMR::BLEN128::SET
|
||||||
|
+ DMASBMR::BLEN64::SET
|
||||||
|
+ DMASBMR::BLEN32::SET
|
||||||
|
+ DMASBMR::EN_LPI::SET
|
||||||
|
+ DMASBMR::WR_OSR_LMT.val(3)
|
||||||
|
+ DMASBMR::RD_OSR_LMT.val(3),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Setup DMA Tx/Rx rings
|
||||||
|
let tx_ring = TxRing::with_capacity(tx_ring_capacity)?;
|
||||||
|
let rx_ring = RxRing::with_capacity(rx_ring_capacity)?;
|
||||||
|
let tx_ring_base = tx_ring.physical_base().try_into_u32().unwrap();
|
||||||
|
let rx_ring_base = rx_ring.physical_base().try_into_u32().unwrap();
|
||||||
|
|
||||||
|
regs.DMA.DMAC0TXRLR.set(tx_ring_capacity as u32 - 1);
|
||||||
|
regs.DMA.DMAC0TXDLAR.set(tx_ring_base);
|
||||||
|
regs.DMA.DMAC0TXDTPR.set(tx_ring_base);
|
||||||
|
|
||||||
|
regs.DMA.DMAC0RXRLR.set(rx_ring_capacity as u32 - 1);
|
||||||
|
regs.DMA.DMAC0RXDLAR.set(rx_ring_base);
|
||||||
|
regs.DMA
|
||||||
|
.DMAC0RXDTPR
|
||||||
|
.set(rx_ring_base + (rx_ring_capacity * size_of::<RxDescriptor>()) as u32);
|
||||||
|
|
||||||
|
// Setup DMA maximum segmen size, Rx buffer size + max burst len
|
||||||
|
regs.DMA.DMAC0CR.write(DMACiCR::PBLX8::CLEAR);
|
||||||
|
regs.DMA
|
||||||
|
.DMAC0TXCR
|
||||||
|
.write(DMACiTXCR::TXPBL.val(32) + DMACiTXCR::OSF::SET);
|
||||||
|
regs.DMA
|
||||||
|
.DMAC0RXCR
|
||||||
|
.write(DMAC0RXCR::RBSZ.val(4096) + DMAC0RXCR::RXPBL.val(32));
|
||||||
|
|
||||||
|
// Enable DMA interrupts
|
||||||
|
// TODO enable abnormal interrupts to handle errors properly
|
||||||
|
regs.DMA.DMAC0IER.write(
|
||||||
|
DMACiIER::NIE::SET
|
||||||
|
+ DMACiIER::RIE::SET
|
||||||
|
+ DMACiIER::TIE::SET
|
||||||
|
+ DMACiIER::RBUE::SET
|
||||||
|
+ DMACiIER::RSE::SET,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start Tx/Rx DMAs
|
||||||
|
regs.DMA.DMAC0TXCR.modify(DMACiTXCR::ST::SET);
|
||||||
|
regs.DMA.DMAC0RXCR.modify(DMAC0RXCR::SR::SET);
|
||||||
|
|
||||||
|
// MTL initialization
|
||||||
|
|
||||||
|
regs.MTL
|
||||||
|
.MTLOMR
|
||||||
|
.write(MTLOMR::RAA::AlgStrictPrio + MTLOMR::SCHALG::AlgStrictPrio);
|
||||||
|
|
||||||
|
// TODO get TQS, RQS from device tree
|
||||||
|
regs.MTL
|
||||||
|
.MTLTXQ0OMR
|
||||||
|
.write(MTLTXQiOMR::TSF::SET + MTLTXQiOMR::TQS.val(7) + MTLTXQiOMR::TXQEN::Enable);
|
||||||
|
regs.MTL.MTLRXQ0OMR.write(
|
||||||
|
MTLRXQiOMR::RQS.val(7)
|
||||||
|
+ MTLRXQiOMR::DIS_TCP_EF::SET
|
||||||
|
+ MTLRXQiOMR::RSF::SET
|
||||||
|
+ MTLRXQiOMR::FEP::SET
|
||||||
|
+ MTLRXQiOMR::FUP::SET,
|
||||||
|
);
|
||||||
|
|
||||||
|
// MAC initialization
|
||||||
|
|
||||||
|
// Setup the MAC address
|
||||||
|
let mac_bytes: [u8; 6] = self.mac.into();
|
||||||
|
regs.MAC.MACA0HR.write(
|
||||||
|
MACAiHR::AE::SET
|
||||||
|
+ MACAiHR::ADDR4.val(mac_bytes[4] as u32)
|
||||||
|
+ MACAiHR::ADDR5.val(mac_bytes[5] as u32),
|
||||||
|
);
|
||||||
|
regs.MAC.MACA0LR.write(
|
||||||
|
MACAiLR::ADDR0.val(mac_bytes[0] as u32)
|
||||||
|
+ MACAiLR::ADDR1.val(mac_bytes[1] as u32)
|
||||||
|
+ MACAiLR::ADDR2.val(mac_bytes[2] as u32)
|
||||||
|
+ MACAiLR::ADDR3.val(mac_bytes[3] as u32),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO proper filtering, don't use promiscuous mode all the time
|
||||||
|
regs.MAC.MACPFR.write(MACPFR::PR::SET + MACPFR::RA::SET);
|
||||||
|
|
||||||
|
// Setup Tx/Rx flow control, enable Rx queue 0
|
||||||
|
regs.MAC.MACQ0TXFCR.write(MACQ0TXFCR::TFE::SET);
|
||||||
|
regs.MAC.MACRXFCR.write(MACRXFCR::RFE::SET);
|
||||||
|
regs.MAC.MACRXQC0R.write(MACRXQC0R::RXQ0EN::Enable);
|
||||||
|
|
||||||
|
// Setup MAC-level interrupts
|
||||||
|
regs.MAC
|
||||||
|
.MACIER
|
||||||
|
.write(MACIER::TXSTSIE::SET + MACIER::RXSTSIE::SET + MACIER::RGSMIIIE::SET);
|
||||||
|
|
||||||
|
// Setup link information
|
||||||
|
regs.MAC
|
||||||
|
.MACCR
|
||||||
|
.modify(MACCR::PS::Ps1000Mbps + MACCR::DM::FullDuplex);
|
||||||
|
|
||||||
|
// Start Tx/Rx
|
||||||
|
regs.MAC.MACCR.modify(MACCR::TE::SET + MACCR::RE::SET);
|
||||||
|
|
||||||
|
// Apply PHY settings
|
||||||
|
regs.MAC
|
||||||
|
.MACPHYCSR
|
||||||
|
.modify(MACPHYCSR::LUD::SET + MACPHYCSR::TC::SET);
|
||||||
|
|
||||||
|
self.inner.init(Inner {
|
||||||
|
regs: IrqSafeSpinlock::new(regs),
|
||||||
|
|
||||||
|
tx_ring: IrqSafeSpinlock::new(tx_ring),
|
||||||
|
rx_ring: IrqSafeSpinlock::new(rx_ring),
|
||||||
|
});
|
||||||
|
|
||||||
|
let iface =
|
||||||
|
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||||
|
self.iface_id.init(iface.id());
|
||||||
|
|
||||||
|
intc.enable_irq(self.irq.irq)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self) -> &str {
|
||||||
|
"Synopsys DesignWare Ethernet MAC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkDevice for Stmmac {
|
||||||
|
fn transmit(&self, packet: PageBox<[u8]>) -> Result<(), Error> {
|
||||||
|
self.start_xmit(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn packet_prefix_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_hardware_address(&self) -> MacAddress {
|
||||||
|
self.mac
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_tree_driver! {
|
||||||
|
compatible: ["starfive,jh7110-dwmac"],
|
||||||
|
driver: {
|
||||||
|
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||||
|
let base = node.map_base(context, 0)?;
|
||||||
|
let clocks = node.clocks()?.collect();
|
||||||
|
let resets = node.resets()?.collect();
|
||||||
|
let mac = read_mac_address(node)?;
|
||||||
|
// TODO named_interrupt()
|
||||||
|
let irq = node.interrupt(0)?;
|
||||||
|
|
||||||
|
Some(Arc::new(Stmmac {
|
||||||
|
base,
|
||||||
|
clocks,
|
||||||
|
resets,
|
||||||
|
mac,
|
||||||
|
irq,
|
||||||
|
|
||||||
|
inner: OneTimeInit::new(),
|
||||||
|
iface_id: OneTimeInit::new(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
243
kernel/driver/net/stmmac/src/regs/dma.rs
Normal file
243
kernel/driver/net/stmmac/src/regs/dma.rs
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
use tock_registers::{register_bitfields, register_structs, registers::ReadWrite};
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
pub DMAMR [
|
||||||
|
/// Interrupt mode
|
||||||
|
INTM OFFSET(16) NUMBITS(2) [],
|
||||||
|
/// Transmit priority
|
||||||
|
TXPR OFFSET(11) NUMBITS(1) [],
|
||||||
|
/// Descriptor posted write
|
||||||
|
DSPW OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Transmit arbitration algorithm
|
||||||
|
TAA OFFSET(2) NUMBITS(3) [],
|
||||||
|
/// Software reset
|
||||||
|
///
|
||||||
|
/// When this bit is set, the MAC and the DMA controllers are reset. This bit is cleared
|
||||||
|
/// automatically when the MAC/DMA reset completes.
|
||||||
|
SWR OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMASBMR [
|
||||||
|
/// Enable Low Power interface
|
||||||
|
EN_LPI OFFSET(31) NUMBITS(1) [],
|
||||||
|
/// Unlock on Magic packet or Remote Wakeup packet
|
||||||
|
LPI_XIT_PKT OFFSET(30) NUMBITS(1) [],
|
||||||
|
/// AXI maximum write outstanding request limit
|
||||||
|
///
|
||||||
|
/// Maximum outstanding requests = WR_OSR_LMT + 1
|
||||||
|
WR_OSR_LMT OFFSET(24) NUMBITS(2) [],
|
||||||
|
/// AXI maximum reaad outstanding request limit
|
||||||
|
///
|
||||||
|
/// Maximum outstanding requests = RD_OSR_LMT + 1
|
||||||
|
RD_OSR_LMT OFFSET(16) NUMBITS(2) [],
|
||||||
|
/// 1 Kbyte boundary crossing enable for the AXI master
|
||||||
|
///
|
||||||
|
/// If set, the burst transfers performed by the AXI master do not cross 1 Kbyte boundary
|
||||||
|
/// If not, the transfers do not cross 4 Kbyte boundary
|
||||||
|
ONEKBBE OFFSET(13) NUMBITS(1) [],
|
||||||
|
/// Address aligned bursts
|
||||||
|
///
|
||||||
|
/// If set, the master performs addres-aligned burst transfers on read and write channels
|
||||||
|
AAL OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// Automatic AXI LPI enable
|
||||||
|
///
|
||||||
|
/// When set, enables AXI master to enter into LPI state when there is no activity on the
|
||||||
|
/// Ethernet peripheral for a number of clock cycles programmed in ETH_DMALPIEI register.
|
||||||
|
AALE OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 256
|
||||||
|
BLEN256 OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 128
|
||||||
|
BLEN128 OFFSET(6) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 64
|
||||||
|
BLEN64 OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 32
|
||||||
|
BLEN32 OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 16
|
||||||
|
BLEN16 OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 8
|
||||||
|
BLEN8 OFFSET(2) NUMBITS(1) [],
|
||||||
|
/// AXI burst length 4
|
||||||
|
BLEN4 OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Fixed burst length
|
||||||
|
FB OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMACiCR [
|
||||||
|
/// Descriptor skip length
|
||||||
|
DSL OFFSET(18) NUMBITS(1) [],
|
||||||
|
/// 8xPBL mode
|
||||||
|
PBLX8 OFFSET(16) NUMBITS(1) [],
|
||||||
|
/// Maximum segment size
|
||||||
|
MSS OFFSET(0) NUMBITS(14) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMACiTXCR [
|
||||||
|
/// Tx QOS
|
||||||
|
TQOS OFFSET(24) NUMBITS(4) [],
|
||||||
|
/// Transmit programmable burst length
|
||||||
|
TXPBL OFFSET(16) NUMBITS(6) [],
|
||||||
|
/// Ignore PBL requirement
|
||||||
|
IPBL OFFSET(15) NUMBITS(1) [],
|
||||||
|
/// TCP segmentation enabled
|
||||||
|
TSE OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// Operate on second packet
|
||||||
|
OSF OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// Tx channel weight
|
||||||
|
TCW OFFSET(1) NUMBITS(3) [],
|
||||||
|
/// Start or stop Tx command
|
||||||
|
///
|
||||||
|
/// When set, the DMA checks the transmit list at current position for a packet to be
|
||||||
|
/// transmitted. If the DMA does not own the current descriptor, the transmission enters
|
||||||
|
/// the Suspended state with TBU bit in DMACiSR set.
|
||||||
|
ST OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMAC0RXCR [
|
||||||
|
/// DMA Rx channel 0 packet flush
|
||||||
|
///
|
||||||
|
/// When set, the DMA automatically flushes the packet from the Rx queues destined to DMA
|
||||||
|
/// Rx channel 0 when the DMA Rx 0 is stopped after a system bus error.
|
||||||
|
RPF OFFSET(31) NUMBITS(1) [],
|
||||||
|
/// Rx QOS
|
||||||
|
RQOS OFFSET(24) NUMBITS(4) [],
|
||||||
|
/// Rx programmable burst length
|
||||||
|
RXPBL OFFSET(16) NUMBITS(6) [],
|
||||||
|
/// Receive buffer size
|
||||||
|
RBSZ OFFSET(1) NUMBITS(14) [],
|
||||||
|
/// Start or stop Rx
|
||||||
|
///
|
||||||
|
/// When set, the DMA tries to acquire the descriptor from the receive list and process the
|
||||||
|
/// incoming packets.
|
||||||
|
SR OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMACiIER [
|
||||||
|
/// Normal interrupt summary enable
|
||||||
|
///
|
||||||
|
/// When this bit is set, the following interrupts are enabled in the Channel i status
|
||||||
|
/// register:
|
||||||
|
///
|
||||||
|
/// * Tx interrupt
|
||||||
|
/// * Tx buffer unavailable
|
||||||
|
/// * Rx interrupt
|
||||||
|
/// * Early Rx interrupt
|
||||||
|
NIE OFFSET(15) NUMBITS(1) [],
|
||||||
|
/// Abnormal interrupt summary enable
|
||||||
|
///
|
||||||
|
/// When this bit is set, the following interrupt summary is enabled:
|
||||||
|
///
|
||||||
|
/// * Tx process stopped
|
||||||
|
/// * Rx buffer unavailable
|
||||||
|
/// * Rx process stopped
|
||||||
|
/// * Rx watchdog timeout
|
||||||
|
/// * Early Tx interrupt
|
||||||
|
/// * Fatal bus error
|
||||||
|
AIE OFFSET(14) NUMBITS(1) [],
|
||||||
|
/// Context descriptor error enable (+AIE)
|
||||||
|
CDEE OFFSET(13) NUMBITS(1) [],
|
||||||
|
/// Fatal bus error enable (+AIE)
|
||||||
|
FBEE OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// Early Rx interrupt enable
|
||||||
|
///
|
||||||
|
/// When this bit is set along with the NIE bit, the Early Rx interrupt is enabled
|
||||||
|
ERIE OFFSET(11) NUMBITS(1) [],
|
||||||
|
/// Early Tx interrupt enable
|
||||||
|
///
|
||||||
|
/// When this bit is set along with the AIE bit, the Early Tx interrupt is enabled
|
||||||
|
ETIE OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// Receive watchdog timeout enable (+AIE)
|
||||||
|
RWTE OFFSET(9) NUMBITS(1) [],
|
||||||
|
/// Rx stopped enable (+AIE)
|
||||||
|
RSE OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Rx buffer unavailable enable (+AIE)
|
||||||
|
RBUE OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// Rx interrupt enable (+NIE)
|
||||||
|
RIE OFFSET(6) NUMBITS(1) [],
|
||||||
|
/// Tx buffer unavailable enable (+NIE)
|
||||||
|
TBUE OFFSET(2) NUMBITS(1) [],
|
||||||
|
/// Tx stopped enable (+AIE)
|
||||||
|
TXSE OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Tx interrupt enable (+NIE)
|
||||||
|
TIE OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub DMACiSR [
|
||||||
|
/// Rx DMA error bits
|
||||||
|
REB OFFSET(19) NUMBITS(3) [],
|
||||||
|
/// Tx DMA error bits
|
||||||
|
TEB OFFSET(16) NUMBITS(3) [],
|
||||||
|
/// Normal interrupt summary
|
||||||
|
NIS OFFSET(15) NUMBITS(1) [],
|
||||||
|
/// Abnormal interrupt summary
|
||||||
|
AIS OFFSET(14) NUMBITS(1) [],
|
||||||
|
/// Context descriptor error
|
||||||
|
CDE OFFSET(13) NUMBITS(1) [],
|
||||||
|
/// Fatal bus error
|
||||||
|
FBE OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// Early Rx interrupt
|
||||||
|
ERI OFFSET(11) NUMBITS(1) [],
|
||||||
|
/// Early Tx interrupt
|
||||||
|
ETI OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// Rx watchdog timeout
|
||||||
|
RWT OFFSET(9) NUMBITS(1) [],
|
||||||
|
/// Rx process stopped
|
||||||
|
RPS OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Rx buffer unavailable. To resume processing Rx descriptors, the driver should change
|
||||||
|
/// the ownership of the descriptors and issue a Rx Poll Demand command. In ring mode, the
|
||||||
|
/// driver should advance the Rx descriptor tail pointer of a channel.
|
||||||
|
RBU OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// Rx interrupt
|
||||||
|
RI OFFSET(6) NUMBITS(1) [],
|
||||||
|
/// Tx buffer unavailable (see RBU, but for Tx)
|
||||||
|
TBU OFFSET(2) NUMBITS(1) [],
|
||||||
|
/// Tx process stopped
|
||||||
|
TPS OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Tx interrupt
|
||||||
|
TI OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub DmaRegs {
|
||||||
|
(0x000 => pub DMAMR: ReadWrite<u32, DMAMR::Register>),
|
||||||
|
(0x004 => pub DMASBMR: ReadWrite<u32, DMASBMR::Register>),
|
||||||
|
(0x008 => pub DMAISR: ReadWrite<u32>),
|
||||||
|
(0x00C => pub DMADSR: ReadWrite<u32>),
|
||||||
|
(0x010 => _0),
|
||||||
|
(0x020 => pub DMAA4TXACR: ReadWrite<u32>),
|
||||||
|
(0x024 => pub DMAA4RXACR: ReadWrite<u32>),
|
||||||
|
(0x028 => pub DMAA4DACR: ReadWrite<u32>),
|
||||||
|
(0x02C => _1),
|
||||||
|
(0x040 => pub DMALPIEI: ReadWrite<u32>),
|
||||||
|
(0x044 => _2),
|
||||||
|
(0x100 => pub DMAC0CR: ReadWrite<u32, DMACiCR::Register>),
|
||||||
|
(0x104 => pub DMAC0TXCR: ReadWrite<u32, DMACiTXCR::Register>),
|
||||||
|
(0x108 => pub DMAC0RXCR: ReadWrite<u32, DMAC0RXCR::Register>),
|
||||||
|
(0x10C => _3),
|
||||||
|
(0x114 => pub DMAC0TXDLAR: ReadWrite<u32>),
|
||||||
|
(0x118 => _4),
|
||||||
|
(0x11C => pub DMAC0RXDLAR: ReadWrite<u32>),
|
||||||
|
(0x120 => pub DMAC0TXDTPR: ReadWrite<u32>),
|
||||||
|
(0x124 => _5),
|
||||||
|
(0x128 => pub DMAC0RXDTPR: ReadWrite<u32>),
|
||||||
|
(0x12C => pub DMAC0TXRLR: ReadWrite<u32>),
|
||||||
|
(0x130 => pub DMAC0RXRLR: ReadWrite<u32>),
|
||||||
|
(0x134 => pub DMAC0IER: ReadWrite<u32, DMACiIER::Register>),
|
||||||
|
(0x138 => pub DMAC0RXIWTR: ReadWrite<u32>),
|
||||||
|
(0x13C => pub DMAC0SFCSR: ReadWrite<u32>),
|
||||||
|
(0x140 => _6),
|
||||||
|
(0x144 => pub DMAC0CATXDR: ReadWrite<u32>),
|
||||||
|
(0x148 => _7),
|
||||||
|
(0x14C => pub DMAC0CARXDR: ReadWrite<u32>),
|
||||||
|
(0x150 => _8),
|
||||||
|
(0x154 => pub DMAC0CATXBR: ReadWrite<u32>),
|
||||||
|
(0x158 => _9),
|
||||||
|
(0x15C => pub DMAC0CARXBR: ReadWrite<u32>),
|
||||||
|
(0x160 => pub DMAC0SR: ReadWrite<u32, DMACiSR::Register>),
|
||||||
|
(0x164 => _10),
|
||||||
|
(0x16C => pub DMAC0MFCR: ReadWrite<u32>),
|
||||||
|
(0x170 => _11),
|
||||||
|
(0x200 => @END),
|
||||||
|
}
|
||||||
|
}
|
500
kernel/driver/net/stmmac/src/regs/mac.rs
Normal file
500
kernel/driver/net/stmmac/src/regs/mac.rs
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
use libk::error::Error;
|
||||||
|
use tock_registers::{
|
||||||
|
interfaces::{Readable, Writeable},
|
||||||
|
register_bitfields, register_structs,
|
||||||
|
registers::{ReadOnly, ReadWrite},
|
||||||
|
};
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
pub MACCR [
|
||||||
|
/// * When set: MAC recognizes ARP requests, responds with ARP responses.
|
||||||
|
/// * When clear: no additional ARP logic, frames are indicates as Type
|
||||||
|
/// frame in the RxStatus.
|
||||||
|
ARPEN OFFSET(31) NUMBITS(1) [],
|
||||||
|
/// Source address insertion or replacement setting.
|
||||||
|
SARC OFFSET(28) NUMBITS(3) [],
|
||||||
|
/// IP checksum offload.
|
||||||
|
///
|
||||||
|
/// When set, enables IPv4 header checksum checking, IPv4, IPv6 TCP+UDP and ICMP
|
||||||
|
/// payload checksum checking.
|
||||||
|
IPC OFFSET(27) NUMBITS(1) [],
|
||||||
|
/// Inter-packet gap setting.
|
||||||
|
IPG OFFSET(24) NUMBITS(1) [],
|
||||||
|
/// Giant packet size limit control enable.
|
||||||
|
GPSCLE OFFSET(23) NUMBITS(1) [],
|
||||||
|
/// IEEE 802.3as support for 2K packets.
|
||||||
|
S2KP OFFSET(22) NUMBITS(1) [],
|
||||||
|
/// CRC stripping for Type packets.
|
||||||
|
CST OFFSET(21) NUMBITS(1) [],
|
||||||
|
/// Automatic pad or CRC stripping.
|
||||||
|
ACS OFFSET(20) NUMBITS(1) [],
|
||||||
|
/// Watchdog disable.
|
||||||
|
///
|
||||||
|
/// When set, disables the watchdog timer on the receiver. The MAC can receive packets
|
||||||
|
/// of up to 16383 bytes.
|
||||||
|
/// When clear, the MAC does not allow packets of more than 2048 bytes (or 10240 with
|
||||||
|
/// JE).
|
||||||
|
WD OFFSET(19) NUMBITS(1) [],
|
||||||
|
/// Packet burst enable.
|
||||||
|
BE OFFSET(18) NUMBITS(1) [],
|
||||||
|
/// Jabber disable.
|
||||||
|
///
|
||||||
|
/// When set, disables the jabber timer on the transmitter. The MAC can send packets of
|
||||||
|
/// up to 16383 bytes.
|
||||||
|
JD OFFSET(17) NUMBITS(1) [],
|
||||||
|
/// Jumbo packet enable.
|
||||||
|
JE OFFSET(16) NUMBITS(1) [],
|
||||||
|
/// Port select
|
||||||
|
PS OFFSET(15) NUMBITS(1) [
|
||||||
|
Ps1000Mbps = 0,
|
||||||
|
Ps10Or100Mbps = 1,
|
||||||
|
],
|
||||||
|
/// MAC speed
|
||||||
|
FES OFFSET(14) NUMBITS(1) [
|
||||||
|
Fes10Mbps = 0,
|
||||||
|
Fes100Mbps = 1,
|
||||||
|
],
|
||||||
|
/// Duplex mode
|
||||||
|
DM OFFSET(13) NUMBITS(1) [
|
||||||
|
HalfDuplex = 0,
|
||||||
|
FullDuplex = 1,
|
||||||
|
],
|
||||||
|
/// Loopback mode. When set, GMII output is looped back into input. The GMII RX clock
|
||||||
|
/// input is required for the loopback to work, because the GMII TX clock is not
|
||||||
|
/// looped back internally.
|
||||||
|
LM OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// Enable carrier-sense before transmission in Full-Duplex mode
|
||||||
|
ECRSFD OFFSET(11) NUMBITS(1) [],
|
||||||
|
/// Disable receive own
|
||||||
|
DO OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// Disable carrier-sense during transmission
|
||||||
|
DCRS OFFSET(9) NUMBITS(1) [],
|
||||||
|
/// Disable retry
|
||||||
|
DR OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Backoff limit
|
||||||
|
BL OFFSET(5) NUMBITS(2) [
|
||||||
|
/// k = min(n, 10)
|
||||||
|
BackoffMin10 = 0,
|
||||||
|
/// k = min(n, 8)
|
||||||
|
BackoffMin8 = 1,
|
||||||
|
/// k = min(n, 4)
|
||||||
|
BackoffMin4 = 2,
|
||||||
|
/// k = min(n, 1)
|
||||||
|
BackoffMin1 = 3,
|
||||||
|
],
|
||||||
|
/// Deferral check
|
||||||
|
DC OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// Preamble length
|
||||||
|
PRELEN OFFSET(2) NUMBITS(2) [
|
||||||
|
Pre7b = 0,
|
||||||
|
Pre5b = 1,
|
||||||
|
Pre3b = 2,
|
||||||
|
],
|
||||||
|
/// Transmitter enable
|
||||||
|
TE OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Receiver enable
|
||||||
|
RE OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACPFR [
|
||||||
|
/// Receive all. When set, the MAC receiver passes all received packets to the application,
|
||||||
|
/// whether they pass the address filter or not.
|
||||||
|
RA OFFSET(31) NUMBITS(1) [],
|
||||||
|
/// Drop Non-TCP/UDP over IP packets
|
||||||
|
DNTU OFFSET(21) NUMBITS(1) [],
|
||||||
|
/// Layer 3 and 4 filter enable
|
||||||
|
IPFE OFFSET(20) NUMBITS(1) [],
|
||||||
|
/// VLAN filter enable
|
||||||
|
VTFE OFFSET(16) NUMBITS(1) [],
|
||||||
|
/// Hash or perfect filter
|
||||||
|
HPF OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// Source address filter
|
||||||
|
SAF OFFSET(9) NUMBITS(1) [],
|
||||||
|
/// SA inverse filtering
|
||||||
|
SAIF OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// Pass control checks
|
||||||
|
PCF OFFSET(6) NUMBITS(2) [],
|
||||||
|
/// Disable broadcast packets
|
||||||
|
DBF OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// Pass all multicast
|
||||||
|
PM OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// DA inverse filtering
|
||||||
|
DAIF OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// Hash multicast
|
||||||
|
HMC OFFSET(2) NUMBITS(1) [],
|
||||||
|
/// Hash unicast
|
||||||
|
HUC OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Promiscuous mode
|
||||||
|
PR OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACQ0TXFCR [
|
||||||
|
/// Pause time
|
||||||
|
PT OFFSET(16) NUMBITS(16) [],
|
||||||
|
/// Disable zero-quanta pause
|
||||||
|
DZPQ OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// Pause low threshold
|
||||||
|
PLT OFFSET(4) NUMBITS(3) [],
|
||||||
|
/// Transmit flow control enable
|
||||||
|
TFE OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Flow control busy or backpressure activate
|
||||||
|
FCB_BPA OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACRXFCR [
|
||||||
|
/// Unicast packet detect
|
||||||
|
UP OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// Rx flow control enable
|
||||||
|
RFE OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACRXQC0R [
|
||||||
|
/// Rx queue 1 enable
|
||||||
|
RXQ1EN OFFSET(2) NUMBITS(2) [
|
||||||
|
Disable = 0b00,
|
||||||
|
EnableAV = 0b01,
|
||||||
|
Enable = 0b10,
|
||||||
|
],
|
||||||
|
/// Rx queue 0 enable
|
||||||
|
RXQ0EN OFFSET(0) NUMBITS(2) [
|
||||||
|
Disable = 0b00,
|
||||||
|
EnableAV = 0b01,
|
||||||
|
Enable = 0b10,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACISR [
|
||||||
|
/// Rx status interrupt
|
||||||
|
RXSTSIS OFFSET(14) NUMBITS(1) [],
|
||||||
|
/// Tx status interrupt
|
||||||
|
TXSTSIS OFFSET(13) NUMBITS(1) [],
|
||||||
|
/// Timestamp interrupt
|
||||||
|
TSIS OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// MMC Tx interrupt
|
||||||
|
MMCTXIS OFFSET(10) NUMBITS(1) [],
|
||||||
|
/// MMC Rx interrupt
|
||||||
|
MMCRXIS OFFSET(9) NUMBITS(1) [],
|
||||||
|
/// MMC interrupt
|
||||||
|
MMCIS OFFSET(8) NUMBITS(1) [],
|
||||||
|
/// LPI interrupt
|
||||||
|
LPIIS OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// PMT interrupt
|
||||||
|
PMTIS OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// PHY interrupt
|
||||||
|
PHYIS OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// RGMII interrupt
|
||||||
|
RGSMIIIS OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACIER [
|
||||||
|
/// Rx status interrupt enable
|
||||||
|
RXSTSIE OFFSET(14) NUMBITS(1) [],
|
||||||
|
/// Tx status interrupt enable
|
||||||
|
TXSTSIE OFFSET(13) NUMBITS(1) [],
|
||||||
|
/// Timestamp interrupt enable
|
||||||
|
TSIE OFFSET(12) NUMBITS(1) [],
|
||||||
|
/// LPI interrupt enable
|
||||||
|
LPIIE OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// PMT interrupt enable
|
||||||
|
PMTIE OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// PHY interrupt enable
|
||||||
|
PHYIE OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// RGMII interrupt enable
|
||||||
|
RGSMIIIE OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACPHYCSR [
|
||||||
|
/// Link status
|
||||||
|
LNKSTS OFFSET(19) NUMBITS(1) [
|
||||||
|
Down = 0,
|
||||||
|
Up = 1,
|
||||||
|
],
|
||||||
|
/// Link speed
|
||||||
|
LNKSPEED OFFSET(17) NUMBITS(2) [
|
||||||
|
Speed2_5MHz = 0b00,
|
||||||
|
Speed25MHz = 0b01,
|
||||||
|
Speed125MHz = 0b10,
|
||||||
|
],
|
||||||
|
/// Link mode
|
||||||
|
LNKMOD OFFSET(16) NUMBITS(1) [
|
||||||
|
HalfDuplex = 0,
|
||||||
|
FullDuplex = 1,
|
||||||
|
],
|
||||||
|
/// Link up or down
|
||||||
|
///
|
||||||
|
/// This bit indicates whether the link is up or down during transmission of configuration
|
||||||
|
/// in the RGMII interface
|
||||||
|
LUD OFFSET(1) NUMBITS(1) [
|
||||||
|
Down = 0,
|
||||||
|
Up = 1,
|
||||||
|
],
|
||||||
|
/// Transmit configuration in RGMII
|
||||||
|
TC OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACMDIOAR [
|
||||||
|
/// Preamble suppress enable
|
||||||
|
///
|
||||||
|
/// If set, SMA suppresses the 32-bit preamble and transmits MDIO frames with only 1
|
||||||
|
/// preamble bit
|
||||||
|
PSE OFFSET(27) NUMBITS(1) [],
|
||||||
|
/// Back to back transactions
|
||||||
|
///
|
||||||
|
/// If set and the NTC has value greater than 0, the MAC informs the completion of a read
|
||||||
|
/// or write command at the end of frame transfer. Must not be set with NTC=0.
|
||||||
|
BTB OFFSET(26) NUMBITS(1) [],
|
||||||
|
/// Physical layer address
|
||||||
|
///
|
||||||
|
/// In Clause 22, indicates a PHY device the MAC is addressing.
|
||||||
|
PA OFFSET(21) NUMBITS(5) [],
|
||||||
|
/// Register/Device address
|
||||||
|
///
|
||||||
|
/// In Clause 22, selects the PHY register
|
||||||
|
RDA OFFSET(16) NUMBITS(5) [],
|
||||||
|
/// Number of trailing clocks
|
||||||
|
NTC OFFSET(12) NUMBITS(3) [],
|
||||||
|
/// CSR clock range
|
||||||
|
CR OFFSET(8) NUMBITS(4) [
|
||||||
|
CSR_20_TO_35_MHZ = 0b0010,
|
||||||
|
],
|
||||||
|
/// Skip address packet
|
||||||
|
///
|
||||||
|
/// If set, the SMA does not send the address packets before read, write or post-read
|
||||||
|
/// increment address packets. Only valid with C45E set.
|
||||||
|
SKAP OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// GMII operation command
|
||||||
|
GOC OFFSET(2) NUMBITS(2) [
|
||||||
|
Write = 0b01,
|
||||||
|
C45EPostReadIncrement = 0b10,
|
||||||
|
Read = 0b11
|
||||||
|
],
|
||||||
|
/// Clause 45 PHY enable
|
||||||
|
C45E OFFSET(1) NUMBITS(1) [],
|
||||||
|
/// GMII busy
|
||||||
|
GB OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACMDIODR [
|
||||||
|
/// Register address
|
||||||
|
///
|
||||||
|
/// Specifies the PHY register when used with Clause 45
|
||||||
|
RA OFFSET(16) NUMBITS(16) [],
|
||||||
|
/// GMII data
|
||||||
|
GD OFFSET(0) NUMBITS(16) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MACAiHR [
|
||||||
|
/// MAC address enable bit. Should always be set to 1 for MAC address 0.
|
||||||
|
AE OFFSET(31) NUMBITS(1) [],
|
||||||
|
ADDR5 OFFSET(8) NUMBITS(8) [],
|
||||||
|
ADDR4 OFFSET(0) NUMBITS(8) [],
|
||||||
|
],
|
||||||
|
pub MACAiLR [
|
||||||
|
ADDR3 OFFSET(24) NUMBITS(8) [],
|
||||||
|
ADDR2 OFFSET(16) NUMBITS(8) [],
|
||||||
|
ADDR1 OFFSET(8) NUMBITS(8) [],
|
||||||
|
ADDR0 OFFSET(0) NUMBITS(8) [],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub MacRegs {
|
||||||
|
/// Operating mode configuration register
|
||||||
|
///
|
||||||
|
/// Reset value: 0x0000 8000
|
||||||
|
///
|
||||||
|
/// Established the operating mode of the MAC.
|
||||||
|
(0x000 => pub MACCR: ReadWrite<u32, MACCR::Register>),
|
||||||
|
/// Extended operating mode configuration register
|
||||||
|
///
|
||||||
|
/// XXX
|
||||||
|
(0x004 => pub MACECR: ReadWrite<u32>),
|
||||||
|
/// Packet filtering control register
|
||||||
|
(0x008 => pub MACPFR: ReadWrite<u32, MACPFR::Register>),
|
||||||
|
/// Watchdog timeout register
|
||||||
|
(0x00C => pub MACWTR: ReadWrite<u32>),
|
||||||
|
/// Hash table 0 register
|
||||||
|
(0x010 => pub MACHT0R: ReadWrite<u32>),
|
||||||
|
/// Hash table 1 register
|
||||||
|
(0x014 => pub MACHT1R: ReadWrite<u32>),
|
||||||
|
(0x018 => _0),
|
||||||
|
/// VLAN tag register
|
||||||
|
(0x050 => pub MACVTR: ReadWrite<u32>),
|
||||||
|
(0x054 => _1),
|
||||||
|
/// VLAN hash table register
|
||||||
|
(0x058 => pub MACVHTR: ReadWrite<u32>),
|
||||||
|
(0x05C => _2),
|
||||||
|
/// VLAN inclusion register
|
||||||
|
(0x060 => pub MACVIR: ReadWrite<u32>),
|
||||||
|
/// Inner VLAN inclusion register
|
||||||
|
(0x064 => pub MACIVIR: ReadWrite<u32>),
|
||||||
|
(0x068 => _3),
|
||||||
|
/// Tx queue 0 flow control register
|
||||||
|
(0x070 => pub MACQ0TXFCR: ReadWrite<u32, MACQ0TXFCR::Register>),
|
||||||
|
(0x074 => _4),
|
||||||
|
/// Rx flow control register
|
||||||
|
(0x090 => pub MACRXFCR: ReadWrite<u32, MACRXFCR::Register>),
|
||||||
|
/// Rx queue control register
|
||||||
|
(0x094 => pub MACRXQCR: ReadWrite<u32>),
|
||||||
|
(0x098 => _5),
|
||||||
|
/// Rx queue control 0 register
|
||||||
|
(0x0A0 => pub MACRXQC0R: ReadWrite<u32, MACRXQC0R::Register>),
|
||||||
|
/// Rx queue control 1 register
|
||||||
|
(0x0A4 => pub MACRXQC1R: ReadWrite<u32>),
|
||||||
|
/// Rx queue control 2 register
|
||||||
|
(0x0A8 => pub MACRXQC2R: ReadWrite<u32>),
|
||||||
|
(0x0AC => _6),
|
||||||
|
/// Interrupt status register
|
||||||
|
(0x0B0 => pub MACISR: ReadWrite<u32, MACISR::Register>),
|
||||||
|
/// Interrupt enable register
|
||||||
|
(0x0B4 => pub MACIER: ReadWrite<u32, MACIER::Register>),
|
||||||
|
/// Rx/Tx status register
|
||||||
|
(0x0B8 => pub MACRXTXSR: ReadWrite<u32>),
|
||||||
|
(0x0BC => _7),
|
||||||
|
/// PMT control status register
|
||||||
|
(0x0C0 => pub MACPCSR: ReadWrite<u32>),
|
||||||
|
/// Remote wakeup packet filter register
|
||||||
|
(0x0C4 => pub MACRWKPFR: ReadWrite<u32>),
|
||||||
|
(0x0C8 => _8),
|
||||||
|
/// LPI control and status register
|
||||||
|
(0x0D0 => pub MACLCSR: ReadWrite<u32>),
|
||||||
|
/// LPI timers control register
|
||||||
|
(0x0D4 => pub MACLTCR: ReadWrite<u32>),
|
||||||
|
/// Tx LPI entry timer
|
||||||
|
(0x0D8 => pub MACLETR: ReadWrite<u32>),
|
||||||
|
/// One-microsecond-tick counter register
|
||||||
|
(0x0DC => pub MAC1USTCR: ReadWrite<u32>),
|
||||||
|
(0x0E0 => _9),
|
||||||
|
/// PHYIF control and status register
|
||||||
|
(0x0F8 => pub MACPHYCSR: ReadWrite<u32, MACPHYCSR::Register>),
|
||||||
|
(0x0FC => _10),
|
||||||
|
/// Version register
|
||||||
|
(0x110 => pub MACVR: ReadOnly<u32>),
|
||||||
|
/// Debug register
|
||||||
|
(0x114 => pub MACDR: ReadOnly<u32>),
|
||||||
|
(0x118 => _11),
|
||||||
|
/// HW feature 0 register
|
||||||
|
(0x11C => pub MACHWF0R: ReadWrite<u32>),
|
||||||
|
/// HW feature 1 register
|
||||||
|
(0x120 => pub MACHWF1R: ReadWrite<u32>),
|
||||||
|
/// HW feature 2 register
|
||||||
|
(0x124 => pub MACHWF2R: ReadWrite<u32>),
|
||||||
|
/// HW feature 3 register
|
||||||
|
(0x128 => pub MACHWF3R: ReadWrite<u32>),
|
||||||
|
(0x12C => _12),
|
||||||
|
/// MDIO address register
|
||||||
|
(0x200 => pub MACMDIOAR: ReadWrite<u32, MACMDIOAR::Register>),
|
||||||
|
/// MDIO data register
|
||||||
|
(0x204 => pub MACMDIODR: ReadWrite<u32, MACMDIODR::Register>),
|
||||||
|
(0x208 => _13),
|
||||||
|
/// ARP address register
|
||||||
|
(0x210 => pub MACARPAR: ReadWrite<u32>),
|
||||||
|
(0x214 => _14),
|
||||||
|
/// CSR software control register
|
||||||
|
(0x230 => pub MACCSRSWCR: ReadWrite<u32>),
|
||||||
|
(0x234 => _15),
|
||||||
|
/// MAC address 0 high register
|
||||||
|
(0x300 => pub MACA0HR: ReadWrite<u32, MACAiHR::Register>),
|
||||||
|
/// MAC address 0 low register
|
||||||
|
(0x304 => pub MACA0LR: ReadWrite<u32, MACAiLR::Register>),
|
||||||
|
/// MAC address 1 high register
|
||||||
|
(0x308 => pub MACA1HR: ReadWrite<u32>),
|
||||||
|
/// MAC address 1 low register
|
||||||
|
(0x30C => pub MACA1LR: ReadWrite<u32>),
|
||||||
|
/// MAC address 2 high register
|
||||||
|
(0x310 => pub MACA2HR: ReadWrite<u32>),
|
||||||
|
/// MAC address 2 low register
|
||||||
|
(0x314 => pub MACA2LR: ReadWrite<u32>),
|
||||||
|
/// MAC address 3 high register
|
||||||
|
(0x318 => pub MACA3HR: ReadWrite<u32>),
|
||||||
|
/// MAC address 3 low register
|
||||||
|
(0x31C => pub MACA3LR: ReadWrite<u32>),
|
||||||
|
(0x320 => _16),
|
||||||
|
/// MMC control register
|
||||||
|
(0x700 => pub MMC_CONTROL: ReadWrite<u32>),
|
||||||
|
/// MMC Rx interrupt register
|
||||||
|
(0x704 => pub MMC_RX_INTERRUPT: ReadWrite<u32>),
|
||||||
|
/// MMC Tx interrupt register
|
||||||
|
(0x708 => pub MMC_TX_INTERRUPT: ReadWrite<u32>),
|
||||||
|
/// MMC Rx interrupt mask register
|
||||||
|
(0x70C => pub MMC_RX_INTERRUPT_MASK: ReadWrite<u32>),
|
||||||
|
/// MMC Tx interrupt mask register
|
||||||
|
(0x710 => pub MMC_TX_INTERRUPT_MASK: ReadWrite<u32>),
|
||||||
|
(0x714 => _17),
|
||||||
|
(0xC00 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MacRegs {
|
||||||
|
fn mdio_wait_busy(&self) -> Result<(), Error> {
|
||||||
|
let mut timeout = 10000;
|
||||||
|
while timeout > 0 && self.MACMDIOAR.matches_all(MACMDIOAR::GB::SET) {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
timeout -= 1;
|
||||||
|
}
|
||||||
|
if timeout == 0 {
|
||||||
|
Err(Error::TimedOut)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mdio_read_c45(
|
||||||
|
&self,
|
||||||
|
phy_addr: u8,
|
||||||
|
mmd_addr: u8,
|
||||||
|
mii_reg: u8,
|
||||||
|
csr_clk_range: u8,
|
||||||
|
) -> Result<u16, Error> {
|
||||||
|
self.mdio_wait_busy()?;
|
||||||
|
self.MACMDIODR.write(MACMDIODR::RA.val(mii_reg as u32));
|
||||||
|
self.MACMDIOAR.write(
|
||||||
|
MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||||
|
+ MACMDIOAR::GOC::Read
|
||||||
|
+ MACMDIOAR::PA.val(phy_addr as u32)
|
||||||
|
+ MACMDIOAR::RDA.val(mmd_addr as u32)
|
||||||
|
+ MACMDIOAR::C45E::SET
|
||||||
|
+ MACMDIOAR::GB::SET,
|
||||||
|
);
|
||||||
|
self.mdio_wait_busy()?;
|
||||||
|
Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mdio_read_c22(
|
||||||
|
&self,
|
||||||
|
mii_addr: u8,
|
||||||
|
mii_reg: u8,
|
||||||
|
csr_clk_range: u8,
|
||||||
|
) -> Result<u16, Error> {
|
||||||
|
self.mdio_wait_busy()?;
|
||||||
|
self.MACMDIOAR.write(
|
||||||
|
MACMDIOAR::GOC::Read
|
||||||
|
+ MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||||
|
+ MACMDIOAR::PA.val(mii_addr as u32)
|
||||||
|
+ MACMDIOAR::RDA.val(mii_reg as u32)
|
||||||
|
+ MACMDIOAR::GB::SET,
|
||||||
|
);
|
||||||
|
self.mdio_wait_busy()?;
|
||||||
|
Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mdio_write_c22(
|
||||||
|
&self,
|
||||||
|
mii_addr: u8,
|
||||||
|
mii_reg: u8,
|
||||||
|
value: u16,
|
||||||
|
csr_clk_range: u8,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.mdio_wait_busy()?;
|
||||||
|
self.MACMDIODR.write(MACMDIODR::GD.val(value as u32));
|
||||||
|
self.MACMDIOAR.write(
|
||||||
|
MACMDIOAR::GOC::Write
|
||||||
|
+ MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||||
|
+ MACMDIOAR::PA.val(mii_addr as u32)
|
||||||
|
+ MACMDIOAR::RDA.val(mii_reg as u32)
|
||||||
|
+ MACMDIOAR::GB::SET,
|
||||||
|
);
|
||||||
|
self.mdio_wait_busy()
|
||||||
|
}
|
||||||
|
}
|
16
kernel/driver/net/stmmac/src/regs/mod.rs
Normal file
16
kernel/driver/net/stmmac/src/regs/mod.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use tock_registers::register_structs;
|
||||||
|
|
||||||
|
pub mod dma;
|
||||||
|
pub mod mac;
|
||||||
|
pub mod mtl;
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub Regs {
|
||||||
|
(0x0000 => pub MAC: mac::MacRegs),
|
||||||
|
(0x0C00 => pub MTL: mtl::MtlRegs),
|
||||||
|
(0x1000 => pub DMA: dma::DmaRegs),
|
||||||
|
(0x1200 => @END),
|
||||||
|
}
|
||||||
|
}
|
132
kernel/driver/net/stmmac/src/regs/mtl.rs
Normal file
132
kernel/driver/net/stmmac/src/regs/mtl.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use tock_registers::{register_bitfields, register_structs, registers::ReadWrite};
|
||||||
|
|
||||||
|
register_bitfields! {
|
||||||
|
u32,
|
||||||
|
pub MTLOMR [
|
||||||
|
CNTCLR OFFSET(9) NUMBITS(1) [],
|
||||||
|
CNTPRST OFFSET(8) NUMBITS(1) [],
|
||||||
|
SCHALG OFFSET(5) NUMBITS(2) [
|
||||||
|
AlgWeightedRR = 0b00,
|
||||||
|
AlgStrictPrio = 0b11,
|
||||||
|
],
|
||||||
|
RAA OFFSET(2) NUMBITS(1) [
|
||||||
|
AlgStrictPrio = 0,
|
||||||
|
AlgWeightedPrio = 1
|
||||||
|
],
|
||||||
|
DTXSTS OFFSET(1) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MTLTXQiOMR [
|
||||||
|
TQS OFFSET(16) NUMBITS(4) [],
|
||||||
|
TTC OFFSET(4) NUMBITS(3) [],
|
||||||
|
TXQEN OFFSET(2) NUMBITS(2) [
|
||||||
|
Disable = 0b00,
|
||||||
|
EnableAv = 0b01,
|
||||||
|
Enable = 0b11,
|
||||||
|
],
|
||||||
|
TSF OFFSET(1) NUMBITS(1) [],
|
||||||
|
FTQ OFFSET(0) NUMBITS(1) [],
|
||||||
|
],
|
||||||
|
|
||||||
|
pub MTLRXQiOMR [
|
||||||
|
RQS OFFSET(20) NUMBITS(4) [],
|
||||||
|
/// Threshold for deactivating flow control
|
||||||
|
RFD OFFSET(14) NUMBITS(3) [
|
||||||
|
FullMinus1K = 0,
|
||||||
|
FullMinus1_5K = 1,
|
||||||
|
FullMinus2K = 2,
|
||||||
|
FullMinus2_5K = 3,
|
||||||
|
FullMinus3K = 4,
|
||||||
|
FullMinus3_5K = 5
|
||||||
|
],
|
||||||
|
/// Threshold for activating flow control. See [RFD].
|
||||||
|
RFA OFFSET(8) NUMBITS(3) [],
|
||||||
|
/// Enable hardware flow control. When set, the flow control signal operation, based on the
|
||||||
|
/// fill-level of the Rx queue, is enabled.
|
||||||
|
EHFC OFFSET(7) NUMBITS(1) [],
|
||||||
|
/// Disable dropping of TCP/IP checksum error packets
|
||||||
|
DIS_TCP_EF OFFSET(6) NUMBITS(1) [],
|
||||||
|
/// Receive queue store and forward. When set, the Ethernet peripheral reads a packet from
|
||||||
|
/// the Rx queue only after the complete packet has been written to it, ignoring the RTC
|
||||||
|
/// field.
|
||||||
|
RSF OFFSET(5) NUMBITS(1) [],
|
||||||
|
/// Forward error packets. When set, the Rx queue does not drop the packets with CRC
|
||||||
|
/// errors, watchdog timeouts, overflows and receive errors.
|
||||||
|
FEP OFFSET(4) NUMBITS(1) [],
|
||||||
|
/// Forward undersized good packets. When set, the Rx queue does not drop packets with no
|
||||||
|
/// errors, but with a length of less than 64 bytes.
|
||||||
|
FUP OFFSET(3) NUMBITS(1) [],
|
||||||
|
/// Rx threshold level
|
||||||
|
RTC OFFSET(0) NUMBITS(2) [
|
||||||
|
Threshold64 = 0b00,
|
||||||
|
Threshold32 = 0b01,
|
||||||
|
Threshold96 = 0b10,
|
||||||
|
Threshold128 = 0b11,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub MtlRegs {
|
||||||
|
/// MTL operating mode register
|
||||||
|
(0x000 => pub MTLOMR: ReadWrite<u32, MTLOMR::Register>),
|
||||||
|
(0x004 => _0),
|
||||||
|
/// Interrupt status register
|
||||||
|
(0x020 => pub MTLISR: ReadWrite<u32>),
|
||||||
|
(0x024 => _1),
|
||||||
|
/// Tx queue 0 operating mode register
|
||||||
|
(0x100 => pub MTLTXQ0OMR: ReadWrite<u32, MTLTXQiOMR::Register>),
|
||||||
|
/// Tx queue 0 underflow register
|
||||||
|
(0x104 => pub MTLTXQ0UR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 0 debug register
|
||||||
|
(0x108 => pub MTLTXQ0DR: ReadWrite<u32>),
|
||||||
|
(0x10C => _2),
|
||||||
|
/// Tx queue 0 ETS status register
|
||||||
|
(0x114 => pub MTLTXQ0ESR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 0 quantum weight register
|
||||||
|
(0x118 => pub MTLTXQ0QWR: ReadWrite<u32>),
|
||||||
|
(0x11C => _3),
|
||||||
|
/// Queue 0 interrupt control status register
|
||||||
|
(0x12C => pub MTLQ0ICSR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 0 operating mode register
|
||||||
|
(0x130 => pub MTLRXQ0OMR: ReadWrite<u32, MTLRXQiOMR::Register>),
|
||||||
|
/// Rx queue 0 missed packet and overflow counter register
|
||||||
|
(0x134 => pub MTLRXQ0MPOCR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 0 debug register
|
||||||
|
(0x138 => pub MTLRXQ0DR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 0 control register
|
||||||
|
(0x13C => pub MTLRXQ0CR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 operating mode register
|
||||||
|
(0x140 => pub MTLTXQ1OMR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 underflow register
|
||||||
|
(0x144 => pub MTLTXQ1UR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 debug register
|
||||||
|
(0x148 => pub MTLTXQ1DR: ReadWrite<u32>),
|
||||||
|
(0x14C => _4),
|
||||||
|
/// Tx queue 1 ETS control register
|
||||||
|
(0x150 => pub MTLTXQ1ECR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 ETS status register
|
||||||
|
(0x154 => pub MTLTXQ1ESR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 quantum weight register
|
||||||
|
(0x158 => pub MTLTXQ1QWR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 send slope credit register
|
||||||
|
(0x15C => pub MTLTXQ1SSCR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 hiCredit register
|
||||||
|
(0x160 => pub MTLTXQ1HCR: ReadWrite<u32>),
|
||||||
|
/// Tx queue 1 loCredit register
|
||||||
|
(0x164 => pub MTLTXQ1LCR: ReadWrite<u32>),
|
||||||
|
(0x168 => _5),
|
||||||
|
/// Queue 1 interrupt control status register
|
||||||
|
(0x16C => pub MTLQ1ICSR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 1 operating mode register
|
||||||
|
(0x170 => pub MTLRXQ1OMR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 1 missed packet and overflow counter register
|
||||||
|
(0x174 => pub MTLRXQ1MPOCR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 1 debug register
|
||||||
|
(0x178 => pub MTLRXQ1DR: ReadWrite<u32>),
|
||||||
|
/// Rx queue 1 control register
|
||||||
|
(0x17C => pub MTLRXQ1CR: ReadWrite<u32>),
|
||||||
|
(0x180 => _6),
|
||||||
|
(0x400 => @END),
|
||||||
|
}
|
||||||
|
}
|
245
kernel/driver/net/stmmac/src/ring.rs
Normal file
245
kernel/driver/net/stmmac/src/ring.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use libk::{debug, error::Error};
|
||||||
|
use libk_mm::{
|
||||||
|
address::{AsPhysicalAddress, PhysicalAddress},
|
||||||
|
PageBox,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TxRing {
|
||||||
|
entries: PageBox<[TxDescriptor]>,
|
||||||
|
buffers: Vec<Option<PageBox<[u8]>>>,
|
||||||
|
|
||||||
|
wr: usize,
|
||||||
|
rd: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RxRing {
|
||||||
|
entries: PageBox<[RxDescriptor]>,
|
||||||
|
buffers: Vec<PageBox<[u8]>>,
|
||||||
|
|
||||||
|
rd: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TxDescriptor {
|
||||||
|
tdes0: u32,
|
||||||
|
tdes1: u32,
|
||||||
|
tdes2: u32,
|
||||||
|
tdes3: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RxDescriptor {
|
||||||
|
rdes0: u32,
|
||||||
|
rdes1: u32,
|
||||||
|
rdes2: u32,
|
||||||
|
rdes3: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxRing {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
|
||||||
|
let entries = PageBox::new_slice(TxDescriptor::empty(), capacity)?;
|
||||||
|
let buffers = (0..capacity).map(|_| None).collect();
|
||||||
|
Ok(Self {
|
||||||
|
entries,
|
||||||
|
buffers,
|
||||||
|
|
||||||
|
wr: 0,
|
||||||
|
rd: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_base(&self) -> PhysicalAddress {
|
||||||
|
unsafe { self.entries.as_physical_address() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capacity(&self) -> usize {
|
||||||
|
self.entries.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn can_xmit(&self) -> bool {
|
||||||
|
self.wr.wrapping_add(1) != self.rd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outstanding_tx(&self) -> bool {
|
||||||
|
self.wr != self.rd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_xmit(&mut self, frame: PageBox<[u8]>) -> Result<usize, Error> {
|
||||||
|
if !self.can_xmit() {
|
||||||
|
return Err(Error::WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
let address = unsafe { PageBox::as_physical_address(&frame) };
|
||||||
|
let frame_len = frame.len();
|
||||||
|
|
||||||
|
let capacity = self.entries.len();
|
||||||
|
let index = self.wr % capacity;
|
||||||
|
assert!(self.buffers[index].is_none());
|
||||||
|
|
||||||
|
self.entries[index].setup_tx(address, frame_len, true)?;
|
||||||
|
self.buffers[index] = Some(frame);
|
||||||
|
self.wr = self.wr.wrapping_add(1);
|
||||||
|
|
||||||
|
Ok(self.wr % self.capacity())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume(&mut self) -> Result<usize, Error> {
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let index = self.rd % self.entries.len();
|
||||||
|
let entry = &self.entries[index];
|
||||||
|
|
||||||
|
if self.rd == self.wr {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(status) = entry.tx_status() {
|
||||||
|
if status != 0 {
|
||||||
|
log::warn!("tx_ring[{index}] error: {status:#x}");
|
||||||
|
}
|
||||||
|
let _ = self.buffers[index].take().unwrap();
|
||||||
|
self.rd = self.rd.wrapping_add(1);
|
||||||
|
count += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxDescriptor {
|
||||||
|
const TDES3_OWN: u32 = 1 << 31;
|
||||||
|
const TDES3_FD: u32 = 1 << 29;
|
||||||
|
const TDES3_LD: u32 = 1 << 28;
|
||||||
|
const TDES2_IOC: u32 = 1 << 31;
|
||||||
|
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
tdes0: 0,
|
||||||
|
tdes1: 0,
|
||||||
|
tdes2: 0,
|
||||||
|
tdes3: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_status(&self) -> Option<u32> {
|
||||||
|
if self.tdes3 & Self::TDES3_OWN == 0 {
|
||||||
|
Some(self.tdes3 & !(0xFFFF << 16))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_tx(
|
||||||
|
&mut self,
|
||||||
|
frame: PhysicalAddress,
|
||||||
|
frame_len: usize,
|
||||||
|
ioc: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let tdes0 = frame.try_into_u32().map_err(|_| Error::InvalidArgument)?;
|
||||||
|
if frame_len & !0x3FFF != 0 {
|
||||||
|
return Err(Error::InvalidArgument);
|
||||||
|
}
|
||||||
|
let mut tdes2 = frame_len as u32;
|
||||||
|
if ioc {
|
||||||
|
tdes2 |= Self::TDES2_IOC;
|
||||||
|
}
|
||||||
|
let tdes3 = Self::TDES3_OWN | Self::TDES3_FD | Self::TDES3_LD;
|
||||||
|
|
||||||
|
self.tdes0 = tdes0;
|
||||||
|
self.tdes1 = 0;
|
||||||
|
self.tdes2 = tdes2;
|
||||||
|
self.tdes3 = tdes3;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxRing {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Result<Self, Error> {
|
||||||
|
let mut entries = PageBox::new_slice(RxDescriptor::empty(), capacity)?;
|
||||||
|
let buffers = (0..capacity)
|
||||||
|
.map(|_| PageBox::new_slice(0, 4096))
|
||||||
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
|
for i in 0..capacity {
|
||||||
|
let address = unsafe { buffers[i].as_physical_address() };
|
||||||
|
entries[i].setup_rx(address, true)?;
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
buffers,
|
||||||
|
entries,
|
||||||
|
|
||||||
|
rd: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_base(&self) -> PhysicalAddress {
|
||||||
|
unsafe { self.entries.as_physical_address() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume<F: Fn(PageBox<[u8]>)>(&mut self, packet_handler: F) -> Result<usize, Error> {
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let index = self.rd % self.entries.len();
|
||||||
|
let entry = &mut self.entries[index];
|
||||||
|
|
||||||
|
if let Some(_) = entry.rx_completed() {
|
||||||
|
// 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 buffer = mem::replace(&mut self.buffers[index], PageBox::new_slice(0, 4096)?);
|
||||||
|
let new_buffer_address = unsafe { self.buffers[index].as_physical_address() };
|
||||||
|
packet_handler(buffer);
|
||||||
|
entry.setup_rx(new_buffer_address, true)?;
|
||||||
|
self.rd = self.rd.wrapping_add(1);
|
||||||
|
count += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxDescriptor {
|
||||||
|
const RDES3_OWN: u32 = 1 << 31;
|
||||||
|
const RDES3_IOC: u32 = 1 << 30;
|
||||||
|
const RDES3_BUF1V: u32 = 1 << 24;
|
||||||
|
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
rdes0: 0,
|
||||||
|
rdes1: 0,
|
||||||
|
rdes2: 0,
|
||||||
|
rdes3: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rx_completed(&self) -> Option<usize> {
|
||||||
|
if self.rdes3 & Self::RDES3_OWN == 0 {
|
||||||
|
Some((self.rdes3 & 0x7FFF) as usize)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_rx(&mut self, buffer: PhysicalAddress, ioc: bool) -> Result<(), Error> {
|
||||||
|
self.rdes0 = buffer.try_into_u32().map_err(|_| Error::InvalidArgument)?;
|
||||||
|
self.rdes1 = 0;
|
||||||
|
self.rdes2 = 0;
|
||||||
|
self.rdes3 = Self::RDES3_BUF1V;
|
||||||
|
if ioc {
|
||||||
|
self.rdes3 |= Self::RDES3_IOC;
|
||||||
|
}
|
||||||
|
self.rdes3 |= Self::RDES3_OWN;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use device_api::interrupt::FullIrq;
|
use device_api::interrupt::FullIrq;
|
||||||
|
use fdt_rs::prelude::PropReader;
|
||||||
|
use yggdrasil_abi::net::MacAddress;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::{lookup_phandle, map_interrupt_at},
|
driver::{lookup_phandle, map_interrupt_at},
|
||||||
@ -99,3 +101,19 @@ pub fn pcie_interrupt_map(
|
|||||||
offset: 0,
|
offset: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads the configured MAC address from the node's fields in the following order:
|
||||||
|
///
|
||||||
|
/// * "mac-address"
|
||||||
|
/// * "local-mac-address"
|
||||||
|
/// * "address"
|
||||||
|
///
|
||||||
|
/// If none are present, [None] is returned.
|
||||||
|
pub fn read_mac_address(node: &Arc<Node>) -> Option<MacAddress> {
|
||||||
|
let property = node
|
||||||
|
.property("mac-address")
|
||||||
|
.or_else(|| node.property("local-mac-address"))
|
||||||
|
.or_else(|| node.property("address"))?;
|
||||||
|
let mac_bytes: [u8; 6] = property.raw().try_into().ok()?;
|
||||||
|
Some(MacAddress::from(mac_bytes))
|
||||||
|
}
|
||||||
|
163
kernel/src/device/clock/jh7110_aoncrg.rs
Normal file
163
kernel/src/device/clock/jh7110_aoncrg.rs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
//! Starfive JH7110 Always-on CRG
|
||||||
|
use abi::error::Error;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use device_api::{
|
||||||
|
clock::{ClockController, ClockHandle, ResetController, ResetHandle},
|
||||||
|
device::Device,
|
||||||
|
};
|
||||||
|
use device_tree::{
|
||||||
|
driver::{
|
||||||
|
device_tree_driver, DeviceTreeClockController, DeviceTreeResetController, Node,
|
||||||
|
ProbeContext,
|
||||||
|
},
|
||||||
|
DeviceTreePropertyRead, TProp,
|
||||||
|
};
|
||||||
|
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||||
|
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||||
|
use tock_registers::{
|
||||||
|
interfaces::{Readable, Writeable},
|
||||||
|
register_structs,
|
||||||
|
registers::ReadWrite,
|
||||||
|
};
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
Regs {
|
||||||
|
(0x000 => CLOCKS: [ReadWrite<u32>; 14]),
|
||||||
|
(0x038 => RESETS: ReadWrite<u32>),
|
||||||
|
(0x03C => AONCRG_RESET_STATUS: ReadWrite<u32>),
|
||||||
|
(0x040 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum ClockRegister {
|
||||||
|
Gate(u32),
|
||||||
|
Unimp,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// JH7110 AONCRG driver
|
||||||
|
pub struct Aoncrg {
|
||||||
|
base: PhysicalAddress,
|
||||||
|
mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Aoncrg {
|
||||||
|
fn ensure_init(&self) -> Result<&IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>, Error> {
|
||||||
|
self.mapping.or_try_init_with(|| {
|
||||||
|
unsafe { DeviceMemoryIo::map(self.base, Default::default()) }.map(IrqSafeSpinlock::new)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_clock_index(index: u32) -> Option<(usize, ClockRegister)> {
|
||||||
|
const CLOCK_MAP: &[(&'static str, usize, ClockRegister)] = &[
|
||||||
|
("clk_osc", 0, ClockRegister::Unimp),
|
||||||
|
("aon_apb_func_clk", 1, ClockRegister::Unimp),
|
||||||
|
("ahb_gmac5_clk", 2, ClockRegister::Gate(31)),
|
||||||
|
("axi_gmac5_clk", 3, ClockRegister::Gate(31)),
|
||||||
|
("axi_gmac0_rmii_rtx_clk", 4, ClockRegister::Unimp),
|
||||||
|
("gmac5_axi64_tx_clk", 5, ClockRegister::Unimp),
|
||||||
|
("gmac5_axi64_clk_tx_inv", 6, ClockRegister::Gate(30)),
|
||||||
|
];
|
||||||
|
let (_, offset, mode) = CLOCK_MAP.get(index as usize)?;
|
||||||
|
Some((*offset, *mode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Aoncrg {
|
||||||
|
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
|
||||||
|
log::warn!("TODO: init jh7110-aoncrg @ {:#x}", self.base);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self) -> &str {
|
||||||
|
"Starfive JH7110 AONCRG"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClockController for Aoncrg {
|
||||||
|
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||||
|
let (offset, mode) = clock
|
||||||
|
.and_then(Self::map_clock_index)
|
||||||
|
.ok_or(Error::InvalidArgument)
|
||||||
|
.inspect_err(|_| log::warn!("jh7110-aoncrg: cannot map clock {clock:?}"))?;
|
||||||
|
|
||||||
|
let mapping = self.ensure_init()?;
|
||||||
|
let regs = mapping.lock();
|
||||||
|
match mode {
|
||||||
|
ClockRegister::Gate(shift) => {
|
||||||
|
log::info!("jh7110-aoncrg: enable clock {clock:?}: reg={offset}, bit={shift}");
|
||||||
|
regs.CLOCKS[offset].set(1 << shift);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||||
|
log::warn!("jh7110: disable clock {clock:?}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResetController for Aoncrg {
|
||||||
|
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||||
|
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||||
|
let mapping = self.ensure_init()?;
|
||||||
|
let regs = mapping.lock();
|
||||||
|
let val = regs.RESETS.get();
|
||||||
|
regs.RESETS.set(val | (1 << reset));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||||
|
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||||
|
let mapping = self.ensure_init()?;
|
||||||
|
let regs = mapping.lock();
|
||||||
|
let val = regs.RESETS.get();
|
||||||
|
regs.RESETS.set(val & !(1 << reset));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceTreeClockController for Aoncrg {
|
||||||
|
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> {
|
||||||
|
let cell = property.read_cell(offset, 1)? as u32;
|
||||||
|
Some((
|
||||||
|
ClockHandle {
|
||||||
|
parent: self,
|
||||||
|
clock: Some(cell),
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceTreeResetController for Aoncrg {
|
||||||
|
fn map_reset(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ResetHandle, usize)> {
|
||||||
|
let cell = property.read_cell(offset, 1)? as u32;
|
||||||
|
Some((
|
||||||
|
ResetHandle {
|
||||||
|
parent: self,
|
||||||
|
reset: Some(cell),
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_tree_driver! {
|
||||||
|
compatible: ["starfive,jh7110-aoncrg"],
|
||||||
|
driver: {
|
||||||
|
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||||
|
let base = node.map_base(context, 0)?;
|
||||||
|
let aoncrg = Arc::new(Aoncrg {
|
||||||
|
base,
|
||||||
|
mapping: OneTimeInit::new()
|
||||||
|
});
|
||||||
|
node.make_reset_controller(aoncrg.clone());
|
||||||
|
node.make_clock_controller(aoncrg.clone());
|
||||||
|
Some(aoncrg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,22 @@ use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
|||||||
|
|
||||||
const CLK_OSC: usize = 0;
|
const CLK_OSC: usize = 0;
|
||||||
|
|
||||||
|
// gmac0;
|
||||||
|
// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(3)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(2)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(109)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(6)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(111)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_aoncrg.rs:86: jh7110: deassert reset Some(0)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_aoncrg.rs:86: jh7110: deassert reset Some(1)
|
||||||
|
|
||||||
|
// gmac1:
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(98)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(97)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(102)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(106)
|
||||||
|
// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(107)
|
||||||
|
|
||||||
const CLK_UART0_CORE: u32 = 146;
|
const CLK_UART0_CORE: u32 = 146;
|
||||||
|
|
||||||
struct Syscrg {
|
struct Syscrg {
|
||||||
@ -48,9 +64,19 @@ impl Device for Syscrg {
|
|||||||
|
|
||||||
impl ClockController for Syscrg {
|
impl ClockController for Syscrg {
|
||||||
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||||
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}");
|
let regs = self.ensure_init()?;
|
||||||
|
match clock.ok_or(Error::InvalidArgument)? {
|
||||||
|
109 => {
|
||||||
|
regs.lock()[109] |= 1 << 31;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
111 => Ok(()),
|
||||||
|
_ => {
|
||||||
|
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}");
|
||||||
|
Err(Error::NotImplemented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||||
log::warn!("TODO: jh7110-syscrg: disable clock {clock:?}");
|
log::warn!("TODO: jh7110-syscrg: disable clock {clock:?}");
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
||||||
pub mod bcm2835_aux;
|
pub mod bcm2835_aux;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
pub mod jh7110_aoncrg;
|
||||||
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
pub mod jh7110_syscrg;
|
pub mod jh7110_syscrg;
|
||||||
|
|
||||||
|
@ -64,6 +64,9 @@ extern crate compiler_builtins;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||||
|
extern crate ygg_driver_net_stmmac;
|
||||||
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
@ -24,7 +24,7 @@ pub struct EthernetFrame {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
|
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct EtherType(u16);
|
pub struct EtherType(pub u16);
|
||||||
|
|
||||||
impl EtherType {
|
impl EtherType {
|
||||||
pub const ARP: Self = Self(0x0806);
|
pub const ARP: Self = Self(0x0806);
|
||||||
|
@ -73,10 +73,10 @@ struct DhcpMessage {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct DhcpOffer {
|
struct DhcpOffer {
|
||||||
router_address: Ipv4Addr,
|
router_address: Option<Ipv4Addr>,
|
||||||
server_address: Ipv4Addr,
|
server_address: Ipv4Addr,
|
||||||
your_address: Ipv4Addr,
|
your_address: Ipv4Addr,
|
||||||
subnet_mask: u32,
|
subnet_mask: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pad_to_align(buffer: &mut Vec<u8>) {
|
fn pad_to_align(buffer: &mut Vec<u8>) {
|
||||||
@ -239,7 +239,9 @@ impl DhcpMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn as_dhcp_acknowledge(&self, requested_address: Ipv4Addr) -> Option<()> {
|
fn as_dhcp_acknowledge(&self, requested_address: Ipv4Addr) -> Option<()> {
|
||||||
let ty = self.message_type()?;
|
let Some(ty) = self.message_type() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
if ty != DhcpMessageType::Acknowledge {
|
if ty != DhcpMessageType::Acknowledge {
|
||||||
return None;
|
return None;
|
||||||
@ -283,13 +285,11 @@ impl DhcpMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let router_address = router?;
|
|
||||||
let server_address = server?;
|
let server_address = server?;
|
||||||
let subnet_mask = subnet_mask?;
|
|
||||||
|
|
||||||
Some(DhcpOffer {
|
Some(DhcpOffer {
|
||||||
server_address,
|
server_address,
|
||||||
router_address,
|
router_address: router,
|
||||||
your_address: Ipv4Addr::from(yiaddr),
|
your_address: Ipv4Addr::from(yiaddr),
|
||||||
subnet_mask,
|
subnet_mask,
|
||||||
})
|
})
|
||||||
@ -464,6 +464,7 @@ fn attempt_request(
|
|||||||
op: 1,
|
op: 1,
|
||||||
htype: 1,
|
htype: 1,
|
||||||
hlen: 6,
|
hlen: 6,
|
||||||
|
flags: (1u16 << 15).to_be(),
|
||||||
xid: transaction_id.to_be(),
|
xid: transaction_id.to_be(),
|
||||||
chaddr: [0; 16],
|
chaddr: [0; 16],
|
||||||
cookie: 0x63825363u32.to_be(),
|
cookie: 0x63825363u32.to_be(),
|
||||||
@ -479,11 +480,11 @@ fn attempt_request(
|
|||||||
let offer = wait_for_dhcp_offer(poll, timer, socket)?;
|
let offer = wait_for_dhcp_offer(poll, timer, socket)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Got DHCP offer: address={} router={} server={} mask={}",
|
"Got DHCP offer: address={} router={:?} server={} mask={:?}",
|
||||||
offer.your_address,
|
offer.your_address,
|
||||||
offer.router_address,
|
offer.router_address,
|
||||||
offer.server_address,
|
offer.server_address,
|
||||||
Ipv4Addr::from(offer.subnet_mask)
|
offer.subnet_mask.map(Ipv4Addr::from)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send DHCP request
|
// Send DHCP request
|
||||||
@ -496,6 +497,7 @@ fn attempt_request(
|
|||||||
chaddr: [0; 16],
|
chaddr: [0; 16],
|
||||||
siaddr: u32::from(offer.server_address).to_be(),
|
siaddr: u32::from(offer.server_address).to_be(),
|
||||||
cookie: 0x63825363u32.to_be(),
|
cookie: 0x63825363u32.to_be(),
|
||||||
|
flags: (1u16 << 15).to_be(),
|
||||||
..DhcpMessageHeader::zeroed()
|
..DhcpMessageHeader::zeroed()
|
||||||
},
|
},
|
||||||
options: vec![
|
options: vec![
|
||||||
@ -541,11 +543,12 @@ fn request_address(interface: &str) -> Result<DhcpOffer, Error> {
|
|||||||
|
|
||||||
fn configure_address(interface: &str, offer: DhcpOffer) -> Result<(), Error> {
|
fn configure_address(interface: &str, offer: DhcpOffer) -> Result<(), Error> {
|
||||||
let mut netconf = NetConfig::open()?;
|
let mut netconf = NetConfig::open()?;
|
||||||
|
let router_address = offer.router_address.unwrap_or(offer.server_address);
|
||||||
netconf.set_interface_address(interface, IpAddr::V4(offer.your_address))?;
|
netconf.set_interface_address(interface, IpAddr::V4(offer.your_address))?;
|
||||||
netconf.add_route(
|
netconf.add_route(
|
||||||
interface,
|
interface,
|
||||||
SubnetAddr::V4(SubnetV4Addr::UNSPECIFIED),
|
SubnetAddr::V4(SubnetV4Addr::UNSPECIFIED),
|
||||||
Some(IpAddr::V4(offer.router_address)),
|
Some(router_address.into())
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user