Without code or error descriptions I can't tell exactly what's wrong, but my guess is that you are using the base address from the device tree as the base address of the GIC 400 and then applying the offsets described in the GIC 400 memory map documentation [1]. If that's the case, then the base address that you're using is wrong, as the actual base address is 0x10_7FFF_8000.
The following Rust code is a Raspberry Pi 5 hacked port from the GIC 400 driver from a bare metal project of mine for the Raspberry Pi 4. It worked without almost any changes apart from modifying certain things that rely on infrastructure that doesn't exist in the Raspberry Pi 5 code to which I ported the driver.
The following is how I tested the above code using the ARM clock which delivers a private peripheral interrupt to the GIC 400:
And the following is the output of that code:
[1]: https://developer.arm.com/documentation ... ap?lang=en
The following Rust code is a Raspberry Pi 5 hacked port from the GIC 400 driver from a bare metal project of mine for the Raspberry Pi 4. It worked without almost any changes apart from modifying certain things that rely on infrastructure that doesn't exist in the Raspberry Pi 5 code to which I ported the driver.
Code:
//! Generic Interrupt Controller (GIC) 400) driver.//!//! Documentation://!//! * [CoreLink GIC-400 Generic Interrupt Controller Technical Reference Manual](https://developer.arm.com/documentation/ddi0471/b)//! * [ARM Generic Interrupt Controller Architecture Specification](https://developer.arm.com/documentation/ihi0048/b)use core::arch::asm;use core::ptr::write_volatile;use core::sync::atomic::{fence, Ordering};/// Number of SPIs on the BCM2711 (not sure if the number differs on the BCM2712).const SPI_COUNT: usize = 192;/// Total number of IRQs on the BCM2711.const IRQ_COUNT: usize = SPI_COUNT + 32;/// Base address of theGIC 400.const GIC_BASE: usize = 0x107fff8000;/// GIC Distributor interface control register.const GICD_CTLR: *mut u32 = (GIC_BASE + 0x1000) as _;/// IRQ set enable registers.const GICD_ISENABLER: *mut [u32; IRQ_COUNT >> 5] = (GIC_BASE + 0x1100) as _;/// IRQ clear enable registers.const GICD_ICENABLER: *mut [u32; IRQ_COUNT >> 5] = (GIC_BASE + 0x1180) as _;/// IRQ priority registers.const GICD_IPRIORITYR: *mut [u8; IRQ_COUNT] = (GIC_BASE + 0x1400) as _;/// IRQ target CPU registers.const GICD_ITARGETSR: *mut [u8; IRQ_COUNT] = (GIC_BASE + 0x1800) as _;/// IRQ trigger configuration registers.const GICD_ICFGR: *mut [u32; IRQ_COUNT >> 4 /* Two bits per field */] = (GIC_BASE + 0x1c00) as _;/// GIC CPU interface control register.const GICC_CTLR: *mut u32 = (GIC_BASE + 0x2000) as _;/// IRQ minimum priority register.const GICC_PMR: *mut u32 = (GIC_BASE + 0x2004) as _;/// IRQ acknowledge register.const GICC_IAR: *mut u32 = (GIC_BASE + 0x200C) as _;/// IRQ dismissal register.const GICC_EOIR: *mut u32 = (GIC_BASE + 0x2010) as _;/// IRQ driver.pub struct Irq{ /// Registered handlers. handlers: [fn(u32); IRQ_COUNT],}impl Irq{ /// Creates and initializes a new interrupt controller driver. pub fn new() -> Self { unsafe { // Disable all IRQs. (*GICD_ICENABLER).iter_mut() .for_each(|element| write_volatile(element, 0xFFFFFFFF)); // Set the minimum priority level (higher values correspond to lower priority // levels). GICC_PMR.write_volatile(0xFF); // Raise the priority of every IRQ as matching the lowest priority level masks // them. (*GICD_IPRIORITYR).iter_mut() .for_each(|element| write_volatile(element, 0x7F)); // Make all IRQs level triggered. (*GICD_ICFGR).iter_mut() .for_each(|element| write_volatile(element, 0x55555555)); // Deliver all SPIs to all cores. (*GICD_ITARGETSR).iter_mut() .skip(32) .for_each(|element| write_volatile(element, 0xFF)); // Enable the distributor interface. GICD_CTLR.write_volatile(0x1); // Enable the CPU interface. GICC_CTLR.write_volatile(0x1); } Self { handlers: [Self::unhandled; IRQ_COUNT] } } /// Registers a handler to be called when the specified IRQ is triggered. /// /// * `irq`: IRQ to wait for. /// * `handler`: Handler function to register. /// /// Panics if the IRQ is out of range. #[track_caller] pub fn register(&mut self, irq: u32, handler: fn(u32)) { assert!((irq as usize) < IRQ_COUNT, "IRQ #{irq} is out of range"); self.handlers[irq as usize] = handler; // Figure out which register and bit to enable for the given IRQ. let val = 0x1 << (irq & 0x1F); let idx = irq as usize >> 5; unsafe { write_volatile((*GICD_ISENABLER).get_mut(idx).unwrap(), val) }; } /// Checks for and processes pending IRQs in an infinite loop. pub fn dispatch(&self) -> ! { loop { let val = unsafe { GICC_IAR.read_volatile() }; let irq = val & 0x3FF; // Strip sender info from SGIs. if irq as usize >= IRQ_COUNT { Self::sleep(); continue; } fence(Ordering::SeqCst); self.handlers[irq as usize](irq); fence(Ordering::SeqCst); unsafe { GICC_EOIR.write_volatile(val as _) }; } } /// Hints the calling CPU to idle in a low power state until an IRQ is /// delivered. fn sleep() { unsafe { asm!("msr daifclr, #0x3", "wfi", options(nomem, nostack, preserves_flags)); } } fn unhandled(irq: u32) { panic!("Received IRQ {irq} without a properly configured handler"); }}impl Drop for Irq { fn drop(&mut self) { unsafe { // Disable all IRQs. (*GICD_ICENABLER).iter_mut() .for_each(|element| write_volatile(element, 0xFFFFFFFF)); // Disable the distributor interface. GICD_CTLR.write_volatile(0x0); // Disable the CPU interface. GICC_CTLR.write_volatile(0x0); } }}
Code:
/// Entry point.#[no_mangle]pub extern "C" fn start() -> !{ println!("Starting"); let mut gic = Irq::new(); let schedule = |_| { println!("Clock tick!"); unsafe { // Schedule an interrupt to the next second from now. asm!( "mrs {tmp}, cntfrq_el0", "msr cntp_tval_el0, {tmp}", "mov {tmp}, #0x1", "msr cntp_ctl_el0, {tmp}", tmp = out (reg) _, options (nomem, nostack, preserves_flags) ); } }; schedule(0); gic.register(30, schedule); gic.dispatch()}
Code:
StartingClock tick!Clock tick!Clock tick!Clock tick!Clock tick!...
Statistics: Posted by Fridux — Sat Jun 08, 2024 11:17 pm