Compare commits

..

2 Commits

Author SHA1 Message Date
70eb6cfaed jh7110: better syscrg clock structs 2025-02-14 12:10:12 +02:00
5c1c980ccd stmmac: link status reporting 2025-02-14 01:08:27 +02:00
2 changed files with 108 additions and 36 deletions
kernel
driver/net/stmmac/src
src/device/clock

@ -60,13 +60,25 @@ struct Stmmac {
impl Inner { impl Inner {
fn link_state(&self) -> LinkState { fn link_state(&self) -> LinkState {
// TODO read the link state properly, i.e., read from PHY's registers, I guess? I didn't let status = self.regs.lock().MAC.MACPHYCSR.extract();
// find a nice way to read the link state from the MAC itself, it only seems to report let link = if status.matches_all(MACPHYCSR::LNKSTS::Up) {
// the MAC<->PHY link state (which is always up, obviously) let speed = match status.read_as_enum(MACPHYCSR::LNKSPEED) {
LinkState::Ethernet(EthernetLinkState::Up( Some(MACPHYCSR::LNKSPEED::Value::Speed2_5MHz) => EthernetSpeed::Speed10,
EthernetSpeed::Unknown, Some(MACPHYCSR::LNKSPEED::Value::Speed25MHz) => EthernetSpeed::Speed100,
Duplex::Unknown, Some(MACPHYCSR::LNKSPEED::Value::Speed125MHz) => EthernetSpeed::Speed1000,
)) _ => EthernetSpeed::Unknown,
};
let duplex = if status.matches_all(MACPHYCSR::LNKMOD::FullDuplex) {
Duplex::Full
} else {
Duplex::Half
};
EthernetLinkState::Up(speed, duplex)
} else {
EthernetLinkState::Down
};
LinkState::Ethernet(link)
} }
} }

@ -16,25 +16,7 @@ use device_tree::{
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
const CLK_OSC: usize = 0; const PARENT_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 { struct Syscrg {
base: PhysicalAddress, base: PhysicalAddress,
@ -42,6 +24,25 @@ struct Syscrg {
mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>>, mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>>,
} }
#[derive(Debug, Clone, Copy)]
enum ClockParent {
#[allow(unused)]
Int(u32),
Ext(usize),
None,
}
#[derive(Debug, Clone, Copy)]
enum ClockRegister {
// Clock gate
Gate(u32, ClockParent),
// Clock inverter
Inv(u32),
// Clock delay selector (TODO)
Delay,
Unimp,
}
impl Syscrg { impl Syscrg {
fn ensure_init(&self) -> Result<&IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>, Error> { fn ensure_init(&self) -> Result<&IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>, Error> {
self.mapping.or_try_init_with(move || { self.mapping.or_try_init_with(move || {
@ -49,6 +50,38 @@ impl Syscrg {
.map(IrqSafeSpinlock::new) .map(IrqSafeSpinlock::new)
}) })
} }
fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> {
const CLOCKS: &[(&'static str, ClockRegister)] = &const {
use ClockParent::*;
use ClockRegister::*;
let mut t = [("", Unimp); 256];
t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, None));
t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, None));
t[0x18C / 4] = ("clk_gmac_source", Unimp);
t[0x190 / 4] = ("clk_gmac1_gtx", Unimp);
t[0x194 / 4] = ("clk_gmac1_rmii_rtx", Unimp);
t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, None));
t[0x19C / 4] = ("clk_gmac5_axi64_rx", Unimp);
t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30));
t[0x1A4 / 4] = ("clk_gmac5_axi64_tx", Gate(31, None));
t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30));
t[0x1AC / 4] = ("clk_gmac1_gtxc", Delay);
t[0x1B0 / 4] = ("clk_gmac0_gtx", Gate(31, None));
t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, None));
t[0x1B8 / 4] = ("clk_gmac_phy", Gate(31, None));
t[0x1BC / 4] = ("clk_gmac0_gtxc", Delay);
t[0x244 / 4] = ("clk_u0_uart_apb", Gate(31, None));
t[0x248 / 4] = ("clk_u0_uart_core", Gate(31, Ext(PARENT_CLK_OSC)));
t
};
let index = index as usize;
CLOCKS.get(index).copied()
}
} }
impl Device for Syscrg { impl Device for Syscrg {
@ -64,15 +97,27 @@ 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> {
let index = clock.ok_or(Error::InvalidArgument)?;
let (name, reg) = Self::map_clock_index(index)
.ok_or(Error::InvalidArgument)
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", clock))?;
let regs = self.ensure_init()?; let regs = self.ensure_init()?;
match clock.ok_or(Error::InvalidArgument)? { let mut lock = regs.lock();
109 => {
regs.lock()[109] |= 1 << 31; match reg {
ClockRegister::Gate(bit, _) => {
log::info!("jh7110-syscrg: enable {name:?}");
lock[index as usize] |= 1 << bit;
Ok(()) Ok(())
} }
111 => Ok(()), ClockRegister::Inv(bit) => {
_ => { log::info!("jh7110-syscrg: enable clk inv {name:?}");
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}"); lock[index as usize] |= 1 << bit;
Ok(())
}
ClockRegister::Delay => Ok(()),
ClockRegister::Unimp => {
log::warn!("jh7110-syscrg: clock not implemented: {name:?}");
Err(Error::NotImplemented) Err(Error::NotImplemented)
} }
} }
@ -84,10 +129,25 @@ impl ClockController for Syscrg {
} }
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> { fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
match clock.ok_or(Error::InvalidArgument)? { let (name, reg) = clock
CLK_UART0_CORE => self.parents[CLK_OSC].rate(), .and_then(Self::map_clock_index)
_ => { .ok_or(Error::InvalidArgument)
log::warn!("TODO: jh7110-syscrg: read rate {:#x?}", clock); .inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", clock))?;
match reg {
ClockRegister::Gate(_, parent) => match parent {
ClockParent::Ext(n) => self.parents[n].rate(),
ClockParent::Int(_) => {
log::warn!("jh7110-syscrg: todo internal clock parents: {:?}", name);
Err(Error::NotImplemented)
}
ClockParent::None => {
log::warn!("jh7110-syscrg: clock parent not specified {:?}", name);
Err(Error::NotImplemented)
}
},
ClockRegister::Unimp | ClockRegister::Delay | ClockRegister::Inv(_) => {
log::warn!("jh7110-syscrg: unimplemented clock {:?}", name);
Err(Error::NotImplemented) Err(Error::NotImplemented)
} }
} }