2 * Copyright (c) 2011 The FreeBSD Foundation
3 * Copyright (c) 2014 Andrew Turner
6 * Developed by Damjan Marion <damjan.marion@gmail.com>
8 * Based on OMAP4 GIC code by Ben Gray
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the company nor the name of the author may be used to
19 * endorse or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/kernel.h>
43 #include <sys/module.h>
47 #include <sys/cpuset.h>
49 #include <sys/mutex.h>
51 #include <machine/bus.h>
52 #include <machine/intr.h>
53 #include <machine/smp.h>
58 #include <arm64/arm64/gic.h>
62 /* We are using GICv2 register naming */
64 /* Distributor Registers */
65 #define GICD_CTLR 0x000 /* v1 ICDDCR */
66 #define GICD_TYPER 0x004 /* v1 ICDICTR */
67 #define GICD_IIDR 0x008 /* v1 ICDIIDR */
68 #define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */
69 #define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */
70 #define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */
71 #define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */
72 #define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */
73 #define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */
74 #define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */
75 #define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
76 #define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
77 #define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
80 #define GICC_CTLR 0x0000 /* v1 ICCICR */
81 #define GICC_PMR 0x0004 /* v1 ICCPMR */
82 #define GICC_BPR 0x0008 /* v1 ICCBPR */
83 #define GICC_IAR 0x000C /* v1 ICCIAR */
84 #define GICC_EOIR 0x0010 /* v1 ICCEOIR */
85 #define GICC_RPR 0x0014 /* v1 ICCRPR */
86 #define GICC_HPPIR 0x0018 /* v1 ICCHPIR */
87 #define GICC_ABPR 0x001C /* v1 ICCABPR */
88 #define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
90 #define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
91 #define GIC_LAST_IPI 15
92 #define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
93 #define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
94 #define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
96 /* First bit is a polarity bit (0 - low, 1 - high) */
97 #define GICD_ICFGR_POL_LOW (0 << 0)
98 #define GICD_ICFGR_POL_HIGH (1 << 0)
99 #define GICD_ICFGR_POL_MASK 0x1
100 /* Second bit is a trigger bit (0 - level, 1 - edge) */
101 #define GICD_ICFGR_TRIG_LVL (0 << 1)
102 #define GICD_ICFGR_TRIG_EDGE (1 << 1)
103 #define GICD_ICFGR_TRIG_MASK 0x2
105 static struct resource_spec arm_gic_spec[] = {
106 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */
107 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */
111 static struct arm_gic_softc *arm_gic_sc = NULL;
113 #define gic_c_read_4(_sc, _reg) \
114 bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
115 #define gic_c_write_4(_sc, _reg, _val) \
116 bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
117 #define gic_d_read_4(_sc, _reg) \
118 bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
119 #define gic_d_write_4(_sc, _reg, _val) \
120 bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
122 static pic_dispatch_t gic_dispatch;
123 static pic_eoi_t gic_eoi;
124 static pic_mask_t gic_mask_irq;
125 static pic_unmask_t gic_unmask_irq;
129 gic_init_secondary(device_t dev)
131 struct arm_gic_softc *sc = device_get_softc(dev);
134 for (i = 0; i < sc->nirqs; i += 4)
135 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
137 /* Set all the interrupts to be in Group 0 (secure) */
138 for (i = 0; i < sc->nirqs; i += 32) {
139 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
142 /* Enable CPU interface */
143 gic_c_write_4(sc, GICC_CTLR, 1);
145 /* Set priority mask register. */
146 gic_c_write_4(sc, GICC_PMR, 0xff);
148 /* Enable interrupt distribution */
149 gic_d_write_4(sc, GICD_CTLR, 0x01);
152 * Activate the timer interrupts: virtual, secure, and non-secure.
154 gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
155 gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
156 gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
161 arm_gic_attach(device_t dev)
163 struct arm_gic_softc *sc;
170 sc = device_get_softc(dev);
172 if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
173 device_printf(dev, "could not allocate resources\n");
180 /* Initialize mutex */
181 mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
183 /* Distributor Interface */
184 sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
185 sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
188 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
189 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
191 /* Disable interrupt forwarding to the CPU interface */
192 gic_d_write_4(sc, GICD_CTLR, 0x00);
194 /* Get the number of interrupts */
195 sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
196 sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
198 arm_register_root_pic(dev, sc->nirqs);
200 icciidr = gic_c_read_4(sc, GICC_IIDR);
201 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
202 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
203 (icciidr & 0xfff), sc->nirqs);
205 /* Set all global interrupts to be level triggered, active low. */
206 for (i = 32; i < sc->nirqs; i += 16) {
207 gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000);
210 /* Disable all interrupts. */
211 for (i = 32; i < sc->nirqs; i += 32) {
212 gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
215 for (i = 0; i < sc->nirqs; i += 4) {
216 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
217 gic_d_write_4(sc, GICD_ITARGETSR(i >> 2),
218 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
221 /* Set all the interrupts to be in Group 0 (secure) */
222 for (i = 0; i < sc->nirqs; i += 32) {
223 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
226 /* Enable CPU interface */
227 gic_c_write_4(sc, GICC_CTLR, 1);
229 /* Set priority mask register. */
230 gic_c_write_4(sc, GICC_PMR, 0xff);
232 /* Enable interrupt distribution */
233 gic_d_write_4(sc, GICD_CTLR, 0x01);
238 static void gic_dispatch(device_t dev, struct trapframe *frame)
240 struct arm_gic_softc *sc = device_get_softc(dev);
245 active_irq = gic_c_read_4(sc, GICC_IAR);
248 * Immediatly EOIR the SGIs, because doing so requires the other
249 * bits (ie CPU number), not just the IRQ number, and we do not
250 * have this information later.
253 if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
254 gic_c_write_4(sc, GICC_EOIR, active_irq);
257 if (active_irq == 0x3FF) {
259 printf("Spurious interrupt detected\n");
263 arm_dispatch_intr(active_irq, frame);
269 gic_eoi(device_t dev, u_int irq)
271 struct arm_gic_softc *sc = device_get_softc(dev);
273 gic_c_write_4(sc, GICC_EOIR, irq);
277 gic_mask_irq(device_t dev, u_int irq)
279 struct arm_gic_softc *sc = device_get_softc(dev);
281 gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
282 gic_c_write_4(sc, GICC_EOIR, irq);
286 gic_unmask_irq(device_t dev, u_int irq)
288 struct arm_gic_softc *sc = device_get_softc(dev);
290 gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
295 gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
297 struct arm_gic_softc *sc = device_get_softc(dev);
300 for (i = 0; i < MAXCPU; i++)
301 if (CPU_ISSET(i, &cpus))
302 val |= 1 << (16 + i);
304 gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
308 arm_gic_ipi_read(device_t dev, int i)
313 * The intr code will automagically give the frame pointer
314 * if the interrupt argument is 0.
316 if ((unsigned int)i > 16)
325 arm_gic_ipi_clear(device_t dev, int ipi)
331 static device_method_t arm_gic_methods[] = {
332 /* Device interface */
333 DEVMETHOD(device_attach, arm_gic_attach),
336 DEVMETHOD(pic_dispatch, gic_dispatch),
337 DEVMETHOD(pic_eoi, gic_eoi),
338 DEVMETHOD(pic_mask, gic_mask_irq),
339 DEVMETHOD(pic_unmask, gic_unmask_irq),
342 DEVMETHOD(pic_init_secondary, gic_init_secondary),
343 DEVMETHOD(pic_ipi_send, gic_ipi_send),
349 DEFINE_CLASS_0(gic, arm_gic_driver, arm_gic_methods,
350 sizeof(struct arm_gic_softc));
352 #define GICV2M_MSI_TYPER 0x008
353 #define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff)
354 #define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff)
355 #define GICv2M_MSI_SETSPI_NS 0x040
356 #define GICV2M_MSI_IIDR 0xFCC
358 struct gicv2m_softc {
359 struct resource *sc_mem;
367 gicv2m_probe(device_t dev)
370 device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX");
371 return (BUS_PROBE_DEFAULT);
375 gicv2m_attach(device_t dev)
377 struct gicv2m_softc *sc;
381 sc = device_get_softc(dev);
384 sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
385 if (sc->sc_mem == NULL) {
386 device_printf(dev, "Unable to allocate resources\n");
390 typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER);
391 sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer);
392 sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer);
394 device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start,
395 sc->sc_spi_start + sc->sc_spi_count - 1);
397 mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF);
399 arm_register_msi_pic(dev);
405 gicv2m_alloc_msix(device_t dev, device_t pci_dev, int *pirq)
407 struct arm_gic_softc *psc;
408 struct gicv2m_softc *sc;
412 psc = device_get_softc(device_get_parent(dev));
413 sc = device_get_softc(dev);
415 mtx_lock(&sc->sc_mutex);
416 /* Find an unused interrupt */
417 KASSERT(sc->sc_spi_offset < sc->sc_spi_count, ("No free SPIs"));
419 irq = sc->sc_spi_start + sc->sc_spi_offset;
422 /* Interrupts need to be edge triggered, set this */
423 reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
424 reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
426 gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
429 mtx_unlock(&sc->sc_mutex);
435 gicv2m_alloc_msi(device_t dev, device_t pci_dev, int count, int *irqs)
437 struct arm_gic_softc *psc;
438 struct gicv2m_softc *sc;
442 psc = device_get_softc(device_get_parent(dev));
443 sc = device_get_softc(dev);
445 mtx_lock(&sc->sc_mutex);
446 KASSERT(sc->sc_spi_offset + count <= sc->sc_spi_count,
447 ("No free SPIs for %d MSI interrupts", count));
449 /* Find an unused interrupt */
450 for (i = 0; i < count; i++) {
451 irq = sc->sc_spi_start + sc->sc_spi_offset;
454 /* Interrupts need to be edge triggered, set this */
455 reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
456 reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
458 gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
462 mtx_unlock(&sc->sc_mutex);
468 gicv2m_map_msi(device_t dev, device_t pci_dev, int irq, uint64_t *addr,
471 struct gicv2m_softc *sc = device_get_softc(dev);
473 *addr = vtophys(rman_get_virtual(sc->sc_mem)) + 0x40;
479 static device_method_t arm_gicv2m_methods[] = {
480 /* Device interface */
481 DEVMETHOD(device_probe, gicv2m_probe),
482 DEVMETHOD(device_attach, gicv2m_attach),
485 DEVMETHOD(pic_alloc_msix, gicv2m_alloc_msix),
486 DEVMETHOD(pic_alloc_msi, gicv2m_alloc_msi),
487 DEVMETHOD(pic_map_msi, gicv2m_map_msi),
492 static devclass_t arm_gicv2m_devclass;
494 DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods,
495 sizeof(struct gicv2m_softc));
496 EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver, arm_gicv2m_devclass,
497 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);