xref: /kvm-unit-tests/lib/arm/gic.c (revision 2e2d471d2aeb249869b525a42dcf22659d6c4bc7)
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 
13*2e2d471dSAndrew Jones struct gic_common_ops {
14*2e2d471dSAndrew Jones 	int gic_version;
15*2e2d471dSAndrew Jones 	void (*enable_defaults)(void);
16*2e2d471dSAndrew Jones 	u32 (*read_iar)(void);
17*2e2d471dSAndrew Jones 	u32 (*iar_irqnr)(u32 iar);
18*2e2d471dSAndrew Jones 	void (*write_eoir)(u32 irqstat);
19*2e2d471dSAndrew Jones 	void (*ipi_send_single)(int irq, int cpu);
20*2e2d471dSAndrew Jones 	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
21*2e2d471dSAndrew Jones };
22*2e2d471dSAndrew Jones 
23*2e2d471dSAndrew Jones static const struct gic_common_ops *gic_common_ops;
24*2e2d471dSAndrew Jones 
25*2e2d471dSAndrew Jones static const struct gic_common_ops gicv2_common_ops = {
26*2e2d471dSAndrew Jones 	.gic_version = 2,
27*2e2d471dSAndrew Jones 	.enable_defaults = gicv2_enable_defaults,
28*2e2d471dSAndrew Jones 	.read_iar = gicv2_read_iar,
29*2e2d471dSAndrew Jones 	.iar_irqnr = gicv2_iar_irqnr,
30*2e2d471dSAndrew Jones 	.write_eoir = gicv2_write_eoir,
31*2e2d471dSAndrew Jones 	.ipi_send_single = gicv2_ipi_send_single,
32*2e2d471dSAndrew Jones 	.ipi_send_mask = gicv2_ipi_send_mask,
33*2e2d471dSAndrew Jones };
34*2e2d471dSAndrew Jones 
35*2e2d471dSAndrew Jones static const struct gic_common_ops gicv3_common_ops = {
36*2e2d471dSAndrew Jones 	.gic_version = 3,
37*2e2d471dSAndrew Jones 	.enable_defaults = gicv3_enable_defaults,
38*2e2d471dSAndrew Jones 	.read_iar = gicv3_read_iar,
39*2e2d471dSAndrew Jones 	.iar_irqnr = gicv3_iar_irqnr,
40*2e2d471dSAndrew Jones 	.write_eoir = gicv3_write_eoir,
41*2e2d471dSAndrew Jones 	.ipi_send_single = gicv3_ipi_send_single,
42*2e2d471dSAndrew Jones 	.ipi_send_mask = gicv3_ipi_send_mask,
43*2e2d471dSAndrew Jones };
44*2e2d471dSAndrew Jones 
4500cc96f0SAndrew Jones /*
4600cc96f0SAndrew Jones  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
4791a6c3ceSAndrew Jones  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
4800cc96f0SAndrew Jones  */
4900cc96f0SAndrew Jones static bool
5000cc96f0SAndrew Jones gic_get_dt_bases(const char *compatible, void **base1, void **base2)
5100cc96f0SAndrew Jones {
5200cc96f0SAndrew Jones 	struct dt_pbus_reg reg;
5300cc96f0SAndrew Jones 	struct dt_device gic;
5400cc96f0SAndrew Jones 	struct dt_bus bus;
5500cc96f0SAndrew Jones 	int node, ret;
5600cc96f0SAndrew Jones 
5700cc96f0SAndrew Jones 	dt_bus_init_defaults(&bus);
5800cc96f0SAndrew Jones 	dt_device_init(&gic, &bus, NULL);
5900cc96f0SAndrew Jones 
6000cc96f0SAndrew Jones 	node = dt_device_find_compatible(&gic, compatible);
6100cc96f0SAndrew Jones 	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
6200cc96f0SAndrew Jones 
6300cc96f0SAndrew Jones 	if (node == -FDT_ERR_NOTFOUND)
6400cc96f0SAndrew Jones 		return false;
6500cc96f0SAndrew Jones 
6600cc96f0SAndrew Jones 	dt_device_bind_node(&gic, node);
6700cc96f0SAndrew Jones 
6800cc96f0SAndrew Jones 	ret = dt_pbus_translate(&gic, 0, &reg);
6900cc96f0SAndrew Jones 	assert(ret == 0);
7000cc96f0SAndrew Jones 	*base1 = ioremap(reg.addr, reg.size);
7100cc96f0SAndrew Jones 
7200cc96f0SAndrew Jones 	ret = dt_pbus_translate(&gic, 1, &reg);
7300cc96f0SAndrew Jones 	assert(ret == 0);
7400cc96f0SAndrew Jones 	*base2 = ioremap(reg.addr, reg.size);
7500cc96f0SAndrew Jones 
7600cc96f0SAndrew Jones 	return true;
7700cc96f0SAndrew Jones }
7800cc96f0SAndrew Jones 
7900cc96f0SAndrew Jones int gicv2_init(void)
8000cc96f0SAndrew Jones {
8100cc96f0SAndrew Jones 	return gic_get_dt_bases("arm,cortex-a15-gic",
8200cc96f0SAndrew Jones 			&gicv2_data.dist_base, &gicv2_data.cpu_base);
8300cc96f0SAndrew Jones }
8400cc96f0SAndrew Jones 
8591a6c3ceSAndrew Jones int gicv3_init(void)
8691a6c3ceSAndrew Jones {
8791a6c3ceSAndrew Jones 	return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
8891a6c3ceSAndrew Jones 			&gicv3_data.redist_base[0]);
8991a6c3ceSAndrew Jones }
9091a6c3ceSAndrew Jones 
9100cc96f0SAndrew Jones int gic_init(void)
9200cc96f0SAndrew Jones {
93*2e2d471dSAndrew Jones 	if (gicv2_init()) {
94*2e2d471dSAndrew Jones 		gic_common_ops = &gicv2_common_ops;
9500cc96f0SAndrew Jones 		return 2;
96*2e2d471dSAndrew Jones 	} else if (gicv3_init()) {
97*2e2d471dSAndrew Jones 		gic_common_ops = &gicv3_common_ops;
9891a6c3ceSAndrew Jones 		return 3;
99*2e2d471dSAndrew Jones 	}
10000cc96f0SAndrew Jones 	return 0;
10100cc96f0SAndrew Jones }
102*2e2d471dSAndrew Jones 
103*2e2d471dSAndrew Jones void gic_enable_defaults(void)
104*2e2d471dSAndrew Jones {
105*2e2d471dSAndrew Jones 	if (!gic_common_ops) {
106*2e2d471dSAndrew Jones 		int ret = gic_init();
107*2e2d471dSAndrew Jones 		assert(ret != 0);
108*2e2d471dSAndrew Jones 	} else
109*2e2d471dSAndrew Jones 		assert(gic_common_ops->enable_defaults);
110*2e2d471dSAndrew Jones 	gic_common_ops->enable_defaults();
111*2e2d471dSAndrew Jones }
112*2e2d471dSAndrew Jones 
113*2e2d471dSAndrew Jones int gic_version(void)
114*2e2d471dSAndrew Jones {
115*2e2d471dSAndrew Jones 	assert(gic_common_ops);
116*2e2d471dSAndrew Jones 	return gic_common_ops->gic_version;
117*2e2d471dSAndrew Jones }
118*2e2d471dSAndrew Jones 
119*2e2d471dSAndrew Jones u32 gic_read_iar(void)
120*2e2d471dSAndrew Jones {
121*2e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->read_iar);
122*2e2d471dSAndrew Jones 	return gic_common_ops->read_iar();
123*2e2d471dSAndrew Jones }
124*2e2d471dSAndrew Jones 
125*2e2d471dSAndrew Jones u32 gic_iar_irqnr(u32 iar)
126*2e2d471dSAndrew Jones {
127*2e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->iar_irqnr);
128*2e2d471dSAndrew Jones 	return gic_common_ops->iar_irqnr(iar);
129*2e2d471dSAndrew Jones }
130*2e2d471dSAndrew Jones 
131*2e2d471dSAndrew Jones void gic_write_eoir(u32 irqstat)
132*2e2d471dSAndrew Jones {
133*2e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->write_eoir);
134*2e2d471dSAndrew Jones 	gic_common_ops->write_eoir(irqstat);
135*2e2d471dSAndrew Jones }
136*2e2d471dSAndrew Jones 
137*2e2d471dSAndrew Jones void gic_ipi_send_single(int irq, int cpu)
138*2e2d471dSAndrew Jones {
139*2e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->ipi_send_single);
140*2e2d471dSAndrew Jones 	gic_common_ops->ipi_send_single(irq, cpu);
141*2e2d471dSAndrew Jones }
142*2e2d471dSAndrew Jones 
143*2e2d471dSAndrew Jones void gic_ipi_send_mask(int irq, const cpumask_t *dest)
144*2e2d471dSAndrew Jones {
145*2e2d471dSAndrew Jones 	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
146*2e2d471dSAndrew Jones 	gic_common_ops->ipi_send_mask(irq, dest);
147*2e2d471dSAndrew Jones }
148