feat: pl031 tick
This commit is contained in:
@@ -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,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 {
|
||||
|
||||
@@ -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 {}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user