veer_el2/
pic.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 for VeeR.
6/* Currently no peripheral that would generate interupts is defined in the reference
7testbench for VeeR EL2, so the Pic is not expected to handle any interrupts. */
8
9use kernel::utilities::cells::VolatileCell;
10use kernel::utilities::registers::interfaces::{Readable, Writeable};
11use kernel::utilities::registers::{
12    register_bitfields, register_structs, LocalRegisterCopy, ReadWrite,
13};
14use kernel::utilities::StaticRef;
15use riscv_csr::csr::ReadWriteRiscvCsr;
16
17register_structs! {
18    pub PicRegisters {
19        /// External Interrupt Priority Level Registers
20        (0x000 => _reserved0),
21        (0x004 => meipl: [ReadWrite<u32, MEIPL::Register>; 255]),
22        (0x400 => _reserved1),
23        /// External Interrupt Pending Registers
24        (0x1000 => meip: [ReadWrite<u32, MEIP::Register>; 8]),
25        (0x1020 => _reserved2),
26        /// External Interrupt Enable Registers
27        (0x2004 => meie: [ReadWrite<u32, MEIE::Register>; 255]),
28        (0x2400 => _reserved3),
29        /// PIC Configuration Register
30        (0x3000 => mpiccfg: ReadWrite<u32, MPICCFG::Register>),
31        (0x3004 => _reserved4),
32        /// External Interrupt Gateway Configuration Registers
33        (0x4004 => meigwctrl: [ReadWrite<u32, MEIGWCTRL::Register>; 255]),
34        (0x4400 => _reserved5),
35        /// External Interrupt Gateway Clear Registers
36        (0x5004 => meigwclr: [ReadWrite<u32>; 255]),
37        (0x5400 => @END),
38    }
39}
40
41register_bitfields![u32,
42    MPICCFG [
43        PRIORD OFFSET(0) NUMBITS(1) [
44            STANDARD = 0,
45            REVERSE = 1,
46        ]
47    ],
48    MEIPL [
49        PRIORITY OFFSET(0) NUMBITS(4) []
50    ],
51    MEIP [
52        INTPEND OFFSET(1) NUMBITS(31) []
53    ],
54    MEIE [
55        INTEN OFFSET(0) NUMBITS(1) [
56            ENABLE = 1,
57            DISABLE = 0,
58        ]
59    ],
60    MEIGWCTRL [
61        POLARITY OFFSET(0) NUMBITS(1) [
62            ACTIVE_HIGH = 0,
63            ACTIVE_LOW = 1,
64        ],
65        TYPE OFFSET(1) NUMBITS(1) [
66            LEVEL_TRIGGERED = 0,
67            EDGE_TRIGGERED = 1,
68        ]
69    ],
70];
71register_bitfields![usize,
72    MEIVT [
73        BASE OFFSET(10) NUMBITS(22) []
74    ],
75    MEIPT [
76        PRITHRESH OFFSET(0) NUMBITS(4) []
77    ],
78    MEICIDPL [
79        CLIDPRI OFFSET(0) NUMBITS(4) []
80    ],
81    MEICURPL [
82        CURRPRI OFFSET(0) NUMBITS(4) []
83    ],
84    MEICPCT [
85        RESERVED OFFSET(0) NUMBITS(32) []
86    ],
87    MEIHAP [
88        ZERO OFFSET(0) NUMBITS(2) [],
89        CLAIMID OFFSET(2) NUMBITS(8) [],
90        BASE OFFSET(10) NUMBITS(22) [],
91    ],
92];
93
94#[allow(dead_code)]
95pub struct Pic {
96    registers: StaticRef<PicRegisters>,
97    saved: [VolatileCell<LocalRegisterCopy<u32>>; 3],
98    meivt: ReadWriteRiscvCsr<usize, MEIVT::Register, 0xBC8>,
99    meipt: ReadWriteRiscvCsr<usize, MEIPT::Register, 0xBC9>,
100    meicpct: ReadWriteRiscvCsr<usize, MEICPCT::Register, 0xBCA>,
101    meicidpl: ReadWriteRiscvCsr<usize, MEICIDPL::Register, 0xBCB>,
102    meicurpl: ReadWriteRiscvCsr<usize, MEICURPL::Register, 0xBCC>,
103    meihap: ReadWriteRiscvCsr<usize, MEIHAP::Register, 0xFC8>,
104}
105
106impl Pic {
107    pub const fn new(base: StaticRef<PicRegisters>) -> Self {
108        Pic {
109            registers: base,
110            saved: [
111                VolatileCell::new(LocalRegisterCopy::new(0)),
112                VolatileCell::new(LocalRegisterCopy::new(0)),
113                VolatileCell::new(LocalRegisterCopy::new(0)),
114            ],
115            meivt: ReadWriteRiscvCsr::new(),
116            meipt: ReadWriteRiscvCsr::new(),
117            meicpct: ReadWriteRiscvCsr::new(),
118            meicidpl: ReadWriteRiscvCsr::new(),
119            meicurpl: ReadWriteRiscvCsr::new(),
120            meihap: ReadWriteRiscvCsr::new(),
121        }
122    }
123
124    /// Clear all pending interrupts.
125    pub fn clear_all_pending(&self) {
126        for clear in self.registers.meigwclr.iter() {
127            clear.set(0);
128        }
129    }
130
131    /// Enable all interrupts.
132    pub fn enable_all(&self) {
133        self.registers.mpiccfg.write(MPICCFG::PRIORD::STANDARD);
134
135        self.disable_all();
136
137        for priority in self.registers.meipl.iter() {
138            priority.write(MEIPL::PRIORITY.val(15));
139        }
140
141        for property in self.registers.meigwctrl.iter() {
142            property.write(MEIGWCTRL::POLARITY::ACTIVE_HIGH + MEIGWCTRL::TYPE::LEVEL_TRIGGERED);
143        }
144
145        self.clear_all_pending();
146
147        self.meipt.set(0);
148        self.meicidpl.set(0);
149        self.meicurpl.set(0);
150
151        // Enable all interrupts
152        for enable in self.registers.meie.iter() {
153            enable.write(MEIE::INTEN::ENABLE);
154        }
155    }
156    /// Disable all interrupts.
157    pub fn disable_all(&self) {
158        for enable in self.registers.meie.iter() {
159            enable.write(MEIE::INTEN::DISABLE);
160        }
161    }
162
163    /// Get the index (0-96) of the lowest number pending interrupt, or `None` if
164    /// none is pending. RISC-V PIC has a "claim" register which makes it easy
165    /// to grab the highest priority pending interrupt.
166    pub fn next_pending(&self) -> Option<u32> {
167        self.meicpct.set(0);
168        let claimid = self.meihap.read(MEIHAP::CLAIMID);
169
170        if claimid == 0 {
171            None
172        } else {
173            // Clear the interrupt
174            self.registers.meigwclr[claimid - 1].set(0);
175            // Disable the interrupt, we re-enable it in the complete step
176            self.registers.meie[claimid - 1].write(MEIE::INTEN::DISABLE);
177
178            Some(claimid as u32)
179        }
180    }
181
182    /// Save the current interrupt to be handled later
183    /// This will save the interrupt at index internally to be handled later.
184    /// Interrupts must be disabled before this is called.
185    /// Saved interrupts can be retrieved by calling `get_saved_interrupts()`.
186    /// Saved interrupts are cleared when `'complete()` is called.
187    pub fn save_interrupt(&self, index: u32) {
188        let offset = if index < 32 {
189            0
190        } else if index < 64 {
191            1
192        } else if index < 96 {
193            2
194        } else {
195            panic!("Unsupported index {}", index);
196        };
197        let irq = index % 32;
198
199        // OR the current saved state with the new value
200        let new_saved = self.saved[offset].get().get() | 1 << irq;
201
202        // Set the new state
203        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
204    }
205
206    /// The `next_pending()` function will only return enabled interrupts.
207    /// This function will return a pending interrupt that has been disabled by
208    /// `save_interrupt()`.
209    pub fn get_saved_interrupts(&self) -> Option<u32> {
210        for (i, pending) in self.saved.iter().enumerate() {
211            let saved = pending.get().get();
212            if saved != 0 {
213                return Some(saved.trailing_zeros() + (i as u32 * 32));
214            }
215        }
216
217        None
218    }
219
220    /// Signal that an interrupt is finished being handled. In Tock, this should be
221    /// called from the normal main loop (not the interrupt handler).
222    /// Interrupts must be disabled before this is called.
223    ///
224    /// # Safety
225    ///
226    /// access to memory-mapped registers
227    pub unsafe fn complete(&self, index: u32) {
228        // Clear the interrupt
229        self.registers.meigwclr[index as usize - 1].set(0);
230        // Enable the interrupt
231        self.registers.meie[index as usize - 1].write(MEIE::INTEN::ENABLE);
232
233        let offset = if index < 32 {
234            0
235        } else if index < 64 {
236            1
237        } else {
238            2
239        };
240        let irq = index % 32;
241
242        // OR the current saved state with the new value
243        let new_saved = self.saved[offset].get().get() & !(1 << irq);
244
245        // Set the new state
246        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
247    }
248}