rv64/jh7110: implement syscrg stub + uart clock/reset
This commit is contained in:
parent
975df985ac
commit
5d406feb07
@ -1,10 +1,73 @@
|
||||
use alloc::sync::Arc;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::device::Device;
|
||||
|
||||
// TODO refine `clock` parameter types somehow
|
||||
|
||||
pub trait ClockController: Device {
|
||||
fn enable_clock(&self, clock: u32) -> Result<(), Error>;
|
||||
fn disable_clock(&self, clock: u32) -> Result<(), Error>;
|
||||
pub struct ClockHandle {
|
||||
pub parent: Arc<dyn ClockController>,
|
||||
pub clock: Option<u32>,
|
||||
}
|
||||
|
||||
pub struct ResetHandle {
|
||||
pub parent: Arc<dyn ResetController>,
|
||||
pub reset: Option<u32>,
|
||||
}
|
||||
|
||||
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> {
|
||||
let _ = clock;
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
fn set_clock_rate(&self, clock: Option<u32>, rate: u64) -> Result<u64, Error> {
|
||||
let _ = clock;
|
||||
let _ = rate;
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResetController: Device {
|
||||
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error>;
|
||||
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl ClockHandle {
|
||||
pub fn enable(&self) -> Result<(), Error> {
|
||||
self.parent.enable_clock(self.clock)
|
||||
}
|
||||
|
||||
pub fn disable(&self) -> Result<(), Error> {
|
||||
self.parent.disable_clock(self.clock)
|
||||
}
|
||||
|
||||
pub fn rate(&self) -> Result<u64, Error> {
|
||||
self.parent.clock_rate(self.clock)
|
||||
}
|
||||
|
||||
pub fn set_rate(&self, rate: u64) -> Result<u64, Error> {
|
||||
self.parent.set_clock_rate(self.clock, rate)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetHandle {
|
||||
pub fn assert(&self) -> Result<(), Error> {
|
||||
self.parent.assert_reset(self.reset)
|
||||
}
|
||||
|
||||
pub fn deassert(&self) -> Result<(), Error> {
|
||||
self.parent.deassert_reset(self.reset)
|
||||
}
|
||||
|
||||
pub fn assert_for_cycles(&self, cycles: u64) -> Result<(), Error> {
|
||||
self.assert()?;
|
||||
for _ in 0..cycles {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
self.deassert()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,57 @@
|
||||
//! Device-tree handling for controllers of various types: interrupt, clock etc.
|
||||
use alloc::sync::Arc;
|
||||
use device_api::interrupt::FullIrq;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
interrupt::FullIrq,
|
||||
};
|
||||
use fdt_rs::spec::Phandle;
|
||||
|
||||
use crate::TProp;
|
||||
use crate::{DeviceTreePropertyRead, TProp};
|
||||
|
||||
use super::{lookup_phandle, Node};
|
||||
|
||||
pub(crate) struct ClockIter<'dt> {
|
||||
pub(crate) clocks: TProp<'dt>,
|
||||
pub(crate) offset: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct ResetIter<'dt> {
|
||||
pub(crate) resets: TProp<'dt>,
|
||||
pub(crate) offset: usize,
|
||||
}
|
||||
|
||||
impl Iterator for ClockIter<'_> {
|
||||
type Item = ClockHandle;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.clocks.len() {
|
||||
return None;
|
||||
}
|
||||
let phandle = self.clocks.read_cell(self.offset, 1)? as Phandle;
|
||||
let clkc = lookup_phandle(phandle, true)?;
|
||||
let clkc = clkc.clock_controler.try_get()?;
|
||||
let (clock, len) = clkc.clone().map_clock(&self.clocks, self.offset + 1)?;
|
||||
self.offset += len + 1;
|
||||
Some(clock)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ResetIter<'_> {
|
||||
type Item = ResetHandle;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.resets.len() {
|
||||
return None;
|
||||
}
|
||||
let phandle = self.resets.read_cell(self.offset, 1)? as Phandle;
|
||||
let rstc = lookup_phandle(phandle, true)?;
|
||||
let rstc = rstc.reset_controller.try_get()?;
|
||||
let (reset, len) = rstc.clone().map_reset(&self.resets, self.offset + 1)?;
|
||||
self.offset += len + 1;
|
||||
Some(reset)
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupt controller handling
|
||||
|
||||
/// Reads interrupt information, as interpreted by `interrupt_controller`, from `property` at a
|
||||
|
@ -14,7 +14,10 @@ pub mod util;
|
||||
pub use controller::{map_interrupt, map_interrupt_at};
|
||||
pub use macros::device_tree_driver;
|
||||
pub use registry::{lookup_phandle, register_driver};
|
||||
pub use traits::{DeviceTreeInterruptController, Driver, ProbeContext};
|
||||
pub use traits::{
|
||||
DeviceTreeClockController, DeviceTreeInterruptController, DeviceTreeResetController, Driver,
|
||||
ProbeContext,
|
||||
};
|
||||
pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node};
|
||||
|
||||
/// Performs a walk of the device tree and initializes nodes which haven't already been
|
||||
|
@ -4,6 +4,7 @@ use core::ops::Range;
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use device_api::{
|
||||
bus::Bus,
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
device::Device,
|
||||
interrupt::{ExternalInterruptController, FullIrq},
|
||||
};
|
||||
@ -28,6 +29,20 @@ pub trait DeviceTreeInterruptController {
|
||||
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController>;
|
||||
}
|
||||
|
||||
/// Device-tree based clock source interface
|
||||
pub trait DeviceTreeClockController {
|
||||
/// Reads clock information from `property` at given `offset` and maps it to a
|
||||
/// [ClockHandle], returning the handle + the size of the clock entry.
|
||||
fn map_clock(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)>;
|
||||
}
|
||||
|
||||
/// Device-tree based reset source interface
|
||||
pub trait DeviceTreeResetController {
|
||||
/// Reads reset information from `property` at given `offset` and maps it to a
|
||||
/// [ResetHandle], returning the handle + the size of the reset entry.
|
||||
fn map_reset(self: Arc<Self>, property: &TProp, offset: usize) -> Option<(ResetHandle, usize)>;
|
||||
}
|
||||
|
||||
/// Context passed to the driver's `probe` function
|
||||
pub struct ProbeContext {
|
||||
pub(crate) bus: Option<Weak<dyn Bus>>,
|
||||
|
@ -7,7 +7,7 @@ use alloc::{
|
||||
};
|
||||
use device_api::{
|
||||
bus::Bus,
|
||||
clock::ClockController,
|
||||
clock::{ClockController, ClockHandle, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
|
||||
};
|
||||
@ -20,9 +20,11 @@ use yggdrasil_abi::error::Error;
|
||||
use crate::{DeviceTree, DeviceTreeNodeExt, DeviceTreePropertyRead, TNode, TProp};
|
||||
|
||||
use super::{
|
||||
controller::{ClockIter, ResetIter},
|
||||
lookup_phandle, map_interrupt,
|
||||
registry::{register_phandle, DEVICE_TREE, DRIVERS, ROOT},
|
||||
DeviceTreeInterruptController, Driver, ProbeContext,
|
||||
DeviceTreeClockController, DeviceTreeInterruptController, DeviceTreeResetController, Driver,
|
||||
ProbeContext,
|
||||
};
|
||||
|
||||
/// Represents a single node in the device tree, which may or may not:
|
||||
@ -47,8 +49,11 @@ pub struct Node {
|
||||
// Driver/device info
|
||||
device: OneTimeInit<NodeDevice>,
|
||||
init_token: OneTimeInit<()>,
|
||||
|
||||
pub(crate) interrupt_controller: OneTimeInit<Arc<dyn DeviceTreeInterruptController>>,
|
||||
pub(crate) msi_controller: OneTimeInit<Arc<dyn MessageInterruptController>>,
|
||||
pub(crate) clock_controler: OneTimeInit<Arc<dyn DeviceTreeClockController>>,
|
||||
pub(crate) reset_controller: OneTimeInit<Arc<dyn DeviceTreeResetController>>,
|
||||
}
|
||||
|
||||
enum NodeDevice {
|
||||
@ -170,6 +175,18 @@ impl Node {
|
||||
self.msi_controller.init(intc);
|
||||
}
|
||||
|
||||
/// Informs the node of its capability as a reset controller, allowing `resets` to be mapped
|
||||
/// through this device.
|
||||
pub fn make_reset_controller(&self, rstc: Arc<dyn DeviceTreeResetController>) {
|
||||
self.reset_controller.init(rstc);
|
||||
}
|
||||
|
||||
/// Informs the node of its capability as a clock controller, allowing `clocks` to be mapped
|
||||
/// through this device.
|
||||
pub fn make_clock_controller(&self, clkc: Arc<dyn DeviceTreeClockController>) {
|
||||
self.clock_controler.init(clkc);
|
||||
}
|
||||
|
||||
/// Returns the device driver associated with this node, if any was probed.
|
||||
pub fn driver(&self) -> Option<&'static dyn Driver> {
|
||||
self.device.try_get()?.driver()
|
||||
@ -287,6 +304,44 @@ impl Node {
|
||||
.map(|range| PhysicalAddress::from_u64(range.start))
|
||||
}
|
||||
|
||||
/// Returns an input `clock` handle for a given reset name
|
||||
pub fn named_clock(&self, name: &str) -> Option<ClockHandle> {
|
||||
self.property("clock-names")?
|
||||
.as_str_list()
|
||||
.position(|n| n == name)
|
||||
.and_then(|i| self.clock(i))
|
||||
}
|
||||
|
||||
/// Returns a `reset` handle for a given reset name
|
||||
pub fn named_reset(&self, name: &str) -> Option<ResetHandle> {
|
||||
self.property("reset-names")?
|
||||
.as_str_list()
|
||||
.position(|n| n == name)
|
||||
.and_then(|i| self.reset(i))
|
||||
}
|
||||
|
||||
/// Returns an iterator over the node's input clocks
|
||||
pub fn clocks(&self) -> Option<impl Iterator<Item = ClockHandle>> {
|
||||
let clocks = self.property("clocks")?;
|
||||
Some(ClockIter { clocks, offset: 0 })
|
||||
}
|
||||
|
||||
/// Returns an iterator over the node's resets
|
||||
pub fn resets(&self) -> Option<impl Iterator<Item = ResetHandle>> {
|
||||
let resets = self.property("resets")?;
|
||||
Some(ResetIter { resets, offset: 0 })
|
||||
}
|
||||
|
||||
/// Returns the `index`th input clock of the node
|
||||
pub fn clock(&self, index: usize) -> Option<ClockHandle> {
|
||||
self.clocks()?.nth(index)
|
||||
}
|
||||
|
||||
/// Returns the `index`th reset of the node
|
||||
pub fn reset(&self, index: usize) -> Option<ResetHandle> {
|
||||
self.resets()?.nth(index)
|
||||
}
|
||||
|
||||
/// Reads interrupt information from `interrupts[index]` property, mapped by the node's
|
||||
/// `interrupt-parent`.
|
||||
pub fn interrupt(&self, index: usize) -> Option<FullIrq> {
|
||||
@ -349,6 +404,11 @@ impl Node {
|
||||
pub fn prop_usize(&self, name: &str) -> Option<usize> {
|
||||
self.dt_node.prop_cell_usize(name)
|
||||
}
|
||||
|
||||
/// Interprets property `name` as a string value
|
||||
pub fn prop_str(&self, name: &str) -> Option<&'static str> {
|
||||
self.dt_node.prop_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Node {
|
||||
@ -397,8 +457,11 @@ fn unflatten_node(
|
||||
|
||||
device: OneTimeInit::new(),
|
||||
init_token: OneTimeInit::new(),
|
||||
|
||||
interrupt_controller: OneTimeInit::new(),
|
||||
msi_controller: OneTimeInit::new(),
|
||||
clock_controler: OneTimeInit::new(),
|
||||
reset_controller: OneTimeInit::new(),
|
||||
});
|
||||
|
||||
if let Some(phandle) = phandle {
|
||||
|
@ -1,4 +1,6 @@
|
||||
//! Device tree nodes' property accessors
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use fdt_rs::{
|
||||
base::iters::StringPropIter,
|
||||
index::DevTreeIndexProp,
|
||||
@ -9,7 +11,7 @@ use fdt_rs::{
|
||||
pub trait CellTuple: Sized {
|
||||
type Sizes: Copy;
|
||||
|
||||
fn read<P: DeviceTreePropertyRead + ?Sized>(
|
||||
fn read<'a, P: DeviceTreePropertyRead<'a> + ?Sized>(
|
||||
property: &P,
|
||||
offset: usize,
|
||||
sizes: Self::Sizes,
|
||||
@ -18,16 +20,16 @@ pub trait CellTuple: Sized {
|
||||
}
|
||||
|
||||
/// Accessor trait for a device tree property
|
||||
pub trait DeviceTreePropertyRead {
|
||||
pub trait DeviceTreePropertyRead<'a> {
|
||||
/// Reads a cell value of `size` at a given `offset`.
|
||||
///
|
||||
/// **NOTE** supported cell sizes are 1 and 2. If the size is 3 and larger,
|
||||
/// perform multiple split reads instead.
|
||||
fn read_cell(&self, offset: usize, size: usize) -> Option<u64>;
|
||||
/// Reads the property as a single string
|
||||
fn as_str(&self) -> Option<&str>;
|
||||
fn as_str(&self) -> Option<&'a str>;
|
||||
/// Reads the property as an iterator over a `<stringlist>`
|
||||
fn as_str_list(&self) -> impl Iterator<Item = &str>;
|
||||
fn as_str_list(&self) -> impl Iterator<Item = &'a str>;
|
||||
/// Returns the length of the property in bytes
|
||||
fn len(&self) -> usize;
|
||||
|
||||
@ -44,11 +46,12 @@ pub trait DeviceTreePropertyRead {
|
||||
|
||||
/// Reads the property as an iterator over uniformly-sized tuples, specified by the
|
||||
/// `sizes` parameter.
|
||||
fn iter_cells<T: CellTuple>(&self, sizes: T::Sizes) -> CellTupleIter<Self, T> {
|
||||
fn iter_cells<T: CellTuple>(&self, sizes: T::Sizes) -> CellTupleIter<'a, '_, Self, T> {
|
||||
CellTupleIter {
|
||||
property: self,
|
||||
offset: 0,
|
||||
sizes,
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,10 +62,11 @@ pub trait DeviceTreePropertyRead {
|
||||
}
|
||||
|
||||
/// An iterator over the tuple cells of some device tree node's property
|
||||
pub struct CellTupleIter<'a, P: DeviceTreePropertyRead + ?Sized, T: CellTuple> {
|
||||
property: &'a P,
|
||||
pub struct CellTupleIter<'a, 'p, P: DeviceTreePropertyRead<'a> + ?Sized, T: CellTuple> {
|
||||
property: &'p P,
|
||||
offset: usize,
|
||||
sizes: T::Sizes,
|
||||
_pd: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
/// An iterator over the string list propoerty
|
||||
@ -70,7 +74,7 @@ pub struct StringListIter<'a> {
|
||||
inner: StringPropIter<'a>,
|
||||
}
|
||||
|
||||
impl DeviceTreePropertyRead for DevTreeIndexProp<'_, '_, '_> {
|
||||
impl<'a> DeviceTreePropertyRead<'a> for DevTreeIndexProp<'a, '_, '_> {
|
||||
fn read_cell(&self, offset: usize, size: usize) -> Option<u64> {
|
||||
match size {
|
||||
1 => self.u32(offset).ok().map(Into::into),
|
||||
@ -84,11 +88,11 @@ impl DeviceTreePropertyRead for DevTreeIndexProp<'_, '_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn as_str(&self) -> Option<&str> {
|
||||
fn as_str(&self) -> Option<&'a str> {
|
||||
self.str().ok()
|
||||
}
|
||||
|
||||
fn as_str_list(&self) -> impl Iterator<Item = &str> {
|
||||
fn as_str_list(&self) -> impl Iterator<Item = &'a str> {
|
||||
StringListIter {
|
||||
inner: self.iter_str(),
|
||||
}
|
||||
@ -99,7 +103,9 @@ impl DeviceTreePropertyRead for DevTreeIndexProp<'_, '_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: DeviceTreePropertyRead + ?Sized, T: CellTuple> Iterator for CellTupleIter<'_, P, T> {
|
||||
impl<'a, P: DeviceTreePropertyRead<'a> + ?Sized, T: CellTuple> Iterator
|
||||
for CellTupleIter<'a, '_, P, T>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@ -153,7 +159,7 @@ macro impl_cell_tuples(
|
||||
impl CellTuple for impl_cell_tuple_types!($($index (u64))+) {
|
||||
type Sizes = impl_cell_tuple_types!($($index (usize))+);
|
||||
|
||||
fn read<P: DeviceTreePropertyRead + ?Sized>(
|
||||
fn read<'a, P: DeviceTreePropertyRead<'a> + ?Sized>(
|
||||
property: &P,
|
||||
offset: usize,
|
||||
sizes: Self::Sizes,
|
||||
|
@ -4,7 +4,11 @@ use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
};
|
||||
use core::{fmt, str::FromStr};
|
||||
use core::{
|
||||
fmt,
|
||||
str::FromStr,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use ring::RingLoggerSink;
|
||||
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
@ -28,6 +32,22 @@ pub use ring::add_kernel_log_file;
|
||||
pub use sink::{add_early_sink, add_serial_sink, add_sink, disable_early_sinks, DebugSink};
|
||||
|
||||
static DEBUG_LOCK: IrqSafeSpinlock<()> = IrqSafeSpinlock::new(());
|
||||
static MUTE_DEBUG: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub struct MuteGuard(bool);
|
||||
|
||||
impl MuteGuard {
|
||||
pub fn acquire() -> Self {
|
||||
let muted = MUTE_DEBUG.swap(true, Ordering::Acquire);
|
||||
Self(muted)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MuteGuard {
|
||||
fn drop(&mut self) {
|
||||
MUTE_DEBUG.store(self.0, Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
struct KernelLoggerSink;
|
||||
|
||||
@ -90,6 +110,10 @@ impl log::Log for KernelLoggerSink {
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
if MUTE_DEBUG.load(Ordering::Acquire) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.enabled(record.metadata()) {
|
||||
return;
|
||||
}
|
||||
|
75
kernel/src/device/clock/fixed.rs
Normal file
75
kernel/src/device/clock/fixed.rs
Normal file
@ -0,0 +1,75 @@
|
||||
//! Fixed clock driver
|
||||
use abi::error::Error;
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockController, ClockHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{device_tree_driver, DeviceTreeClockController, Node, ProbeContext},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
|
||||
struct FixedClock {
|
||||
name: &'static str,
|
||||
frequency: u64,
|
||||
}
|
||||
|
||||
impl Device for FixedClock {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockController for FixedClock {
|
||||
fn clock_rate(&self, clock: Option<u32>) -> Result<u64, Error> {
|
||||
debug_assert!(clock.is_none());
|
||||
Ok(self.frequency)
|
||||
}
|
||||
|
||||
fn set_clock_rate(&self, _clock: Option<u32>, _rate: u64) -> Result<u64, Error> {
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
|
||||
fn enable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
|
||||
fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceTreeClockController for FixedClock {
|
||||
fn map_clock(
|
||||
self: Arc<Self>,
|
||||
_property: &TProp,
|
||||
_offset: usize,
|
||||
) -> Option<(ClockHandle, usize)> {
|
||||
Some((
|
||||
ClockHandle {
|
||||
clock: None,
|
||||
parent: self,
|
||||
},
|
||||
0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["fixed-clock"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let name = node.name()?;
|
||||
let frequency = 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());
|
||||
Some(fixed)
|
||||
}
|
||||
}
|
||||
}
|
141
kernel/src/device/clock/jh7110_syscrg.rs
Normal file
141
kernel/src/device/clock/jh7110_syscrg.rs
Normal file
@ -0,0 +1,141 @@
|
||||
//! 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 CLK_OSC: usize = 0;
|
||||
|
||||
const CLK_UART0_CORE: u32 = 146;
|
||||
|
||||
struct Syscrg {
|
||||
base: PhysicalAddress,
|
||||
parents: [ClockHandle; 1],
|
||||
mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIoMut<'static, [u32]>>>,
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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> {
|
||||
match clock.ok_or(Error::InvalidArgument)? {
|
||||
CLK_UART0_CORE => self.parents[CLK_OSC].rate(),
|
||||
_ => {
|
||||
log::warn!("TODO: jh7110-syscrg: read rate {:#x?}", clock);
|
||||
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 ResetController for Syscrg {
|
||||
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||
let reg = reset / 32;
|
||||
let bit = reset % 32;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
regs.lock()[190 + reg as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||
let reg = reset / 32;
|
||||
let bit = reset % 32;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
regs.lock()[190 + reg as usize] &= !(1 << bit);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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: &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)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,3 +2,9 @@
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
||||
pub mod bcm2835_aux;
|
||||
|
||||
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
|
||||
pub mod jh7110_syscrg;
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64", rust_analyzer))]
|
||||
pub mod fixed;
|
||||
|
@ -2,12 +2,13 @@
|
||||
use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
debug::{self, DebugSink},
|
||||
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
|
||||
vfs::{Terminal, TerminalInput, TerminalOutput},
|
||||
};
|
||||
@ -21,20 +22,29 @@ use tock_registers::{
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
LCR [
|
||||
DLAB OFFSET(7) NUMBITS(1) [],
|
||||
DLS OFFSET(0) NUMBITS(2) [
|
||||
DL8b = 0b11,
|
||||
],
|
||||
],
|
||||
IER [
|
||||
PTIME OFFSET(7) NUMBITS(1) [],
|
||||
EDSSI OFFSET(3) NUMBITS(1) [],
|
||||
ELSI OFFSET(2) NUMBITS(1) [],
|
||||
PTIME OFFSET(7) NUMBITS(1) [],
|
||||
EDSSI OFFSET(3) NUMBITS(1) [],
|
||||
ELSI OFFSET(2) NUMBITS(1) [],
|
||||
// Transmit buffer available
|
||||
ETBEI OFFSET(1) NUMBITS(1) [],
|
||||
ETBEI OFFSET(1) NUMBITS(1) [],
|
||||
// Receive data available
|
||||
ERBFI OFFSET(0) NUMBITS(1) [],
|
||||
ERBFI OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
LSR [
|
||||
// Data ready bit
|
||||
DR OFFSET(0) NUMBITS(1) [],
|
||||
DR OFFSET(0) NUMBITS(1) [],
|
||||
// Transmitter holding register empty
|
||||
THRE OFFSET(5) NUMBITS(1) [],
|
||||
THRE OFFSET(5) NUMBITS(1) [],
|
||||
],
|
||||
USR [
|
||||
BUSY OFFSET(0) NUMBITS(1) [],
|
||||
]
|
||||
}
|
||||
|
||||
@ -50,7 +60,7 @@ register_structs! {
|
||||
// Read: interrupt identification register/Write: frame control register
|
||||
(0x008 => IIR: ReadWrite<u32>),
|
||||
// Line control register
|
||||
(0x00C => LCR: ReadWrite<u32>),
|
||||
(0x00C => LCR: ReadWrite<u32, LCR::Register>),
|
||||
// Modem control register
|
||||
(0x010 => MCR: ReadWrite<u32>),
|
||||
// Line status register
|
||||
@ -69,7 +79,7 @@ register_structs! {
|
||||
(0x070 => FAR: ReadWrite<u32>),
|
||||
(0x074 => TFR: ReadOnly<u32>),
|
||||
(0x078 => RFW: WriteOnly<u32>),
|
||||
(0x07C => USR: ReadOnly<u32>),
|
||||
(0x07C => USR: ReadOnly<u32, USR::Register>),
|
||||
(0x080 => TFL: ReadOnly<u32>),
|
||||
(0x084 => RFL: ReadOnly<u32>),
|
||||
(0x088 => SRR: WriteOnly<u32>),
|
||||
@ -101,6 +111,11 @@ struct Inner {
|
||||
pub struct DwUart {
|
||||
base: PhysicalAddress,
|
||||
irq: FullIrq,
|
||||
clk_baud: ClockHandle,
|
||||
#[allow(unused)]
|
||||
clk_apb: Option<ClockHandle>,
|
||||
rst: Option<ResetHandle>,
|
||||
|
||||
inner: OneTimeInit<Arc<Terminal<Inner>>>,
|
||||
}
|
||||
|
||||
@ -117,8 +132,33 @@ impl Io {
|
||||
self.regs.DR.set(byte as u32);
|
||||
}
|
||||
|
||||
fn init(&mut self) {
|
||||
fn init(&mut self, baud_clock: u64, baud_rate: u64) {
|
||||
let divisor = (baud_clock / (baud_rate * 16)) as u32;
|
||||
|
||||
self.wait_busy();
|
||||
self.regs.IER.set(0);
|
||||
for _ in 0..100 {
|
||||
let _ = self.regs.LSR.get();
|
||||
}
|
||||
for _ in 0..100 {
|
||||
let _ = self.regs.DR.get();
|
||||
}
|
||||
self.wait_busy();
|
||||
self.regs.LCR.write(LCR::DLAB::SET);
|
||||
self.wait_busy();
|
||||
self.regs.DR.set(divisor & 0xFF);
|
||||
self.regs.IER.set((divisor >> 8) & 0xFF);
|
||||
self.wait_busy();
|
||||
self.regs.LCR.write(LCR::DLS::DL8b);
|
||||
self.wait_busy();
|
||||
self.regs.IIR.set(0x01);
|
||||
self.wait_busy();
|
||||
self.regs.MCR.set(0x00);
|
||||
let _ = self.regs.LSR.get();
|
||||
for _ in 0..100 {
|
||||
let _ = self.regs.DR.get();
|
||||
}
|
||||
self.regs.SCR.set(0x00);
|
||||
}
|
||||
|
||||
fn handle_irq(&mut self) -> Option<u8> {
|
||||
@ -130,6 +170,17 @@ impl Io {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_busy(&self) {
|
||||
for _ in 0..100000 {
|
||||
core::hint::spin_loop();
|
||||
}
|
||||
let mut timeout = 1000000;
|
||||
while timeout > 0 && self.regs.USR.matches_all(USR::BUSY::SET) {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterruptHandler for DwUart {
|
||||
@ -149,9 +200,26 @@ impl InterruptHandler for DwUart {
|
||||
|
||||
impl Device for DwUart {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
let regs = DeviceMemoryIo::map(self.base, Default::default())?;
|
||||
let baud_rate = 115200;
|
||||
let clk_baud_rate = self.clk_baud.rate()?;
|
||||
|
||||
// Prevent firmware (SBI in riscv64) from printing to UART while it's being
|
||||
// reset/initialized
|
||||
let guard = debug::MuteGuard::acquire();
|
||||
|
||||
let regs = DeviceMemoryIo::<Regs>::map(self.base, Default::default())?;
|
||||
let mut io = Io { regs };
|
||||
io.init();
|
||||
|
||||
if let Some(reset) = self.rst.as_ref() {
|
||||
reset.assert_for_cycles(100000)?;
|
||||
}
|
||||
|
||||
io.init(clk_baud_rate, baud_rate);
|
||||
|
||||
io.send(b'\r');
|
||||
io.send(b'\n');
|
||||
|
||||
drop(guard);
|
||||
|
||||
let input = TerminalInput::with_capacity(64)?;
|
||||
let output = Inner {
|
||||
@ -219,10 +287,17 @@ device_tree_driver! {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clk_baud = node.named_clock("baudclk")?;
|
||||
let clk_apb = node.named_clock("apb_pclk");
|
||||
let rst = node.reset(0);
|
||||
|
||||
Some(Arc::new(DwUart {
|
||||
base,
|
||||
irq,
|
||||
clk_baud,
|
||||
clk_apb,
|
||||
rst,
|
||||
|
||||
inner: OneTimeInit::new()
|
||||
}))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user