clock: implement Hertz type
This commit is contained in:
@@ -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,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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user