xref: /kvm-unit-tests/lib/arm/gic.c (revision 00cc96f0d25b6c110fda00bc03bfb428be186590)
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 
12 /*
13  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
14  */
15 static bool
16 gic_get_dt_bases(const char *compatible, void **base1, void **base2)
17 {
18 	struct dt_pbus_reg reg;
19 	struct dt_device gic;
20 	struct dt_bus bus;
21 	int node, ret;
22 
23 	dt_bus_init_defaults(&bus);
24 	dt_device_init(&gic, &bus, NULL);
25 
26 	node = dt_device_find_compatible(&gic, compatible);
27 	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
28 
29 	if (node == -FDT_ERR_NOTFOUND)
30 		return false;
31 
32 	dt_device_bind_node(&gic, node);
33 
34 	ret = dt_pbus_translate(&gic, 0, &reg);
35 	assert(ret == 0);
36 	*base1 = ioremap(reg.addr, reg.size);
37 
38 	ret = dt_pbus_translate(&gic, 1, &reg);
39 	assert(ret == 0);
40 	*base2 = ioremap(reg.addr, reg.size);
41 
42 	return true;
43 }
44 
45 int gicv2_init(void)
46 {
47 	return gic_get_dt_bases("arm,cortex-a15-gic",
48 			&gicv2_data.dist_base, &gicv2_data.cpu_base);
49 }
50 
51 int gic_init(void)
52 {
53 	if (gicv2_init())
54 		return 2;
55 	return 0;
56 }
57 
58 void gicv2_enable_defaults(void)
59 {
60 	void *dist = gicv2_dist_base();
61 	void *cpu_base = gicv2_cpu_base();
62 	unsigned int i;
63 
64 	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
65 	if (gicv2_data.irq_nr > 1020)
66 		gicv2_data.irq_nr = 1020;
67 
68 	for (i = 0; i < gicv2_data.irq_nr; i += 4)
69 		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
70 
71 	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
72 	writel(GICD_ENABLE, dist + GICD_CTLR);
73 
74 	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
75 	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
76 }
77