stmmac: implement a basic stmmac driver

This commit is contained in:
Mark Poliakov 2025-01-27 10:31:21 +02:00
parent 24f1f41217
commit f2cfc9136a
17 changed files with 1818 additions and 53 deletions

129
Cargo.lock generated
View File

@ -187,9 +187,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.85"
version = "0.1.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
dependencies = [
"proc-macro2",
"quote",
@ -294,9 +294,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.16.0"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "bytemuck"
@ -326,9 +326,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.10"
version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"jobserver",
"libc",
@ -357,9 +357,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.27"
version = "4.5.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
dependencies = [
"clap_builder",
"clap_derive",
@ -367,9 +367,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.27"
version = "4.5.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
dependencies = [
"anstream",
"anstyle",
@ -379,9 +379,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.24"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
dependencies = [
"heck",
"proc-macro2",
@ -409,9 +409,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "compiler_builtins"
version = "0.1.144"
version = "0.1.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d18a7b7b5a56aa131e62314b4d862c9f6aa2860f615f3770094ec9064d7ec572"
checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311"
dependencies = [
"rustc-std-workspace-core",
]
@ -761,7 +761,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets",
]
[[package]]
@ -1040,9 +1052,9 @@ dependencies = [
[[package]]
name = "indicatif"
version = "0.17.9"
version = "0.17.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281"
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
dependencies = [
"console",
"number_prefix",
@ -1332,9 +1344,9 @@ dependencies = [
[[package]]
name = "libssh2-sys"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9"
dependencies = [
"cc",
"libc",
@ -1457,9 +1469,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.3"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
dependencies = [
"adler2",
]
@ -1511,9 +1523,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.2"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "openssl-probe"
@ -1523,9 +1535,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.104"
version = "0.9.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
dependencies = [
"cc",
"libc",
@ -1696,7 +1708,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
"getrandom 0.2.15",
]
[[package]]
@ -1903,9 +1915,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.137"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
dependencies = [
"itoa",
"memchr",
@ -2031,13 +2043,13 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.15.0"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
dependencies = [
"cfg-if",
"fastrand",
"getrandom",
"getrandom 0.3.1",
"once_cell",
"rustix",
"windows-sys",
@ -2135,9 +2147,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.19"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
@ -2156,9 +2168,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.22"
version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [
"indexmap",
"serde",
@ -2270,9 +2282,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.12.1"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0"
dependencies = [
"bytemuck",
]
@ -2307,9 +2319,9 @@ dependencies = [
[[package]]
name = "wait-timeout"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
dependencies = [
"libc",
]
@ -2330,6 +2342,15 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
@ -2525,9 +2546,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.25"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603"
dependencies = [
"memchr",
]
@ -2538,6 +2559,15 @@ version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.8.0",
]
[[package]]
name = "write16"
version = "1.0.0"
@ -2733,6 +2763,22 @@ dependencies = [
"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",
"ygg_driver_net_core",
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_nvme"
version = "0.1.0"
@ -2931,6 +2977,7 @@ dependencies = [
"ygg_driver_net_igbe",
"ygg_driver_net_loopback",
"ygg_driver_net_rtl81xx",
"ygg_driver_net_stmmac",
"ygg_driver_nvme",
"ygg_driver_pci",
"ygg_driver_usb",

View File

@ -60,6 +60,7 @@ kernel-arch-aarch64.workspace = true
[target.'cfg(target_arch = "riscv64")'.dependencies]
device-tree.workspace = true
kernel-arch-riscv64.workspace = true
ygg_driver_net_stmmac.path = "driver/net/stmmac"
[target.'cfg(target_arch = "x86_64")'.dependencies]
yboot-proto.workspace = true
@ -91,6 +92,7 @@ kernel-arch-aarch64.workspace = true
kernel-arch-riscv64.workspace = true
ygg_driver_acpi.path = "driver/acpi"
ygg_driver_net_stmmac.path = "driver/net/stmmac"
[features]
default = ["fb_console"]

View File

@ -70,6 +70,7 @@ pub fn handle(packet: L2Packet) {
match ty {
EtherType::ARP => l3::arp::handle_packet(packet),
EtherType::IPV4 => l3::ip::handle_v4_packet(packet),
EtherType(0x0027) => (),
p => {
log::debug!(
"Unrecognized L2 protocol: {:#06x}",

View 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

View File

@ -0,0 +1,344 @@
#![no_std]
use core::mem::MaybeUninit;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
clock::{ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
dma::DmaAllocator,
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext};
use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
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},
RxPacket,
};
use yggdrasil_abi::net::{
link::{EthernetLinkState, LinkState},
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,
dma: OneTimeInit<Arc<dyn DmaAllocator>>,
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: DmaBuffer<[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
.buffer_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: IrqVector) -> 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) {
let dma = self.dma.get();
regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET);
let iface = *self.iface_id.get();
let mut rx_ring = inner.rx_ring.lock();
rx_ring
.consume(dma.as_ref(), |packet| {
let packet = RxPacket::new(packet, 0, iface);
ygg_driver_net_core::receive_packet(packet).ok();
})
.ok();
}
true
}
}
impl Device for Stmmac {
unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
// TODO this is a dirty fix for the device tree double initialization problem
if self.dma.is_initialized() {
return Err(Error::AlreadyExists);
}
let dma = self.dma.init(cx.dma_allocator.clone());
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!("stmmac: 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!("stmmac: reset timeout");
return Err(Error::TimedOut);
}
// Setup DMA parameters
// TODO get these params from device tree
regs.DMA.DMASBMR.write(
DMASBMR::FB::SET
+ DMASBMR::AAL::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(dma.as_ref(), tx_ring_capacity)?;
let rx_ring = RxRing::with_capacity(dma.as_ref(), rx_ring_capacity)?;
let tx_ring_base = tx_ring.buffer_base().try_into_u32().unwrap();
let rx_ring_base = rx_ring.buffer_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 + DMACiCR::MSS.val(1024));
regs.DMA.DMAC0TXCR.write(DMACiTXCR::TXPBL.val(256));
regs.DMA
.DMAC0RXCR
.write(DMAC0RXCR::RBSZ.val(4096) + DMAC0RXCR::RXPBL.val(256));
// 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(1) + MTLTXQiOMR::TXQEN::Enable);
regs.MTL.MTLRXQ0OMR.write(
MTLRXQiOMR::RQS.val(1)
+ 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::FES::Fes100Mbps + 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 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 {
self.mac
}
fn link_state(&self) -> LinkState {
// TODO
LinkState::Ethernet(EthernetLinkState::Down)
}
}
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,
dma: OneTimeInit::new(),
inner: OneTimeInit::new(),
iface_id: OneTimeInit::new(),
}))
}
}
}

View 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),
}
}

View 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()
}
}

View 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),
}
}

