|
|
|
@@ -6,17 +6,22 @@
|
|
|
|
//! # Examples
|
|
|
|
//! # Examples
|
|
|
|
//!
|
|
|
|
//!
|
|
|
|
//! - [GTC ticks](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/gtc-ticks.rs)
|
|
|
|
//! - [GTC ticks](https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/src/branch/main/examples/simple/src/bin/gtc-ticks.rs)
|
|
|
|
|
|
|
|
#![deny(missing_docs)]
|
|
|
|
use arbitrary_int::prelude::*;
|
|
|
|
use arbitrary_int::prelude::*;
|
|
|
|
|
|
|
|
|
|
|
|
use aarch32_cpu::interrupt;
|
|
|
|
use aarch32_cpu::interrupt;
|
|
|
|
use zynq7000::gic::{
|
|
|
|
use zynq7000::gic::{
|
|
|
|
CpuInterfaceRegisters, DistributorControlRegister, DistributorRegisters, InterfaceControl,
|
|
|
|
CpuInterfaceRegisters, DistributorControlRegister, DistributorRegisters, InterfaceControl,
|
|
|
|
InterruptSignalRegister, MmioCpuInterfaceRegisters, MmioDistributorRegisters, PriorityRegister,
|
|
|
|
InterruptProcessorTargetRegister, InterruptSignalRegister, MmioCpuInterfaceRegisters,
|
|
|
|
|
|
|
|
MmioDistributorRegisters, PriorityRegister,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const SPURIOUS_INTERRUPT_ID: u32 = 1023;
|
|
|
|
/// Spurious interrupt ID.
|
|
|
|
|
|
|
|
pub const SPURIOUS_INTERRUPT_ID: u32 = 1023;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Highest interrupt priority (smallest number).
|
|
|
|
pub const HIGHEST_PRIORITY: u8 = 0;
|
|
|
|
pub const HIGHEST_PRIORITY: u8 = 0;
|
|
|
|
|
|
|
|
/// Lowest interrupt priority (largest number).
|
|
|
|
pub const LOWEST_PRIORITY: u8 = 31;
|
|
|
|
pub const LOWEST_PRIORITY: u8 = 31;
|
|
|
|
|
|
|
|
|
|
|
|
/// These fixed values must be programmed according to the Zynq7000 TRM p.236.
|
|
|
|
/// These fixed values must be programmed according to the Zynq7000 TRM p.236.
|
|
|
|
@@ -36,119 +41,218 @@ pub const ICFR_4_FIXED_VALUE: u32 = 0b01110101010101010101010101010101;
|
|
|
|
pub const ICFR_5_FIXED_VALUE: u32 = 0b00000011010101010101010101010101;
|
|
|
|
pub const ICFR_5_FIXED_VALUE: u32 = 0b00000011010101010101010101010101;
|
|
|
|
|
|
|
|
|
|
|
|
/// Helper value to target all interrupts which can be targetted to CPU 0
|
|
|
|
/// Helper value to target all interrupts which can be targetted to CPU 0
|
|
|
|
pub const TARGETS_ALL_CPU_0_IPTR_VAL: u32 = 0x01010101;
|
|
|
|
pub const TARGETS_ALL_CPU_0_IPTR_VAL: InterruptProcessorTargetRegister =
|
|
|
|
|
|
|
|
InterruptProcessorTargetRegister::new_with_raw_value(0x01010101);
|
|
|
|
/// Helper value to target all interrupts which can be targetted to CPU 1
|
|
|
|
/// Helper value to target all interrupts which can be targetted to CPU 1
|
|
|
|
pub const TARGETS_ALL_CPU_1_IPTR_VAL: u32 = 0x02020202;
|
|
|
|
pub const TARGETS_ALL_CPU_1_IPTR_VAL: InterruptProcessorTargetRegister =
|
|
|
|
|
|
|
|
InterruptProcessorTargetRegister::new_with_raw_value(0x02020202);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Mask for activating all softare generated interrupts.
|
|
|
|
pub const ACTIVATE_ALL_SGIS_MASK_ISER: u32 = 0x0000_FFFF;
|
|
|
|
pub const ACTIVATE_ALL_SGIS_MASK_ISER: u32 = 0x0000_FFFF;
|
|
|
|
|
|
|
|
/// Mask for activating all private peripheral interrupts.
|
|
|
|
pub const ACTIVATE_ALL_PPIS_MASK_ISER: u32 = 0xF800_0000;
|
|
|
|
pub const ACTIVATE_ALL_PPIS_MASK_ISER: u32 = 0xF800_0000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Shared peripheral interrupt sensitivity.
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
pub enum SpiSensitivity {
|
|
|
|
pub enum SpiSensitivity {
|
|
|
|
|
|
|
|
/// Level triggered interrupt.
|
|
|
|
Level = 0b01,
|
|
|
|
Level = 0b01,
|
|
|
|
|
|
|
|
/// Edge triggered interrupt.
|
|
|
|
Edge = 0b11,
|
|
|
|
Edge = 0b11,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub enum TargetCpu {
|
|
|
|
/// CPU enumeration.
|
|
|
|
None = 0b00,
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
Cpu0 = 0b01,
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
Cpu1 = 0b10,
|
|
|
|
pub enum Cpu {
|
|
|
|
Both = 0b11,
|
|
|
|
/// CPU 0.
|
|
|
|
|
|
|
|
Cpu0,
|
|
|
|
|
|
|
|
/// CPU 1.
|
|
|
|
|
|
|
|
Cpu1,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bitflags::bitflags! {
|
|
|
|
|
|
|
|
/// Target CPU bitflags.
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
|
|
|
|
pub struct TargetCpus: u8 {
|
|
|
|
|
|
|
|
/// No CPU.
|
|
|
|
|
|
|
|
const NONE = 0b00;
|
|
|
|
|
|
|
|
/// CPU 0.
|
|
|
|
|
|
|
|
const CPU_0 = 0b01;
|
|
|
|
|
|
|
|
/// CPU 1.
|
|
|
|
|
|
|
|
const CPU_1 = 0b10;
|
|
|
|
|
|
|
|
/// Both CPUs.
|
|
|
|
|
|
|
|
const BOTH_CPUS = 0b11;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Private Peripheral Interrupt (PPI) which are private to the CPU.
|
|
|
|
/// Private Peripheral Interrupt (PPI) which are private to the CPU.
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[repr(u8)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum PpiInterrupt {
|
|
|
|
pub enum PpiInterrupt {
|
|
|
|
|
|
|
|
/// Global timer.
|
|
|
|
GlobalTimer = 27,
|
|
|
|
GlobalTimer = 27,
|
|
|
|
// Interrupt signal from the PL. CPU0: `IRQF2P[18]` and CPU1: `IRQF2P[19]`
|
|
|
|
/// Interrupt signal from the PL. CPU0: `IRQF2P[18]` and CPU1: `IRQF2P[19]`
|
|
|
|
NFiq = 28,
|
|
|
|
NFiq = 28,
|
|
|
|
|
|
|
|
/// CPU private timer.
|
|
|
|
CpuPrivateTimer = 29,
|
|
|
|
CpuPrivateTimer = 29,
|
|
|
|
/// AWDT0 and AWDT1 for each CPU.
|
|
|
|
/// AWDT0 and AWDT1 for each CPU.
|
|
|
|
Awdt = 30,
|
|
|
|
Awdt = 30,
|
|
|
|
// Interrupt signal from the PL. CPU0: `IRQF2P[16]` and CPU1: `IRQF2P[17]`
|
|
|
|
/// Interrupt signal from the PL. CPU0: `IRQF2P[16]` and CPU1: `IRQF2P[17]`
|
|
|
|
NIrq = 31,
|
|
|
|
NIrq = 31,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Shared Peripheral Interrupt IDs.
|
|
|
|
/// Shared Peripheral Interrupt IDs.
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[repr(u8)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum SpiInterrupt {
|
|
|
|
pub enum SpiInterrupt {
|
|
|
|
|
|
|
|
/// CPU 0.
|
|
|
|
Cpu0 = 32,
|
|
|
|
Cpu0 = 32,
|
|
|
|
|
|
|
|
/// CPU 1.
|
|
|
|
Cpu1 = 33,
|
|
|
|
Cpu1 = 33,
|
|
|
|
|
|
|
|
/// L2 cache.
|
|
|
|
L2Cache = 34,
|
|
|
|
L2Cache = 34,
|
|
|
|
|
|
|
|
/// On-chip memory.
|
|
|
|
Ocm = 35,
|
|
|
|
Ocm = 35,
|
|
|
|
|
|
|
|
/// Reserved.
|
|
|
|
_Reserved0 = 36,
|
|
|
|
_Reserved0 = 36,
|
|
|
|
|
|
|
|
/// Performance monitor unit 0.
|
|
|
|
Pmu0 = 37,
|
|
|
|
Pmu0 = 37,
|
|
|
|
|
|
|
|
/// Performance monitor unit 1.
|
|
|
|
Pmu1 = 38,
|
|
|
|
Pmu1 = 38,
|
|
|
|
|
|
|
|
/// XADC.
|
|
|
|
Xadc = 39,
|
|
|
|
Xadc = 39,
|
|
|
|
|
|
|
|
/// Device configuration.
|
|
|
|
DevC = 40,
|
|
|
|
DevC = 40,
|
|
|
|
|
|
|
|
/// System watchdog timer.
|
|
|
|
Swdt = 41,
|
|
|
|
Swdt = 41,
|
|
|
|
|
|
|
|
/// Triple timer counter 00.
|
|
|
|
Ttc00 = 42,
|
|
|
|
Ttc00 = 42,
|
|
|
|
|
|
|
|
/// Triple timer counter 01.
|
|
|
|
Ttc01 = 43,
|
|
|
|
Ttc01 = 43,
|
|
|
|
|
|
|
|
/// Triple timer counter 02.
|
|
|
|
Ttc02 = 44,
|
|
|
|
Ttc02 = 44,
|
|
|
|
|
|
|
|
/// DMAC abort.
|
|
|
|
DmacAbort = 45,
|
|
|
|
DmacAbort = 45,
|
|
|
|
|
|
|
|
/// DMAC 0.
|
|
|
|
Dmac0 = 46,
|
|
|
|
Dmac0 = 46,
|
|
|
|
|
|
|
|
/// DMAC 1.
|
|
|
|
Dmac1 = 47,
|
|
|
|
Dmac1 = 47,
|
|
|
|
|
|
|
|
/// DMAC 2.
|
|
|
|
Dmac2 = 48,
|
|
|
|
Dmac2 = 48,
|
|
|
|
|
|
|
|
/// DMAC 3.
|
|
|
|
Dmac3 = 49,
|
|
|
|
Dmac3 = 49,
|
|
|
|
|
|
|
|
/// Shared memory controller.
|
|
|
|
Smc = 50,
|
|
|
|
Smc = 50,
|
|
|
|
|
|
|
|
/// Quad SPI.
|
|
|
|
Qspi = 51,
|
|
|
|
Qspi = 51,
|
|
|
|
|
|
|
|
/// GPIO.
|
|
|
|
Gpio = 52,
|
|
|
|
Gpio = 52,
|
|
|
|
|
|
|
|
/// USB 0.
|
|
|
|
Usb0 = 53,
|
|
|
|
Usb0 = 53,
|
|
|
|
|
|
|
|
/// Ethernet 0.
|
|
|
|
Eth0 = 54,
|
|
|
|
Eth0 = 54,
|
|
|
|
|
|
|
|
/// Ethernet 0 wakeup.
|
|
|
|
Eth0Wakeup = 55,
|
|
|
|
Eth0Wakeup = 55,
|
|
|
|
|
|
|
|
/// SDIO 0.
|
|
|
|
Sdio0 = 56,
|
|
|
|
Sdio0 = 56,
|
|
|
|
|
|
|
|
/// I2C 0.
|
|
|
|
I2c0 = 57,
|
|
|
|
I2c0 = 57,
|
|
|
|
|
|
|
|
/// SPI 0.
|
|
|
|
Spi0 = 58,
|
|
|
|
Spi0 = 58,
|
|
|
|
|
|
|
|
/// UART 0.
|
|
|
|
Uart0 = 59,
|
|
|
|
Uart0 = 59,
|
|
|
|
|
|
|
|
/// CAN 0.
|
|
|
|
Can0 = 60,
|
|
|
|
Can0 = 60,
|
|
|
|
|
|
|
|
/// Programmable Logic 0.
|
|
|
|
Pl0 = 61,
|
|
|
|
Pl0 = 61,
|
|
|
|
|
|
|
|
/// Programmable Logic 1.
|
|
|
|
Pl1 = 62,
|
|
|
|
Pl1 = 62,
|
|
|
|
|
|
|
|
/// Programmable Logic 2.
|
|
|
|
Pl2 = 63,
|
|
|
|
Pl2 = 63,
|
|
|
|
|
|
|
|
/// Programmable Logic 3.
|
|
|
|
Pl3 = 64,
|
|
|
|
Pl3 = 64,
|
|
|
|
|
|
|
|
/// Programmable Logic 4.
|
|
|
|
Pl4 = 65,
|
|
|
|
Pl4 = 65,
|
|
|
|
|
|
|
|
/// Programmable Logic 5.
|
|
|
|
Pl5 = 66,
|
|
|
|
Pl5 = 66,
|
|
|
|
|
|
|
|
/// Programmable Logic 6.
|
|
|
|
Pl6 = 67,
|
|
|
|
Pl6 = 67,
|
|
|
|
|
|
|
|
/// Programmable Logic 7.
|
|
|
|
Pl7 = 68,
|
|
|
|
Pl7 = 68,
|
|
|
|
|
|
|
|
/// Triple timer counter 10.
|
|
|
|
Ttc10 = 69,
|
|
|
|
Ttc10 = 69,
|
|
|
|
|
|
|
|
/// Triple timer counter 11.
|
|
|
|
Ttc11 = 70,
|
|
|
|
Ttc11 = 70,
|
|
|
|
|
|
|
|
/// Triple timer counter 12.
|
|
|
|
Ttc12 = 71,
|
|
|
|
Ttc12 = 71,
|
|
|
|
|
|
|
|
/// DMAC 4.
|
|
|
|
Dmac4 = 72,
|
|
|
|
Dmac4 = 72,
|
|
|
|
|
|
|
|
/// DMAC 5.
|
|
|
|
Dmac5 = 73,
|
|
|
|
Dmac5 = 73,
|
|
|
|
|
|
|
|
/// DMAC 6.
|
|
|
|
Dmac6 = 74,
|
|
|
|
Dmac6 = 74,
|
|
|
|
|
|
|
|
/// DMAC 7.
|
|
|
|
Dmac7 = 75,
|
|
|
|
Dmac7 = 75,
|
|
|
|
|
|
|
|
/// USB 1.
|
|
|
|
Usb1 = 76,
|
|
|
|
Usb1 = 76,
|
|
|
|
|
|
|
|
/// Ethernet 1.
|
|
|
|
Eth1 = 77,
|
|
|
|
Eth1 = 77,
|
|
|
|
|
|
|
|
/// Ethernet 1 wakeup.
|
|
|
|
Eth1Wakeup = 78,
|
|
|
|
Eth1Wakeup = 78,
|
|
|
|
|
|
|
|
/// SDIO 1.
|
|
|
|
Sdio1 = 79,
|
|
|
|
Sdio1 = 79,
|
|
|
|
|
|
|
|
/// I2C 1.
|
|
|
|
I2c1 = 80,
|
|
|
|
I2c1 = 80,
|
|
|
|
|
|
|
|
/// SPI 1.
|
|
|
|
Spi1 = 81,
|
|
|
|
Spi1 = 81,
|
|
|
|
|
|
|
|
/// UART 1.
|
|
|
|
Uart1 = 82,
|
|
|
|
Uart1 = 82,
|
|
|
|
|
|
|
|
/// CAN 1.
|
|
|
|
Can1 = 83,
|
|
|
|
Can1 = 83,
|
|
|
|
|
|
|
|
/// Programmable Logic 8.
|
|
|
|
Pl8 = 84,
|
|
|
|
Pl8 = 84,
|
|
|
|
|
|
|
|
/// Programmable Logic 9.
|
|
|
|
Pl9 = 85,
|
|
|
|
Pl9 = 85,
|
|
|
|
|
|
|
|
/// Programmable Logic 10.
|
|
|
|
Pl10 = 86,
|
|
|
|
Pl10 = 86,
|
|
|
|
|
|
|
|
/// Programmable Logic 11.
|
|
|
|
Pl11 = 87,
|
|
|
|
Pl11 = 87,
|
|
|
|
|
|
|
|
/// Programmable Logic 12.
|
|
|
|
Pl12 = 88,
|
|
|
|
Pl12 = 88,
|
|
|
|
|
|
|
|
/// Programmable Logic 13.
|
|
|
|
Pl13 = 89,
|
|
|
|
Pl13 = 89,
|
|
|
|
|
|
|
|
/// Programmable Logic 14.
|
|
|
|
Pl14 = 90,
|
|
|
|
Pl14 = 90,
|
|
|
|
|
|
|
|
/// Programmable Logic 15.
|
|
|
|
Pl15 = 91,
|
|
|
|
Pl15 = 91,
|
|
|
|
|
|
|
|
/// Snoop control unit parity.
|
|
|
|
ScuParity = 92,
|
|
|
|
ScuParity = 92,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Interrupt ID wrapper.
|
|
|
|
/// Interrupt ID wrapper.
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
pub enum Interrupt {
|
|
|
|
pub enum Interrupt {
|
|
|
|
|
|
|
|
/// Software-generated interrupt (SGI).
|
|
|
|
Sgi(usize),
|
|
|
|
Sgi(usize),
|
|
|
|
|
|
|
|
/// Private peripheral interrupt (PPI).
|
|
|
|
Ppi(PpiInterrupt),
|
|
|
|
Ppi(PpiInterrupt),
|
|
|
|
|
|
|
|
/// Shared peripheral interrupt (SPI).
|
|
|
|
Spi(SpiInterrupt),
|
|
|
|
Spi(SpiInterrupt),
|
|
|
|
/// Detects an invalid interrupt ID.
|
|
|
|
/// Detects an invalid interrupt ID.
|
|
|
|
Invalid(usize),
|
|
|
|
Invalid(usize),
|
|
|
|
/// Spurious interrupt (ID# 1023).
|
|
|
|
/// Spurious interrupt (ID# 1023, [SPURIOUS_INTERRUPT_ID]).
|
|
|
|
Spurious,
|
|
|
|
Spurious,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Interrupt information structure.
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
pub struct InterruptInfo {
|
|
|
|
pub struct InterruptInfo {
|
|
|
|
raw_reg: InterruptSignalRegister,
|
|
|
|
raw_reg: InterruptSignalRegister,
|
|
|
|
interrupt: Interrupt,
|
|
|
|
interrupt: Interrupt,
|
|
|
|
@@ -156,34 +260,46 @@ pub struct InterruptInfo {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl InterruptInfo {
|
|
|
|
impl InterruptInfo {
|
|
|
|
pub fn raw_reg(&self) -> InterruptSignalRegister {
|
|
|
|
/// Raw interrupt signal register value.
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub const fn raw_reg(&self) -> InterruptSignalRegister {
|
|
|
|
self.raw_reg
|
|
|
|
self.raw_reg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn cpu_id(&self) -> u8 {
|
|
|
|
/// CPU ID.
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub const fn cpu_id(&self) -> u8 {
|
|
|
|
self.cpu_id
|
|
|
|
self.cpu_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn interrupt(&self) -> Interrupt {
|
|
|
|
/// Interrupt ID.
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub const fn interrupt(&self) -> Interrupt {
|
|
|
|
self.interrupt
|
|
|
|
self.interrupt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Invalid priority value error.
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[error("Invalid priority value {0}, range is [0, 31]")]
|
|
|
|
#[error("Invalid priority value {0}, range is [0, 31]")]
|
|
|
|
pub struct InvalidPriorityValue(pub u8);
|
|
|
|
pub struct InvalidPriorityValue(pub u8);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Invalid programmable logic interrupt ID.
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[error("Invalid PL interrupt ID {0}")]
|
|
|
|
#[error("Invalid PL interrupt ID {0}")]
|
|
|
|
pub struct InvalidPlInterruptId(pub usize);
|
|
|
|
pub struct InvalidPlInterruptId(pub usize);
|
|
|
|
|
|
|
|
|
|
|
|
/// Invalid Shared Peripheral Interrupt (SPI) ID.
|
|
|
|
/// Invalid Shared Peripheral Interrupt (SPI) ID.
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[error("Invalid SPI interrupt ID {0}")]
|
|
|
|
#[error("Invalid SPI interrupt ID {0}")]
|
|
|
|
pub struct InvalidSpiInterruptId(pub usize);
|
|
|
|
pub struct InvalidSpiInterruptId(pub usize);
|
|
|
|
|
|
|
|
|
|
|
|
/// Invalid Software Generated Interrupt (SGI) ID.
|
|
|
|
/// Invalid Software Generated Interrupt (SGI) ID.
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
|
|
|
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
#[error("Invalid SGI interrupt ID {0}")]
|
|
|
|
#[error("Invalid SGI interrupt ID {0}")]
|
|
|
|
pub struct InvalidSgiInterruptId(pub usize);
|
|
|
|
pub struct InvalidSgiInterruptId(pub usize);
|
|
|
|
|
|
|
|
|
|
|
|
@@ -202,7 +318,8 @@ pub struct InvalidSgiInterruptId(pub usize);
|
|
|
|
/// the [SpiSensitivity] enum. You can use the following (helper) API to configure the
|
|
|
|
/// the [SpiSensitivity] enum. You can use the following (helper) API to configure the
|
|
|
|
/// interrupts:
|
|
|
|
/// interrupts:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// - [Self::set_spi_interrupt_cpu_target]
|
|
|
|
/// - [Self::set_spi_interrupt_target_for_cpu]
|
|
|
|
|
|
|
|
/// - [Self::set_spi_interrupt_cpu_target_flags]
|
|
|
|
/// - [Self::set_all_spi_interrupt_targets_cpu0]
|
|
|
|
/// - [Self::set_all_spi_interrupt_targets_cpu0]
|
|
|
|
/// - [Self::set_pl_interrupt_sensitivity]
|
|
|
|
/// - [Self::set_pl_interrupt_sensitivity]
|
|
|
|
///
|
|
|
|
///
|
|
|
|
@@ -219,12 +336,14 @@ pub struct InvalidSgiInterruptId(pub usize);
|
|
|
|
/// You might also chose to enable these interrupts at run-time after the GIC was started.
|
|
|
|
/// You might also chose to enable these interrupts at run-time after the GIC was started.
|
|
|
|
/// 4. Start the GIC by calling [Self::update_ctrl_regs] with the required settings or
|
|
|
|
/// 4. Start the GIC by calling [Self::update_ctrl_regs] with the required settings or
|
|
|
|
/// with [Self::enable] which assumes a certain configuration.
|
|
|
|
/// with [Self::enable] which assumes a certain configuration.
|
|
|
|
/// 5. Enable interrupts for the Cortex-AR core by calling [Self::enable_interrupts].
|
|
|
|
/// 5. Enable interrupts for the Cortex-A core by calling [Self::enable_interrupts].
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// For the handling of the interrupts, you can use the [GicInterruptHelper] which assumes a
|
|
|
|
/// For the handling of the interrupts, you can use the [GicInterruptHelper] which assumes a
|
|
|
|
/// properly configured GIC.
|
|
|
|
/// properly configured GIC.
|
|
|
|
pub struct GicConfigurator {
|
|
|
|
pub struct GicConfigurator {
|
|
|
|
|
|
|
|
/// GIC CPU interface registers.
|
|
|
|
pub gicc: MmioCpuInterfaceRegisters<'static>,
|
|
|
|
pub gicc: MmioCpuInterfaceRegisters<'static>,
|
|
|
|
|
|
|
|
/// GIC Distributor interface registers.
|
|
|
|
pub gicd: MmioDistributorRegisters<'static>,
|
|
|
|
pub gicd: MmioDistributorRegisters<'static>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -325,45 +444,90 @@ impl GicConfigurator {
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Set the CPU target for a SPI interrupt.
|
|
|
|
/// Set the CPU target(s) for a SPI interrupt.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// See [Self::set_all_spi_interrupt_targets_cpu0] for a utility method to handle all
|
|
|
|
/// See [Self::set_all_spi_interrupt_targets_cpu0] for a utility method to handle all
|
|
|
|
/// interrupts with one core.
|
|
|
|
/// interrupts with one core.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn set_spi_interrupt_cpu_target(&mut self, spi_int: SpiInterrupt, target: TargetCpu) {
|
|
|
|
pub fn set_spi_interrupt_cpu_target_flags(
|
|
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
|
|
spi_int: SpiInterrupt,
|
|
|
|
|
|
|
|
target: TargetCpus,
|
|
|
|
|
|
|
|
) {
|
|
|
|
let spi_int_raw = spi_int as u32;
|
|
|
|
let spi_int_raw = spi_int as u32;
|
|
|
|
let spi_offset_to_0 = spi_int_raw as usize - 32;
|
|
|
|
let spi_offset_to_0 = spi_int_raw as usize - 32;
|
|
|
|
// Unwrap okay, calculated index is always valid.
|
|
|
|
// Unwrap okay, calculated index is always valid.
|
|
|
|
self.gicd
|
|
|
|
self.gicd
|
|
|
|
.write_iptr_spi(
|
|
|
|
.modify_iptr_spi(spi_offset_to_0 / 4, |mut v| {
|
|
|
|
spi_offset_to_0 / 4,
|
|
|
|
// Every register contains 4 target flags, the modulo extracts the index because
|
|
|
|
(target as u32) << ((spi_offset_to_0 % 4) * 8),
|
|
|
|
// counting starts at 32 (32 -> index 0, 33 -> index 1 etc.).
|
|
|
|
)
|
|
|
|
v.set_targets(spi_offset_to_0 % 4, u2::new(target.bits()));
|
|
|
|
|
|
|
|
v
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable SPI interrupt target for a specific CPU without clearing the other CPU bit if it is
|
|
|
|
|
|
|
|
/// set.
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub fn set_spi_interrupt_target_for_cpu(&mut self, spi_int: SpiInterrupt, cpu: Cpu) {
|
|
|
|
|
|
|
|
let bitflag = match cpu {
|
|
|
|
|
|
|
|
Cpu::Cpu0 => TargetCpus::CPU_0,
|
|
|
|
|
|
|
|
Cpu::Cpu1 => TargetCpus::CPU_1,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let spi_int_raw = spi_int as u32;
|
|
|
|
|
|
|
|
let spi_offset_to_0 = spi_int_raw as usize - 32;
|
|
|
|
|
|
|
|
// Unwrap okay, calculated index is always valid.
|
|
|
|
|
|
|
|
self.gicd
|
|
|
|
|
|
|
|
.modify_iptr_spi(spi_offset_to_0 / 4, |mut v| {
|
|
|
|
|
|
|
|
v.set_targets(
|
|
|
|
|
|
|
|
spi_offset_to_0 % 4,
|
|
|
|
|
|
|
|
// Extract the target bits, bitwise OR them with [TargetCpus::CPU_0], and set
|
|
|
|
|
|
|
|
// them back.
|
|
|
|
|
|
|
|
u2::new(
|
|
|
|
|
|
|
|
(TargetCpus::from_bits(v.targets(spi_offset_to_0 % 4).as_u8()).unwrap()
|
|
|
|
|
|
|
|
| bitflag)
|
|
|
|
|
|
|
|
.bits(),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
v
|
|
|
|
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Utility function to set all SGI interrupt targets to CPU0.
|
|
|
|
/// Utility function to set all SGI interrupt targets to CPU0.
|
|
|
|
///
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This does not clear interrupt target bits for CPU1, it only activates the interrupts for
|
|
|
|
|
|
|
|
/// CPU 0 as well.
|
|
|
|
/// This is useful if only CPU0 is active in a system, or if CPU0 handles most interrupts in
|
|
|
|
/// This is useful if only CPU0 is active in a system, or if CPU0 handles most interrupts in
|
|
|
|
/// the system.
|
|
|
|
/// the system.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn set_all_spi_interrupt_targets_cpu0(&mut self) {
|
|
|
|
pub fn set_all_spi_interrupt_targets_cpu0(&mut self) {
|
|
|
|
for i in 0..0x10 {
|
|
|
|
for i in 0..0x10 {
|
|
|
|
self.gicd
|
|
|
|
self.gicd
|
|
|
|
.write_iptr_spi(i, TARGETS_ALL_CPU_0_IPTR_VAL)
|
|
|
|
.modify_iptr_spi(i, |v| {
|
|
|
|
|
|
|
|
InterruptProcessorTargetRegister::new_with_raw_value(
|
|
|
|
|
|
|
|
v.raw_value() | TARGETS_ALL_CPU_0_IPTR_VAL.raw_value(),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable a specific SGI interrupt.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_sgi_interrupt(&mut self, int_id: usize) -> Result<(), InvalidSpiInterruptId> {
|
|
|
|
pub fn enable_sgi_interrupt(&mut self, int_id: usize) -> Result<(), InvalidSpiInterruptId> {
|
|
|
|
if int_id >= 16 {
|
|
|
|
if int_id >= 16 {
|
|
|
|
return Err(InvalidSpiInterruptId(int_id));
|
|
|
|
return Err(InvalidSpiInterruptId(int_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsafe { self.gicd.write_iser_unchecked(0, 1 << int_id) };
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
self.gicd
|
|
|
|
|
|
|
|
.modify_iser_unchecked(0, |val| val | (1 << int_id))
|
|
|
|
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable all SGI interrupts.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_all_sgi_interrupts(&mut self) {
|
|
|
|
pub fn enable_all_sgi_interrupts(&mut self) {
|
|
|
|
// Unwrap okay, index is valid.
|
|
|
|
// Unwrap okay, index is valid.
|
|
|
|
@@ -375,17 +539,16 @@ impl GicConfigurator {
|
|
|
|
.unwrap();
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable specific PPI interrupt.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_ppi_interrupt(&mut self, ppi_int: PpiInterrupt) {
|
|
|
|
pub fn enable_ppi_interrupt(&mut self, ppi_int: PpiInterrupt) {
|
|
|
|
// Unwrap okay, index is valid.
|
|
|
|
// Unwrap okay, index is valid.
|
|
|
|
self.gicd
|
|
|
|
self.gicd
|
|
|
|
.modify_iser(0, |mut v| {
|
|
|
|
.modify_iser(0, |v| v | 1 << (ppi_int as u32))
|
|
|
|
v |= 1 << (ppi_int as u32);
|
|
|
|
|
|
|
|
v
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.unwrap();
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable all PPI interrupts.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_all_ppi_interrupts(&mut self) {
|
|
|
|
pub fn enable_all_ppi_interrupts(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
unsafe {
|
|
|
|
@@ -396,6 +559,7 @@ impl GicConfigurator {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable specific SPI interrupt.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_spi_interrupt(&mut self, spi_int: SpiInterrupt) {
|
|
|
|
pub fn enable_spi_interrupt(&mut self, spi_int: SpiInterrupt) {
|
|
|
|
let spi_int_raw = spi_int as u32;
|
|
|
|
let spi_int_raw = spi_int as u32;
|
|
|
|
@@ -403,17 +567,18 @@ impl GicConfigurator {
|
|
|
|
32..=63 => {
|
|
|
|
32..=63 => {
|
|
|
|
let bit_pos = spi_int_raw - 32;
|
|
|
|
let bit_pos = spi_int_raw - 32;
|
|
|
|
// Unwrap okay, valid index.
|
|
|
|
// Unwrap okay, valid index.
|
|
|
|
self.gicd.write_iser(1, 1 << bit_pos).unwrap();
|
|
|
|
self.gicd.modify_iser(1, |v| v | (1 << bit_pos)).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
64..=92 => {
|
|
|
|
64..=92 => {
|
|
|
|
let bit_pos = spi_int_raw - 64;
|
|
|
|
let bit_pos = spi_int_raw - 64;
|
|
|
|
// Unwrap okay, valid index.
|
|
|
|
// Unwrap okay, valid index.
|
|
|
|
self.gicd.write_iser(2, 1 << bit_pos).unwrap();
|
|
|
|
self.gicd.modify_iser(2, |v| v | (1 << bit_pos)).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enable all SPI interrupts.
|
|
|
|
#[inline]
|
|
|
|
#[inline]
|
|
|
|
pub fn enable_all_spi_interrupts(&mut self) {
|
|
|
|
pub fn enable_all_spi_interrupts(&mut self) {
|
|
|
|
self.gicd.write_iser(1, 0xFFFF_FFFF).unwrap();
|
|
|
|
self.gicd.write_iser(1, 0xFFFF_FFFF).unwrap();
|
|
|
|
|