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
|
//! ARM Generic Interrupt Controller
|
||||||
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use libregister::{RegisterW, RegisterRW};
|
use libregister::{RegisterW, RegisterRW, RegisterR};
|
||||||
use super::mpcore;
|
use super::mpcore;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum InterruptSensitivity {
|
pub enum InterruptSensitivity {
|
||||||
@ -14,19 +58,21 @@ pub enum InterruptSensitivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct InterruptController {
|
pub struct InterruptController {
|
||||||
mpcore: mpcore::RegisterBlock,
|
mpcore: &'static mut mpcore::RegisterBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InterruptController {
|
impl InterruptController {
|
||||||
pub fn new(mpcore: mpcore::RegisterBlock) -> Self {
|
pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
||||||
InterruptController { mpcore }
|
InterruptController { mpcore }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable_interrupts(&mut self) {
|
pub fn disable_interrupts(&mut self) {
|
||||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
|
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
|
||||||
.enable_s(false));
|
.enable_s(false));
|
||||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
// FIXME: Should we disable the distributor globally when we disable interrupt (for a single
|
||||||
.enable_non_secure(false));
|
// core)?
|
||||||
|
// self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
||||||
|
// .enable_non_secure(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// enable interrupt signaling
|
/// enable interrupt signaling
|
||||||
@ -34,10 +80,26 @@ impl InterruptController {
|
|||||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
||||||
.enable_s(true));
|
.enable_s(true));
|
||||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(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) {
|
/// send software generated interrupt
|
||||||
assert!(target_cpu < 2);
|
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();
|
self.disable_interrupts();
|
||||||
|
|
||||||
@ -53,7 +115,7 @@ impl InterruptController {
|
|||||||
let m = (id.0 >> 2) as usize;
|
let m = (id.0 >> 2) as usize;
|
||||||
let n = (8 * (id.0 & 3)) as usize;
|
let n = (8 * (id.0 & 3)) as usize;
|
||||||
unsafe {
|
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
|
// sensitivity
|
||||||
@ -66,9 +128,23 @@ impl InterruptController {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter no interrupts (lowest priority)
|
// priority
|
||||||
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
|
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();
|
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>,
|
pub icdabr2: RW<u32>,
|
||||||
unused13: [u32; 61],
|
unused13: [u32; 61],
|
||||||
/// Interrupt Priority Register
|
/// Interrupt Priority Register
|
||||||
pub icdipr0: RW<u32>,
|
pub icdipr: [RW<u32>; 24],
|
||||||
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>,
|
|
||||||
unused14: [u32; 232],
|
unused14: [u32; 232],
|
||||||
/// Interrupt Processor Targets Registers
|
/// Interrupt Processor Targets Registers
|
||||||
pub icdiptr: [RW<u32>; 24],
|
pub icdiptr: [RW<u32>; 24],
|
||||||
|
Loading…
Reference in New Issue
Block a user