View 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),
}
}

View File

@ -0,0 +1,248 @@
use core::mem::{self, MaybeUninit};
use alloc::vec::Vec;
use device_api::dma::DmaAllocator;
use libk::{
dma::{BusAddress, DmaBuffer},
error::Error,
};
pub struct TxRing {
entries: DmaBuffer<[TxDescriptor]>,
buffers: Vec<Option<DmaBuffer<[u8]>>>,
wr: usize,
rd: usize,
}
pub struct RxRing {
entries: DmaBuffer<[RxDescriptor]>,
buffers: Vec<DmaBuffer<[MaybeUninit<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(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let entries = DmaBuffer::new_slice(dma, TxDescriptor::empty(), capacity)?;
let buffers = (0..capacity).map(|_| None).collect();
Ok(Self {
entries,
buffers,
wr: 0,
rd: 0,
})
}
pub fn buffer_base(&self) -> BusAddress {
self.entries.bus_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: DmaBuffer<[u8]>) -> Result<usize, Error> {
if !self.can_xmit() {
return Err(Error::WouldBlock);
}
let address = frame.bus_address();
let frame_len = frame.len();
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, true)?;
self.entries.cache_flush_element(index, 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 entry.tx_completed() {
// Drop the buffer
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_completed(&self) -> bool {
self.tdes3 & Self::TDES3_OWN == 0
}
pub fn setup_tx(
&mut self,
frame: BusAddress,
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(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, Error> {
let mut entries = DmaBuffer::new_slice(dma, RxDescriptor::empty(), capacity)?;
let buffers = (0..capacity)
.map(|_| DmaBuffer::new_uninit_slice(dma, 4096))
.collect::<Result<Vec<_>, _>>()?;
for i in 0..capacity {
entries[i].setup_rx(buffers[i].bus_address(), true)?;
}
Ok(Self {
buffers,
entries,
rd: 0,
})
}
pub fn buffer_base(&self) -> BusAddress {
self.entries.bus_address()
}
pub fn consume<F: Fn(DmaBuffer<[u8]>)>(
&mut self,
dma: &dyn DmaAllocator,
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 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, 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: BusAddress, 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(())
}
}

View File

@ -2,6 +2,8 @@
use alloc::sync::Arc;
use device_api::interrupt::{FullIrq, MessageInterruptController};
use fdt_rs::prelude::PropReader;
use yggdrasil_abi::net::MacAddress;
use crate::{
driver::{lookup_phandle, map_interrupt_at},
@ -177,3 +179,19 @@ pub fn pcie_msi_map(node: &Arc<Node>) -> Option<PcieMsiMapIter<'static>> {
let msi_map = node.property("msi-map")?;
Some(PcieMsiMapIter { msi_map, 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))
}

View 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, DeviceInitContext},
};
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>, _cx: DeviceInitContext) -> 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)
}
}
}

