arm_gic_driver/version/
v2.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use core::ptr::NonNull;

use tock_registers::{register_structs, registers::*};

use super::*;

/// GICv2 driver. (support GICv1)
pub struct GicV2 {
    gicd: NonNull<Distributor>,
    gicc: NonNull<CpuInterface>,
}

unsafe impl Send for GicV2 {}
unsafe impl Sync for GicV2 {}

impl GicV2 {
    /// `gicd`: Distributor register base address. `gicc`: CPU interface register base address.
    pub fn new(gicd: NonNull<u8>, gicc: NonNull<u8>) -> GicResult<Self> {
        let s = Self {
            gicd: gicd.cast(),
            gicc: gicc.cast(),
        };
        unsafe {
            s.gicd.as_ref().disable_all_interrupts();
            s.gicd.as_ref().CTLR.write(CTLR::EnableGrp0::SET);
        }
        Ok(s)
    }

    fn gicd(&self) -> &Distributor {
        unsafe { self.gicd.as_ref() }
    }
    fn gicc(&self) -> &CpuInterface {
        unsafe { self.gicc.as_ref() }
    }
}

impl GicGeneric for GicV2 {
    fn get_and_acknowledge_interrupt(&self) -> Option<super::IntId> {
        self.gicc().get_and_acknowledge_interrupt()
    }

    fn end_interrupt(&self, intid: super::IntId) {
        self.gicc().end_interrupt(intid)
    }

    fn irq_max_size(&self) -> usize {
        self.gicd().irq_line_max() as _
    }

    fn irq_disable(&mut self, intid: super::IntId) {
        self.gicd().set_enable_interrupt(intid, false);
    }

    fn current_cpu_setup(&self) {
        self.gicc().enable();
        self.gicc().set_priority_mask(0xff);
    }

    fn irq_enable(&mut self, intid: super::IntId) {
        self.gicd().set_enable_interrupt(intid, true);
    }

    fn set_priority(&mut self, intid: super::IntId, priority: usize) {
        self.gicd().set_priority(intid, priority as _);
    }

    fn set_trigger(&mut self, intid: super::IntId, trigger: Trigger) {
        self.gicd().set_cfgr(intid, trigger);
    }

    fn set_bind_cpu(&mut self, intid: super::IntId, target_list: &[super::CPUTarget]) {
        self.gicd().set_bind_cpu(
            intid,
            target_list
                .iter()
                .fold(0, |acc, &cpu| acc | cpu.cpu_target_list()),
        );
    }
}

register_structs! {
    /// GIC CPU Interface registers.
    #[allow(non_snake_case)]
    pub CpuInterface {
        /// CPU Interface Control Register.
        (0x0000 => CTLR: ReadWrite<u32>),
        /// Interrupt Priority Mask Register.
        (0x0004 => PMR: ReadWrite<u32>),
        /// Binary Point Register.
        (0x0008 => BPR: ReadWrite<u32>),
        /// Interrupt Acknowledge Register.
        (0x000c => IAR: ReadOnly<u32, IAR::Register>),
        /// End of Interrupt Register.
        (0x0010 => EOIR: WriteOnly<u32>),
        /// Running Priority Register.
        (0x0014 => RPR: ReadOnly<u32>),
        /// Highest Priority Pending Interrupt Register.
        (0x0018 => HPPIR: ReadOnly<u32>),
        (0x001c => _reserved_1),
        /// CPU Interface Identification Register.
        (0x00fc => IIDR: ReadOnly<u32>),
        (0x0100 => _reserved_2),
        /// Deactivate Interrupt Register.
        (0x1000 => DIR: WriteOnly<u32>),
        (0x1004 => @END),
    }
}

impl CpuInterface {
    pub fn set_priority_mask(&self, priority: u8) {
        self.PMR.set(priority as u32);
    }

    pub fn enable(&self) {
        self.CTLR.set(1);
    }

    pub fn get_and_acknowledge_interrupt(&self) -> Option<IntId> {
        let id = self.IAR.read(IAR::INTID);
        if id == 1023 {
            None
        } else {
            unsafe { Some(IntId::raw(id)) }
        }
    }

    pub fn end_interrupt(&self, intid: IntId) {
        self.EOIR.set(intid.into())
    }
}