esp32_c3/intc.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.
//! Platform Level Interrupt Control peripheral driver.
use crate::interrupts;
use kernel::utilities::cells::VolatileCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{
register_bitfields, register_structs, LocalRegisterCopy, ReadWrite,
};
use kernel::utilities::StaticRef;
register_structs! {
pub IntcRegisters {
(0x000 => _reserved0),
(0x040 => gpio_interrupt_pro_map: ReadWrite<u32>),
(0x044 => gpio_interrupt_pro_nmi_map: ReadWrite<u32>),
(0x048 => _reserved1),
(0x054 => uart0_intr_map: ReadWrite<u32>),
(0x058 => _reserved2),
(0x080 => timg0_intr_map: ReadWrite<u32>),
(0x084 => timg1_intr_map: ReadWrite<u32>),
(0x088 => _reserved3),
(0x0f8 => status: [ReadWrite<u32>; 2]),
(0x100 => clk_en: ReadWrite<u32>),
(0x104 => enable: ReadWrite<u32, INT::Register>),
(0x108 => type_reg: ReadWrite<u32, INT::Register>),
(0x10C => clear: ReadWrite<u32, INT::Register>),
(0x110 => eip: ReadWrite<u32, INT::Register>),
(0x114 => _reserved4),
(0x118 => priority: [ReadWrite<u32, PRIORITY::Register>; 31]),
(0x194 => thresh: ReadWrite<u32, THRESH::Register>),
(0x198 => @END),
}
}
register_bitfields![u32,
INT [
ONE OFFSET(1) NUMBITS(1) [],
TWO OFFSET(2) NUMBITS(1) [],
THREE OFFSET(3) NUMBITS(1) [],
FOUR OFFSET(4) NUMBITS(1) [],
FIVE OFFSET(5) NUMBITS(1) [],
SIX OFFSET(6) NUMBITS(1) [],
SEVEN OFFSET(7) NUMBITS(1) [],
EIGHT OFFSET(8) NUMBITS(1) [],
],
PRIORITY [
PRIORITY OFFSET(0) NUMBITS(4) [],
],
THRESH [
THRESH OFFSET(0) NUMBITS(4) [],
],
];
pub struct Intc {
registers: StaticRef<IntcRegisters>,
saved: VolatileCell<LocalRegisterCopy<u32>>,
}
impl Intc {
pub const fn new(base: StaticRef<IntcRegisters>) -> Self {
Intc {
registers: base,
saved: VolatileCell::new(LocalRegisterCopy::new(0)),
}
}
/// The ESP32C3 is interesting. It allows interrupts to be mapped on the
/// fly by setting the `intr_map` registers. This feature is completely
/// undocumented. The ESP32 HAL and projects that use that (like Zephyr)
/// call into the ROM code to enable interrupts which maps the interrupts.
/// In Tock we map them ourselves so we don't need to call into the ROM.
pub fn map_interrupts(&self) {
self.registers.uart0_intr_map.set(interrupts::IRQ_UART0);
self.registers.timg0_intr_map.set(interrupts::IRQ_TIMER1);
self.registers.timg1_intr_map.set(interrupts::IRQ_TIMER2);
self.registers
.gpio_interrupt_pro_map
.set(interrupts::IRQ_GPIO);
self.registers
.gpio_interrupt_pro_nmi_map
.set(interrupts::IRQ_GPIO_NMI);
}
/// Clear all pending interrupts.
pub fn clear_all_pending(&self) {
self.registers.clear.set(0xFF);
}
/// Enable all interrupts.
pub fn enable_all(&self) {
self.registers.enable.set(0xFFFF_FFFF);
// Set some default priority for each interrupt. This is not really used
// at this point.
for priority in self.registers.priority.iter() {
priority.write(PRIORITY::PRIORITY.val(3));
}
// Accept all interrupts.
self.registers.thresh.write(THRESH::THRESH.val(1));
}
/// Disable interrupt.
pub fn disable(&self, irq: u32) {
let mask = !(1 << irq);
let value = self.registers.enable.get() & mask;
self.registers.enable.set(value);
}
/// Disable all interrupts.
pub fn disable_all(&self) {
self.registers.enable.set(0x00);
}
/// Get the index (0-256) of the lowest number pending interrupt, or `None` if
/// none is pending. RISC-V Intc has a "claim" register which makes it easy
/// to grab the highest priority pending interrupt.
pub fn next_pending(&self) -> Option<u32> {
let eip = self.registers.eip.get();
if eip == 0 {
None
} else {
Some(eip.trailing_zeros())
}
}
/// Save the current interrupt to be handled later
/// This will save the interrupt at index internally to be handled later.
/// Interrupts must be disabled before this is called.
/// Saved interrupts can be retrieved by calling `get_saved_interrupts()`.
/// Saved interrupts are cleared when `'complete()` is called.
pub unsafe fn save_interrupt(&self, irq: u32) {
// OR the current saved state with the new value
let new_saved = self.saved.get().get() | 1 << irq;
// Set the new state
self.saved.set(LocalRegisterCopy::new(new_saved));
}
/// The `next_pending()` function will only return enabled interrupts.
/// This function will return a pending interrupt that has been disabled by
/// `save_interrupt()`.
pub fn get_saved_interrupts(&self) -> Option<u32> {
let saved = self.saved.get().get();
if saved != 0 {
return Some(saved.trailing_zeros());
}
None
}
/// Signal that an interrupt is finished being handled. In Tock, this should be
/// called from the normal main loop (not the interrupt handler).
/// Interrupts must be disabled before this is called.
pub unsafe fn complete(&self, irq: u32) {
// OR the current saved state with the new value
let new_saved = self.saved.get().get() & !(1 << irq);
// Set the new state
self.saved.set(LocalRegisterCopy::new(new_saved));
}
}