esp32_c3/
intc.rs

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