clock: implement Hertz type

This commit is contained in:
2025-07-27 13:37:39 +03:00
parent 18d01e82c8
commit e0b6290a54
6 changed files with 110 additions and 21 deletions
+86
View File
@@ -0,0 +1,86 @@
use core::{
fmt,
ops::{Div, Mul},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Hertz(pub u64);
const KILO: u64 = 1_000;
const MEGA: u64 = 1_000_000;
const GIGA: u64 = 1_000_000_000;
pub trait IntoHertz {
fn hz(&self) -> Hertz;
#[inline]
fn khz(&self) -> Hertz {
self.hz() * KILO
}
#[inline]
fn mhz(&self) -> Hertz {
self.hz() * MEGA
}
#[inline]
fn ghz(&self) -> Hertz {
self.hz() * GIGA
}
}
impl Mul<u32> for Hertz {
type Output = Hertz;
fn mul(self, rhs: u32) -> Self::Output {
Self(self.0 * rhs as u64)
}
}
impl Mul<u64> for Hertz {
type Output = Hertz;
fn mul(self, rhs: u64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl Div<u32> for Hertz {
type Output = Hertz;
fn div(self, rhs: u32) -> Self::Output {
Self(self.0 / rhs as u64)
}
}
impl fmt::Display for Hertz {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (scale, suffix) = match self.0 {
x if x >= GIGA => (GIGA, "GHz"),
x if x >= MEGA => (MEGA, "MHz"),
x if x >= KILO => (KILO, "kHz"),
x => return write!(f, "{x}Hz"),
};
let int = self.0 / scale;
let frac = (self.0 / (scale / 1000)) % 1000;
if frac == 0 {
write!(f, "{int}{suffix}")
} else {
write!(f, "{int}.{frac:03}{suffix}")
}
}
}
macro_rules! impl_into_hertz {
($($ty:ty),+ $(,)?) => {
$(
impl IntoHertz for $ty {
#[inline(always)]
fn hz(&self) -> Hertz {
Hertz(*self as u64)
}
}
)+
};
}
impl_into_hertz!(u8, u16, u32, u64);
@@ -3,7 +3,9 @@ use yggdrasil_abi::error::Error;
use crate::device::Device;
// TODO refine `clock` parameter types somehow
pub use freq::{Hertz, IntoHertz};
mod freq;
pub struct ClockHandle {
pub parent: Arc<dyn ClockController>,
@@ -19,11 +21,11 @@ pub trait ClockController: Device {
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error>;
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error>;
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
let _ = clock;
Err(Error::NotImplemented)
}
fn set_clock_rate(&self, clock: Option<u32>, rate: u64) -> Result<u64, Error> {
fn set_clock_rate(&self, clock: Option<u32>, rate: Hertz) -> Result<Hertz, Error> {
let _ = clock;
let _ = rate;
Err(Error::NotImplemented)
@@ -44,11 +46,11 @@ impl ClockHandle {
self.parent.disable_clock(self.clock)
}
pub fn rate(&self) -> Result<u64, Error> {
pub fn rate(&self) -> Result<Hertz, Error> {
self.parent.clock_rate(self.clock)
}
pub fn set_rate(&self, rate: u64) -> Result<u64, Error> {
pub fn set_rate(&self, rate: Hertz) -> Result<Hertz, Error> {
self.parent.set_clock_rate(self.clock, rate)
}
}
+2 -1
View File
@@ -2,6 +2,7 @@
use core::sync::atomic::{self, Ordering};
use abi::error::Error;
use device_api::clock::Hertz;
use device_tree::{
driver::{unflatten_device_tree, InitSequence},
DeviceTree, DeviceTreeNodeExt,
@@ -249,7 +250,7 @@ impl Riscv64 {
.prop_cell("timebase-frequency", 1)
.ok_or(Error::DoesNotExist)?;
timer::FREQUENCY.store(timebase_frequency, Ordering::Release);
log::info!("System timer frequency: {timebase_frequency}");
log::info!("System timer frequency: {}", Hertz(timebase_frequency));
Ok(())
}
+5 -5
View File
@@ -2,7 +2,7 @@
use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
clock::{ClockController, ClockHandle},
clock::{ClockController, ClockHandle, Hertz},
device::{Device, DeviceInitContext},
};
use device_tree::{
@@ -12,7 +12,7 @@ use device_tree::{
struct FixedClock {
name: &'static str,
frequency: u64,
frequency: Hertz,
}
impl Device for FixedClock {
@@ -26,12 +26,12 @@ impl Device for FixedClock {
}
impl ClockController for FixedClock {
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, Error> {
debug_assert!(clock.is_none());
Ok(self.frequency)
}
fn set_clock_rate(&self, _clock: Option<u32>, _rate: u64) -> Result<u64, Error> {
fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
Err(Error::InvalidOperation)
}
@@ -66,7 +66,7 @@ device_tree_driver! {
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let name = node.name()?;
let frequency = node.property("clock-frequency")?.read_cell(0, 1)?;
let frequency = Hertz(node.property("clock-frequency")?.read_cell(0, 1)?);
log::info!("fixed-clock {name}: {frequency}");
let fixed = Arc::new(FixedClock { name, frequency });
node.make_clock_controller(fixed.clone());
+7 -7
View File
@@ -5,7 +5,7 @@ use core::{marker::PhantomData, ops::Index};
use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
clock::{ClockController, ClockHandle, ResetController, ResetHandle},
clock::{ClockController, ClockHandle, Hertz, ResetController, ResetHandle},
device::Device,
};
use device_tree::{
@@ -285,7 +285,7 @@ impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> Crg<C, P> {
Ok(())
}
fn clock_rate_inner(&self, index: usize) -> Result<u64, Error> {
fn clock_rate_inner(&self, index: usize) -> Result<Hertz, Error> {
if index >= C::CLOCKS.len() {
return self.parents[index - C::CLOCKS.len()].rate();
}
@@ -303,7 +303,7 @@ impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> Crg<C, P> {
let parent_rate = self.clock_rate_inner(parent)?;
Ok(parent_rate / div as u64)
Ok(parent_rate / div)
}
fn set_reset_asserted_inner(&self, index: usize, asserted: bool) -> Result<(), Error> {
@@ -332,12 +332,12 @@ impl<C: ClockDefinition, P> Device for Crg<C, P> {
}
impl<C: ClockDefinition, P: Index<usize, Output = ClockHandle>> ClockController for Crg<C, P> {
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
fn clock_rate(&self, clock: Option<u32>) -> Result<Hertz, 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> {
fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
todo!("Clock rate update not supported for jh71x0 CRGs")
}
@@ -400,11 +400,11 @@ impl Device for Pll {
}
impl ClockController for Pll {
fn set_clock_rate(&self, _clock: Option<u32>, _rate: u64) -> Result<u64, Error> {
fn set_clock_rate(&self, _clock: Option<u32>, _rate: Hertz) -> Result<Hertz, Error> {
todo!("PLL rate configuration not yet implemented")
}
fn clock_rate(&self, _clock: Option<u32>) -> Result<u64, Error> {
fn clock_rate(&self, _clock: Option<u32>) -> Result<Hertz, Error> {
todo!("PLL rate query not yet implemented")
}
+3 -3
View File
@@ -2,7 +2,7 @@
use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, ResetHandle},
clock::{ClockHandle, Hertz, ResetHandle},
device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
@@ -132,8 +132,8 @@ impl Io {
self.regs.DR.set(byte as u32);
}
fn init(&mut self, baud_clock: u64, baud_rate: u64) {
let divisor = (baud_clock / (baud_rate * 16)) as u32;
fn init(&mut self, baud_clock: Hertz, baud_rate: u64) {
let divisor = (baud_clock.0 / (baud_rate * 16)) as u32;
self.wait_busy();
self.regs.IER.set(0);