forked from M-Labs/zynq-rs
libboard_zynq/gic: refactored and added SGI functions.
This commit is contained in:
parent
187801c4a7
commit
2927c43309
|
@ -1,11 +1,55 @@
|
|||
//! ARM Generic Interrupt Controller
|
||||
|
||||
use bit_field::BitField;
|
||||
use libregister::{RegisterW, RegisterRW};
|
||||
use libregister::{RegisterW, RegisterRW, RegisterR};
|
||||
use super::mpcore;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InterruptId(u8);
|
||||
pub struct InterruptId(pub u8);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
pub enum CPUCore {
|
||||
Core0 = 0b01,
|
||||
Core1 = 0b10
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TargetCPU(u8);
|
||||
|
||||
impl TargetCPU {
|
||||
pub const fn none() -> TargetCPU {
|
||||
TargetCPU(0)
|
||||
}
|
||||
|
||||
pub const fn and(self, other: TargetCPU) -> TargetCPU {
|
||||
TargetCPU(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CPUCore> for TargetCPU {
|
||||
fn from(core: CPUCore) -> Self {
|
||||
TargetCPU(core as u8)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TargetList {
|
||||
CPUList(TargetCPU),
|
||||
Others,
|
||||
This
|
||||
}
|
||||
|
||||
impl From<CPUCore> for TargetList {
|
||||
fn from(core: CPUCore) -> Self {
|
||||
TargetList::CPUList(TargetCPU(core as u8))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TargetCPU> for TargetList {
|
||||
fn from(cpu: TargetCPU) -> Self {
|
||||
TargetList::CPUList(cpu)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum InterruptSensitivity {
|
||||
|
@ -14,19 +58,21 @@ pub enum InterruptSensitivity {
|
|||
}
|
||||
|
||||
pub struct InterruptController {
|
||||
mpcore: mpcore::RegisterBlock,
|
||||
mpcore: &'static mut mpcore::RegisterBlock,
|
||||
}
|
||||
|
||||
impl InterruptController {
|
||||
pub fn new(mpcore: mpcore::RegisterBlock) -> Self {
|
||||
pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
||||
InterruptController { mpcore }
|
||||
}
|
||||
|
||||
pub fn disable_interrupts(&mut self) {
|
||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
|
||||
.enable_s(false));
|
||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
||||
.enable_non_secure(false));
|
||||
// FIXME: Should we disable the distributor globally when we disable interrupt (for a single
|
||||
// core)?
|
||||
// self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
||||
// .enable_non_secure(false));
|
||||
}
|
||||
|
||||
/// enable interrupt signaling
|
||||
|
@ -34,10 +80,26 @@ impl InterruptController {
|
|||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
||||
.enable_s(true));
|
||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(true));
|
||||
|
||||
// Enable all interrupts except those of the lowest priority.
|
||||
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
|
||||
}
|
||||
|
||||
pub fn enable(&mut self, id: InterruptId, target_cpu: u32, sensitivity: InterruptSensitivity) {
|
||||
assert!(target_cpu < 2);
|
||||
/// send software generated interrupt
|
||||
pub fn send_sgi(&mut self, id: InterruptId, targets: TargetList) {
|
||||
assert!(id.0 < 16);
|
||||
self.mpcore.icdsgir.modify(|_, w| match targets {
|
||||
TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0),
|
||||
TargetList::Others => w.target_list_filter(0b01),
|
||||
TargetList::This => w.target_list_filter(0b10)
|
||||
}.sgiintid(id.0).satt(false));
|
||||
}
|
||||
|
||||
/// enable the interrupt *for this core*.
|
||||
/// Not needed for SGI.
|
||||
pub fn enable(&mut self, id: InterruptId, target_cpu: CPUCore, sensitivity: InterruptSensitivity, priority: u8) {
|
||||
// only 5 bits of the priority is useful
|
||||
assert!(priority < 32);
|
||||
|
||||
self.disable_interrupts();
|
||||
|
||||
|
@ -53,7 +115,7 @@ impl InterruptController {
|
|||
let m = (id.0 >> 2) as usize;
|
||||
let n = (8 * (id.0 & 3)) as usize;
|
||||
unsafe {
|
||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu + 1));
|
||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1));
|
||||
}
|
||||
|
||||
// sensitivity
|
||||
|
@ -66,9 +128,23 @@ impl InterruptController {
|
|||
}));
|
||||
}
|
||||
|
||||
// filter no interrupts (lowest priority)
|
||||
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
|
||||
// priority
|
||||
let offset = (id.0 % 4) * 8;
|
||||
let priority: u32 = (priority as u32) << (offset + 3);
|
||||
let mask: u32 = 0xFFFFFFFF ^ (0xFF << offset);
|
||||
unsafe {
|
||||
self.mpcore.icdipr[id.0 as usize / 4].modify(|v| (v & mask) | priority);
|
||||
}
|
||||
|
||||
self.enable_interrupts();
|
||||
}
|
||||
|
||||
pub fn end_interrupt(&mut self, id: InterruptId) {
|
||||
self.mpcore.icceoir.modify(|_, w| w.eoiintid(id.0 as u32));
|
||||
}
|
||||
|
||||
pub fn get_interrupt_id(&self) -> InterruptId {
|
||||
InterruptId(self.mpcore.icciar.read().ackintid() as u8)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -119,30 +119,7 @@ pub struct RegisterBlock {
|
|||
pub icdabr2: RW<u32>,
|
||||
unused13: [u32; 61],
|
||||
/// Interrupt Priority Register
|
||||
pub icdipr0: RW<u32>,
|
||||
pub icdipr1: RW<u32>,
|
||||
pub icdipr2: RW<u32>,
|
||||
pub icdipr3: RW<u32>,
|
||||
pub icdipr4: RW<u32>,
|
||||
pub icdipr5: RW<u32>,
|
||||
pub icdipr6: RW<u32>,
|
||||
pub icdipr7: RW<u32>,
|
||||
pub icdipr8: RW<u32>,
|
||||
pub icdipr9: RW<u32>,
|
||||
pub icdipr10: RW<u32>,
|
||||
pub icdipr11: RW<u32>,
|
||||
pub icdipr12: RW<u32>,
|
||||
pub icdipr13: RW<u32>,
|
||||
pub icdipr14: RW<u32>,
|
||||
pub icdipr15: RW<u32>,
|
||||
pub icdipr16: RW<u32>,
|
||||
pub icdipr17: RW<u32>,
|
||||
pub icdipr18: RW<u32>,
|
||||
pub icdipr19: RW<u32>,
|
||||
pub icdipr20: RW<u32>,
|
||||
pub icdipr21: RW<u32>,
|
||||
pub icdipr22: RW<u32>,
|
||||
pub icdipr23: RW<u32>,
|
||||
pub icdipr: [RW<u32>; 24],
|
||||
unused14: [u32; 232],
|
||||
/// Interrupt Processor Targets Registers
|
||||
pub icdiptr: [RW<u32>; 24],
|
||||
|
|
Loading…
Reference in New Issue