diff --git a/kernel/lib/device-api/src/clock.rs b/kernel/lib/device-api/src/clock.rs index 6a99d36c..081199e6 100644 --- a/kernel/lib/device-api/src/clock.rs +++ b/kernel/lib/device-api/src/clock.rs @@ -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, + pub clock: Option, +} + +pub struct ResetHandle { + pub parent: Arc, + pub reset: Option, +} + +pub trait ClockController: Device { + fn enable_clock(&self, clock: Option) -> Result<(), Error>; + fn disable_clock(&self, clock: Option) -> Result<(), Error>; + + fn clock_rate(&self, clock: Option) -> Result { + let _ = clock; + Err(Error::NotImplemented) + } + fn set_clock_rate(&self, clock: Option, rate: u64) -> Result { + let _ = clock; + let _ = rate; + Err(Error::NotImplemented) + } +} + +pub trait ResetController: Device { + fn assert_reset(&self, reset: Option) -> Result<(), Error>; + fn deassert_reset(&self, reset: Option) -> 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 { + self.parent.clock_rate(self.clock) + } + + pub fn set_rate(&self, rate: u64) -> Result { + 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(()) + } } diff --git a/kernel/lib/device-tree/src/driver/controller.rs b/kernel/lib/device-tree/src/driver/controller.rs index 6084fc89..ee3ab012 100644 --- a/kernel/lib/device-tree/src/driver/controller.rs +++ b/kernel/lib/device-tree/src/driver/controller.rs @@ -1,20 +1,55 @@ //! 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}; -/// Looks up an `interrupt-controller` node by its phandle with lazy probe. -pub fn interrupt_controller(phandle: Phandle) -> Option> { - lookup_phandle(phandle, true) +pub(crate) struct ClockIter<'dt> { + pub(crate) clocks: TProp<'dt>, + pub(crate) offset: usize, } -/// Looks up a clock controller by its phandle with lazy probe. -pub fn clock_controller(phandle: Phandle) -> Option> { - lookup_phandle(phandle, true) +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 { + 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 { + 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 @@ -33,7 +68,7 @@ pub fn map_interrupt_at( /// Same as [map_interrupt_at], but uses a phandle to address the `interrupt-controller` node /// and a scaled `index`. pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option { - let interrupt_controller = interrupt_controller(phandle)?; + let interrupt_controller = lookup_phandle(phandle, true)?; let interrupt_cells = interrupt_controller.self_interrupt_cells()?; map_interrupt_at(&interrupt_controller, property, index * interrupt_cells) } diff --git a/kernel/lib/device-tree/src/driver/mod.rs b/kernel/lib/device-tree/src/driver/mod.rs index c49d1dd3..462d1337 100644 --- a/kernel/lib/device-tree/src/driver/mod.rs +++ b/kernel/lib/device-tree/src/driver/mod.rs @@ -11,10 +11,13 @@ mod tree; pub mod util; -pub use controller::{interrupt_controller, map_interrupt, map_interrupt_at}; +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 diff --git a/kernel/lib/device-tree/src/driver/traits.rs b/kernel/lib/device-tree/src/driver/traits.rs index a5db8ac0..52b3a23b 100644 --- a/kernel/lib/device-tree/src/driver/traits.rs +++ b/kernel/lib/device-tree/src/driver/traits.rs @@ -2,7 +2,12 @@ use core::ops::Range; use alloc::sync::{Arc, Weak}; -use device_api::{bus::Bus, device::Device, interrupt::FullIrq}; +use device_api::{ + bus::Bus, + clock::{ClockHandle, ResetHandle}, + device::Device, + interrupt::FullIrq, +}; use crate::TProp; @@ -21,6 +26,20 @@ pub trait DeviceTreeInterruptController { fn map_interrupt(&self, property: &TProp, offset: usize) -> Option; } +/// 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, 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, property: &TProp, offset: usize) -> Option<(ResetHandle, usize)>; +} + /// Context passed to the driver's `probe` function pub struct ProbeContext { pub(crate) bus: Option>, diff --git a/kernel/lib/device-tree/src/driver/tree.rs b/kernel/lib/device-tree/src/driver/tree.rs index 8e2103c5..1c039389 100644 --- a/kernel/lib/device-tree/src/driver/tree.rs +++ b/kernel/lib/device-tree/src/driver/tree.rs @@ -5,7 +5,12 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; -use device_api::{bus::Bus, clock::ClockController, device::Device, interrupt::FullIrq}; +use device_api::{ + bus::Bus, + clock::{ClockController, ClockHandle, ResetHandle}, + device::Device, + interrupt::FullIrq, +}; use fdt_rs::spec::Phandle; use libk_mm::address::PhysicalAddress; use libk_util::OneTimeInit; @@ -14,9 +19,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: @@ -41,7 +48,10 @@ pub struct Node { // Driver/device info device: OneTimeInit, init_token: OneTimeInit<()>, + pub(crate) interrupt_controller: OneTimeInit>, + pub(crate) clock_controler: OneTimeInit>, + pub(crate) reset_controller: OneTimeInit>, } enum NodeDevice { @@ -157,6 +167,18 @@ impl Node { self.interrupt_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) { + 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) { + 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() @@ -264,6 +286,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 { + 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 { + 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> { + let clocks = self.property("clocks")?; + Some(ClockIter { clocks, offset: 0 }) + } + + /// Returns an iterator over the node's resets + pub fn resets(&self) -> Option> { + 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 { + self.clocks()?.nth(index) + } + + /// Returns the `index`th reset of the node + pub fn reset(&self, index: usize) -> Option { + 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 { @@ -319,6 +379,11 @@ impl Node { pub fn prop_usize(&self, name: &str) -> Option { 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 { @@ -367,7 +432,10 @@ fn unflatten_node( device: OneTimeInit::new(), init_token: OneTimeInit::new(), + interrupt_controller: OneTimeInit::new(), + clock_controler: OneTimeInit::new(), + reset_controller: OneTimeInit::new(), }); if let Some(phandle) = phandle { diff --git a/kernel/lib/device-tree/src/property.rs b/kernel/lib/device-tree/src/property.rs index c6527e3f..03204d3c 100644 --- a/kernel/lib/device-tree/src/property.rs +++ b/kernel/lib/device-tree/src/property.rs @@ -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( + 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; /// 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 `` - fn as_str_list(&self) -> impl Iterator; + fn as_str_list(&self) -> impl Iterator; /// 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(&self, sizes: T::Sizes) -> CellTupleIter { + fn iter_cells(&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 { 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 { + fn as_str_list(&self) -> impl Iterator { StringListIter { inner: self.iter_str(), } @@ -99,7 +103,9 @@ impl DeviceTreePropertyRead for DevTreeIndexProp<'_, '_, '_> { } } -impl 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 { @@ -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( + fn read<'a, P: DeviceTreePropertyRead<'a> + ?Sized>( property: &P, offset: usize, sizes: Self::Sizes, diff --git a/kernel/libk/src/debug.rs b/kernel/libk/src/debug.rs index 4b1e6cce..a1db31b8 100644 --- a/kernel/libk/src/debug.rs +++ b/kernel/libk/src/debug.rs @@ -41,6 +41,22 @@ const RING_LOGGER_CAPACITY: usize = 65536; static RING_AVAILABLE: AtomicBool = AtomicBool::new(false); static SERIAL_SINK_SET_UP: AtomicBool = AtomicBool::new(false); 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; /// Locking log sink for dumping panic info @@ -219,6 +235,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; } @@ -416,6 +436,10 @@ pub fn add_early_sink(sink: &'static dyn DebugSink, level: LogLevel) { add_sink_inner(DebugSinkWrapper::Static(level, sink)); } +pub fn set_debug_mute(mute: bool) { + MUTE_DEBUG.store(mute, Ordering::Release); +} + pub fn disable_early_sinks() { let mut sinks = DEBUG_SINKS.write(); // TODO proper sink storage/manipulation diff --git a/kernel/src/device/clock/fixed.rs b/kernel/src/device/clock/fixed.rs new file mode 100644 index 00000000..84c0167e --- /dev/null +++ b/kernel/src/device/clock/fixed.rs @@ -0,0 +1,75 @@ +//! Fixed clock driver +use abi::error::Error; +use alloc::sync::Arc; +use device_api::{ + clock::{ClockController, ClockHandle}, + device::Device, +}; +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) -> Result<(), Error> { + Ok(()) + } + + fn display_name(&self) -> &str { + self.name + } +} + +impl ClockController for FixedClock { + fn clock_rate(&self, clock: Option) -> Result { + debug_assert!(clock.is_none()); + Ok(self.frequency) + } + + fn set_clock_rate(&self, _clock: Option, _rate: u64) -> Result { + Err(Error::InvalidOperation) + } + + fn enable_clock(&self, _clock: Option) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + + fn disable_clock(&self, _clock: Option) -> Result<(), Error> { + Err(Error::InvalidOperation) + } +} + +impl DeviceTreeClockController for FixedClock { + fn map_clock( + self: Arc, + _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, _context: &ProbeContext) -> Option> { + 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) + } + } +} diff --git a/kernel/src/device/clock/jh7110_syscrg.rs b/kernel/src/device/clock/jh7110_syscrg.rs new file mode 100644 index 00000000..373b269f --- /dev/null +++ b/kernel/src/device/clock/jh7110_syscrg.rs @@ -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, +}; +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>>, +} + +impl Syscrg { + fn ensure_init(&self) -> Result<&IrqSafeSpinlock>, 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) -> 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) -> Result<(), Error> { + log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}"); + Ok(()) + } + + fn disable_clock(&self, clock: Option) -> Result<(), Error> { + log::warn!("TODO: jh7110-syscrg: disable clock {clock:?}"); + Ok(()) + } + + fn clock_rate(&self, clock: Option) -> Result { + 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, rate: u64) -> Result { + log::warn!("TODO: jh7110-syscrg: set rate {clock:?} -> {rate}"); + Ok(rate) + } +} + +impl ResetController for Syscrg { + fn assert_reset(&self, reset: Option) -> 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) -> 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, 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, 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, context: &ProbeContext) -> Option> { + 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) + } + } +} diff --git a/kernel/src/device/clock/mod.rs b/kernel/src/device/clock/mod.rs index 083cc1b1..5f267992 100644 --- a/kernel/src/device/clock/mod.rs +++ b/kernel/src/device/clock/mod.rs @@ -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; diff --git a/kernel/src/device/serial/snps_dw_apb_uart.rs b/kernel/src/device/serial/snps_dw_apb_uart.rs index 4951124e..683c7a28 100644 --- a/kernel/src/device/serial/snps_dw_apb_uart.rs +++ b/kernel/src/device/serial/snps_dw_apb_uart.rs @@ -2,12 +2,13 @@ use abi::{error::Error, io::TerminalOptions}; use alloc::sync::Arc; use device_api::{ + clock::{ClockHandle, ResetHandle}, device::Device, interrupt::{FullIrq, InterruptHandler}, }; 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), // Line control register - (0x00C => LCR: ReadWrite), + (0x00C => LCR: ReadWrite), // Modem control register (0x010 => MCR: ReadWrite), // Line status register @@ -69,7 +79,7 @@ register_structs! { (0x070 => FAR: ReadWrite), (0x074 => TFR: ReadOnly), (0x078 => RFW: WriteOnly), - (0x07C => USR: ReadOnly), + (0x07C => USR: ReadOnly), (0x080 => TFL: ReadOnly), (0x084 => RFL: ReadOnly), (0x088 => SRR: WriteOnly), @@ -101,6 +111,11 @@ struct Inner { pub struct DwUart { base: PhysicalAddress, irq: FullIrq, + clk_baud: ClockHandle, + #[allow(unused)] + clk_apb: Option, + rst: Option, + inner: OneTimeInit>>, } @@ -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 { @@ -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) -> 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::::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, context: &ProbeContext) -> Option> { 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() })) }