// SPDX-License-Identifier: MIT OR Apache-2.0 // // Copyright (c) 2020 Andre Richter //! GICC Driver - GIC CPU interface. use crate::exception; use core::ops; use register::{mmio::*, register_bitfields, register_structs}; //-------------------------------------------------------------------------------------------------- // Private Definitions //-------------------------------------------------------------------------------------------------- register_bitfields! { u32, /// CPU Interface Control Register CTLR [ Enable OFFSET(0) NUMBITS(1) [] ], /// Interrupt Priority Mask Register PMR [ Priority OFFSET(0) NUMBITS(8) [] ], /// Interrupt Acknowledge Register IAR [ InterruptID OFFSET(0) NUMBITS(10) [] ], /// End of Interrupt Register EOIR [ EOIINTID OFFSET(0) NUMBITS(10) [] ] } //-------------------------------------------------------------------------------------------------- // Public Definitions //-------------------------------------------------------------------------------------------------- register_structs! { #[allow(non_snake_case)] pub RegisterBlock { (0x000 => CTLR: ReadWrite), (0x004 => PMR: ReadWrite), (0x008 => _reserved1), (0x00C => IAR: ReadWrite), (0x010 => EOIR: ReadWrite), (0x014 => @END), } } /// Representation of the GIC CPU interface. pub struct GICC { base_addr: usize, } //-------------------------------------------------------------------------------------------------- // Public Code //-------------------------------------------------------------------------------------------------- impl ops::Deref for GICC { type Target = RegisterBlock; fn deref(&self) -> &Self::Target { unsafe { &*self.ptr() } } } impl GICC { /// Create an instance. /// /// # Safety /// /// - The user must ensure to provide the correct `base_addr`. pub const unsafe fn new(base_addr: usize) -> Self { Self { base_addr } } /// Return a pointer to the associated MMIO register block. fn ptr(&self) -> *const RegisterBlock { self.base_addr as *const _ } /// Accept interrupts of any priority. /// /// Quoting the GICv2 Architecture Specification: /// /// "Writing 255 to the GICC_PMR always sets it to the largest supported priority field /// value." /// /// # Safety /// /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn priority_accept_all(&self) { self.PMR.write(PMR::Priority.val(255)); // Comment in arch spec. } /// Enable the interface - start accepting IRQs. /// /// # Safety /// /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. pub fn enable(&self) { self.CTLR.write(CTLR::Enable::SET); } /// Extract the number of the highest-priority pending IRQ. /// /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. /// /// # Safety /// /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn get_pending_number<'irq_context>( &self, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) -> usize { self.IAR.read(IAR::InterruptID) as usize } /// Complete handling of the currently active IRQ. /// /// Can only be called from IRQ context, which is ensured by taking an `IRQContext` token. /// /// To be called after `get_pending_number()`. /// /// # Safety /// /// - GICC MMIO registers are banked per CPU core. It is therefore safe to have `&self` instead /// of `&mut self`. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn mark_comleted<'irq_context>( &self, irq_number: u32, _ic: &exception::asynchronous::IRQContext<'irq_context>, ) { self.EOIR.write(EOIR::EOIINTID.val(irq_number)); } }