arm_gic_driver/version/
v2.rs

1use core::ptr::NonNull;
2
3use rdif_intc::*;
4use tock_registers::{register_structs, registers::*};
5
6use super::*;
7
8/// GICv2 driver. (support GICv1)
9pub struct Gic {
10    gicd: NonNull<Distributor>,
11    gicc: NonNull<CpuInterface>,
12}
13
14unsafe impl Send for Gic {}
15
16impl Gic {
17    /// `gicd`: Distributor register base address. `gicc`: CPU interface register base address.
18    pub fn new(gicd: NonNull<u8>, gicc: NonNull<u8>) -> Self {
19        Self {
20            gicd: gicd.cast(),
21            gicc: gicc.cast(),
22        }
23    }
24
25    fn gicd(&self) -> &Distributor {
26        unsafe { self.gicd.as_ref() }
27    }
28    fn gicc(&self) -> &CpuInterface {
29        unsafe { self.gicc.as_ref() }
30    }
31}
32
33impl DriverGeneric for Gic {
34    fn open(&mut self) -> DriverResult {
35        self.gicd().disable_all_interrupts();
36        self.gicd().CTLR.write(CTLR::EnableGrp0::SET);
37        Ok(())
38    }
39
40    fn close(&mut self) -> DriverResult {
41        Ok(())
42    }
43}
44
45impl Interface for Gic {
46    fn current_cpu_setup(&self) -> HardwareCPU {
47        self.gicc().enable();
48        self.gicc().set_priority_mask(0xff);
49        Box::new(GicCpu { ptr: self.gicc })
50    }
51
52    fn irq_enable(&mut self, irq: IrqId) {
53        self.gicd().set_enable_interrupt(irq.into(), true);
54    }
55
56    fn irq_disable(&mut self, irq: IrqId) {
57        self.gicd().set_enable_interrupt(irq.into(), false);
58    }
59
60    fn set_priority(&mut self, irq: IrqId, priority: usize) {
61        self.gicd().set_priority(irq.into(), priority as _);
62    }
63
64    fn set_trigger(&mut self, irq: IrqId, trigger: Trigger) {
65        self.gicd().set_cfgr(irq.into(), trigger);
66    }
67
68    fn set_target_cpu(&mut self, irq: IrqId, cpu: CpuId) {
69        let target_list = 1u8 << usize::from(cpu);
70        self.gicd().set_bind_cpu(irq.into(), target_list);
71    }
72}
73
74pub struct GicCpu {
75    ptr: NonNull<CpuInterface>,
76}
77
78unsafe impl Sync for GicCpu {}
79unsafe impl Send for GicCpu {}
80
81impl GicCpu {
82    fn gicc(&self) -> &CpuInterface {
83        unsafe { self.ptr.as_ref() }
84    }
85}
86
87impl InterfaceCPU for GicCpu {
88    fn get_and_acknowledge_interrupt(&self) -> Option<IrqId> {
89        self.gicc()
90            .get_and_acknowledge_interrupt()
91            .map(|i| (u32::from(i) as usize).into())
92    }
93
94    fn end_interrupt(&self, irq: IrqId) {
95        self.gicc().end_interrupt(IntId::from(irq))
96    }
97}
98
99register_structs! {
100    /// GIC CPU Interface registers.
101    #[allow(non_snake_case)]
102    pub CpuInterface {
103        /// CPU Interface Control Register.
104        (0x0000 => CTLR: ReadWrite<u32>),
105        /// Interrupt Priority Mask Register.
106        (0x0004 => PMR: ReadWrite<u32>),
107        /// Binary Point Register.
108        (0x0008 => BPR: ReadWrite<u32>),
109        /// Interrupt Acknowledge Register.
110        (0x000c => IAR: ReadOnly<u32, IAR::Register>),
111        /// End of Interrupt Register.
112        (0x0010 => EOIR: WriteOnly<u32>),
113        /// Running Priority Register.
114        (0x0014 => RPR: ReadOnly<u32>),
115        /// Highest Priority Pending Interrupt Register.
116        (0x0018 => HPPIR: ReadOnly<u32>),
117        (0x001c => _reserved_1),
118        /// CPU Interface Identification Register.
119        (0x00fc => IIDR: ReadOnly<u32>),
120        (0x0100 => _reserved_2),
121        /// Deactivate Interrupt Register.
122        (0x1000 => DIR: WriteOnly<u32>),
123        (0x1004 => @END),
124    }
125}
126
127impl CpuInterface {
128    pub fn set_priority_mask(&self, priority: u8) {
129        self.PMR.set(priority as u32);
130    }
131
132    pub fn enable(&self) {
133        self.CTLR.set(1);
134    }
135
136    pub fn get_and_acknowledge_interrupt(&self) -> Option<IntId> {
137        let id = self.IAR.read(IAR::INTID);
138        if id == 1023 {
139            None
140        } else {
141            unsafe { Some(IntId::raw(id)) }
142        }
143    }
144
145    pub fn end_interrupt(&self, intid: IntId) {
146        self.EOIR.set(intid.into())
147    }
148}