From cf21dc9b9aadcb2c84d75f3834b5ee9f657c041a Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 7 Oct 2021 19:07:59 +0300 Subject: [PATCH] feat: orangepi3 reset via r_wdog --- kernel/src/arch/aarch64/mach_orangepi3/mod.rs | 13 ++++ kernel/src/arch/aarch64/mach_orangepi3/rtc.rs | 22 ++++-- .../src/arch/aarch64/mach_orangepi3/uart.rs | 11 ++- .../src/arch/aarch64/mach_orangepi3/wdog.rs | 70 +++++++++++++++++++ 4 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 kernel/src/arch/aarch64/mach_orangepi3/wdog.rs diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs index d90c481..3458f8d 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -16,12 +16,14 @@ use error::Errno; mod gpio; mod uart; mod rtc; +mod wdog; pub use gic::IrqNumber; pub use gpio::PinAddress; use gpio::Gpio; use uart::Uart; use rtc::Rtc; +use wdog::RWdog; #[allow(missing_docs)] pub fn init_board() -> Result<(), Errno> { @@ -40,6 +42,16 @@ pub fn init_board() -> Result<(), Errno> { Ok(()) } +/// Performs board reset +/// +/// # Safety +/// +/// Unsafe: may interrupt critical processes +pub unsafe fn reset_board() -> ! { + R_WDOG.reset_board() +} + +const R_WDOG_BASE: usize = 0x07020400; const UART0_BASE: usize = 0x05000000; const RTC_BASE: usize = 0x07000000; const PIO_BASE: usize = 0x0300B000; @@ -64,6 +76,7 @@ pub fn intc() -> &'static impl IntController { &GIC } +static R_WDOG: RWdog = unsafe { RWdog::new(R_WDOG_BASE) }; 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) }; diff --git a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs index 0ee6403..4149d4c 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/rtc.rs @@ -1,11 +1,18 @@ -use crate::dev::{Device, rtc::RtcDevice, irq::{IntController, IntSource}}; -use crate::arch::{MemoryIo, machine::{self, IrqNumber}}; +use crate::arch::{ + machine::{self, IrqNumber}, + MemoryIo, +}; +use crate::dev::{ + irq::{IntController, IntSource}, + rtc::RtcDevice, + Device, +}; use crate::sync::IrqSafeNullLock; use error::Errno; use tock_registers::{ - interfaces::{Readable, Writeable, ReadWriteable}, + interfaces::{Readable, Writeable}, register_bitfields, register_structs, - registers::{ReadOnly, ReadWrite, WriteOnly}, + registers::{ReadOnly, ReadWrite}, }; register_bitfields! { @@ -42,7 +49,7 @@ register_structs! { pub struct Rtc { regs: IrqSafeNullLock>, - irq: IrqNumber + irq: IrqNumber, } impl Regs { @@ -51,7 +58,8 @@ impl Regs { if sec == 0 { return; } - self.ALARM0_IRQ_STA.write(ALARM0_IRQ_STA::ALARM0_IRQ_PEND::SET); + 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); @@ -94,7 +102,7 @@ impl Rtc { pub const unsafe fn new(base: usize, irq: IrqNumber) -> Self { Self { regs: IrqSafeNullLock::new(MemoryIo::new(base)), - irq + irq, } } } diff --git a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs index a5ebadc..0b1f386 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/uart.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/uart.rs @@ -110,9 +110,16 @@ impl SerialDevice for Uart { impl IntSource for Uart { fn handle_irq(&self) -> Result<(), Errno> { - let regs = self.regs.lock(); - let byte = regs.DR_DLL.get(); + let byte = self.regs.lock().DR_DLL.get(); debugln!("irq byte = {:#04x}!", byte); + + if byte == 0x1B { + debugln!("Received ESC, resetting"); + unsafe { + machine::reset_board(); + } + } + use crate::dev::gpio::{GpioDevice}; machine::GPIO.toggle_pin(machine::PinAddress::new(3, 26)); Ok(()) diff --git a/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs new file mode 100644 index 0000000..f1b0207 --- /dev/null +++ b/kernel/src/arch/aarch64/mach_orangepi3/wdog.rs @@ -0,0 +1,70 @@ +use crate::arch::MemoryIo; +use crate::sync::IrqSafeNullLock; +use tock_registers::{ + interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite, +}; + +register_bitfields! { + u32, + CTRL [ + KEY OFFSET(1) NUMBITS(12) [ + Value = 0xA57 + ], + RESTART OFFSET(0) NUMBITS(1) [] + ], + CFG [ + CONFIG OFFSET(0) NUMBITS(2) [ + System = 1 + ] + ], + MODE [ + EN OFFSET(0) NUMBITS(1) [] + ] +} + +register_structs! { + #[allow(non_snake_case)] + RWdogRegs { + (0x00 => IRQ_EN: ReadWrite), + (0x04 => IRQ_STA: ReadWrite), + (0x08 => _res0), + (0x10 => CTRL: ReadWrite), + (0x14 => CFG: ReadWrite), + (0x18 => MODE: ReadWrite), + (0x1C => @END), + } +} + +pub(super) struct RWdog { + regs: IrqSafeNullLock>, +} + +impl RWdog { + /// Performs board reset + /// + /// # Safety + /// + /// Unsafe: may interrupt critical processes + pub unsafe fn reset_board(&self) -> ! { + let regs = self.regs.lock(); + + regs.CFG.write(CFG::CONFIG::System); + regs.MODE.write(MODE::EN::SET); + regs.CTRL.write(CTRL::KEY::Value + CTRL::RESTART::SET); + + loop { + asm!("wfe"); + } + } + + /// Constructs an instance of R_WDOG peripheral. + /// + /// # Safety + /// + /// Does not perform `base` validation. + pub const unsafe fn new(base: usize) -> Self { + Self { + regs: IrqSafeNullLock::new(MemoryIo::new(base)), + } + } +}