POD Interrupt handler
Contents
Interrupt handler mechanism
This page details the software mechanism we have to implement in the CPU connected to the FPGA, to handle the multiple IP interrupt sources with only one interrupt physical signal. Althought dedicated to Linux on ARM9, it should applies to every "well coded" OSes.
Preamble
ARM cores handle only 2 interrupts by default:
- FIQ: "Fast interrupt", highest priority one
- NIQ: "Normal interrupt"
Then constructors add their own logic to extend the number of interrupts connected to these 2 ones.
So on ARM systems there is a global interrupt handler which is called each time an interrupt occurs. Its job is to identify the interrupt source and then to delegate the job to the sub "interrupt handler".
Linux integrates this mechanism and provides an API to handle multiple interrupt handler registering and IT dispatching:
set_irq_chip(irq, struct irq_chip*);
set_irq_handler(irq, handler);
set_irq_flags(irq, flad);
set_irq_chained_handler(muxed_irq, demux_handler);
set_irq_chained_handler(muxed_irq, demux_handler);
...
How it actually works on i.XML
Interrupts are divided in 2 categories:
- i.MXL internal peripheral interrupts ("MPU"), with attributed numbers between 0 and 64
- GPIO interrupts ("GPIO"), with attributed numbers between 65 and 192 (32x 4 GPIO ports)
On a running system:
# cat /proc/interrupts
CPU0
26: 0 MPU IMX-uart
29: 183 MPU IMX-uart
30: 495 MPU IMX-uart
35: 4592 MPU imx-mmc
39: 1 MPU I2C_IMX
40: 56534 MPU spi_imx.2
41: 0 MPU spi_imx.1
59: 326869 MPU i.MX Timer Tick
60: 0 MPU DMA
61: 1405 MPU DMA
110: 935 GPIO eth0
168: 6517 GPIO tsc2102
Err: 0
The GPIO family interrupts can be seen as a subclass of MPU interrupts (ITs). Indeed there is only one hardware interrupt per GPIO ports.
- GPIO_INT_PORTA has number 11
- GPIO_INT_PORTB has number 12
- GPIO_INT_PORTC has number 13
- GPIO_INT_PORTD has number 62
So, GPIO ITs are multiplexed for each port. Linux allows to have a "virtual" interrupt number, not reflecting the hardware one and which remove demultiplexing handling from the peripheral drivers. This mechanism is used for handling POD single IT.
How to implement it for POD
We will declare IT 65 as a chained IRQ (if possible as it's already a virtual interrupt of IT 11) and add a demultiplexer for FPGA in the IRQ handler. This way usable IT numbers for IP will be in the range [192-255?].
Interrupt register in the FPGA
To handle the interrupts, the IT manager IP will have 2 registers:
- an Interrupt Mask Register (IMR) for interrupt activation/deactivation. Actually this is a 16 bits register at address 0x00 with 1 bit per IT -> 16 IT handled:
FPGA_IMR | Interrupt Mask Register | Addr 0x0000 | ||||||||||||||
BIT | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
IT_15 | IT_14 | IT_13 | IT_12 | IT_11 | IT_10 | IT_9 | IT_8 | IT_7 | IT_6 | IT_5 | IT_4 | IT_3 | IT_2 | IT_1 | IT_0 | |
TYPE | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw |
RESET | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0x0000 |
Name | Description | Settings |
---|---|---|
Bit 15-0 | Enable/disable corresponding interrupt | 0 -> IT masked/deactivated 1 -> IT enabled |
- an Interrupt Status Register (ISR) which holds the number of the IT generating the interrupt:
FPGA_ISR | Interrupt Status Register | Addr 0x0002 | ||||||||||||||
BIT | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
IT_15 | IT_14 | IT_13 | IT_12 | IT_11 | IT_10 | IT_9 | IT_8 | IT_7 | IT_6 | IT_5 | IT_4 | IT_3 | IT_2 | IT_1 | IT_0 | |
TYPE | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw | rw |
RESET | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0x0000 |
Name | Description | Settings |
---|---|---|
Bit 15-0 | Indicate whether the corresponding IT is pending or not. Writing a 1 to this bit acknowledges the IT and clears it. |
0 -> IT not pending 1 -> IT pending |