use core::sync::atomic::AtomicI32;
use aarch64_cpu::registers::*;
use axplat::irq::{HandlerTable, IrqHandler, IrqIf};
use log::*;
use rdif_intc::*;
use rdrive::Device;
use spin::Mutex;
use crate::fdt::find_trigger;
mod v2;
mod v3;
const MAX_IRQ_COUNT: usize = 1024;
static VERSION: AtomicI32 = AtomicI32::new(0);
static IRQ_HANDLER_TABLE: HandlerTable<MAX_IRQ_COUNT> = HandlerTable::new();
struct IrqIfImpl;
#[impl_plat_interface]
impl IrqIf for IrqIfImpl {
fn set_enable(irq_raw: usize, enabled: bool) {
set_enable(irq_raw, enabled);
}
fn register(irq_num: usize, handler: IrqHandler) -> bool {
trace!("register handler IRQ {}", irq_num);
if IRQ_HANDLER_TABLE.register_handler(irq_num, handler) {
Self::set_enable(irq_num, true);
return true;
}
warn!("register handler for IRQ {} failed", irq_num);
false
}
fn unregister(irq_num: usize) -> Option<IrqHandler> {
trace!("unregister handler IRQ {}", irq_num);
Self::set_enable(irq_num, false);
IRQ_HANDLER_TABLE.unregister_handler(irq_num)
}
fn handle(irq_num: usize) -> Option<usize> {
match gic_version() {
2 => v2::handle(irq_num),
3 => v3::handle(irq_num),
_ => panic!("Unsupported GIC version"),
}
}
fn send_ipi(id: usize, target: axplat::irq::IpiTarget) {
match gic_version() {
2 => v2::send_ipi(id, target),
3 => v3::send_ipi(id, target),
_ => panic!("Unsupported GIC version"),
}
}
}
pub(crate) fn init() {
let intc = get_gicd();
debug!("Initializing GICD...");
let mut gic = intc.lock().unwrap();
gic.open().unwrap();
debug!("GICD initialized");
}
fn gic_version() -> i32 {
VERSION.load(core::sync::atomic::Ordering::SeqCst)
}
pub(crate) fn init_current_cpu() {
{
let mut intc = get_gicd().lock().unwrap();
if let Some(v) = intc.typed_mut::<v2::Gic>() {
let cpu = v.cpu_interface();
v2::TRAP.call_once(|| cpu.trap_operations());
v2::CPU_IF.with_current(|c| {
c.call_once(|| Mutex::new(cpu));
});
VERSION.store(2, core::sync::atomic::Ordering::SeqCst);
}
if let Some(v) = intc.typed_mut::<v3::Gic>() {
let cpu = v.cpu_interface();
v3::TRAP.call_once(|| cpu.trap_operations());
v3::CPU_IF.with_current(|c| {
c.call_once(|| Mutex::new(cpu));
});
VERSION.store(3, core::sync::atomic::Ordering::SeqCst);
}
}
match gic_version() {
2 => v2::init_current_cpu(),
3 => v3::init_current_cpu(),
_ => panic!("Unsupported GIC version"),
}
debug!("GIC initialized for current CPU");
}
fn get_gicd() -> Device<Intc> {
rdrive::get_one().expect("no interrupt controller found")
}
fn current_cpu() -> usize {
MPIDR_EL1.get() as usize & 0xffffff
}
pub(crate) fn set_enable(irq_raw: usize, enabled: bool) {
let t = find_trigger(irq_raw);
trace!(
"set_enable: irq_raw={:#x}, trigger={:?}, enabled={}",
irq_raw, t, enabled
);
match gic_version() {
2 => v2::set_enable(irq_raw, t, enabled),
3 => v3::set_enable(irq_raw, t, enabled),
_ => panic!("Unsupported GIC version"),
}
}
pub fn parse_fdt_irqs(fdt_irqs: &[u32]) -> IrqConfig {
let raw = arm_gic_driver::fdt_parse_irq_config(fdt_irqs).unwrap();
IrqConfig {
irq: (raw.id.to_u32() as usize).into(),
trigger: match raw.trigger {
arm_gic_driver::v3::Trigger::Edge => Trigger::EdgeRising,
arm_gic_driver::v3::Trigger::Level => Trigger::LevelHigh,
},
is_private: raw.id.is_private(),
}
}