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