3 * - By John Hodge (thePowersGang)
18 extern void *gpIRQHandler;
19 extern tPAddr gGIC_DistributorAddr;
20 extern tPAddr gGIC_InterfaceAddr;
23 typedef void (*tIRQ_Handler)(int, void*);
26 int GIC_Install(char **Arguments);
27 void GIC_IRQHandler(void);
30 MODULE_DEFINE(0, 0x100, armv7_GIC, GIC_Install, NULL, NULL);
31 volatile Uint32 *gpGIC_DistributorBase;
32 volatile Uint32 *gpGIC_InterfaceBase;
33 tIRQ_Handler gaIRQ_Handlers[N_IRQS];
34 void *gaIRQ_HandlerData[N_IRQS];
37 int GIC_Install(char **Arguments)
40 Log_Debug("GIC", "Dist: %P, Interface: %P",
41 gGIC_DistributorAddr, gGIC_InterfaceAddr);
42 gpGIC_InterfaceBase = (void*)MM_MapHWPages(gGIC_InterfaceAddr, 1);
43 LOG("gpGIC_InterfaceBase = %p", gpGIC_InterfaceBase);
44 gpGIC_DistributorBase = (void*)MM_MapHWPages(gGIC_DistributorAddr, 1);
45 LOG("gpGIC_DistributorBase = %p", gpGIC_DistributorBase);
47 gpGIC_InterfaceBase[GICC_CTLR] = 0; // Disable CPU interaface
48 LOG("GICC_IAR = %x (CTLR=0)", gpGIC_InterfaceBase[GICC_IAR]);
50 gpGIC_InterfaceBase[GICC_PMR] = 0xFF; // Effectively disable prioritories
51 gpGIC_InterfaceBase[GICC_CTLR] = 1; // Enable CPU
52 gpGIC_DistributorBase[GICD_CTLR] = 1; // Enable Distributor
54 gpIRQHandler = GIC_IRQHandler;
56 __asm__ __volatile__ ("cpsie if"); // Enable IRQs and FIQs
59 for( int i = 0; i < N_IRQS/32; i ++ ) {
60 Log_Debug("GIC", "GICD_ISENABLER%i %x = %08x",
61 i, GICD_ISENABLER0 + i,
62 gpGIC_DistributorBase[GICD_ISENABLER0+i]);
63 gpGIC_DistributorBase[GICD_ISENABLER0+i] = 0;
68 // Testing - First 32 actual interrupts enabled
69 gpGIC_DistributorBase[GICD_ISENABLER0+1] = 0xFFFFFFFF;
70 for( int i = 0; i < 32/4; i ++ )
71 gpGIC_DistributorBase[GICD_ITARGETSR0+8+i] = 0x01010101;
74 // Clear out pending IRQs.
75 gpGIC_InterfaceBase[GICC_EOIR] = gpGIC_InterfaceBase[GICC_IAR];
80 void GIC_IRQHandler(void)
82 Uint32 num = gpGIC_InterfaceBase[GICC_IAR];
83 Log_Debug("GIC", "IRQ 0x%x", num);
84 gaIRQ_Handlers[num]( num, gaIRQ_HandlerData[num] );
85 gpGIC_InterfaceBase[GICC_EOIR] = num;
88 int IRQ_AddHandler(int IRQ, tIRQ_Handler Handler, void *Ptr)
90 if( IRQ < 0 || IRQ >= N_IRQS-32 ) {
94 IRQ += 32; // 32 internal IRQs
95 // - Enable IRQ, clear pending and send to CPU 1 only
96 gpGIC_DistributorBase[GICD_ISENABLER0+IRQ/32] = 1 << (IRQ & (32-1));
97 ((Uint8*)&gpGIC_DistributorBase[GICD_ITARGETSR0])[IRQ] = 1;
98 gpGIC_DistributorBase[GICD_ICPENDR0+IRQ/32] = 1 << (IRQ & (32-1));
100 // TODO: Does the GIC need to handle IRQ sharing?
101 if( gaIRQ_Handlers[IRQ] ) {
102 Log_Warning("GIC", "IRQ %i already handled by %p, %p ignored",
103 IRQ, gaIRQ_Handlers[IRQ], Handler);
107 gaIRQ_Handlers[IRQ] = Handler;
108 gaIRQ_HandlerData[IRQ] = Ptr;
110 Log_Debug("GIC", "IRQ %i handled by %p(%p)", IRQ, Handler, Ptr);
112 // DEBUG! Trip the interrupt
113 gpGIC_DistributorBase[GICD_ISPENDR0+IRQ/32] = 1 << (IRQ & (32-1));