voron

experimental ARM OS
git clone git://git.2f30.org/voron
Log | Files | Refs | README | LICENSE

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 }