earlgrey/
plic.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::registers::top_earlgrey::RV_PLIC_BASE_ADDR;
8use kernel::utilities::cells::VolatileCell;
9use kernel::utilities::registers::interfaces::{Readable, Writeable};
10use kernel::utilities::registers::LocalRegisterCopy;
11use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
12use kernel::utilities::StaticRef;
13
14pub const PLIC_BASE: StaticRef<PlicRegisters> =
15    unsafe { StaticRef::new(RV_PLIC_BASE_ADDR as *const PlicRegisters) };
16
17pub static mut PLIC: Plic = Plic::new(PLIC_BASE);
18
19pub const PLIC_REGS: usize = 6;
20pub const PLIC_IRQ_NUM: usize = 185;
21
22register_structs! {
23    pub PlicRegisters {
24        /// Interrupt Priority Registers
25        (0x000 => priority: [ReadWrite<u32, priority::Register>; PLIC_IRQ_NUM]),
26        (0x2e4 => _reserved0),
27        /// Interrupt Pending Register
28        (0x1000 => pending: [ReadOnly<u32>; PLIC_REGS]),
29        (0x1018 => _reserved1),
30        /// Interrupt Enable Register
31        (0x2000 => enable: [ReadWrite<u32>; PLIC_REGS]),
32        (0x2018 => _reserved2),
33        /// Priority Threshold Register
34        (0x200000 => threshold: ReadWrite<u32, priority::Register>),
35        /// Claim/Complete Register
36        (0x200004 => claim: ReadWrite<u32>),
37        (0x200008 => _reserved3),
38        /// MSIP Register
39        (0x4000000 => msip: ReadWrite<u32>),
40        (0x4000004 => _reserved4),
41        (0x4004000 => alert_test: ReadWrite<u32>),
42        (0x4004004 => @END),
43    }
44}
45
46register_bitfields![u32,
47    priority [
48        Priority OFFSET(0) NUMBITS(2) []
49    ]
50];
51
52pub struct Plic {
53    registers: StaticRef<PlicRegisters>,
54    saved: [VolatileCell<LocalRegisterCopy<u32>>; PLIC_REGS],
55}
56
57impl Plic {
58    pub const fn new(base: StaticRef<PlicRegisters>) -> Self {
59        Plic {
60            registers: base,
61            saved: [
62                VolatileCell::new(LocalRegisterCopy::new(0)),
63                VolatileCell::new(LocalRegisterCopy::new(0)),
64                VolatileCell::new(LocalRegisterCopy::new(0)),
65                VolatileCell::new(LocalRegisterCopy::new(0)),
66                VolatileCell::new(LocalRegisterCopy::new(0)),
67                VolatileCell::new(LocalRegisterCopy::new(0)),
68            ],
69        }
70    }
71
72    /// Clear all pending interrupts.
73    pub fn clear_all_pending(&self) {
74        unimplemented!()
75    }
76
77    /// Enable all interrupts.
78    pub fn enable_all(&self) {
79        for enable in self.registers.enable.iter() {
80            enable.set(0xFFFF_FFFF);
81        }
82
83        // Set the max priority for each interrupt. This is not really used
84        // at this point.
85        for priority in self.registers.priority.iter() {
86            priority.write(priority::Priority.val(3));
87        }
88
89        // Accept all interrupts.
90        self.registers.threshold.write(priority::Priority.val(1));
91    }
92
93    /// Disable specific interrupt.
94    pub fn disable(&self, index: u32) {
95        if index >= PLIC_IRQ_NUM as u32 {
96            panic!("Invalid IRQ: {}", index)
97        }
98        let offset = (index / 32) as usize;
99        let mask = !(1 << (index % 32));
100
101        self.registers.enable[offset].set(self.registers.enable[offset].get() & mask);
102    }
103
104    /// Disable all interrupts.
105    pub fn disable_all(&self) {
106        for enable in self.registers.enable.iter() {
107            enable.set(0);
108        }
109    }
110
111    /// Get the index (0-256) of the lowest number pending interrupt, or `None` if
112    /// none is pending. RISC-V PLIC has a "claim" register which makes it easy
113    /// to grab the highest priority pending interrupt.
114    pub fn next_pending(&self) -> Option<u32> {
115        let claim = self.registers.claim.get();
116        if claim == 0 {
117            None
118        } else {
119            Some(claim)
120        }
121    }
122
123    /// Save the current interrupt to be handled later
124    /// This will save the interrupt at index internally to be handled later.
125    /// Interrupts must be disabled before this is called.
126    /// Saved interrupts can be retrieved by calling `get_saved_interrupts()`.
127    /// Saved interrupts are cleared when `'complete()` is called.
128    pub unsafe fn save_interrupt(&self, index: u32) {
129        if index >= PLIC_IRQ_NUM as u32 {
130            panic!("Invalid IRQ: {}", index)
131        }
132        let offset = (index / 32) as usize;
133        let mask = 1 << (index % 32);
134
135        // OR the current saved state with the new value
136        let new_saved = self.saved[offset].get().get() | mask;
137
138        // Set the new state
139        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
140    }
141
142    /// The `next_pending()` function will only return enabled interrupts.
143    /// This function will return a pending interrupt that has been disabled by
144    /// `save_interrupt()`.
145    pub fn get_saved_interrupts(&self) -> Option<u32> {
146        for (i, pending) in self.saved.iter().enumerate() {
147            let saved = pending.get().get();
148            if saved != 0 {
149                return Some(saved.trailing_zeros() + (i as u32 * 32));
150            }
151        }
152        None
153    }
154
155    /// Signal that an interrupt is finished being handled. In Tock, this should be
156    /// called from the normal main loop (not the interrupt handler).
157    /// Interrupts must be disabled before this is called.
158    pub unsafe fn complete(&self, index: u32) {
159        self.registers.claim.set(index);
160        if index >= PLIC_IRQ_NUM as u32 {
161            panic!("Invalid IRQ: {}", index)
162        }
163        let offset = (index / 32) as usize;
164        let mask = !(1 << (index % 32));
165
166        // OR the current saved state with the new value
167        let new_saved = self.saved[offset].get().get() & mask;
168
169        // Set the new state
170        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
171    }
172}