1 /* 2 * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> 3 * 4 * This work is licensed under the terms of the GNU LGPL, version 2. 5 */ 6 #include <devicetree.h> 7 #include <asm/gic.h> 8 #include <asm/io.h> 9 10 struct gicv2_data gicv2_data; 11 struct gicv3_data gicv3_data; 12 13 struct gic_common_ops { 14 void (*enable_defaults)(void); 15 u32 (*read_iar)(void); 16 u32 (*iar_irqnr)(u32 iar); 17 void (*write_eoir)(u32 irqstat); 18 void (*ipi_send_single)(int irq, int cpu); 19 void (*ipi_send_mask)(int irq, const cpumask_t *dest); 20 }; 21 22 static const struct gic_common_ops *gic_common_ops; 23 24 static const struct gic_common_ops gicv2_common_ops = { 25 .enable_defaults = gicv2_enable_defaults, 26 .read_iar = gicv2_read_iar, 27 .iar_irqnr = gicv2_iar_irqnr, 28 .write_eoir = gicv2_write_eoir, 29 .ipi_send_single = gicv2_ipi_send_single, 30 .ipi_send_mask = gicv2_ipi_send_mask, 31 }; 32 33 static const struct gic_common_ops gicv3_common_ops = { 34 .enable_defaults = gicv3_enable_defaults, 35 .read_iar = gicv3_read_iar, 36 .iar_irqnr = gicv3_iar_irqnr, 37 .write_eoir = gicv3_write_eoir, 38 .ipi_send_single = gicv3_ipi_send_single, 39 .ipi_send_mask = gicv3_ipi_send_mask, 40 }; 41 42 /* 43 * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt 44 * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt 45 */ 46 static bool 47 gic_get_dt_bases(const char *compatible, void **base1, void **base2) 48 { 49 struct dt_pbus_reg reg; 50 struct dt_device gic; 51 struct dt_bus bus; 52 int node, ret; 53 54 dt_bus_init_defaults(&bus); 55 dt_device_init(&gic, &bus, NULL); 56 57 node = dt_device_find_compatible(&gic, compatible); 58 assert(node >= 0 || node == -FDT_ERR_NOTFOUND); 59 60 if (node == -FDT_ERR_NOTFOUND) 61 return false; 62 63 dt_device_bind_node(&gic, node); 64 65 ret = dt_pbus_translate(&gic, 0, ®); 66 assert(ret == 0); 67 *base1 = ioremap(reg.addr, reg.size); 68 69 ret = dt_pbus_translate(&gic, 1, ®); 70 assert(ret == 0); 71 *base2 = ioremap(reg.addr, reg.size); 72 73 return true; 74 } 75 76 int gicv2_init(void) 77 { 78 return gic_get_dt_bases("arm,cortex-a15-gic", 79 &gicv2_data.dist_base, &gicv2_data.cpu_base); 80 } 81 82 int gicv3_init(void) 83 { 84 return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, 85 &gicv3_data.redist_base[0]); 86 } 87 88 int gic_version(void) 89 { 90 if (gic_common_ops == &gicv2_common_ops) 91 return 2; 92 else if (gic_common_ops == &gicv3_common_ops) 93 return 3; 94 return 0; 95 } 96 97 int gic_init(void) 98 { 99 if (gicv2_init()) 100 gic_common_ops = &gicv2_common_ops; 101 else if (gicv3_init()) 102 gic_common_ops = &gicv3_common_ops; 103 return gic_version(); 104 } 105 106 void gic_enable_defaults(void) 107 { 108 if (!gic_common_ops) { 109 int ret = gic_init(); 110 assert(ret != 0); 111 } else 112 assert(gic_common_ops->enable_defaults); 113 gic_common_ops->enable_defaults(); 114 } 115 116 u32 gic_read_iar(void) 117 { 118 assert(gic_common_ops && gic_common_ops->read_iar); 119 return gic_common_ops->read_iar(); 120 } 121 122 u32 gic_iar_irqnr(u32 iar) 123 { 124 assert(gic_common_ops && gic_common_ops->iar_irqnr); 125 return gic_common_ops->iar_irqnr(iar); 126 } 127 128 void gic_write_eoir(u32 irqstat) 129 { 130 assert(gic_common_ops && gic_common_ops->write_eoir); 131 gic_common_ops->write_eoir(irqstat); 132 } 133 134 void gic_ipi_send_single(int irq, int cpu) 135 { 136 assert(gic_common_ops && gic_common_ops->ipi_send_single); 137 gic_common_ops->ipi_send_single(irq, cpu); 138 } 139 140 void gic_ipi_send_mask(int irq, const cpumask_t *dest) 141 { 142 assert(gic_common_ops && gic_common_ops->ipi_send_mask); 143 gic_common_ops->ipi_send_mask(irq, dest); 144 } 145