100cc96f0SAndrew Jones /* 200cc96f0SAndrew Jones * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> 300cc96f0SAndrew Jones * 400cc96f0SAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 500cc96f0SAndrew Jones */ 600cc96f0SAndrew Jones #include <devicetree.h> 700cc96f0SAndrew Jones #include <asm/gic.h> 800cc96f0SAndrew Jones #include <asm/io.h> 900cc96f0SAndrew Jones 1000cc96f0SAndrew Jones struct gicv2_data gicv2_data; 1191a6c3ceSAndrew Jones struct gicv3_data gicv3_data; 1200cc96f0SAndrew Jones 13*2e2d471dSAndrew Jones struct gic_common_ops { 14*2e2d471dSAndrew Jones int gic_version; 15*2e2d471dSAndrew Jones void (*enable_defaults)(void); 16*2e2d471dSAndrew Jones u32 (*read_iar)(void); 17*2e2d471dSAndrew Jones u32 (*iar_irqnr)(u32 iar); 18*2e2d471dSAndrew Jones void (*write_eoir)(u32 irqstat); 19*2e2d471dSAndrew Jones void (*ipi_send_single)(int irq, int cpu); 20*2e2d471dSAndrew Jones void (*ipi_send_mask)(int irq, const cpumask_t *dest); 21*2e2d471dSAndrew Jones }; 22*2e2d471dSAndrew Jones 23*2e2d471dSAndrew Jones static const struct gic_common_ops *gic_common_ops; 24*2e2d471dSAndrew Jones 25*2e2d471dSAndrew Jones static const struct gic_common_ops gicv2_common_ops = { 26*2e2d471dSAndrew Jones .gic_version = 2, 27*2e2d471dSAndrew Jones .enable_defaults = gicv2_enable_defaults, 28*2e2d471dSAndrew Jones .read_iar = gicv2_read_iar, 29*2e2d471dSAndrew Jones .iar_irqnr = gicv2_iar_irqnr, 30*2e2d471dSAndrew Jones .write_eoir = gicv2_write_eoir, 31*2e2d471dSAndrew Jones .ipi_send_single = gicv2_ipi_send_single, 32*2e2d471dSAndrew Jones .ipi_send_mask = gicv2_ipi_send_mask, 33*2e2d471dSAndrew Jones }; 34*2e2d471dSAndrew Jones 35*2e2d471dSAndrew Jones static const struct gic_common_ops gicv3_common_ops = { 36*2e2d471dSAndrew Jones .gic_version = 3, 37*2e2d471dSAndrew Jones .enable_defaults = gicv3_enable_defaults, 38*2e2d471dSAndrew Jones .read_iar = gicv3_read_iar, 39*2e2d471dSAndrew Jones .iar_irqnr = gicv3_iar_irqnr, 40*2e2d471dSAndrew Jones .write_eoir = gicv3_write_eoir, 41*2e2d471dSAndrew Jones .ipi_send_single = gicv3_ipi_send_single, 42*2e2d471dSAndrew Jones .ipi_send_mask = gicv3_ipi_send_mask, 43*2e2d471dSAndrew Jones }; 44*2e2d471dSAndrew Jones 4500cc96f0SAndrew Jones /* 4600cc96f0SAndrew Jones * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt 4791a6c3ceSAndrew Jones * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt 4800cc96f0SAndrew Jones */ 4900cc96f0SAndrew Jones static bool 5000cc96f0SAndrew Jones gic_get_dt_bases(const char *compatible, void **base1, void **base2) 5100cc96f0SAndrew Jones { 5200cc96f0SAndrew Jones struct dt_pbus_reg reg; 5300cc96f0SAndrew Jones struct dt_device gic; 5400cc96f0SAndrew Jones struct dt_bus bus; 5500cc96f0SAndrew Jones int node, ret; 5600cc96f0SAndrew Jones 5700cc96f0SAndrew Jones dt_bus_init_defaults(&bus); 5800cc96f0SAndrew Jones dt_device_init(&gic, &bus, NULL); 5900cc96f0SAndrew Jones 6000cc96f0SAndrew Jones node = dt_device_find_compatible(&gic, compatible); 6100cc96f0SAndrew Jones assert(node >= 0 || node == -FDT_ERR_NOTFOUND); 6200cc96f0SAndrew Jones 6300cc96f0SAndrew Jones if (node == -FDT_ERR_NOTFOUND) 6400cc96f0SAndrew Jones return false; 6500cc96f0SAndrew Jones 6600cc96f0SAndrew Jones dt_device_bind_node(&gic, node); 6700cc96f0SAndrew Jones 6800cc96f0SAndrew Jones ret = dt_pbus_translate(&gic, 0, ®); 6900cc96f0SAndrew Jones assert(ret == 0); 7000cc96f0SAndrew Jones *base1 = ioremap(reg.addr, reg.size); 7100cc96f0SAndrew Jones 7200cc96f0SAndrew Jones ret = dt_pbus_translate(&gic, 1, ®); 7300cc96f0SAndrew Jones assert(ret == 0); 7400cc96f0SAndrew Jones *base2 = ioremap(reg.addr, reg.size); 7500cc96f0SAndrew Jones 7600cc96f0SAndrew Jones return true; 7700cc96f0SAndrew Jones } 7800cc96f0SAndrew Jones 7900cc96f0SAndrew Jones int gicv2_init(void) 8000cc96f0SAndrew Jones { 8100cc96f0SAndrew Jones return gic_get_dt_bases("arm,cortex-a15-gic", 8200cc96f0SAndrew Jones &gicv2_data.dist_base, &gicv2_data.cpu_base); 8300cc96f0SAndrew Jones } 8400cc96f0SAndrew Jones 8591a6c3ceSAndrew Jones int gicv3_init(void) 8691a6c3ceSAndrew Jones { 8791a6c3ceSAndrew Jones return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, 8891a6c3ceSAndrew Jones &gicv3_data.redist_base[0]); 8991a6c3ceSAndrew Jones } 9091a6c3ceSAndrew Jones 9100cc96f0SAndrew Jones int gic_init(void) 9200cc96f0SAndrew Jones { 93*2e2d471dSAndrew Jones if (gicv2_init()) { 94*2e2d471dSAndrew Jones gic_common_ops = &gicv2_common_ops; 9500cc96f0SAndrew Jones return 2; 96*2e2d471dSAndrew Jones } else if (gicv3_init()) { 97*2e2d471dSAndrew Jones gic_common_ops = &gicv3_common_ops; 9891a6c3ceSAndrew Jones return 3; 99*2e2d471dSAndrew Jones } 10000cc96f0SAndrew Jones return 0; 10100cc96f0SAndrew Jones } 102*2e2d471dSAndrew Jones 103*2e2d471dSAndrew Jones void gic_enable_defaults(void) 104*2e2d471dSAndrew Jones { 105*2e2d471dSAndrew Jones if (!gic_common_ops) { 106*2e2d471dSAndrew Jones int ret = gic_init(); 107*2e2d471dSAndrew Jones assert(ret != 0); 108*2e2d471dSAndrew Jones } else 109*2e2d471dSAndrew Jones assert(gic_common_ops->enable_defaults); 110*2e2d471dSAndrew Jones gic_common_ops->enable_defaults(); 111*2e2d471dSAndrew Jones } 112*2e2d471dSAndrew Jones 113*2e2d471dSAndrew Jones int gic_version(void) 114*2e2d471dSAndrew Jones { 115*2e2d471dSAndrew Jones assert(gic_common_ops); 116*2e2d471dSAndrew Jones return gic_common_ops->gic_version; 117*2e2d471dSAndrew Jones } 118*2e2d471dSAndrew Jones 119*2e2d471dSAndrew Jones u32 gic_read_iar(void) 120*2e2d471dSAndrew Jones { 121*2e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->read_iar); 122*2e2d471dSAndrew Jones return gic_common_ops->read_iar(); 123*2e2d471dSAndrew Jones } 124*2e2d471dSAndrew Jones 125*2e2d471dSAndrew Jones u32 gic_iar_irqnr(u32 iar) 126*2e2d471dSAndrew Jones { 127*2e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->iar_irqnr); 128*2e2d471dSAndrew Jones return gic_common_ops->iar_irqnr(iar); 129*2e2d471dSAndrew Jones } 130*2e2d471dSAndrew Jones 131*2e2d471dSAndrew Jones void gic_write_eoir(u32 irqstat) 132*2e2d471dSAndrew Jones { 133*2e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->write_eoir); 134*2e2d471dSAndrew Jones gic_common_ops->write_eoir(irqstat); 135*2e2d471dSAndrew Jones } 136*2e2d471dSAndrew Jones 137*2e2d471dSAndrew Jones void gic_ipi_send_single(int irq, int cpu) 138*2e2d471dSAndrew Jones { 139*2e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->ipi_send_single); 140*2e2d471dSAndrew Jones gic_common_ops->ipi_send_single(irq, cpu); 141*2e2d471dSAndrew Jones } 142*2e2d471dSAndrew Jones 143*2e2d471dSAndrew Jones void gic_ipi_send_mask(int irq, const cpumask_t *dest) 144*2e2d471dSAndrew Jones { 145*2e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->ipi_send_mask); 146*2e2d471dSAndrew Jones gic_common_ops->ipi_send_mask(irq, dest); 147*2e2d471dSAndrew Jones } 148