xref: /kvm-unit-tests/lib/arm/gic.c (revision db198544ab60bf79562191295aff2171499c9e85)
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, &reg);
6600cc96f0SAndrew Jones 	assert(ret == 0);
6700cc96f0SAndrew Jones 	*base1 = ioremap(reg.addr, reg.size);
6800cc96f0SAndrew Jones 
6900cc96f0SAndrew Jones 	ret = dt_pbus_translate(&gic, 1, &reg);
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