forked from M-Labs/zynq-rs
75 lines
2.2 KiB
Rust
75 lines
2.2 KiB
Rust
|
//! ARM Generic Interrupt Controller
|
||
|
|
||
|
use bit_field::BitField;
|
||
|
use libregister::{RegisterW, RegisterRW};
|
||
|
use super::mpcore;
|
||
|
|
||
|
#[derive(Debug, Clone, Copy)]
|
||
|
pub struct InterruptId(u8);
|
||
|
|
||
|
#[derive(Debug, Clone, Copy)]
|
||
|
pub enum InterruptSensitivity {
|
||
|
Level,
|
||
|
Edge,
|
||
|
}
|
||
|
|
||
|
pub struct InterruptController {
|
||
|
mpcore: mpcore::RegisterBlock,
|
||
|
}
|
||
|
|
||
|
impl InterruptController {
|
||
|
pub fn new(mpcore: 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));
|
||
|
}
|
||
|
|
||
|
/// enable interrupt signaling
|
||
|
pub fn enable_interrupts(&mut self) {
|
||
|
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
||
|
.enable_s(true));
|
||
|
self.mpcore.icddcr.modify(|_, w| w.enable_secure(true));
|
||
|
}
|
||
|
|
||
|
pub fn enable(&mut self, id: InterruptId, target_cpu: u32, sensitivity: InterruptSensitivity) {
|
||
|
assert!(target_cpu < 2);
|
||
|
|
||
|
self.disable_interrupts();
|
||
|
|
||
|
// enable
|
||
|
let m = (id.0 >> 5) as usize;
|
||
|
let n = (id.0 & 0x1F) as usize;
|
||
|
assert!(m < 3);
|
||
|
unsafe {
|
||
|
self.mpcore.icdiser[m].modify(|mut icdiser| *icdiser.set_bit(n, true));
|
||
|
}
|
||
|
|
||
|
// target cpu
|
||
|
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));
|
||
|
}
|
||
|
|
||
|
// sensitivity
|
||
|
let m = (id.0 >> 4) as usize;
|
||
|
let n = (2 * (id.0 & 0xF)) as usize;
|
||
|
unsafe {
|
||
|
self.mpcore.icdicfr[m].modify(|mut icdicfr| *icdicfr.set_bits(n..=n+1, match sensitivity {
|
||
|
InterruptSensitivity::Level => 0b00,
|
||
|
InterruptSensitivity::Edge => 0b10,
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
// filter no interrupts (lowest priority)
|
||
|
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
|
||
|
|
||
|
self.enable_interrupts();
|
||
|
}
|
||
|
}
|