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 132e2d471dSAndrew Jones struct gic_common_ops { 142e2d471dSAndrew Jones void (*enable_defaults)(void); 152e2d471dSAndrew Jones u32 (*read_iar)(void); 162e2d471dSAndrew Jones u32 (*iar_irqnr)(u32 iar); 172e2d471dSAndrew Jones void (*write_eoir)(u32 irqstat); 182e2d471dSAndrew Jones void (*ipi_send_single)(int irq, int cpu); 192e2d471dSAndrew Jones void (*ipi_send_mask)(int irq, const cpumask_t *dest); 202e2d471dSAndrew Jones }; 212e2d471dSAndrew Jones 222e2d471dSAndrew Jones static const struct gic_common_ops *gic_common_ops; 232e2d471dSAndrew Jones 242e2d471dSAndrew Jones static const struct gic_common_ops gicv2_common_ops = { 252e2d471dSAndrew Jones .enable_defaults = gicv2_enable_defaults, 262e2d471dSAndrew Jones .read_iar = gicv2_read_iar, 272e2d471dSAndrew Jones .iar_irqnr = gicv2_iar_irqnr, 282e2d471dSAndrew Jones .write_eoir = gicv2_write_eoir, 292e2d471dSAndrew Jones .ipi_send_single = gicv2_ipi_send_single, 302e2d471dSAndrew Jones .ipi_send_mask = gicv2_ipi_send_mask, 312e2d471dSAndrew Jones }; 322e2d471dSAndrew Jones 332e2d471dSAndrew Jones static const struct gic_common_ops gicv3_common_ops = { 342e2d471dSAndrew Jones .enable_defaults = gicv3_enable_defaults, 352e2d471dSAndrew Jones .read_iar = gicv3_read_iar, 362e2d471dSAndrew Jones .iar_irqnr = gicv3_iar_irqnr, 372e2d471dSAndrew Jones .write_eoir = gicv3_write_eoir, 382e2d471dSAndrew Jones .ipi_send_single = gicv3_ipi_send_single, 392e2d471dSAndrew Jones .ipi_send_mask = gicv3_ipi_send_mask, 402e2d471dSAndrew Jones }; 412e2d471dSAndrew Jones 4200cc96f0SAndrew Jones /* 4300cc96f0SAndrew Jones * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt 4491a6c3ceSAndrew Jones * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt 4500cc96f0SAndrew Jones */ 4600cc96f0SAndrew Jones static bool 4700cc96f0SAndrew Jones gic_get_dt_bases(const char *compatible, void **base1, void **base2) 4800cc96f0SAndrew Jones { 4900cc96f0SAndrew Jones struct dt_pbus_reg reg; 5000cc96f0SAndrew Jones struct dt_device gic; 5100cc96f0SAndrew Jones struct dt_bus bus; 5200cc96f0SAndrew Jones int node, ret; 5300cc96f0SAndrew Jones 5400cc96f0SAndrew Jones dt_bus_init_defaults(&bus); 5500cc96f0SAndrew Jones dt_device_init(&gic, &bus, NULL); 5600cc96f0SAndrew Jones 5700cc96f0SAndrew Jones node = dt_device_find_compatible(&gic, compatible); 5800cc96f0SAndrew Jones assert(node >= 0 || node == -FDT_ERR_NOTFOUND); 5900cc96f0SAndrew Jones 6000cc96f0SAndrew Jones if (node == -FDT_ERR_NOTFOUND) 6100cc96f0SAndrew Jones return false; 6200cc96f0SAndrew Jones 6300cc96f0SAndrew Jones dt_device_bind_node(&gic, node); 6400cc96f0SAndrew Jones 6500cc96f0SAndrew Jones ret = dt_pbus_translate(&gic, 0, ®); 6600cc96f0SAndrew Jones assert(ret == 0); 6700cc96f0SAndrew Jones *base1 = ioremap(reg.addr, reg.size); 6800cc96f0SAndrew Jones 6900cc96f0SAndrew Jones ret = dt_pbus_translate(&gic, 1, ®); 7000cc96f0SAndrew Jones assert(ret == 0); 7100cc96f0SAndrew Jones *base2 = ioremap(reg.addr, reg.size); 7200cc96f0SAndrew Jones 7300cc96f0SAndrew Jones return true; 7400cc96f0SAndrew Jones } 7500cc96f0SAndrew Jones 7600cc96f0SAndrew Jones int gicv2_init(void) 7700cc96f0SAndrew Jones { 7800cc96f0SAndrew Jones return gic_get_dt_bases("arm,cortex-a15-gic", 7900cc96f0SAndrew Jones &gicv2_data.dist_base, &gicv2_data.cpu_base); 8000cc96f0SAndrew Jones } 8100cc96f0SAndrew Jones 8291a6c3ceSAndrew Jones int gicv3_init(void) 8391a6c3ceSAndrew Jones { 8491a6c3ceSAndrew Jones return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, 8591a6c3ceSAndrew Jones &gicv3_data.redist_base[0]); 8691a6c3ceSAndrew Jones } 8791a6c3ceSAndrew Jones 88*db198544SAndrew Jones int gic_version(void) 89*db198544SAndrew Jones { 90*db198544SAndrew Jones if (gic_common_ops == &gicv2_common_ops) 91*db198544SAndrew Jones return 2; 92*db198544SAndrew Jones else if (gic_common_ops == &gicv3_common_ops) 93*db198544SAndrew Jones return 3; 94*db198544SAndrew Jones return 0; 95*db198544SAndrew Jones } 96*db198544SAndrew Jones 9700cc96f0SAndrew Jones int gic_init(void) 9800cc96f0SAndrew Jones { 99*db198544SAndrew Jones if (gicv2_init()) 1002e2d471dSAndrew Jones gic_common_ops = &gicv2_common_ops; 101*db198544SAndrew Jones else if (gicv3_init()) 1022e2d471dSAndrew Jones gic_common_ops = &gicv3_common_ops; 103*db198544SAndrew Jones return gic_version(); 10400cc96f0SAndrew Jones } 1052e2d471dSAndrew Jones 1062e2d471dSAndrew Jones void gic_enable_defaults(void) 1072e2d471dSAndrew Jones { 1082e2d471dSAndrew Jones if (!gic_common_ops) { 1092e2d471dSAndrew Jones int ret = gic_init(); 1102e2d471dSAndrew Jones assert(ret != 0); 1112e2d471dSAndrew Jones } else 1122e2d471dSAndrew Jones assert(gic_common_ops->enable_defaults); 1132e2d471dSAndrew Jones gic_common_ops->enable_defaults(); 1142e2d471dSAndrew Jones } 1152e2d471dSAndrew Jones 1162e2d471dSAndrew Jones u32 gic_read_iar(void) 1172e2d471dSAndrew Jones { 1182e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->read_iar); 1192e2d471dSAndrew Jones return gic_common_ops->read_iar(); 1202e2d471dSAndrew Jones } 1212e2d471dSAndrew Jones 1222e2d471dSAndrew Jones u32 gic_iar_irqnr(u32 iar) 1232e2d471dSAndrew Jones { 1242e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->iar_irqnr); 1252e2d471dSAndrew Jones return gic_common_ops->iar_irqnr(iar); 1262e2d471dSAndrew Jones } 1272e2d471dSAndrew Jones 1282e2d471dSAndrew Jones void gic_write_eoir(u32 irqstat) 1292e2d471dSAndrew Jones { 1302e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->write_eoir); 1312e2d471dSAndrew Jones gic_common_ops->write_eoir(irqstat); 1322e2d471dSAndrew Jones } 1332e2d471dSAndrew Jones 1342e2d471dSAndrew Jones void gic_ipi_send_single(int irq, int cpu) 1352e2d471dSAndrew Jones { 1362e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->ipi_send_single); 1372e2d471dSAndrew Jones gic_common_ops->ipi_send_single(irq, cpu); 1382e2d471dSAndrew Jones } 1392e2d471dSAndrew Jones 1402e2d471dSAndrew Jones void gic_ipi_send_mask(int irq, const cpumask_t *dest) 1412e2d471dSAndrew Jones { 1422e2d471dSAndrew Jones assert(gic_common_ops && gic_common_ops->ipi_send_mask); 1432e2d471dSAndrew Jones gic_common_ops->ipi_send_mask(irq, dest); 1442e2d471dSAndrew Jones } 145