View File

@ -18,6 +18,22 @@ use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
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;
struct Syscrg {
@ -48,8 +64,18 @@ impl Device for Syscrg {
impl ClockController for Syscrg {
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}");
Ok(())
let regs = self.ensure_init()?;
match clock.ok_or(Error::InvalidArgument)? {
109 => {
regs.lock()[109] |= 1 << 31;
Ok(())
}
111 => Ok(()),
_ => {
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}");
Err(Error::NotImplemented)
}
}
}
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {

View File

@ -3,6 +3,8 @@
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod bcm2835_aux;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub mod jh7110_aoncrg;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub mod jh7110_syscrg;

View File

@ -78,6 +78,9 @@ cfg_if::cfg_if! {
#[macro_use]
pub mod arch;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
extern crate ygg_driver_net_stmmac;
pub mod device;
pub mod fs;
pub mod init;

View File

@ -24,7 +24,7 @@ pub struct EthernetFrame {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
#[repr(transparent)]
pub struct EtherType(u16);
pub struct EtherType(pub u16);
impl EtherType {
pub const ARP: Self = Self(0x0806);

View File

@ -73,10 +73,10 @@ struct DhcpMessage {
#[derive(Debug)]
struct DhcpOffer {
router_address: Ipv4Addr,
router_address: Option<Ipv4Addr>,
server_address: Ipv4Addr,
your_address: Ipv4Addr,
subnet_mask: u32,
subnet_mask: Option<u32>,
}
fn pad_to_align(buffer: &mut Vec<u8>) {
@ -242,7 +242,9 @@ impl DhcpMessage {
}
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 {
return None;
@ -286,13 +288,11 @@ impl DhcpMessage {
}
}
let router_address = router?;
let server_address = server?;
let subnet_mask = subnet_mask?;
Some(DhcpOffer {
server_address,
router_address,
router_address: router,
your_address: Ipv4Addr::from(yiaddr),
subnet_mask,
})
@ -467,6 +467,7 @@ fn attempt_request(
op: 1,
htype: 1,
hlen: 6,
flags: (1u16 << 15).to_be(),
xid: transaction_id.to_be(),
chaddr: [0; 16],
cookie: 0x63825363u32.to_be(),
@ -486,11 +487,11 @@ fn attempt_request(
let offer = wait_for_dhcp_offer(poll, timer, socket)?;
println!(
"Got DHCP offer: address={} router={} server={} mask={}",
"Got DHCP offer: address={} router={:?} server={} mask={:?}",
offer.your_address,
offer.router_address,
offer.server_address,
Ipv4Addr::from(offer.subnet_mask)
offer.subnet_mask.map(Ipv4Addr::from)
);
// Send DHCP request
@ -503,6 +504,7 @@ fn attempt_request(
chaddr: [0; 16],
siaddr: u32::from(offer.server_address).to_be(),
cookie: 0x63825363u32.to_be(),
flags: (1u16 << 15).to_be(),
..DhcpMessageHeader::zeroed()
},
options: vec![
@ -548,11 +550,12 @@ fn request_address(interface: &str) -> Result<DhcpOffer, Error> {
fn configure_address(interface: &str, offer: DhcpOffer) -> Result<(), Error> {
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.add_route(
interface,
SubnetAddr::V4(SubnetV4Addr::UNSPECIFIED),
Some(IpAddr::V4(offer.router_address)),
Some(router_address.into())
)?;
Ok(())
}