feat: pl031 tick

This commit is contained in:
2021-10-07 16:35:07 +03:00
parent be56fdc45e
commit 3a142fbe34
4 changed files with 112 additions and 2 deletions
+6
View File
@@ -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<IrqNumber = IrqNumber> {
}
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 {};
+3 -2
View File
@@ -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 {
+10
View File
@@ -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 {}
+93
View File
@@ -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<u32>),
(0x04 => MR: ReadWrite<u32>),
(0x08 => LR: ReadWrite<u32>),
(0x0C => CR: ReadWrite<u32, CR::Register>),
(0x10 => IMSC: ReadWrite<u32, IMSC::Register>),
(0x14 => RIS: ReadOnly<u32>),
(0x18 => MIS: ReadOnly<u32>),
(0x1C => ICR: WriteOnly<u32, ICR::Register>),
(0x20 => @END),
}
}
/// Device struct for PL031
pub struct Pl031 {
regs: IrqSafeNullLock<MemoryIo<Regs>>,
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
}
}
}