sunxi-h6: reset through watchdog
This commit is contained in:
parent
887d65f890
commit
f6b27eb42f
@ -22,3 +22,7 @@ pub trait CpuBringupDevice: Device {
|
||||
/// misused.
|
||||
unsafe fn start_cpu(&self, id: usize, ip: usize, arg0: usize) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait ResetDevice: Device {
|
||||
unsafe fn reset(&self) -> !;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use device_api::{
|
||||
ExternalInterruptController, IpiDeliveryTarget, IrqNumber, LocalInterruptController,
|
||||
},
|
||||
timer::MonotonicTimestampProviderDevice,
|
||||
ResetDevice,
|
||||
};
|
||||
use fdt_rs::prelude::PropReader;
|
||||
use git_version::git_version;
|
||||
@ -70,6 +71,7 @@ pub struct AArch64 {
|
||||
ext_intc: OneTimeInit<&'static dyn ExternalInterruptController>,
|
||||
local_intc: OneTimeInit<&'static dyn LocalInterruptController<IpiMessage = CpuMessage>>,
|
||||
mtimer: OneTimeInit<&'static dyn MonotonicTimestampProviderDevice>,
|
||||
reset: OneTimeInit<&'static dyn ResetDevice>,
|
||||
|
||||
// ARM-only devices
|
||||
/// ARM PSCI instance on this system (there may not be one)
|
||||
@ -82,6 +84,7 @@ pub static ARCHITECTURE: AArch64 = AArch64 {
|
||||
ext_intc: OneTimeInit::new(),
|
||||
local_intc: OneTimeInit::new(),
|
||||
mtimer: OneTimeInit::new(),
|
||||
reset: OneTimeInit::new(),
|
||||
|
||||
// ARM-only devices
|
||||
psci: OneTimeInit::new(),
|
||||
@ -180,6 +183,11 @@ impl Architecture for AArch64 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_reset_device(&self, reset: &'static dyn ResetDevice) -> Result<(), Error> {
|
||||
self.reset.init(reset);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn external_interrupt_controller(&self) -> &'static dyn ExternalInterruptController {
|
||||
*self.ext_intc.get()
|
||||
}
|
||||
@ -203,7 +211,8 @@ impl Architecture for AArch64 {
|
||||
}
|
||||
|
||||
unsafe fn reset(&self) -> ! {
|
||||
todo!()
|
||||
let reset = self.reset.get();
|
||||
reset.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
|
||||
use device_api::{
|
||||
interrupt::{ExternalInterruptController, IpiDeliveryTarget, LocalInterruptController},
|
||||
timer::MonotonicTimestampProviderDevice,
|
||||
ResetDevice,
|
||||
};
|
||||
// cfg_if! {
|
||||
// if #[cfg(target_arch = "aarch64")] {
|
||||
@ -106,6 +107,8 @@ pub trait Architecture {
|
||||
timer: &'static dyn MonotonicTimestampProviderDevice,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
fn register_reset_device(&self, reset: &'static dyn ResetDevice) -> Result<(), Error>;
|
||||
|
||||
// TODO only supports 1 extintc per system
|
||||
/// Returns the primary external interrupt controller
|
||||
fn external_interrupt_controller(&self) -> &'static dyn ExternalInterruptController;
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! Power-management related device drivers
|
||||
|
||||
pub mod arm_psci;
|
||||
pub mod sunxi_rwdog;
|
||||
|
110
src/device/power/sunxi_rwdog.rs
Normal file
110
src/device/power/sunxi_rwdog.rs
Normal file
@ -0,0 +1,110 @@
|
||||
//! Allwinner (H6) R Watchdog driver
|
||||
|
||||
use abi::error::Error;
|
||||
use alloc::boxed::Box;
|
||||
use device_api::{Device, ResetDevice};
|
||||
use tock_registers::{
|
||||
interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
aarch64::devtree::{self, DevTreeIndexNodePropGet, DevTreeIndexPropExt},
|
||||
Architecture, ARCHITECTURE,
|
||||
},
|
||||
device_tree_driver,
|
||||
mem::device::DeviceMemoryIo,
|
||||
sync::IrqSafeSpinlock,
|
||||
util::OneTimeInit,
|
||||
};
|
||||
|
||||
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)]
|
||||
Regs {
|
||||
(0x00 => IRQ_EN: ReadWrite<u32>),
|
||||
(0x04 => IRQ_STA: ReadWrite<u32>),
|
||||
(0x08 => _0),
|
||||
(0x10 => CTRL: ReadWrite<u32, CTRL::Register>),
|
||||
(0x14 => CFG: ReadWrite<u32, CFG::Register>),
|
||||
(0x18 => MODE: ReadWrite<u32, MODE::Register>),
|
||||
(0x1C => @END),
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
regs: DeviceMemoryIo<Regs>,
|
||||
}
|
||||
|
||||
struct RWdog {
|
||||
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
|
||||
base: usize,
|
||||
}
|
||||
|
||||
impl ResetDevice for RWdog {
|
||||
unsafe fn reset(&self) -> ! {
|
||||
// TODO disable IRQs
|
||||
let inner = self.inner.get().lock();
|
||||
|
||||
inner.regs.CFG.write(CFG::CONFIG::System);
|
||||
inner.regs.MODE.write(MODE::EN::SET);
|
||||
inner.regs.CTRL.write(CTRL::KEY::Value + CTRL::RESTART::SET);
|
||||
|
||||
loop {
|
||||
core::arch::asm!("wfe");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for RWdog {
|
||||
fn display_name(&self) -> &'static str {
|
||||
"Allwinner H6 Watchdog"
|
||||
}
|
||||
|
||||
unsafe fn init(&'static self) -> Result<(), Error> {
|
||||
let regs = DeviceMemoryIo::map("r_wdog", self.base)?;
|
||||
|
||||
self.inner.init(IrqSafeSpinlock::new(Inner { regs }));
|
||||
|
||||
ARCHITECTURE.register_reset_device(self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["allwinner,sun50i-h6-wdt"],
|
||||
probe(of) => {
|
||||
let reg = devtree::find_prop(&of.node, "reg")?;
|
||||
let status: &str = of.node.prop("status").unwrap_or("enabled");
|
||||
|
||||
if status == "disabled" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (base, _) = reg.cell2_array_item(0, of.address_cells, of.size_cells)?;
|
||||
let base = base as usize;
|
||||
|
||||
Some(Box::new(RWdog {
|
||||
inner: OneTimeInit::new(),
|
||||
base
|
||||
}))
|
||||
}
|
||||
}
|
@ -107,6 +107,10 @@ impl InterruptHandler for SunxiUart {
|
||||
let byte = inner.regs.DLL.get();
|
||||
drop(inner);
|
||||
|
||||
if byte == b'\x1b' as u32 {
|
||||
panic!("RESET TRIGGERED");
|
||||
}
|
||||
|
||||
self.recv_byte(byte as u8);
|
||||
}
|
||||
// inner.regs.ICR.write(ICR::ALL::CLEAR);
|
||||
|
@ -97,6 +97,11 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
||||
|
||||
log_print_raw!(LogLevel::Fatal, "X");
|
||||
PANIC_FINISHED_FENCE.signal();
|
||||
|
||||
#[cfg(feature = "aarch64_orange_pi3")]
|
||||
unsafe {
|
||||
ARCHITECTURE.reset();
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
|
Loading…
x
Reference in New Issue
Block a user