jh7110: better clock driver

This commit is contained in:
2025-07-27 13:24:25 +03:00
parent 3a61529b24
commit 18d01e82c8
5 changed files with 517 additions and 478 deletions
+2 -1
View File
@@ -36,7 +36,8 @@ impl ClockController for FixedClock {
}
fn enable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
Err(Error::InvalidOperation)
// Assume always enabled
Ok(())
}
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
-211
View File
@@ -1,211 +0,0 @@
//! 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;
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
registers::ReadWrite,
};
const PARENT_OSC: usize = 0;
// const PARENT_GMAC0_RMII_REFIN: usize = 1;
// const PARENT_GMAC0_RGMII_RXIN: usize = 2;
const PARENT_STG_AXIAHB: usize = 3;
// const PARENT_APB_BUS: usize = 4;
// const PARENT_GMAC0_GTXCLK: usize = 5;
// const PARENT_RTC_OSC: usize = 6;
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, ClockParent),
#[allow(unused)]
FixedDiv(u32, ClockParent),
// TODO
Fixed,
Unimp,
}
#[derive(Debug, Clone, Copy)]
enum ClockParent {
Int(u32),
Ext(usize),
}
/// JH7110 AONCRG driver
pub struct Aoncrg {
base: PhysicalAddress,
clock_parents: [ClockHandle; 7],
mapping: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl Aoncrg {
fn clk_enable_int(&self, index: u32) -> Result<(), Error> {
let (name, reg) = Self::map_clock_index(index)
.ok_or(Error::InvalidArgument)
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?;
match reg {
ClockRegister::Fixed => Ok(()),
ClockRegister::Gate(bit, parent) => {
self.clk_enable_parent(parent)?;
log::info!("jh7110-aoncrg: enable {name:?} @ {index}");
let lock = self.mapping.lock();
lock.CLOCKS[index as usize].set(lock.CLOCKS[index as usize].get() | (1 << bit));
Ok(())
}
ClockRegister::Unimp => {
log::warn!("jh7110-aoncrg: unimplemented clock {name:?}");
Err(Error::NotImplemented)
}
ClockRegister::FixedDiv(_, parent) => {
self.clk_enable_parent(parent)?;
Ok(())
}
}
}
fn clk_enable_parent(&self, parent: ClockParent) -> Result<(), Error> {
match parent {
ClockParent::Int(index) => self.clk_enable_int(index),
ClockParent::Ext(clock) => self.clock_parents[clock].enable(),
}
}
fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> {
use ClockParent::*;
use ClockRegister::*;
const CLOCK_MAP: &[(&str, ClockRegister)] = &[
/* 0 */ ("clk_osc", FixedDiv(4, Ext(PARENT_OSC))),
/* 1 */ ("clk_aon_apb_func", Unimp),
/* 2 */ ("clk_gmac5_ahb", Gate(31, Ext(PARENT_STG_AXIAHB))),
/* 3 */ ("clk_gmac5_axi", Gate(31, Ext(PARENT_STG_AXIAHB))),
/* 4 */ ("clk_gmac5_rmii_rtx", Unimp),
/* 5 */ ("clk_gmac5_axi64_tx", Fixed),
/* 6 */ ("clk_gmac5_axi64_tx_inv", Gate(30, Int(5))),
];
CLOCK_MAP.get(index as usize).copied()
}
}
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 index = clock.ok_or(Error::InvalidArgument)?;
self.clk_enable_int(index)
}
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 regs = self.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 regs = self.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: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let clock_parents = [
node.named_clock("osc")?,
node.named_clock("gmac0_rmii_refin")?,
node.named_clock("gmac0_rgmii_rxin")?,
node.named_clock("stg_axiahb")?,
node.named_clock("apb_bus")?,
node.named_clock("gmac0_gtxclk")?,
node.named_clock("rtc_osc")?,
];
let mapping = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let aoncrg = Arc::new(Aoncrg {
base,
clock_parents,
mapping: IrqSafeSpinlock::new(mapping)
});
node.make_reset_controller(aoncrg.clone());
node.make_clock_controller(aoncrg.clone());
Some(aoncrg)
}
}
}
+514
View File
@@ -0,0 +1,514 @@
//! StarFive JH7110 clock drivers
use core::{marker::PhantomData, ops::Index};
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::DeviceMemoryIoMut};
use libk_util::sync::IrqSafeSpinlock;
// SYSCRG clocks
const SYSCRG_CPU_ROOT: usize = 0x000 / 4;
const SYSCRG_CPU_CORE: usize = 0x004 / 4;
const SYSCRG_CPU_BUS: usize = 0x008 / 4;
const SYSCRG_GPU_ROOT: usize = 0x00C / 4;
const SYSCRG_PERH_ROOT: usize = 0x010 / 4;
const SYSCRG_BUS_ROOT: usize = 0x014 / 4;
const SYSCRG_NOCSTG_BUS: usize = 0x018 / 4;
const SYSCRG_AXI_CFG0: usize = 0x01C / 4;
const SYSCRG_STG_AXIAHB: usize = 0x020 / 4;
const SYSCRG_AHB0: usize = 0x024 / 4;
const SYSCRG_AHB1: usize = 0x028 / 4;
const SYSCRG_APB_BUS: usize = 0x02C / 4;
const SYSCRG_APB0: usize = 0x030 / 4;
// gmac1
const SYSCRG_GMAC1_AHB: usize = 0x184 / 4;
const SYSCRG_GMAC1_AXI: usize = 0x188 / 4;
const SYSCRG_GMAC_SRC: usize = 0x18C / 4;
const SYSCRG_GMAC1_GTXCLK: usize = 0x190 / 4;
const SYSCRG_GMAC1_RMII_RTX: usize = 0x194 / 4;
const SYSCRG_GMAC1_PTP: usize = 0x198 / 4;
const SYSCRG_GMAC1_RX: usize = 0x19C / 4;
const SYSCRG_GMAC1_RX_INV: usize = 0x1A0 / 4;
const SYSCRG_GMAC1_TX: usize = 0x1A4 / 4;
const SYSCRG_GMAC1_TX_INV: usize = 0x1A8 / 4;
const SYSCRG_GMAC1_GTXC: usize = 0x1AC / 4;
// gmac0
const SYSCRG_GMAC0_GTXCLK: usize = 0x1B0 / 4;
const SYSCRG_GMAC0_PTP: usize = 0x1B4 / 4;
const SYSCRG_GMAC_PHY: usize = 0x1B8 / 4;
const SYSCRG_GMAC0_GTXC: usize = 0x1BC / 4;
// TODO ...
// uart
const SYSCRG_UART0_APB: usize = 0x244 / 4;
const SYSCRG_UART0_CORE: usize = 0x248 / 4;
// jtag
const SYSCRG_JTAG_CERTIFICATION_TRNG: usize = 0x2F4 / 4;
const SYSCRG_CLOCK_COUNT: usize = SYSCRG_JTAG_CERTIFICATION_TRNG + 1;
const SYSCRG_OSC: usize = SYSCRG_CLOCK_COUNT;
const SYSCRG_GMAC1_RMII_REFIN: usize = SYSCRG_CLOCK_COUNT + 1;
const SYSCRG_GMAC1_RGMII_RXIN: usize = SYSCRG_CLOCK_COUNT + 2;
#[allow(unused)]
const SYSCRG_I2STX_BCLK_EXT: usize = SYSCRG_CLOCK_COUNT + 3;
#[allow(unused)]
const SYSCRG_I2STX_LRCK_EXT: usize = SYSCRG_CLOCK_COUNT + 4;
#[allow(unused)]
const SYSCRG_I2SRX_BCLK_EXT: usize = SYSCRG_CLOCK_COUNT + 5;
#[allow(unused)]
const SYSCRG_I2SRX_LRCK_EXT: usize = SYSCRG_CLOCK_COUNT + 6;
#[allow(unused)]
const SYSCRG_TDM_EXT: usize = SYSCRG_CLOCK_COUNT + 7;
#[allow(unused)]
const SYSCRG_MCLK_EXT: usize = SYSCRG_CLOCK_COUNT + 8;
const SYSCRG_PLL0_OUT: usize = SYSCRG_CLOCK_COUNT + 9;
const SYSCRG_PLL1_OUT: usize = SYSCRG_CLOCK_COUNT + 10;
const SYSCRG_PLL2_OUT: usize = SYSCRG_CLOCK_COUNT + 11;
// AONCRG clocks
const AONCRG_OSC_DIV4: usize = 0x00 / 4;
const AONCRG_APB_FUNC: usize = 0x04 / 4;
// gmac0
const AONCRG_GMAC0_AHB: usize = 0x08 / 4;
const AONCRG_GMAC0_AXI: usize = 0x0C / 4;
const AONCRG_GMAC0_RMII_RTX: usize = 0x10 / 4;
const AONCRG_GMAC0_TX: usize = 0x14 / 4;
const AONCRG_GMAC0_TX_INV: usize = 0x18 / 4;
const AONCRG_GMAC0_RX: usize = 0x1C / 4;
const AONCRG_GMAC0_RX_INV: usize = 0x20 / 4;
// otpc
const AONCRG_OTPC_APB: usize = 0x24 / 4;
// rtc
const AONCRG_RTC_APB: usize = 0x28 / 4;
const AONCRG_RTC_INTERNAL: usize = 0x2C / 4;
const AONCRG_RTC_32K: usize = 0x30 / 4;
const AONCRG_RTC_CAL: usize = 0x34 / 4;
const AONCRG_CLOCK_COUNT: usize = AONCRG_RTC_CAL + 1;
const AONCRG_OSC: usize = AONCRG_CLOCK_COUNT;
const AONCRG_GMAC0_RMII_REFIN: usize = AONCRG_CLOCK_COUNT + 1;
const AONCRG_GMAC0_RGMII_RXIN: usize = AONCRG_CLOCK_COUNT + 2;
const AONCRG_STG_AXIAHB: usize = AONCRG_CLOCK_COUNT + 3;
const AONCRG_APB_BUS: usize = AONCRG_CLOCK_COUNT + 4;
const AONCRG_GMAC0_GTXCLK: usize = AONCRG_CLOCK_COUNT + 5;
const AONCRG_RTC_OSC: usize = AONCRG_CLOCK_COUNT + 6;
#[allow(unused)]
enum ClockDef {
Mux(&'static [usize]),
Div(u32, usize),
MuxDiv(u32, &'static [usize]),
Gate(usize),
GateDiv(u32, usize),
GateMux(&'static [usize]),
Inv(usize),
}
trait ClockDefinition {
const NAME: &'static str;
const CLOCKS: &'static [Option<(&'static str, ClockDef)>];
}
const SYSCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
use ClockDef::*;
let mut t = [const { None }; SYSCRG_CLOCK_COUNT];
t[SYSCRG_CPU_ROOT] = Some(("clk_cpu_root", Mux(&[SYSCRG_OSC, SYSCRG_PLL0_OUT])));
t[SYSCRG_CPU_CORE] = Some(("clk_cpu_core", Div(7, SYSCRG_CPU_ROOT)));
t[SYSCRG_CPU_BUS] = Some(("clk_cpu_bus", Div(2, SYSCRG_CPU_CORE)));
t[SYSCRG_GPU_ROOT] = Some(("clk_gpu_root", Mux(&[SYSCRG_PLL2_OUT, SYSCRG_PLL1_OUT])));
t[SYSCRG_PERH_ROOT] = Some((
"clk_perh_root",
MuxDiv(2, &[SYSCRG_PLL0_OUT, SYSCRG_PLL2_OUT]),
));
t[SYSCRG_BUS_ROOT] = Some(("clk_bus_root", Mux(&[SYSCRG_OSC, SYSCRG_PLL2_OUT])));
t[SYSCRG_NOCSTG_BUS] = Some(("clk_nocstg_bus", Div(3, SYSCRG_BUS_ROOT)));
t[SYSCRG_AXI_CFG0] = Some(("clk_axi_cfg0", Div(3, SYSCRG_BUS_ROOT)));
t[SYSCRG_STG_AXIAHB] = Some(("clk_stg_axiahb", Div(2, SYSCRG_AXI_CFG0)));
t[SYSCRG_AHB0] = Some(("clk_ahb0", Gate(SYSCRG_STG_AXIAHB)));
t[SYSCRG_AHB1] = Some(("clk_ahb1", Gate(SYSCRG_STG_AXIAHB)));
t[SYSCRG_APB_BUS] = Some(("clk_apb_bus", Div(8, SYSCRG_STG_AXIAHB)));
t[SYSCRG_APB0] = Some(("clk_apb0", Gate(SYSCRG_APB_BUS)));
// gmac1
t[SYSCRG_GMAC1_AHB] = Some(("clk_gmac1_ahb", Gate(SYSCRG_AHB0)));
t[SYSCRG_GMAC1_AXI] = Some(("clk_gmac1_axi", Gate(SYSCRG_STG_AXIAHB)));
t[SYSCRG_GMAC_SRC] = Some(("clk_gmac_src", Div(7, SYSCRG_PLL0_OUT)));
t[SYSCRG_GMAC1_GTXCLK] = Some(("clk_gmac1_gtxclk", Div(15, SYSCRG_PLL0_OUT)));
t[SYSCRG_GMAC1_RMII_RTX] = Some(("clk_gmac1_rmii_rtx", Div(30, SYSCRG_GMAC1_RMII_REFIN)));
t[SYSCRG_GMAC1_PTP] = Some(("clk_gmac1_ptp", GateDiv(31, SYSCRG_GMAC_SRC)));
t[SYSCRG_GMAC1_RX] = Some((
"clk_gmac1_rx",
Mux(&[SYSCRG_GMAC1_RGMII_RXIN, SYSCRG_GMAC1_RMII_RTX]),
));
t[SYSCRG_GMAC1_RX_INV] = Some(("clk_gmac1_rx_inv", Inv(SYSCRG_GMAC1_RX)));
t[SYSCRG_GMAC1_TX] = Some((
"clk_gmac1_tx",
GateMux(&[SYSCRG_GMAC1_GTXCLK, SYSCRG_GMAC1_RMII_RTX]),
));
t[SYSCRG_GMAC1_TX_INV] = Some(("clk_gmac1_tx_inv", Inv(SYSCRG_GMAC1_TX)));
t[SYSCRG_GMAC1_GTXC] = Some(("clk_gmac1_gtxc", Gate(SYSCRG_GMAC1_GTXCLK)));
// gmac0
t[SYSCRG_GMAC0_GTXCLK] = Some(("clk_gmac0_gtxclk", GateDiv(15, SYSCRG_PLL0_OUT)));
t[SYSCRG_GMAC0_PTP] = Some(("clk_gmac0_ptp", GateDiv(31, SYSCRG_GMAC_SRC)));
t[SYSCRG_GMAC_PHY] = Some(("clk_gmac_phy", GateDiv(31, SYSCRG_GMAC_SRC)));
t[SYSCRG_GMAC0_GTXC] = Some(("clk_gmac0_gtxc", Gate(SYSCRG_GMAC0_GTXCLK)));
// TODO ...
// uart
t[SYSCRG_UART0_APB] = Some(("clk_uart0_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART0_CORE] = Some(("clk_uart0_core", Gate(SYSCRG_OSC)));
t
};
const AONCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
use ClockDef::*;
let mut t = [const { None }; AONCRG_CLOCK_COUNT];
t[AONCRG_OSC_DIV4] = Some(("clk_osc_div4", Div(4, AONCRG_OSC)));
t[AONCRG_APB_FUNC] = Some(("clk_apb_func", Mux(&[AONCRG_OSC_DIV4, AONCRG_OSC])));
// gmac0
t[AONCRG_GMAC0_AHB] = Some(("clk_gmac0_ahb", Gate(AONCRG_STG_AXIAHB)));
t[AONCRG_GMAC0_AXI] = Some(("clk_gmac0_axi", Gate(AONCRG_STG_AXIAHB)));
t[AONCRG_GMAC0_RMII_RTX] = Some(("clk_gmac0_rmii_rtx", Div(30, AONCRG_GMAC0_RMII_REFIN)));
t[AONCRG_GMAC0_TX] = Some((
"clk_gmac0_tx",
GateMux(&[AONCRG_GMAC0_GTXCLK, AONCRG_GMAC0_RMII_RTX]),
));
t[AONCRG_GMAC0_TX_INV] = Some(("clk_gmac0_tx_inv", Inv(AONCRG_GMAC0_TX)));
t[AONCRG_GMAC0_RX] = Some((
"clk_gmac0_rx",
Mux(&[AONCRG_GMAC0_RGMII_RXIN, AONCRG_GMAC0_RMII_RTX]),
));
t[AONCRG_GMAC0_RX_INV] = Some(("clk_gmac0_rx_inv", Inv(AONCRG_GMAC0_RX)));
// otpc
t[AONCRG_OTPC_APB] = Some(("clk_otpc_apb", Gate(AONCRG_APB_BUS)));
// rtc
t[AONCRG_RTC_APB] = Some(("clk_rtc_apb", Gate(AONCRG_APB_BUS)));
t[AONCRG_RTC_INTERNAL] = Some(("clk_rtc_internal", Div(1022, AONCRG_OSC)));
t[AONCRG_RTC_32K] = Some(("clk_rtc_32k", Mux(&[AONCRG_RTC_OSC, AONCRG_RTC_INTERNAL])));
t[AONCRG_RTC_CAL] = Some(("clk_rtc_cal", Gate(AONCRG_OSC)));
t
};
struct Crg<C, P> {
clock_mapping: IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>,
reset_mapping: IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>,
parents: P,
_pd: PhantomData<C>,
}
// TODO this is just a dummy, which is assumed to be always running
struct Pll;
unsafe impl<C, P> Send for Crg<C, P> {}
unsafe impl<C, P> Sync for Crg<C, P> {}
impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> Crg<C, P> {
unsafe fn map(base: PhysicalAddress, parents: P) -> Result<Arc<Self>, Error> {
let clock_mapping =
DeviceMemoryIoMut::map_slice(base, C::CLOCKS.len(), Default::default())?;
let reset_mapping =
DeviceMemoryIoMut::map_slice(base.add(C::CLOCKS.len() * 4), 16, Default::default())?;
Ok(Arc::new(Self {
clock_mapping: IrqSafeSpinlock::new(clock_mapping),
reset_mapping: IrqSafeSpinlock::new(reset_mapping),
parents,
_pd: PhantomData,
}))
}
fn clock(&self, index: usize) -> Result<&(&str, ClockDef), Error> {
C::CLOCKS
.get(index)
.ok_or(Error::DoesNotExist)?
.as_ref()
.ok_or(Error::DoesNotExist)
.inspect_err(|_| {
log::error!(
"{}: clock {:#x} does not exist/is not implemented",
C::NAME,
index
)
})
}
fn enable_clock_inner(&self, index: usize) -> Result<(), Error> {
if index >= C::CLOCKS.len() {
return self.parents[index - C::CLOCKS.len()].enable();
}
let (clk_name, clk_def) = self.clock(index)?;
let (parent, write_gate) = match clk_def {
ClockDef::GateDiv(_, parent) | ClockDef::Gate(parent) => (*parent, true),
ClockDef::GateMux(parents) => (parents[0], true),
ClockDef::Inv(parent) | ClockDef::Div(_, parent) => (*parent, false),
ClockDef::Mux(parents) | ClockDef::MuxDiv(_, parents) => (parents[0], false),
};
// Enable parent
self.enable_clock_inner(parent)?;
// Enable clock
if write_gate {
let mut lock = self.clock_mapping.lock();
let ptr = &raw mut lock[index];
unsafe {
let val = ptr.read_volatile();
if val & (1 << 31) == 0 {
log::info!("{}: enable clock {:?}", C::NAME, clk_name);
ptr.write_volatile(val | (1 << 31));
}
}
}
Ok(())
}
fn clock_rate_inner(&self, index: usize) -> Result<u64, Error> {
if index >= C::CLOCKS.len() {
return self.parents[index - C::CLOCKS.len()].rate();
}
let (_, clk_def) = self.clock(index)?;
let (parent, div) = match clk_def {
&ClockDef::Gate(parent) | &ClockDef::Inv(parent) => (parent, 1),
&ClockDef::Div(div, parent) => (parent, div),
// TODO read actual parent for muxes
&ClockDef::GateDiv(div, parent) => (parent, div),
ClockDef::GateMux(parents) | ClockDef::Mux(parents) => (parents[0], 1),
ClockDef::MuxDiv(div, parents) => (parents[0], *div),
};
let parent_rate = self.clock_rate_inner(parent)?;
Ok(parent_rate / div as u64)
}
fn set_reset_asserted_inner(&self, index: usize, asserted: bool) -> Result<(), Error> {
let reg_index = index / 32;
let reg_shift = index % 32;
let mut lock = self.reset_mapping.lock();
let ptr = &raw mut lock[reg_index];
unsafe {
let val = ptr.read_volatile();
if asserted {
ptr.write_volatile(val | (1 << reg_shift));
} else {
ptr.write_volatile(val & !(1 << reg_shift));
}
}
Ok(())
}
}
impl<C: ClockDefinition, P> Device for Crg<C, P> {
fn display_name(&self) -> &str {
C::NAME
}
}
impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> ClockController for Crg<C, P> {
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
let index = clock.ok_or(Error::InvalidArgument)? as usize;
self.clock_rate_inner(index)
}
fn set_clock_rate(&self, _clock: Option<u32>, _rate: u64) -> Result<u64, Error> {
todo!("Clock rate update not supported for jh71x0 CRGs")
}
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
let index = clock.ok_or(Error::InvalidArgument)? as usize;
self.enable_clock_inner(index)
}
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
todo!("Clock disable not supported for jh71x0 CRGs")
}
}
impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> ResetController for Crg<C, P> {
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
let reset = reset.ok_or(Error::InvalidArgument)? as usize;
self.set_reset_asserted_inner(reset, true)
}
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
let reset = reset.ok_or(Error::InvalidArgument)? as usize;
self.set_reset_asserted_inner(reset, false)
}
}
impl<C: ClockDefinition + 'static, P: Index<usize, Output = ClockHandle> + 'static>
DeviceTreeClockController for Crg<C, P>
{
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<C: ClockDefinition + 'static, P: Index<usize, Output = ClockHandle> + 'static>
DeviceTreeResetController for Crg<C, P>
{
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,
))
}
}
impl Device for Pll {
fn display_name(&self) -> &str {
"jh7110-pll"
}
}
impl ClockController for Pll {
fn set_clock_rate(&self, _clock: Option<u32>, _rate: u64) -> Result<u64, Error> {
todo!("PLL rate configuration not yet implemented")
}
fn clock_rate(&self, _clock: Option<u32>) -> Result<u64, Error> {
todo!("PLL rate query not yet implemented")
}
fn enable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
// Assumed always enabled
Ok(())
}
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
}
impl DeviceTreeClockController for Pll {
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,
))
}
}
device_tree_driver! {
compatible: ["starfive,jh7110-syscrg"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
struct Syscrg;
impl ClockDefinition for Syscrg {
const NAME: &'static str = "jh7110-syscrg";
const CLOCKS: &'static [Option<(&'static str, ClockDef)>] = SYSCRG_CLOCKS;
}
let base = node.map_base(context, 0)?;
let parents = [
node.named_clock("osc")?,
node.named_clock("gmac1_rmii_refin")?,
node.named_clock("gmac1_rgmii_rxin")?,
node.named_clock("i2stx_bclk_ext")?,
node.named_clock("i2stx_lrck_ext")?,
node.named_clock("i2srx_bclk_ext")?,
node.named_clock("i2srx_lrck_ext")?,
node.named_clock("tdm_ext")?,
node.named_clock("mclk_ext")?,
node.named_clock("pll0_out")?,
node.named_clock("pll1_out")?,
node.named_clock("pll2_out")?
];
let syscrg = unsafe { Crg::<Syscrg, _>::map(base, parents) }.ok()?;
node.make_clock_controller(syscrg.clone());
node.make_reset_controller(syscrg.clone());
Some(syscrg)
}
}
}
device_tree_driver! {
compatible: ["starfive,jh7110-aoncrg"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
struct Aoncrg;
impl ClockDefinition for Aoncrg {
const NAME: &'static str = "jh7110-aoncrg";
const CLOCKS: &'static [Option<(&'static str, ClockDef)>] = AONCRG_CLOCKS;
}
let base = node.map_base(context, 0)?;
let parents = [
node.named_clock("osc")?,
node.named_clock("gmac0_rmii_refin")?,
node.named_clock("gmac0_rgmii_rxin")?,
node.named_clock("stg_axiahb")?,
node.named_clock("apb_bus")?,
node.named_clock("gmac0_gtxclk")?,
node.named_clock("rtc_osc")?,
];
let aoncrg = unsafe { Crg::<Aoncrg, _>::map(base, parents) }.ok()?;
node.make_clock_controller(aoncrg.clone());
node.make_reset_controller(aoncrg.clone());
Some(aoncrg)
}
}
}
device_tree_driver! {
compatible: ["starfive,jh7110-pll"],
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let pll = Arc::new(Pll);
node.make_clock_controller(pll.clone());
Some(pll)
}
}
}
-263
View File
@@ -1,263 +0,0 @@
//! 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;
const PARENT_CLK_OSC: usize = 0;
struct Syscrg {
base: PhysicalAddress,
parents: [ClockHandle; 1],
mapping: 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 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))?;
match reg {
ClockRegister::Gate(bit, parent) => {
log::info!("jh7110-syscrg: enable {name:?} @ {index} /{depth}");
self.clk_enable_parent(parent, depth)?;
let mut lock = self.mapping.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 = self.mapping.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: &[(&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 mut regs = self.mapping.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,
))
}
}
unsafe impl Sync for Syscrg {}
unsafe impl Send for Syscrg {}
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 mapping = unsafe { DeviceMemoryIoMut::map_slice(base, 256, Default::default()) }
.inspect_err(|error| log::error!("jh7110-syscrg: {error:?}"))
.ok()?;
let syscrg = Arc::new(Syscrg {
base,
parents: [osc],
mapping: IrqSafeSpinlock::new(mapping),
});
node.make_reset_controller(syscrg.clone());
node.make_clock_controller(syscrg.clone());
Some(syscrg)
}
}
}
+1 -3
View File
@@ -4,9 +4,7 @@
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;
pub mod jh7110_clocks;
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", rust_analyzer))]
pub mod fixed;