start adding GIC and GTP driver
This commit is contained in:
parent
7279c96f03
commit
ae6e78e93b
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use cortex_ar::asm::nop;
|
use cortex_ar::asm::nop;
|
||||||
|
use zynq7000::{hal::gic::Gic, pac::gic::{Gicc, Gicd}};
|
||||||
use zynq7000_rt as _;
|
use zynq7000_rt as _;
|
||||||
|
|
||||||
/// One user LED is MIO7
|
/// One user LED is MIO7
|
||||||
@ -19,6 +20,11 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
|
|||||||
|
|
||||||
#[unsafe(export_name = "main")]
|
#[unsafe(export_name = "main")]
|
||||||
pub fn main() -> ! {
|
pub fn main() -> ! {
|
||||||
|
let mut gic = Gic::new(unsafe { Gicc::new_mmio() }, unsafe { Gicd::new_mmio() });
|
||||||
|
gic.enable_all_interrupts();
|
||||||
|
gic.set_all_spi_interrupt_targets_cpu0();
|
||||||
|
gic.enable();
|
||||||
|
|
||||||
let mut gpio = unsafe { zynq7000::pac::gpio::Gpio::new_mmio() };
|
let mut gpio = unsafe { zynq7000::pac::gpio::Gpio::new_mmio() };
|
||||||
gpio.modify_dirm_0(|v| v | ZEDBOARD_LED_MASK);
|
gpio.modify_dirm_0(|v| v | ZEDBOARD_LED_MASK);
|
||||||
gpio.modify_out_en_0(|v| v | ZEDBOARD_LED_MASK);
|
gpio.modify_out_en_0(|v| v | ZEDBOARD_LED_MASK);
|
||||||
@ -30,6 +36,12 @@ pub fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub extern "C" fn _irq_handler() {
|
||||||
|
let mut gic = Gic::new(unsafe { Gicc::new_mmio() }, unsafe { Gicd::new_mmio() });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// Panic handler
|
/// Panic handler
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &PanicInfo) -> ! {
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
|
@ -16,6 +16,10 @@ derive-mmio = { path = "../../derive-mmio", default-features = false }
|
|||||||
bitbybit = "1.3"
|
bitbybit = "1.3"
|
||||||
arbitrary-int = "1.3"
|
arbitrary-int = "1.3"
|
||||||
thiserror = { version = "2", default-features = false }
|
thiserror = { version = "2", default-features = false }
|
||||||
|
num_enum = { version = "0.7", default-features = false }
|
||||||
|
critical-section = "1"
|
||||||
|
embassy-time-driver = "0.2"
|
||||||
|
embassy-time-queue-utils = "0.1"
|
||||||
# cortex-r
|
# cortex-r
|
||||||
# defmt = { version = "0.3", optional = true }
|
# defmt = { version = "0.3", optional = true }
|
||||||
# critical-section = { version = "1", optional = true }
|
# critical-section = { version = "1", optional = true }
|
||||||
|
@ -1,14 +1,4 @@
|
|||||||
use crate::pac::gic::{MmioGicc, MmioGicd};
|
use crate::pac::gic::{Dcr, Icr, MmioGicc, MmioGicd};
|
||||||
|
|
||||||
pub struct Gic {
|
|
||||||
pub gicc: MmioGicc<'static>,
|
|
||||||
pub gicd: MmioGicd<'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum SpiSensitivity {
|
|
||||||
Level = 0b01,
|
|
||||||
Edge = 0b11,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ICFR_2_FIXED_VALUE: u32 = 0b01010101010111010101010001011111;
|
pub const ICFR_2_FIXED_VALUE: u32 = 0b01010101010111010101010001011111;
|
||||||
/// This configures PL[2:0] to high-level sensitivity.
|
/// This configures PL[2:0] to high-level sensitivity.
|
||||||
@ -18,13 +8,159 @@ pub const ICFR_4_FIXED_VALUE: u32 = 0b01110101010101010101010101010101;
|
|||||||
/// This configures PL[15:8] to high-level sensitivity.
|
/// This configures PL[15:8] to high-level sensitivity.
|
||||||
pub const ICFR_5_FIXED_VALUE: u32 = 0b00000011010101010101010101010101;
|
pub const ICFR_5_FIXED_VALUE: u32 = 0b00000011010101010101010101010101;
|
||||||
|
|
||||||
|
pub const TARGETS_ALL_CPU_0_IPTR_VAL: u32 = 0x01010101;
|
||||||
|
pub const TARGETS_ALL_CPU_1_IPTR_VAL: u32 = 0x02020202;
|
||||||
|
|
||||||
|
pub const ACTIVATE_ALL_SGIS_MASK_ISER: u32 = 0x0000_FFFF;
|
||||||
|
pub const ACTIVATE_ALL_PPIS_MASK_ISER: u32 = 0xF800_0000;
|
||||||
|
|
||||||
|
pub enum SpiSensitivity {
|
||||||
|
Level = 0b01,
|
||||||
|
Edge = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TargetCpu {
|
||||||
|
None = 0b00,
|
||||||
|
Cpu0 = 0b01,
|
||||||
|
Cpu1 = 0b10,
|
||||||
|
Both = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Private Peripheral Interrupt (PPI) which are private to the CPU.
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum PpiInterrupt {
|
||||||
|
GlobalTimer = 27,
|
||||||
|
// Interrupt signal from the PL. CPU0: IRQF2P[18] and CPU1: IRQF2P[19]
|
||||||
|
NFiq = 28,
|
||||||
|
CpuPrivateTimer = 29,
|
||||||
|
/// AWDT0 and AWDT1 for each CPU.
|
||||||
|
Awdt = 30,
|
||||||
|
// Interrupt signal from the PL. CPU0: IRQF2P[16] and CPU1: IRQF2P[17]
|
||||||
|
NIrq = 31,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, num_enum::TryFromPrimitive)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum SpiInterrupt {
|
||||||
|
Cpu0 = 32,
|
||||||
|
Cpu1 = 33,
|
||||||
|
L2Cache = 34,
|
||||||
|
Ocm = 35,
|
||||||
|
_Reserved0 = 36,
|
||||||
|
Pmu0 = 37,
|
||||||
|
Pmu1 = 38,
|
||||||
|
Xadc = 39,
|
||||||
|
DevC = 40,
|
||||||
|
Swdt = 41,
|
||||||
|
Ttc00 = 42,
|
||||||
|
Ttc01 = 43,
|
||||||
|
Ttc02 = 44,
|
||||||
|
DmacAbort = 45,
|
||||||
|
Dmac0 = 46,
|
||||||
|
Dmac1 = 47,
|
||||||
|
Dmac2 = 48,
|
||||||
|
Dmac3 = 49,
|
||||||
|
Smc = 50,
|
||||||
|
Qspi = 51,
|
||||||
|
Gpio = 52,
|
||||||
|
Usb0 = 53,
|
||||||
|
Eth0 = 54,
|
||||||
|
Eth0Wakeup = 55,
|
||||||
|
Sdio0 = 56,
|
||||||
|
I2c0 = 57,
|
||||||
|
Spi0 = 58,
|
||||||
|
Uart0 = 59,
|
||||||
|
Can0 = 60,
|
||||||
|
Pl0 = 61,
|
||||||
|
Pl1 = 62,
|
||||||
|
Pl2 = 63,
|
||||||
|
Pl3 = 64,
|
||||||
|
Pl4 = 65,
|
||||||
|
Pl5 = 66,
|
||||||
|
Pl6 = 67,
|
||||||
|
Pl7 = 68,
|
||||||
|
Ttc10 = 69,
|
||||||
|
Ttc11 = 70,
|
||||||
|
Ttc12 = 71,
|
||||||
|
Dmac4 = 72,
|
||||||
|
Dmac5 = 73,
|
||||||
|
Dmac6 = 74,
|
||||||
|
Dmac7 = 75,
|
||||||
|
Usb1 = 76,
|
||||||
|
Eth1 = 77,
|
||||||
|
Eth1Wakeup = 78,
|
||||||
|
Sdio1 = 79,
|
||||||
|
I2c1 = 80,
|
||||||
|
Spi1 = 81,
|
||||||
|
Uart1 = 82,
|
||||||
|
Can1 = 83,
|
||||||
|
Pl8 = 84,
|
||||||
|
Pl9 = 85,
|
||||||
|
Pl10 = 86,
|
||||||
|
Pl11 = 87,
|
||||||
|
Pl12 = 88,
|
||||||
|
Pl13 = 89,
|
||||||
|
Pl14 = 90,
|
||||||
|
Pl15 = 91,
|
||||||
|
ScuParity = 92,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[error("Invalid PL interrupt ID {0}")]
|
#[error("Invalid PL interrupt ID {0}")]
|
||||||
pub struct InvalidPlInterruptId(pub u32);
|
pub struct InvalidPlInterruptId(pub usize);
|
||||||
|
|
||||||
|
/// Invalid Shared Peripheral Interrupt (SPI) ID.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error("Invalid SPI interrupt ID {0}")]
|
||||||
|
pub struct InvalidSpiInterruptId(pub usize);
|
||||||
|
|
||||||
|
/// Invalid Software Generated Interrupt (SGI) ID.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
#[error("Invalid SGI interrupt ID {0}")]
|
||||||
|
pub struct InvalidSgiInterruptId(pub usize);
|
||||||
|
/// Higher-level GIC controller for the Zynq70000 SoC.
|
||||||
|
///
|
||||||
|
/// The flow of using this controller is as follows:
|
||||||
|
///
|
||||||
|
/// 1. Create the controller using [Self::new]. You can use the [crate::pac::gic::Gicc::new_mmio]
|
||||||
|
/// and [crate::pac::gic::Gicd::new_mmio] functions to create the MMIO instances. The
|
||||||
|
/// constructor configures all PL interrupts sensivities to high-level sensitivity and
|
||||||
|
/// configures all sensitivities which are expected to have a certain value.
|
||||||
|
/// 2. Perform the configuration of the interrupt targets and the interrupt sensitivities.
|
||||||
|
/// The CPU targets are encoded with [TargetCpu] while the sensitivities are encoded by
|
||||||
|
/// the [SpiSensitivity] enum. You can use the following API to configure the interrupts:
|
||||||
|
///
|
||||||
|
/// - [Self::set_spi_interrupt_cpu_target]
|
||||||
|
/// - [Self::set_all_spi_interrupt_targets_cpu0]
|
||||||
|
/// - [Self::set_pl_interrupt_sensitivity]
|
||||||
|
///
|
||||||
|
/// 3. Enable all required interrupts. The following API can be used for this:
|
||||||
|
///
|
||||||
|
/// - [Self::enable_sgi_interrupt]
|
||||||
|
/// - [Self::enable_ppi_interrupt]
|
||||||
|
/// - [Self::enable_spi_interrupt]
|
||||||
|
/// - [Self::enable_all_spi_interrupts]
|
||||||
|
/// - [Self::enable_all_ppi_interrupts]
|
||||||
|
/// - [Self::enable_all_sgi_interrupts]
|
||||||
|
/// - [Self::enable_all_interrupts]
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// with [Self::enable] which assumes a certain configuration.
|
||||||
|
pub struct Gic {
|
||||||
|
pub gicc: MmioGicc<'static>,
|
||||||
|
pub gicd: MmioGicd<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Gic {
|
impl Gic {
|
||||||
|
/// Create a new GIC controller instance and calls [Self::initialize] to perform
|
||||||
|
/// strongly recommended initialization routines for the GIC.
|
||||||
|
///
|
||||||
|
#[inline]
|
||||||
pub fn new(gicc: MmioGicc<'static>, gicd: MmioGicd<'static>) -> Self {
|
pub fn new(gicc: MmioGicc<'static>, gicd: MmioGicd<'static>) -> Self {
|
||||||
Gic { gicc, gicd }
|
let mut gic = Gic { gicc, gicd };
|
||||||
|
gic.initialize();
|
||||||
|
gic
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the GIC by configuring the required sensitivites for the shared peripheral
|
/// Sets up the GIC by configuring the required sensitivites for the shared peripheral
|
||||||
@ -35,6 +171,7 @@ impl Gic {
|
|||||||
/// logic. These are configured to high level sensitivity by this function.
|
/// logic. These are configured to high level sensitivity by this function.
|
||||||
/// If you need a different sensitivity, you need to update the bits using the
|
/// If you need a different sensitivity, you need to update the bits using the
|
||||||
/// [Self::set_pl_interrupt_sensitivity] function.
|
/// [Self::set_pl_interrupt_sensitivity] function.
|
||||||
|
#[inline]
|
||||||
pub fn initialize(&mut self) {
|
pub fn initialize(&mut self) {
|
||||||
self.gicd.write_icfr_2_spi(ICFR_2_FIXED_VALUE);
|
self.gicd.write_icfr_2_spi(ICFR_2_FIXED_VALUE);
|
||||||
self.gicd.write_icfr_3_spi(ICFR_3_FIXED_VALUE);
|
self.gicd.write_icfr_3_spi(ICFR_3_FIXED_VALUE);
|
||||||
@ -42,9 +179,15 @@ impl Gic {
|
|||||||
self.gicd.write_icfr_5_spi(ICFR_5_FIXED_VALUE);
|
self.gicd.write_icfr_5_spi(ICFR_5_FIXED_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the sensitivity of a the Programmable Logic SPI interrupts.
|
||||||
|
///
|
||||||
|
/// These are the only interrupt IDs which are configurable for SPI. They are set
|
||||||
|
/// to high-level sensitivity by default by the [Self::initialize] function. You can
|
||||||
|
/// use this method to override certain sensitivies.
|
||||||
|
#[inline]
|
||||||
pub fn set_pl_interrupt_sensitivity(
|
pub fn set_pl_interrupt_sensitivity(
|
||||||
&mut self,
|
&mut self,
|
||||||
pl_int_id: u32,
|
pl_int_id: usize,
|
||||||
sensitivity: SpiSensitivity,
|
sensitivity: SpiSensitivity,
|
||||||
) -> Result<(), InvalidPlInterruptId> {
|
) -> Result<(), InvalidPlInterruptId> {
|
||||||
if pl_int_id >= 16 {
|
if pl_int_id >= 16 {
|
||||||
@ -73,4 +216,144 @@ impl Gic {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the CPU target for a SPI interrupt.
|
||||||
|
///
|
||||||
|
/// See [Self::set_all_spi_interrupt_targets_cpu0] for a utility method to handle all
|
||||||
|
/// interrupts with one core.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_spi_interrupt_cpu_target(&mut self, spi_int: SpiInterrupt, target: TargetCpu) {
|
||||||
|
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
|
||||||
|
.write_iptr_spi(
|
||||||
|
spi_offset_to_0 / 4,
|
||||||
|
(target as u32) << ((spi_offset_to_0 % 4) * 8),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Utility function to set all SGI interrupt targets to CPU0.
|
||||||
|
///
|
||||||
|
/// This is useful if only CPU0 is active in a system, or if CPU0 handles most interrupts in
|
||||||
|
/// the system.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_all_spi_interrupt_targets_cpu0(&mut self) {
|
||||||
|
self.gicd
|
||||||
|
.write_iptr_spi(0, TARGETS_ALL_CPU_0_IPTR_VAL)
|
||||||
|
.unwrap();
|
||||||
|
self.gicd
|
||||||
|
.write_iptr_spi(1, TARGETS_ALL_CPU_0_IPTR_VAL)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_sgi_interrupt(&mut self, int_id: usize) -> Result<(), InvalidSpiInterruptId> {
|
||||||
|
if int_id >= 16 {
|
||||||
|
return Err(InvalidSpiInterruptId(int_id));
|
||||||
|
}
|
||||||
|
unsafe { self.gicd.write_iser_unchecked(0, 1 << int_id) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_all_sgi_interrupts(&mut self) {
|
||||||
|
// Unwrap okay, index is valid.
|
||||||
|
self.gicd
|
||||||
|
.modify_iser(0, |mut v| {
|
||||||
|
v |= ACTIVATE_ALL_SGIS_MASK_ISER;
|
||||||
|
v
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_ppi_interrupt(&mut self, ppi_int: PpiInterrupt) {
|
||||||
|
// Unwrap okay, index is valid.
|
||||||
|
self.gicd
|
||||||
|
.modify_iser(0, |mut v| {
|
||||||
|
v |= 1 << (ppi_int as u32);
|
||||||
|
v
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_all_ppi_interrupts(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.gicd.modify_iser_unchecked(0, |mut v| {
|
||||||
|
v |= ACTIVATE_ALL_PPIS_MASK_ISER;
|
||||||
|
v
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_spi_interrupt(&mut self, spi_int: SpiInterrupt) {
|
||||||
|
let spi_int_raw = spi_int as u32;
|
||||||
|
match spi_int_raw {
|
||||||
|
32..=63 => {
|
||||||
|
let bit_pos = spi_int_raw - 32;
|
||||||
|
// Unwrap okay, valid index.
|
||||||
|
self.gicd.write_iser(1, 1 << bit_pos).unwrap();
|
||||||
|
}
|
||||||
|
64..=92 => {
|
||||||
|
let bit_pos = spi_int_raw - 64;
|
||||||
|
// Unwrap okay, valid index.
|
||||||
|
self.gicd.write_iser(2, 1 << bit_pos).unwrap();
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn enable_all_spi_interrupts(&mut self) {
|
||||||
|
self.gicd.write_iser(1, 0xFFFF_FFFF).unwrap();
|
||||||
|
self.gicd.write_iser(2, 0xFFFF_FFFF).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables all interrupts by calling [Self::enable_all_sgi_interrupts],
|
||||||
|
/// [Self::enable_all_ppi_interrupts] and [Self::enable_all_spi_interrupts].
|
||||||
|
pub fn enable_all_interrupts(&mut self) {
|
||||||
|
self.enable_all_sgi_interrupts();
|
||||||
|
self.enable_all_ppi_interrupts();
|
||||||
|
self.enable_all_spi_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable the GIC assuming a possibly non-secure configuration.
|
||||||
|
///
|
||||||
|
/// This function will NOT configure and enable the various interrupt sources. You need to
|
||||||
|
/// set the interrupt
|
||||||
|
/// This function configured the control registers with the following settings:
|
||||||
|
///
|
||||||
|
/// - CPU interface: Secure and non-secure interrupts are enabled. SBPR, FIQen and AckCtrl
|
||||||
|
/// fields set to default value 0.
|
||||||
|
/// - Distributor interface: Both non-secure and secure interrupt distribution enabled.
|
||||||
|
///
|
||||||
|
/// It calls [Self::update_ctrl_regs] to update the control registers.
|
||||||
|
/// If you need custom settings, you can call [Self::update_ctrl_regs] with your required
|
||||||
|
/// settings.
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.update_ctrl_regs(
|
||||||
|
Icr::builder()
|
||||||
|
.with_sbpr(false)
|
||||||
|
.with_fiq_en(false)
|
||||||
|
.with_ack_ctrl(false)
|
||||||
|
.with_enable_non_secure(true)
|
||||||
|
.with_enable_secure(true)
|
||||||
|
.build(),
|
||||||
|
Dcr::builder()
|
||||||
|
.with_enable_non_secure(true)
|
||||||
|
.with_enable_secure(true)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the control registers which control the safety configuration and which also enable
|
||||||
|
/// the GIC.
|
||||||
|
pub fn update_ctrl_regs(&mut self, icr: Icr, dcr: Dcr) {
|
||||||
|
self.gicc.write_icr(icr);
|
||||||
|
self.gicd.write_dcr(dcr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
34
zynq7000/src/hal/gtc.rs
Normal file
34
zynq7000/src/hal/gtc.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use core::{
|
||||||
|
cell::RefCell,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::pac::gtc::MmioGtc;
|
||||||
|
|
||||||
|
/// High level GTC driver.
|
||||||
|
pub struct Gtc(pub RefCell<MmioGtc<'static>>);
|
||||||
|
|
||||||
|
impl Gtc {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(mmio_gtc: MmioGtc<'static>) -> Self {
|
||||||
|
Self(RefCell::new(mmio_gtc))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn steal() -> Self {
|
||||||
|
Self::new(unsafe { crate::pac::gtc::Gtc::new_mmio() })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_timer(&self) -> u64 {
|
||||||
|
let mut periph = self.0.borrow_mut();
|
||||||
|
let upper = periph.read_count_upper();
|
||||||
|
loop {
|
||||||
|
let lower = periph.read_count_lower();
|
||||||
|
if periph.read_count_upper() == upper {
|
||||||
|
return ((upper as u64) << 32) | (lower as u64);
|
||||||
|
}
|
||||||
|
// Overflow, read upper again.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod gic;
|
pub mod gic;
|
||||||
|
pub mod gtc;
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
|
|
||||||
pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000;
|
pub const MPCORE_BASE_ADDR: usize = 0xF8F0_0000;
|
||||||
|
|
||||||
pub mod pac;
|
|
||||||
pub mod hal;
|
pub mod hal;
|
||||||
|
pub mod pac;
|
||||||
|
pub mod time_driver;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
pub use crate::pac::mpcore::{GICC_BASE_ADDR, GICD_BASE_ADDR};
|
pub use crate::pac::mpcore::{GICC_BASE_ADDR, GICD_BASE_ADDR};
|
||||||
use arbitrary_int::{u10, u3, u5};
|
use arbitrary_int::{u3, u5, u10};
|
||||||
use static_assertions::const_assert_eq;
|
use static_assertions::const_assert_eq;
|
||||||
|
|
||||||
/// Distributor Control Register
|
/// Distributor Control Register
|
||||||
#[bitbybit::bitfield(u32)]
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
pub struct Dcr {
|
pub struct Dcr {
|
||||||
#[bit(1, rw)]
|
#[bit(1, rw)]
|
||||||
enable_non_secure: bool,
|
enable_non_secure: bool,
|
||||||
@ -75,7 +75,10 @@ pub struct Gicd {
|
|||||||
pub ipr: [u32; 0x18],
|
pub ipr: [u32; 0x18],
|
||||||
_reserved_11: [u32; 0xE8],
|
_reserved_11: [u32; 0xE8],
|
||||||
/// Interrupt Processor Targes Registers
|
/// Interrupt Processor Targes Registers
|
||||||
pub iptr: [u32; 0x18],
|
pub iptr_sgi: [u32; 0x4],
|
||||||
|
// TODO: Mark those read-only as soon as that works for arrays.
|
||||||
|
pub iptr_ppi: [u32; 0x4],
|
||||||
|
pub iptr_spi: [u32; 0x10],
|
||||||
// Those are split in the ARM documentation for some reason..
|
// Those are split in the ARM documentation for some reason..
|
||||||
_reserved_12: [u32; 0xE8],
|
_reserved_12: [u32; 0xE8],
|
||||||
/// Interrupt Configuration Registers
|
/// Interrupt Configuration Registers
|
||||||
@ -125,7 +128,7 @@ impl Gicd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// CPU interface control register.
|
/// CPU interface control register.
|
||||||
#[bitbybit::bitfield(u32)]
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
||||||
pub struct Icr {
|
pub struct Icr {
|
||||||
#[bit(4, rw)]
|
#[bit(4, rw)]
|
||||||
sbpr: bool,
|
sbpr: bool,
|
||||||
|
@ -2,6 +2,24 @@
|
|||||||
|
|
||||||
pub const GTC_BASE_ADDR: usize = crate::pac::mpcore::MPCORE_BASE_ADDR + 0x0000_0200;
|
pub const GTC_BASE_ADDR: usize = crate::pac::mpcore::MPCORE_BASE_ADDR + 0x0000_0200;
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
pub struct GtcCtrl {
|
||||||
|
#[bits(8..=15, rw)]
|
||||||
|
prescaler: u8,
|
||||||
|
#[bit(2, rw)]
|
||||||
|
irq_enable: bool,
|
||||||
|
#[bit(1, rw)]
|
||||||
|
comparator_enable: bool,
|
||||||
|
#[bit(0, rw)]
|
||||||
|
enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitbybit::bitfield(u32)]
|
||||||
|
pub struct InterruptStatus {
|
||||||
|
#[bit(0, rw)]
|
||||||
|
event_flag: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Global timer counter.
|
/// Global timer counter.
|
||||||
#[derive(derive_mmio::Mmio)]
|
#[derive(derive_mmio::Mmio)]
|
||||||
#[mmio(no_ctors)]
|
#[mmio(no_ctors)]
|
||||||
@ -12,9 +30,9 @@ pub struct Gtc {
|
|||||||
/// Count register 1, upper 32 bits
|
/// Count register 1, upper 32 bits
|
||||||
count_upper: u32,
|
count_upper: u32,
|
||||||
/// Control register
|
/// Control register
|
||||||
ctrl: u32,
|
ctrl: GtcCtrl,
|
||||||
/// Interrupt status register
|
/// Interrupt status register
|
||||||
isr: u32,
|
isr: InterruptStatus,
|
||||||
/// Comparator 0, lower 32 bits
|
/// Comparator 0, lower 32 bits
|
||||||
comparator_lower: u32,
|
comparator_lower: u32,
|
||||||
/// Comparator 1, upper 32 bits
|
/// Comparator 1, upper 32 bits
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
pub mod gpio;
|
|
||||||
pub mod uart;
|
|
||||||
pub mod gtc;
|
|
||||||
pub mod slcr;
|
|
||||||
pub mod mpcore;
|
|
||||||
pub mod gic;
|
pub mod gic;
|
||||||
|
pub mod gpio;
|
||||||
|
pub mod gtc;
|
||||||
|
pub mod mpcore;
|
||||||
|
pub mod slcr;
|
||||||
|
pub mod uart;
|
||||||
|
77
zynq7000/src/time_driver.rs
Normal file
77
zynq7000/src/time_driver.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use core::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
sync::atomic::AtomicU64,
|
||||||
|
};
|
||||||
|
|
||||||
|
use critical_section::{CriticalSection, Mutex};
|
||||||
|
use embassy_time_driver::Driver;
|
||||||
|
use embassy_time_queue_utils::Queue;
|
||||||
|
|
||||||
|
struct AlarmState {
|
||||||
|
timestamp: Cell<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlarmState {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
timestamp: Cell::new(u64::MAX),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for AlarmState {}
|
||||||
|
|
||||||
|
pub struct TimerDriver {
|
||||||
|
periods: AtomicU64,
|
||||||
|
/// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
|
||||||
|
alarms: Mutex<AlarmState>,
|
||||||
|
queue: Mutex<RefCell<Queue>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimerDriver {
|
||||||
|
|
||||||
|
fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
impl Driver for TimerDriver {
|
||||||
|
fn now(&self) -> u64 {
|
||||||
|
/*
|
||||||
|
if SCALE.get().is_none() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let mut period1: u32;
|
||||||
|
let mut period2: u32;
|
||||||
|
let mut counter_val: u32;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Acquire ensures that we get the latest value of `periods` and
|
||||||
|
// no instructions can be reordered before the load.
|
||||||
|
period1 = self.periods.load(Ordering::Acquire);
|
||||||
|
|
||||||
|
counter_val = u32::MAX - Self::timekeeper_tim().cnt_value().read().bits();
|
||||||
|
|
||||||
|
// Double read to protect against race conditions when the counter is overflowing.
|
||||||
|
period2 = self.periods.load(Ordering::Relaxed);
|
||||||
|
if period1 == period2 {
|
||||||
|
let now = (((period1 as u64) << 32) | counter_val as u64) / *SCALE.get().unwrap();
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut queue = self.queue.borrow(cs).borrow_mut();
|
||||||
|
|
||||||
|
if queue.schedule_wake(at, waker) {
|
||||||
|
let mut next = queue.next_expiration(self.now());
|
||||||
|
while !self.set_alarm(cs, next) {
|
||||||
|
next = queue.next_expiration(self.now());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user