From eb3460a01049cc98d2286a1f522d1f671d93ad72 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 7 Oct 2021 17:20:31 +0300 Subject: [PATCH] feat: orangepi3 rtc tick --- kernel/src/arch/aarch64/mach_orangepi3/mod.rs | 7 ++ kernel/src/arch/aarch64/mach_orangepi3/rtc.rs | 100 ++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 kernel/src/arch/aarch64/mach_orangepi3/rtc.rs diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs index f1697ec..d90c481 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -15,11 +15,13 @@ use error::Errno; mod gpio; mod uart; +mod rtc; pub use gic::IrqNumber; pub use gpio::PinAddress; use gpio::Gpio; use uart::Uart; +use rtc::Rtc; #[allow(missing_docs)] pub fn init_board() -> Result<(), Errno> { @@ -31,11 +33,15 @@ pub fn init_board() -> Result<(), Errno> { UART0.enable()?; UART0.init_irqs()?; + + RTC.enable()?; + RTC.init_irqs()?; } Ok(()) } const UART0_BASE: usize = 0x05000000; +const RTC_BASE: usize = 0x07000000; const PIO_BASE: usize = 0x0300B000; const GICD_BASE: usize = 0x03021000; const GICC_BASE: usize = 0x03022000; @@ -61,4 +67,5 @@ pub fn intc() -> &'static impl IntController { static UART0: Uart = unsafe { Uart::new(UART0_BASE, IrqNumber::new(32)) }; static LOCAL_TIMER: GenericTimer = GenericTimer {}; pub(super) static GPIO: Gpio = unsafe { Gpio::new(PIO_BASE) }; +static RTC: Rtc = unsafe { Rtc::new(RTC_BASE, IrqNumber::new(133)) }; static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) }; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs new file mode 100644 index 0000000..0ee6403 --- /dev/null +++ b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs @@ -0,0 +1,100 @@ +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, + ALARM0_IRQ_EN [ + ALARM0_IRQ_EN OFFSET(0) NUMBITS(1) [] + ], + ALARM0_ENABLE [ + ALM_0_EN OFFSET(0) NUMBITS(1) [] + ], + ALARM0_IRQ_STA [ + ALARM0_IRQ_PEND OFFSET(0) NUMBITS(1) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + Regs { + (0x00 => LOSC_CTRL: ReadWrite), + (0x04 => LOSC_AUTO_SWT_STA: ReadWrite), + (0x08 => INTOSC_CLK_PRESCAL: ReadWrite), + (0x0C => INTOSC_CLK_AUTO_CALI: ReadWrite), + (0x10 => RTC_YY_MM_DD: ReadWrite), + (0x14 => RTC_HH_MM_SS: ReadWrite), + (0x18 => _res0), + (0x20 => ALARM0_COUNTER: ReadWrite), + (0x24 => ALARM0_CUR_VLU: ReadOnly), + (0x28 => ALARM0_ENABLE: ReadWrite), + (0x2C => ALARM0_IRQ_EN: ReadWrite), + (0x30 => ALARM0_IRQ_STA: ReadWrite), + (0x34 => @END), + } +} + +pub struct Rtc { + regs: IrqSafeNullLock>, + irq: IrqNumber +} + +impl Regs { + fn arm_alarm0_irq(&self, sec: u32) { + // Clear IRQ pending status + if sec == 0 { + return; + } + self.ALARM0_IRQ_STA.write(ALARM0_IRQ_STA::ALARM0_IRQ_PEND::SET); + self.ALARM0_IRQ_EN.write(ALARM0_IRQ_EN::ALARM0_IRQ_EN::SET); + self.ALARM0_COUNTER.set(self.ALARM0_CUR_VLU.get() + sec - 1); + self.ALARM0_ENABLE.write(ALARM0_ENABLE::ALM_0_EN::SET); + } +} + +impl RtcDevice for Rtc {} + +impl IntSource for Rtc { + fn handle_irq(&self) -> Result<(), Errno> { + self.regs.lock().arm_alarm0_irq(1); + Ok(()) + } + + fn init_irqs(&'static self) -> Result<(), Errno> { + machine::intc().register_handler(self.irq, self)?; + self.regs.lock().arm_alarm0_irq(1); + machine::intc().enable_irq(self.irq)?; + + Ok(()) + } +} + +impl Device for Rtc { + fn name(&self) -> &'static str { + "Allwinner H6 RTC" + } + + unsafe fn enable(&self) -> Result<(), Errno> { + Ok(()) + } +} + +impl Rtc { + /// Constructs an instance of RTC 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 + } + } +}