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, i; 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 for (i = 0; i < GICV3_NR_REDISTS; ++i) { 70 ret = dt_pbus_translate(&gic, i + 1, ®); 71 if (ret == -FDT_ERR_NOTFOUND) 72 break; 73 assert(ret == 0); 74 base2[i] = ioremap(reg.addr, reg.size); 75 } 76 77 return true; 78 } 79 80 int gicv2_init(void) 81 { 82 return gic_get_dt_bases("arm,cortex-a15-gic", 83 &gicv2_data.dist_base, &gicv2_data.cpu_base); 84 } 85 86 int gicv3_init(void) 87 { 88 return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, 89 &gicv3_data.redist_bases[0]); 90 } 91 92 int gic_version(void) 93 { 94 if (gic_common_ops == &gicv2_common_ops) 95 return 2; 96 else if (gic_common_ops == &gicv3_common_ops) 97 return 3; 98 return 0; 99 } 100 101 int gic_init(void) 102 { 103 if (gicv2_init()) 104 gic_common_ops = &gicv2_common_ops; 105 else if (gicv3_init()) 106 gic_common_ops = &gicv3_common_ops; 107 return gic_version(); 108 } 109 110 void gic_enable_defaults(void) 111 { 112 if (!gic_common_ops) { 113 int ret = gic_init(); 114 assert(ret != 0); 115 } else 116 assert(gic_common_ops->enable_defaults); 117 gic_common_ops->enable_defaults(); 118 } 119 120 u32 gic_read_iar(void) 121 { 122 assert(gic_common_ops && gic_common_ops->read_iar); 123 return gic_common_ops->read_iar(); 124 } 125 126 u32 gic_iar_irqnr(u32 iar) 127 { 128 assert(gic_common_ops && gic_common_ops->iar_irqnr); 129 return gic_common_ops->iar_irqnr(iar); 130 } 131 132 void gic_write_eoir(u32 irqstat) 133 { 134 assert(gic_common_ops && gic_common_ops->write_eoir); 135 gic_common_ops->write_eoir(irqstat); 136 } 137 138 void gic_ipi_send_single(int irq, int cpu) 139 { 140 assert(gic_common_ops && gic_common_ops->ipi_send_single); 141 gic_common_ops->ipi_send_single(irq, cpu); 142 } 143 144 void gic_ipi_send_mask(int irq, const cpumask_t *dest) 145 { 146 assert(gic_common_ops && gic_common_ops->ipi_send_mask); 147 gic_common_ops->ipi_send_mask(irq, dest); 148 } 149 150 enum gic_irq_state gic_irq_state(int irq) 151 { 152 enum gic_irq_state state; 153 void *ispendr, *isactiver; 154 bool pending, active; 155 int offset, mask; 156 157 assert(gic_common_ops); 158 assert(irq < 1020); 159 160 switch (gic_version()) { 161 case 2: 162 ispendr = gicv2_dist_base() + GICD_ISPENDR; 163 isactiver = gicv2_dist_base() + GICD_ISACTIVER; 164 break; 165 case 3: 166 if (irq < GIC_NR_PRIVATE_IRQS) { 167 ispendr = gicv3_sgi_base() + GICR_ISPENDR0; 168 isactiver = gicv3_sgi_base() + GICR_ISACTIVER0; 169 } else { 170 ispendr = gicv3_dist_base() + GICD_ISPENDR; 171 isactiver = gicv3_dist_base() + GICD_ISACTIVER; 172 } 173 break; 174 default: 175 assert(0); 176 } 177 178 offset = irq / 32 * 4; 179 mask = 1 << (irq % 32); 180 pending = readl(ispendr + offset) & mask; 181 active = readl(isactiver + offset) & mask; 182 183 if (!active && !pending) 184 state = GIC_IRQ_STATE_INACTIVE; 185 if (pending) 186 state = GIC_IRQ_STATE_PENDING; 187 if (active) 188 state = GIC_IRQ_STATE_ACTIVE; 189 if (active && pending) 190 state = GIC_IRQ_STATE_ACTIVE_PENDING; 191 192 return state; 193 } 194