yggdrasil/kernel/src/device/clock/jh7110_syscrg.rs

267 lines
8.8 KiB
Rust

//! Starfive JH7110 System Control Registers
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::DeviceMemoryIoMut};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
const PARENT_CLK_OSC: usize = 0;
struct Syscrg {
base: PhysicalAddress,
parents: [ClockHandle; 1],
mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>>,
}
#[derive(Debug, Clone, Copy)]
enum ClockParent {
Int(u32),
Ext(usize),
None,
}
#[derive(Debug, Clone, Copy)]
enum ClockRegister {
// Clock gate
Gate(u32, ClockParent),
// Clock inverter
Inv(u32, ClockParent),
// Clock divider (TODO)
Div(ClockParent),
Unimp,
}
impl Syscrg {
fn ensure_init(&self) -> Result<&IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>, Error> {
self.mapping.or_try_init_with(move || {
unsafe { DeviceMemoryIoMut::map_slice(self.base, 256, Default::default()) }
.map(IrqSafeSpinlock::new)
})
}
fn clk_enable_int(&self, index: u32, depth: u32) -> Result<(), Error> {
let (name, reg) = Self::map_clock_index(index)
.ok_or(Error::InvalidArgument)
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?;
let regs = self.ensure_init()?;
match reg {
ClockRegister::Gate(bit, parent) => {
log::info!("jh7110-syscrg: enable {name:?} @ {index} /{depth}");
self.clk_enable_parent(parent, depth)?;
let mut lock = regs.lock();
lock[index as usize] |= 1 << bit;
Ok(())
}
ClockRegister::Inv(bit, parent) => {
log::info!("jh7110-syscrg: enable clk inv {name:?} @ {index}");
self.clk_enable_parent(parent, depth)?;
let mut lock = regs.lock();
lock[index as usize] |= 1 << bit;
Ok(())
}
ClockRegister::Div(parent) => self.clk_enable_parent(parent, depth),
ClockRegister::Unimp => {
log::warn!("jh7110-syscrg: clock not implemented: {name:?}");
Err(Error::NotImplemented)
}
}
}
fn clk_enable_parent(&self, parent: ClockParent, depth: u32) -> Result<(), Error> {
match parent {
ClockParent::Int(index) => self.clk_enable_int(index, depth + 1),
ClockParent::Ext(clock) => self.parents.get(clock).ok_or(Error::DoesNotExist)?.enable(),
ClockParent::None => Ok(()),
}
}
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[0x01C / 4] = ("clk_axi_cfg0", Div(None));
t[0x020 / 4] = ("clk_stg_axiahb", Div(Int(0x01C / 4)));
t[0x024 / 4] = ("clk_ahb0", Gate(31, Int(0x020 / 4)));
t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, Int(0x024 / 4)));
t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, Int(0x020 / 4)));
t[0x18C / 4] = ("clk_gmac_source", Div(None));
t[0x190 / 4] = ("clk_gmac1_gtx", Gate(31, None));
t[0x194 / 4] = ("clk_gmac1_rmii_rtx", Unimp);
t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, Int(0x18C / 4)));
t[0x19C / 4] = ("clk_gmac5_axi64_rx", Unimp);
t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30, Int(0x19C / 4)));
t[0x1A4 / 4] = ("clk_gmac5_axi64_tx", Gate(31, None));
t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30, Int(0x1A4 / 4)));
t[0x1AC / 4] = ("clk_gmac1_gtxc", Gate(31, Int(0x190 / 4)));
t[0x1B0 / 4] = ("clk_gmac0_gtx", Gate(31, None));
t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, Int(0x18C / 4)));
t[0x1B8 / 4] = ("clk_gmac_phy", Gate(31, None));
t[0x1BC / 4] = ("clk_gmac0_gtxc", Gate(31, Int(0x1B0 / 4)));
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 {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
log::warn!("TODO: init jh7110-syscrg @ {:#x}", self.base);
Ok(())
}
fn display_name(&self) -> &str {
"Starfive JH7110 SYSCRG"
}
}
impl ClockController for Syscrg {
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
let index = clock.ok_or(Error::InvalidArgument)?;
self.clk_enable_int(index, 0)
}
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
log::warn!("TODO: jh7110-syscrg: disable clock {clock:?}");
Ok(())
}
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
let (name, reg) = clock
.and_then(Self::map_clock_index)
.ok_or(Error::InvalidArgument)
.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::Div(_) | ClockRegister::Inv(_, _) => {
log::warn!("jh7110-syscrg: unimplemented clock {:?}", name);
Err(Error::NotImplemented)
}
}
}
fn set_clock_rate(&self, clock: Option<u32>, rate: u64) -> Result<u64, Error> {
log::warn!("TODO: jh7110-syscrg: set rate {clock:?} -> {rate}");
Ok(rate)
}
}
impl Syscrg {
fn rst_trigger(&self, reset: u32, assert: bool) -> Result<(), Error> {
let reg = (190 + reset / 32) as usize;
let bit = reset % 32;
let regs = self.ensure_init()?;
let mut regs = regs.lock();
let expect = if assert {
regs[reg] |= 1 << bit;
1 << bit
} else {
regs[reg] &= !(1 << bit);
0
};
let mut timeout = 1 << 20;
while timeout > 0 && regs[reg] & (1 << bit) != expect {
core::hint::spin_loop();
timeout -= 1;
}
if timeout > 0 {
Ok(())
} else {
log::warn!("jh7110-syscrg: reset timeout {reset}");
Err(Error::TimedOut)
}
}
}
impl ResetController for Syscrg {
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
let reset = reset.ok_or(Error::InvalidArgument)?;
self.rst_trigger(reset, true)
}
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
let reset = reset.ok_or(Error::InvalidArgument)?;
self.rst_trigger(reset, false)
}
}
impl DeviceTreeClockController for Syscrg {
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> {
let clock = property.read_cell(offset, 1)? as u32;
Some((
ClockHandle {
clock: Some(clock),
parent: self.clone(),
},
1,
))
}
}
impl DeviceTreeResetController for Syscrg {
fn map_reset(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ResetHandle, usize)> {
let reset = property.read_cell(offset, 1)? as u32;
Some((
ResetHandle {
reset: Some(reset),
parent: self.clone(),
},
1,
))
}
}
device_tree_driver! {
compatible: ["starfive,jh7110-syscrg"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let osc = node.named_clock("osc")?;
let syscrg = Arc::new(Syscrg {
base,
parents: [osc],
mapping: OneTimeInit::new(),
});
node.make_reset_controller(syscrg.clone());
node.make_clock_controller(syscrg.clone());
Some(syscrg)
}
}
}