gic.c (2440B)
1 #include <kernel.h> 2 #include <irq.h> 3 #include <gic.h> 4 5 #define IAR_ID(x) (x & 0x3ff) 6 7 /* GICv1 CPU interface registers */ 8 struct gicc { 9 u32 ctlr; 10 u32 pmr; 11 u32 bpr; 12 u32 iar; 13 u32 eoir; 14 u32 rpr; 15 u32 hppir; 16 u32 abpr; 17 u32 _pad[55]; 18 u32 iidr; 19 }; 20 21 #define MAX_IT_LINES_NUMBER 32 22 /* Forward the interrupt only to the CPU interface 23 * of the processor that requested the interrupt. */ 24 #define SGIR_TARGER_CPU_REQ (2 << 24) 25 26 #define NR_SGI 15 27 28 /* GICv1 Distributor registers */ 29 struct gicd { 30 u32 ctlr; 31 u32 typer; 32 u32 iidr; 33 u32 _pad1[29]; 34 u32 igrour[MAX_IT_LINES_NUMBER]; 35 u32 isenabler[MAX_IT_LINES_NUMBER]; 36 u32 icenabler[MAX_IT_LINES_NUMBER]; 37 u32 ispendr[MAX_IT_LINES_NUMBER]; 38 u32 icpendr[MAX_IT_LINES_NUMBER]; 39 u32 isactiver[MAX_IT_LINES_NUMBER]; 40 u32 _pad2[32]; 41 u32 ipriorityr[8 * MAX_IT_LINES_NUMBER]; 42 u32 itargetsr[8 * MAX_IT_LINES_NUMBER]; 43 u32 icfgr[2 * MAX_IT_LINES_NUMBER]; 44 u32 _pad3[128]; 45 u32 sgir; 46 }; 47 48 static struct gicc *gicc = (struct gicc*)0x48240100; 49 static struct gicd *gicd = (struct gicd*)0x48241000; 50 static irq_callback_func irq_handlers[NR_IRQ]; 51 52 int 53 gic_register(u32 irq_num, irq_callback_func func) 54 { 55 int i; 56 u32 val; 57 58 if (irq_num >= NR_IRQ) 59 return -EINVAL; 60 61 /* set callback function */ 62 irq_handlers[irq_num] = func; 63 64 /* enable irq number */ 65 i = irq_num / 32; 66 val = readl(&gicd->isenabler[i]); 67 val |= 1 << (irq_num % 32); 68 writel(val, &gicd->isenabler[i]); 69 70 /* send the interrupt to CPU0 */ 71 i = irq_num / 4; 72 val = readl(&gicd->itargetsr[i]); 73 val &= ~(0xff << (8 * (irq_num % 4))); 74 val |= 1 << (8 * (irq_num % 4)); 75 writel(val, &gicd->itargetsr[i]); 76 77 return 0; 78 } 79 80 void 81 gic_handler(struct regs *regs) 82 { 83 u32 iar, id; 84 85 /* read interrupt id */ 86 iar = readl(&gicc->iar); 87 id = IAR_ID(iar); 88 89 /* call handler */ 90 if (id < NR_IRQ && irq_handlers[id] != NULL) 91 irq_handlers[id](id, regs); 92 93 /* end of interrupt */ 94 writel(iar, &gicc->eoir); 95 } 96 97 int 98 gic_trigger_sgi(u32 irq_num) 99 { 100 if (irq_num > NR_SGI) 101 return -EINVAL; 102 103 writel(irq_num | SGIR_TARGER_CPU_REQ, &gicd->sgir); 104 105 return 0; 106 } 107 108 void 109 gic_init(void) 110 { 111 /* disable gic cpu interface */ 112 writel(0, &gicc->ctlr); 113 /* disable gic distributor */ 114 writel(0, &gicd->ctlr); 115 116 /* make sure that software interrupts are enabled */ 117 writel(0xffff, &gicd->isenabler[0]); 118 119 /* set lower priority level */ 120 writel(0xf0, &gicc->pmr); 121 /* enable gic cpu interface */ 122 writel(1, &gicc->ctlr); 123 /* enable gic cpu distributor */ 124 writel(1, &gicd->ctlr); 125 }