From 40c94b5abcedd158ea250fcac09310ad1f84dfa2 Mon Sep 17 00:00:00 2001 From: bunnie Date: Wed, 26 Nov 2025 20:45:12 +0800 Subject: [PATCH] add kpc_aoint abstraction layers --- libs/bao1x-hal/src/kpc_aoint.rs | 110 ++++++++++++++++++++ services/bao1x-hal-service/src/kpc_aoint.rs | 34 ++++++ 2 files changed, 144 insertions(+) create mode 100644 libs/bao1x-hal/src/kpc_aoint.rs create mode 100644 services/bao1x-hal-service/src/kpc_aoint.rs diff --git a/libs/bao1x-hal/src/kpc_aoint.rs b/libs/bao1x-hal/src/kpc_aoint.rs new file mode 100644 index 000000000..57575d402 --- /dev/null +++ b/libs/bao1x-hal/src/kpc_aoint.rs @@ -0,0 +1,110 @@ +use std::pin::Pin; + +use arbitrary_int::u4; +use bao1x_api::IrqNotification; +use bitbybit::bitfield; +use utralib::*; + +#[bitfield(u32)] +#[derive(PartialEq, Eq, Debug)] +// this is the AOFR register - ao_sysctrl::SFR_AOFR +pub struct AoIntStatus { + #[bit(6, rw)] + ao_pad_in0: bool, + #[bit(5, rw)] + ao_pad_in1: bool, + #[bit(4, rw)] + wakeup_valid: bool, + #[bit(3, rw)] + kpc_interrupt: bool, + #[bit(2, rw)] + timer_interrupt: bool, + #[bit(1, rw)] + rtc_interrupt: bool, + #[bit(0, rw)] + wdt_reset: bool, +} + +// Numbers here are relative to the bit position within the IRQ2 register +#[repr(u32)] +pub enum IrqMapping { + // AoWakeup triggers based on either of PI0 or PI1 going low, plus a subset of internal wakeup sources + AoWakeup = 15, + // This is the subset of internal sources + AoInt = 14, + Watchdog = 13, + Timer1 = 12, + Timer0 = 11, + Reram = 22, + Mailbox3 = 5, + Mailbox2 = 4, + Mailbox1 = 3, + Mailbox0 = 2, + Mdma = 1, + Qfc = 0, +} +/// This structure is only available in `std` environment due to the very different +/// way in which interrupts are handled between the two environments. +pub struct KpcAoInt { + pub kpc: CSR, + pub ao: CSR, + pub irq: CSR, + pub args: Vec, + enable: u32, +} + +impl KpcAoInt { + pub fn new(handler: Option) -> Pin> { + let mem = xous::map_memory( + xous::MemoryAddress::new(utra::dkpc::HW_DKPC_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("Couldn't map dkpc range"); + let irq = xous::map_memory( + xous::MemoryAddress::new(utra::irqarray2::HW_IRQARRAY2_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("Couldn't map irq2 range"); + let ao = xous::map_memory( + xous::MemoryAddress::new(utra::ao_sysctrl::HW_AO_SYSCTRL_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("Couldn't map ao_sysctrl range"); + + let mut kpc_aoint = Box::pin(KpcAoInt { + kpc: CSR::new(mem.as_ptr() as *mut u32), + irq: CSR::new(irq.as_ptr() as *mut u32), + ao: CSR::new(ao.as_ptr() as *mut u32), + args: Vec::new(), + enable: 0, + }); + + if let Some(handler) = handler { + xous::claim_interrupt( + utra::irqarray2::IRQARRAY2_IRQ, + handler, + Pin::as_mut(&mut kpc_aoint).get_mut() as *mut KpcAoInt as *mut usize, + ) + .expect("couldn't claim ao/kpc handler interrupt"); + } + kpc_aoint + } + + /// Adds a notifier to the IRQ stack. Does not also enable the IRQ. + pub fn add_irq_notifier(&mut self, notification: IrqNotification) { self.args.push(notification) } + + pub fn modify_irq_ena(&mut self, bit: u4, enable: bool) { + if enable { + self.enable |= 1 << bit.value() as u32; + } else { + self.enable &= !(1 << bit.value() as u32); + } + self.irq.wo(utra::irqarray2::EV_ENABLE, self.enable); + } +} diff --git a/services/bao1x-hal-service/src/kpc_aoint.rs b/services/bao1x-hal-service/src/kpc_aoint.rs new file mode 100644 index 000000000..519e13490 --- /dev/null +++ b/services/bao1x-hal-service/src/kpc_aoint.rs @@ -0,0 +1,34 @@ +use bao1x_hal::kpc_aoint::KpcAoInt; +use utralib::utra::irqarray2; + +pub fn handler(_irq_no: usize, arg: *mut usize) { + let kpc_aoint = unsafe { &mut *(arg as *mut KpcAoInt) }; + let pending = kpc_aoint.irq.r(irqarray2::EV_PENDING); + // clear all pending interrupts + kpc_aoint.irq.wo(irqarray2::EV_PENDING, pending); + + // Note to self: this routine might need augmentation if the interrupt source also + // has to be *disabled*. This would be necessary if the interrupt persists as asserted + // instead of being a pulse, to prevent re-entrant interrupting. + + for bit in 0..16u32 { + let mask = 1u32 << bit; + if (pending & mask) != 0 { + for notifier in kpc_aoint.args.iter() { + if notifier.bit.value() as u32 == bit { + xous::try_send_message( + notifier.conn, + xous::Message::new_scalar( + notifier.opcode, + pending as usize, + notifier.args[1], + notifier.args[2], + notifier.args[3], + ), + ) + .ok(); + } + } + } + } +}