From 3a142fbe34eac7d92c8b2f9507ead6e3ae164863 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 7 Oct 2021 16:35:07 +0300 Subject: [PATCH] feat: pl031 tick --- kernel/src/arch/aarch64/mach_qemu/mod.rs | 6 ++ kernel/src/dev/mod.rs | 5 +- kernel/src/dev/rtc/mod.rs | 10 +++ kernel/src/dev/rtc/pl031.rs | 93 ++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 kernel/src/dev/rtc/mod.rs create mode 100644 kernel/src/dev/rtc/pl031.rs diff --git a/kernel/src/arch/aarch64/mach_qemu/mod.rs b/kernel/src/arch/aarch64/mach_qemu/mod.rs index d1dcedc..244f216 100644 --- a/kernel/src/arch/aarch64/mach_qemu/mod.rs +++ b/kernel/src/arch/aarch64/mach_qemu/mod.rs @@ -7,6 +7,7 @@ use crate::arch::aarch64::{ use crate::dev::timer::TimestampSource; use crate::dev::{ irq::{IntController, IntSource}, + rtc::pl031::Pl031, serial::{pl011::Pl011, SerialDevice}, Device, }; @@ -15,6 +16,7 @@ use error::Errno; pub use gic::IrqNumber; const UART0_BASE: usize = 0x09000000; +const RTC_BASE: usize = 0x09010000; const GICD_BASE: usize = 0x08000000; const GICC_BASE: usize = 0x08010000; @@ -25,6 +27,9 @@ pub fn init_board() -> Result<(), Errno> { UART0.enable()?; UART0.init_irqs()?; + + RTC.enable()?; + RTC.init_irqs()?; } Ok(()) } @@ -48,5 +53,6 @@ pub fn intc() -> &'static impl IntController { } static UART0: Pl011 = unsafe { Pl011::new(UART0_BASE, IrqNumber::new(33)) }; +static RTC: Pl031 = unsafe { Pl031::new(RTC_BASE, IrqNumber::new(34)) }; static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) }; static LOCAL_TIMER: GenericTimer = GenericTimer {}; diff --git a/kernel/src/dev/mod.rs b/kernel/src/dev/mod.rs index 583f438..1a03c41 100644 --- a/kernel/src/dev/mod.rs +++ b/kernel/src/dev/mod.rs @@ -3,10 +3,11 @@ use error::Errno; // Device classes -pub mod serial; -pub mod timer; pub mod gpio; pub mod irq; +pub mod rtc; +pub mod serial; +pub mod timer; /// Generic device trait pub trait Device { diff --git a/kernel/src/dev/rtc/mod.rs b/kernel/src/dev/rtc/mod.rs new file mode 100644 index 0000000..f38fb8e --- /dev/null +++ b/kernel/src/dev/rtc/mod.rs @@ -0,0 +1,10 @@ +//! Interfaces and drivers for real-time clock devices + +use crate::dev::Device; + +pub mod pl031; + +// TODO define what RTC devices can do +// alarms? read real time? +/// Interface for generic RTC device +pub trait RtcDevice: Device {} diff --git a/kernel/src/dev/rtc/pl031.rs b/kernel/src/dev/rtc/pl031.rs new file mode 100644 index 0000000..bc4136c --- /dev/null +++ b/kernel/src/dev/rtc/pl031.rs @@ -0,0 +1,93 @@ +//! PL031 - ARM PrimeCell real-time clock implementation +use crate::dev::{Device, rtc::RtcDevice, irq::{IntController, IntSource}}; +use crate::arch::{MemoryIo, machine::{self, IrqNumber}}; +use crate::sync::IrqSafeNullLock; +use error::Errno; +use tock_registers::{ + interfaces::{Readable, Writeable, ReadWriteable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite, WriteOnly}, +}; + +register_bitfields! { + u32, + CR [ + RTCStart OFFSET(0) NUMBITS(1) [] + ], + IMSC [ + RTCIMSC OFFSET(0) NUMBITS(1) [] + ], + ICR [ + RTCICR OFFSET(0) NUMBITS(1) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + Regs { + (0x00 => DR: ReadOnly), + (0x04 => MR: ReadWrite), + (0x08 => LR: ReadWrite), + (0x0C => CR: ReadWrite), + (0x10 => IMSC: ReadWrite), + (0x14 => RIS: ReadOnly), + (0x18 => MIS: ReadOnly), + (0x1C => ICR: WriteOnly), + (0x20 => @END), + } +} + +/// Device struct for PL031 +pub struct Pl031 { + regs: IrqSafeNullLock>, + irq: IrqNumber +} + +impl RtcDevice for Pl031 { +} + +impl IntSource for Pl031 { + fn handle_irq(&self) -> Result<(), Errno> { + let regs = self.regs.lock(); + regs.ICR.write(ICR::RTCICR::SET); + let data = regs.DR.get(); + regs.MR.set(data + 1); + Ok(()) + } + + fn init_irqs(&'static self) -> Result<(), Errno> { + machine::intc().register_handler(self.irq, self)?; + self.regs.lock().IMSC.modify(IMSC::RTCIMSC::SET); + machine::intc().enable_irq(self.irq)?; + + Ok(()) + } +} + +impl Device for Pl031 { + fn name(&self) -> &'static str { + "PL031 RTC" + } + + unsafe fn enable(&self) -> Result<(), Errno> { + let regs = self.regs.lock(); + regs.CR.modify(CR::RTCStart::CLEAR); + regs.MR.set(regs.DR.get() + 1); + regs.CR.modify(CR::RTCStart::SET); + Ok(()) + } +} + +impl Pl031 { + /// Constructs an instance of PL031 device. + /// + /// # Safety + /// + /// Does not perform `base` validation. + pub const unsafe fn new(base: usize, irq: IrqNumber) -> Self { + Self { + regs: IrqSafeNullLock::new(MemoryIo::new(base)), + irq + } + } +}