1use 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        (0x000 => _reserved0),
21        (0x004 => meipl: [ReadWrite<u32, MEIPL::Register>; 255]),
22        (0x400 => _reserved1),
23        (0x1000 => meip: [ReadWrite<u32, MEIP::Register>; 8]),
25        (0x1020 => _reserved2),
26        (0x2004 => meie: [ReadWrite<u32, MEIE::Register>; 255]),
28        (0x2400 => _reserved3),
29        (0x3000 => mpiccfg: ReadWrite<u32, MPICCFG::Register>),
31        (0x3004 => _reserved4),
32        (0x4004 => meigwctrl: [ReadWrite<u32, MEIGWCTRL::Register>; 255]),
34        (0x4400 => _reserved5),
35        (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    pub fn clear_all_pending(&self) {
126        for clear in self.registers.meigwclr.iter() {
127            clear.set(0);
128        }
129    }
130
131    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        for enable in self.registers.meie.iter() {
153            enable.write(MEIE::INTEN::ENABLE);
154        }
155    }
156    pub fn disable_all(&self) {
158        for enable in self.registers.meie.iter() {
159            enable.write(MEIE::INTEN::DISABLE);
160        }
161    }
162
163    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            self.registers.meigwclr[claimid - 1].set(0);
175            self.registers.meie[claimid - 1].write(MEIE::INTEN::DISABLE);
177
178            Some(claimid as u32)
179        }
180    }
181
182    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        let new_saved = self.saved[offset].get().get() | 1 << irq;
201
202        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
204    }
205
206    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    pub unsafe fn complete(&self, index: u32) {
228        self.registers.meigwclr[index as usize - 1].set(0);
230        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        let new_saved = self.saved[offset].get().get() & !(1 << irq);
244
245        self.saved[offset].set(LocalRegisterCopy::new(new_saved));
247    }
248}