Closed maxstreitberger closed 2 years ago
I found out that the raspberry pi 4 uses the GIC-400 interrupt controller. I used the CoreLinkTM GIC-400 Generic Interrupt Controller Manual, ARM Generic Interrupt Controller Architecture Specification, and the BCM2711 ARM Peripherals Manual to get information about it.
To implement the timer interrupt we need the following information:
The irq.h file would then look like this:
#ifndef _P_IRQ_H
#define _P_IRQ_H
#include <peripherals/base.h>
#define GIC_BASE 0xFF840000
#define GICD_DIST_BASE (GIC_BASE+0x00001000)
#define GICC_CPU_BASE (GIC_BASE+0x00002000)
#define GICD_ENABLE_IRQ_BASE (GICD_DIST_BASE+0x00000100)
#define GICC_IAR (GICC_CPU_BASE+0x0000000C)
#define GICC_EOIR (GICC_CPU_BASE+0x00000010)
#define GIC_IRQ_TARGET_BASE (GICD_DIST_BASE+0x00000800)
//VC (=VideoCore) starts at 96
#define SYSTEM_TIMER_IRQ_0 (0x60) //96
#define SYSTEM_TIMER_IRQ_1 (0x61) //97
#define SYSTEM_TIMER_IRQ_2 (0x62) //98
#define SYSTEM_TIMER_IRQ_3 (0x63) //99
#endif
The irq.c looks then as follows:
#include "utils.h"
#include "printf.h"
#include "timer.h"
#include "entry.h"
#include "peripherals/irq.h"
#include "arm/sysregs.h"
const char *entry_error_messages[] = {
"SYNC_INVALID_EL1t",
"IRQ_INVALID_EL1t",
"FIQ_INVALID_EL1t",
"ERROR_INVALID_EL1T",
"SYNC_INVALID_EL1h",
"IRQ_INVALID_EL1h",
"FIQ_INVALID_EL1h",
"ERROR_INVALID_EL1h",
"SYNC_INVALID_EL0_64",
"IRQ_INVALID_EL0_64",
"FIQ_INVALID_EL0_64",
"ERROR_INVALID_EL0_64",
"SYNC_INVALID_EL0_32",
"IRQ_INVALID_EL0_32",
"FIQ_INVALID_EL0_32",
"ERROR_INVALID_EL0_32"
};
void enable_interrupt(unsigned int irq) {
printf("%x\r\n", irq);
unsigned int n = irq / 32;
unsigned int offset = irq % 32;
unsigned int enableRegister = GICD_ENABLE_IRQ_BASE + (4*n);
printf("EnableRegister: %x\r\n", enableRegister);
put32(enableRegister, 1 << offset);
}
void assign_target(unsigned int irq, unsigned int cpu) {
unsigned int n = irq / 4;
unsigned int targetRegister = GIC_IRQ_TARGET_BASE + (4*n);
// Currently we only enter the target CPU 0
put32(targetRegister, get32(targetRegister) | (1 << 8));
}
void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) {
printf("%s, ESR: %x, address, %x\r\n", entry_error_messages[type], esr, address);
}
void enable_interrupt_controller() {
assign_target(SYSTEM_TIMER_IRQ_1, 0);
enable_interrupt(SYSTEM_TIMER_IRQ_1);
}
void handle_irq(void) {
unsigned int irq_ack_reg = get32(GICC_IAR);
unsigned int irq = irq_ack_reg & 0x2FF;
switch (irq) {
case (SYSTEM_TIMER_IRQ_1):
handle_timer_irq();
put32(GICC_EOIR, irq_ack_reg);
break;
default:
printf("Unknown pending irq: %x\r\n", irq);
break;
}
}
@maxstreitberger thanks for your effort, but do you know why doesn't Low Level Devel need to configure the GIC? I (rpi4b) also followed the youtube video and everything works fine. By now I'm just confused. The bcm2711 peripheral datasheet doesn't explain clearly, what are the ARMC registers? why do the ARMC registers control the VC interrupts when on page 87 the VC interrupts are connected to the GIC? why is ARMC also listed as an interrupt source? should I configure both the ARMC registers and the GIC? so many questions... I'd be very thankful if anyone can help.
hello past self, here's what I think is happening after some testing:
Low Level Devel doesn't need to configure the GIC because he used a custom armstub
to start the RPI4, which does not enable the GIC. The default armstub
probably sets up the GIC which causes the "ARMC" interrupt handling code to fail. An interesting point is that according to the rpi docs, the GIC is enabled by default, but once I remove the GIC enabling code in the armstub
, the ARMC code works again, I guess this means that the GIC needs to be explicitly enabled in the armstub
.
With all this, I think ARMC is a part of the legacy interrupt controller, but still I don't know what "ARMC" stands for.
A good reference for GIC enabling code can be found in raspberrypi/tools.
@rhythm16 I hope I can provide some answers to your questions.
Please correct me if I'm wrong somewhere.
Brilliant. I spent hours trying to figure out how to get timer interrupts working on my raspberry pi 4b. The GIC-400 initialization and interrupt setup code here is what I needed. Thanks!
I have some problems with converting the code for the RPi 3 to the RPi 4. I think I narrowed it down to the point where there is a problem with the handle_irq() function that doesn't get fired. But I don't know why it doesn't get called. I also tried to follow this video which helped a little, but it still doesn't work. Here are the functions I have in irq.c:
This is the irq.h file I use: