arm_gic_driver/version/
mod.rs

1use tock_registers::{interfaces::*, registers::*};
2
3pub mod v2;
4pub mod v3;
5
6use crate::define::*;
7
8#[cfg(feature = "rdif")]
9mod rdif;
10
11/// 通用 trait:为一组 ReadWrite<u32> 寄存器设置某一位
12trait IrqVecWriteable {
13    fn set_irq_bit(&self, intid: u32);
14    fn clear_irq_bit(&self, intid: u32);
15}
16trait IrqVecReadable {
17    fn get_irq_bit(&self, intid: u32) -> bool;
18}
19
20impl IrqVecWriteable for [ReadWrite<u32>] {
21    fn set_irq_bit(&self, index: u32) {
22        let reg_index = (index / 32) as usize;
23        let bit = 1 << (index % 32);
24        // For GIC ISENABLER/ISPENDR/ISACTIVER etc, writing 1 sets the bit
25        // Writing 0 has no effect, so we can safely write only the target bit
26        self[reg_index].set(bit);
27    }
28    fn clear_irq_bit(&self, intid: u32) {
29        let reg_index = (intid / 32) as usize;
30        let bit = 1 << (intid % 32);
31        let old = self[reg_index].get();
32        if old & bit == 0 {
33            return; // Already cleared
34        }
35        self[reg_index].set(old & !bit);
36    }
37}
38
39impl IrqVecReadable for [ReadWrite<u32>] {
40    fn get_irq_bit(&self, index: u32) -> bool {
41        let reg_index = (index / 32) as usize;
42        let bit = 1 << (index % 32);
43        self[reg_index].get() & bit != 0
44    }
45}
46
47/// Parse interrupt configuration from device tree interrupt specifier.
48///
49/// This function interprets device tree interrupt specifiers according to the
50/// ARM GIC device tree binding specification. It supports various interrupt types
51/// and configurations as defined by the Linux kernel's GIC driver.
52///
53/// Based on Linux GIC driver's `gic_irq_domain_translate` function.
54///
55/// # Arguments
56///
57/// * `itr` - Interrupt specifier array from device tree. The format depends on
58///   the interrupt type:
59///   - SGI: `[sgi_id]` - Single parameter for SGI 0-15
60///   - PPI/SPI: `[type, number, flags]` - Standard 3-parameter format
61///   - Extended: `[type, number, flags]` - For ESPI/EPPI/LPI/Partitioned PPI
62///
63/// # Interrupt Types (first parameter)
64///
65/// - `0` (SPI): Shared Peripheral Interrupt
66/// - `1` (PPI): Private Peripheral Interrupt  
67/// - `2` (ESPI): Extended SPI (starting at ID 4096)
68/// - `3` (EPPI): Extended PPI (starting at ID 1056)
69/// - `4` (LPI): Locality-specific Peripheral Interrupt
70/// - `5` (PARTITION): Partitioned PPI
71///
72/// # Interrupt Flags (third parameter)
73///
74/// - `0x1`: Edge rising
75/// - `0x2`: Edge falling  
76/// - `0x3`: Edge both
77/// - `0x4`: Level high
78/// - `0x8`: Level low
79///
80/// # Returns
81///
82/// Returns `Ok(IrqConfig)` with the parsed interrupt configuration, or
83/// `Err(&'static str)` if the input is invalid.
84///
85/// # Errors
86///
87/// - "Invalid IRQ configuration: need at least 3 parameters" - Insufficient parameters
88/// - "Invalid IRQ type" - Unknown interrupt type
89/// - "IRQ_TYPE_NONE is not allowed for IRQ type" - Missing trigger configuration
90/// - "Invalid IRQ trigger type" - Unknown trigger flags
91///
92/// # Examples
93///
94/// ```no_run
95/// use arm_gic_driver::{fdt_parse_irq_config, IntId, Trigger};
96///
97/// // SGI interrupt
98/// let sgi_config = fdt_parse_irq_config(&[5]).unwrap();
99/// assert!(sgi_config.id.is_sgi());
100///
101/// // SPI interrupt (type=0, number=42, level-high)
102/// let spi_config = fdt_parse_irq_config(&[0, 42, 4]).unwrap();
103/// assert_eq!(spi_config.id.to_u32(), 74); // 32 + 42
104/// assert_eq!(spi_config.trigger, Trigger::Level);
105///
106/// // PPI interrupt (type=1, number=2, edge-rising)
107/// let ppi_config = fdt_parse_irq_config(&[1, 2, 1]).unwrap();
108/// assert_eq!(spi_config.id.to_u32(), 18); // 16 + 2
109/// assert_eq!(ppi_config.trigger, Trigger::Edge);
110/// ```
111pub fn fdt_parse_irq_config(itr: &[u32]) -> Result<IrqConfig, &'static str> {
112    // Handle single parameter case (SGI)
113    if itr.len() == 1 && itr[0] < 16 {
114        return Ok(IrqConfig {
115            id: IntId::sgi(itr[0]),
116            trigger: Trigger::Edge, // SGI is always edge-triggered
117        });
118    }
119
120    // Need at least 3 parameters for full specification
121    if itr.len() < 3 {
122        return Err("Invalid IRQ configuration: need at least 3 parameters");
123    }
124
125    // Interrupt type constants (from Linux kernel)
126    const SPI: u32 = 0; // Shared Peripheral Interrupt
127    const PPI: u32 = 1; // Private Peripheral Interrupt
128    const ESPI: u32 = 2; // Extended SPI
129    const EPPI: u32 = 3; // Extended PPI
130    const LPI: u32 = 4; // Locality-specific Peripheral Interrupt
131    const PARTITION: u32 = 5; // Partitioned PPI
132
133    // Base interrupt IDs for extended interrupts
134    const ESPI_BASE_INTID: u32 = 4096;
135    const EPPI_BASE_INTID: u32 = 1056;
136
137    // IRQ type sense mask (from Linux include/linux/irq.h)
138    const IRQ_TYPE_NONE: u32 = 0x00000000;
139    const IRQ_TYPE_EDGE_RISING: u32 = 0x00000001;
140    const IRQ_TYPE_EDGE_FALLING: u32 = 0x00000002;
141    const IRQ_TYPE_EDGE_BOTH: u32 = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
142    const IRQ_TYPE_LEVEL_HIGH: u32 = 0x00000004;
143    const IRQ_TYPE_LEVEL_LOW: u32 = 0x00000008;
144    const IRQ_TYPE_SENSE_MASK: u32 = 0x0000000f;
145
146    let irq_type = itr[0];
147    let irq_num = itr[1];
148    let irq_flags = itr[2] & IRQ_TYPE_SENSE_MASK;
149
150    // Calculate hardware interrupt ID based on type
151    let hwirq = match irq_type {
152        SPI => {
153            // SPI: hwirq = param[1] + 32
154            SPI_RANGE.start + irq_num
155        }
156        PPI => {
157            // PPI: hwirq = param[1] + 16
158            PPI_RANGE.start + irq_num
159        }
160        ESPI => {
161            // ESPI: hwirq = param[1] + ESPI_BASE_INTID
162            ESPI_BASE_INTID + irq_num
163        }
164        EPPI => {
165            // EPPI: hwirq = param[1] + EPPI_BASE_INTID
166            EPPI_BASE_INTID + irq_num
167        }
168        LPI => {
169            // LPI: hwirq = param[1]
170            irq_num
171        }
172        PARTITION => {
173            // Partitioned PPI: special handling
174            if irq_num >= 16 {
175                EPPI_BASE_INTID + irq_num - 16
176            } else {
177                16 + irq_num
178            }
179        }
180        _ => {
181            return Err("Invalid IRQ type");
182        }
183    };
184
185    // Create IntId from hardware interrupt ID
186    let intid = unsafe { IntId::raw(hwirq) };
187
188    // Determine trigger type from flags
189    let trigger = match irq_flags {
190        IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_BOTH => Trigger::Edge,
191        IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW => Trigger::Level,
192        IRQ_TYPE_NONE if irq_type == PARTITION => {
193            // Partitioned PPIs can have IRQ_TYPE_NONE, default to level
194            Trigger::Level
195        }
196        IRQ_TYPE_NONE => {
197            return Err("IRQ_TYPE_NONE is not allowed for IRQ type");
198        }
199        _ => {
200            return Err("Invalid IRQ trigger type");
201        }
202    };
203
204    Ok(IrqConfig { id: intid, trigger })
205}