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 */
78 #define GICD_SGI_TARGET_SHIFT 16
81 #define GICC_CTLR 0x0000 /* v1 ICCICR */
82 #define GICC_PMR 0x0004 /* v1 ICCPMR */
83 #define GICC_BPR 0x0008 /* v1 ICCBPR */
84 #define GICC_IAR 0x000C /* v1 ICCIAR */
85 #define GICC_EOIR 0x0010 /* v1 ICCEOIR */
86 #define GICC_RPR 0x0014 /* v1 ICCRPR */
87 #define GICC_HPPIR 0x0018 /* v1 ICCHPIR */
88 #define GICC_ABPR 0x001C /* v1 ICCABPR */
89 #define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
91 #define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
92 #define GIC_LAST_IPI 15
93 #define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
94 #define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
95 #define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
97 /* First bit is a polarity bit (0 - low, 1 - high) */
98 #define GICD_ICFGR_POL_LOW (0 << 0)
99 #define GICD_ICFGR_POL_HIGH (1 << 0)
100 #define GICD_ICFGR_POL_MASK 0x1
101 /* Second bit is a trigger bit (0 - level, 1 - edge) */
102 #define GICD_ICFGR_TRIG_LVL (0 << 1)
103 #define GICD_ICFGR_TRIG_EDGE (1 << 1)
104 #define GICD_ICFGR_TRIG_MASK 0x2
106 static struct resource_spec arm_gic_spec[] = {
107 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */
108 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */
112 static u_int arm_gic_map[MAXCPU];
114 static struct arm_gic_softc *arm_gic_sc = NULL;
116 #define gic_c_read_4(_sc, _reg) \
117 bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
118 #define gic_c_write_4(_sc, _reg, _val) \
119 bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
120 #define gic_d_read_4(_sc, _reg) \
121 bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
122 #define gic_d_write_4(_sc, _reg, _val) \
123 bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
125 static pic_dispatch_t gic_dispatch;
126 static pic_eoi_t gic_eoi;
127 static pic_mask_t gic_mask_irq;
128 static pic_unmask_t gic_unmask_irq;
131 gic_cpu_mask(struct arm_gic_softc *sc)
136 /* Read the current cpuid mask by reading ITARGETSR{0..7} */
137 for (i = 0; i < 8; i++) {
138 mask = gic_d_read_4(sc, GICD_ITARGETSR(i));
142 /* No mask found, assume we are on CPU interface 0 */
146 /* Collect the mask in the lower byte */
155 gic_init_secondary(device_t dev)
157 struct arm_gic_softc *sc = device_get_softc(dev);
160 /* Set the mask so we can find this CPU to send it IPIs */
161 arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
163 for (i = 0; i < sc->nirqs; i += 4)
164 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
166 /* Set all the interrupts to be in Group 0 (secure) */
167 for (i = 0; i < sc->nirqs; i += 32) {
168 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
171 /* Enable CPU interface */
172 gic_c_write_4(sc, GICC_CTLR, 1);
174 /* Set priority mask register. */
175 gic_c_write_4(sc, GICC_PMR, 0xff);
177 /* Enable interrupt distribution */
178 gic_d_write_4(sc, GICD_CTLR, 0x01);
181 * Activate the timer interrupts: virtual, secure, and non-secure.
183 gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
184 gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
185 gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
190 arm_gic_attach(device_t dev)
192 struct arm_gic_softc *sc;
194 uint32_t icciidr, mask;
199 sc = device_get_softc(dev);
201 if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
202 device_printf(dev, "could not allocate resources\n");
209 /* Initialize mutex */
210 mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
212 /* Distributor Interface */
213 sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
214 sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
217 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
218 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
220 /* Disable interrupt forwarding to the CPU interface */
221 gic_d_write_4(sc, GICD_CTLR, 0x00);
223 /* Get the number of interrupts */
224 sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
225 sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
227 arm_register_root_pic(dev, sc->nirqs);
229 icciidr = gic_c_read_4(sc, GICC_IIDR);
230 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
231 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
232 (icciidr & 0xfff), sc->nirqs);
234 /* Set all global interrupts to be level triggered, active low. */
235 for (i = 32; i < sc->nirqs; i += 16) {
236 gic_d_write_4(sc, GICD_ICFGR(i >> 4), 0x00000000);
239 /* Disable all interrupts. */
240 for (i = 32; i < sc->nirqs; i += 32) {
241 gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
244 /* Find the current cpu mask */
245 mask = gic_cpu_mask(sc);
246 /* Set the mask so we can find this CPU to send it IPIs */
247 arm_gic_map[PCPU_GET(cpuid)] = mask;
248 /* Set all four targets to this cpu */
252 for (i = 0; i < sc->nirqs; i += 4) {
253 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
255 gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
259 /* Set all the interrupts to be in Group 0 (secure) */
260 for (i = 0; i < sc->nirqs; i += 32) {
261 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
264 /* Enable CPU interface */
265 gic_c_write_4(sc, GICC_CTLR, 1);
267 /* Set priority mask register. */
268 gic_c_write_4(sc, GICC_PMR, 0xff);
270 /* Enable interrupt distribution */
271 gic_d_write_4(sc, GICD_CTLR, 0x01);
276 static void gic_dispatch(device_t dev, struct trapframe *frame)
278 struct arm_gic_softc *sc = device_get_softc(dev);
283 active_irq = gic_c_read_4(sc, GICC_IAR);
286 * Immediatly EOIR the SGIs, because doing so requires the other
287 * bits (ie CPU number), not just the IRQ number, and we do not
288 * have this information later.
291 if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
292 gic_c_write_4(sc, GICC_EOIR, active_irq);
295 if (active_irq == 0x3FF) {
297 printf("Spurious interrupt detected\n");
301 arm_dispatch_intr(active_irq, frame);
307 gic_eoi(device_t dev, u_int irq)
309 struct arm_gic_softc *sc = device_get_softc(dev);
311 gic_c_write_4(sc, GICC_EOIR, irq);
315 gic_mask_irq(device_t dev, u_int irq)
317 struct arm_gic_softc *sc = device_get_softc(dev);
319 gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
320 gic_c_write_4(sc, GICC_EOIR, irq);
324 gic_unmask_irq(device_t dev, u_int irq)
326 struct arm_gic_softc *sc = device_get_softc(dev);
328 gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
333 gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
335 struct arm_gic_softc *sc = device_get_softc(dev);
338 for (i = 0; i < MAXCPU; i++)
339 if (CPU_ISSET(i, &cpus))
340 val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
342 gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
346 static device_method_t arm_gic_methods[] = {
347 /* Device interface */
348 DEVMETHOD(device_attach, arm_gic_attach),
351 DEVMETHOD(pic_dispatch, gic_dispatch),
352 DEVMETHOD(pic_eoi, gic_eoi),
353 DEVMETHOD(pic_mask, gic_mask_irq),
354 DEVMETHOD(pic_unmask, gic_unmask_irq),
357 DEVMETHOD(pic_init_secondary, gic_init_secondary),
358 DEVMETHOD(pic_ipi_send, gic_ipi_send),
364 DEFINE_CLASS_0(gic, arm_gic_driver, arm_gic_methods,
365 sizeof(struct arm_gic_softc));
367 #define GICV2M_MSI_TYPER 0x008
368 #define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff)
369 #define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff)
370 #define GICv2M_MSI_SETSPI_NS 0x040
371 #define GICV2M_MSI_IIDR 0xFCC
374 gicv2m_attach(device_t dev)
376 struct gicv2m_softc *sc;
380 sc = device_get_softc(dev);
383 sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
384 if (sc->sc_mem == NULL) {
385 device_printf(dev, "Unable to allocate resources\n");
389 typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER);
390 sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer);
391 sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer);
393 device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start,
394 sc->sc_spi_start + sc->sc_spi_count - 1);
396 mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF);
398 arm_register_msi_pic(dev);
404 gicv2m_alloc_msix(device_t dev, device_t pci_dev, int *pirq)
406 struct arm_gic_softc *psc;
407 struct gicv2m_softc *sc;
411 psc = device_get_softc(device_get_parent(dev));
412 sc = device_get_softc(dev);
414 mtx_lock(&sc->sc_mutex);
415 /* Find an unused interrupt */
416 KASSERT(sc->sc_spi_offset < sc->sc_spi_count, ("No free SPIs"));
418 irq = sc->sc_spi_start + sc->sc_spi_offset;
421 /* Interrupts need to be edge triggered, set this */
422 reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
423 reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
425 gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
428 mtx_unlock(&sc->sc_mutex);
434 gicv2m_alloc_msi(device_t dev, device_t pci_dev, int count, int *irqs)
436 struct arm_gic_softc *psc;
437 struct gicv2m_softc *sc;
441 psc = device_get_softc(device_get_parent(dev));
442 sc = device_get_softc(dev);
444 mtx_lock(&sc->sc_mutex);
445 KASSERT(sc->sc_spi_offset + count <= sc->sc_spi_count,
446 ("No free SPIs for %d MSI interrupts", count));
448 /* Find an unused interrupt */
449 for (i = 0; i < count; i++) {
450 irq = sc->sc_spi_start + sc->sc_spi_offset;
453 /* Interrupts need to be edge triggered, set this */
454 reg = gic_d_read_4(psc, GICD_ICFGR(irq >> 4));
455 reg |= (GICD_ICFGR_TRIG_EDGE | GICD_ICFGR_POL_HIGH) <<
457 gic_d_write_4(psc, GICD_ICFGR(irq >> 4), reg);
461 mtx_unlock(&sc->sc_mutex);
467 gicv2m_map_msi(device_t dev, device_t pci_dev, int irq, uint64_t *addr,
470 struct gicv2m_softc *sc = device_get_softc(dev);
472 *addr = vtophys(rman_get_virtual(sc->sc_mem)) + 0x40;
478 static device_method_t arm_gicv2m_methods[] = {
479 /* Device interface */
480 DEVMETHOD(device_attach, gicv2m_attach),
483 DEVMETHOD(pic_alloc_msix, gicv2m_alloc_msix),
484 DEVMETHOD(pic_alloc_msi, gicv2m_alloc_msi),
485 DEVMETHOD(pic_map_msi, gicv2m_map_msi),
490 DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods,
491 sizeof(struct gicv2m_softc));