Adda new common GIC header to handle the common parts of the GICv2 and

GICv3 drivers. For now it just contains common distributor registers.

Obtained from:	ABT Systems Ltd
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Andrew Turner 2016-12-06 12:57:28 +00:00
parent 3cbaf64f2e
commit 4d7d72fb23
2 changed files with 102 additions and 47 deletions

View file

@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <arm/arm/gic.h>
#include <arm/arm/gic_common.h>
#ifdef INTRNG
#include "pic_if.h"
@ -76,20 +77,6 @@ __FBSDID("$FreeBSD$");
/* We are using GICv2 register naming */
/* Distributor Registers */
#define GICD_CTLR 0x000 /* v1 ICDDCR */
#define GICD_TYPER 0x004 /* v1 ICDICTR */
#define GICD_IIDR 0x008 /* v1 ICDIIDR */
#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */
#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */
#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */
#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */
#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */
#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */
#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */
#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */
#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */
#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */
#define GICD_SGI_TARGET_SHIFT 16
/* CPU Registers */
#define GICC_CTLR 0x0000 /* v1 ICCICR */
@ -107,14 +94,6 @@ __FBSDID("$FreeBSD$");
#define GIC_SUPPORT_SECEXT(_sc) \
((_sc->typer & GICD_TYPER_SECURITYEXT) == GICD_TYPER_SECURITYEXT)
/* First bit is a polarity bit (0 - low, 1 - high) */
#define GICD_ICFGR_POL_LOW (0 << 0)
#define GICD_ICFGR_POL_HIGH (1 << 0)
#define GICD_ICFGR_POL_MASK 0x1
/* Second bit is a trigger bit (0 - level, 1 - edge) */
#define GICD_ICFGR_TRIG_LVL (0 << 1)
#define GICD_ICFGR_TRIG_EDGE (1 << 1)
#define GICD_ICFGR_TRIG_MASK 0x2
#ifndef GIC_DEFAULT_ICFGR_INIT
#define GIC_DEFAULT_ICFGR_INIT 0x00000000
@ -192,14 +171,14 @@ static inline void
gic_irq_unmask(struct arm_gic_softc *sc, u_int irq)
{
gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(irq), (1UL << (irq & 0x1F)));
}
static inline void
gic_irq_mask(struct arm_gic_softc *sc, u_int irq)
{
gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
gic_d_write_4(sc, GICD_ICENABLER(irq), (1UL << (irq & 0x1F)));
}
#endif
@ -239,11 +218,11 @@ arm_gic_init_secondary(device_t dev)
arm_gic_map[cpu] = gic_cpu_mask(sc);
for (irq = 0; irq < sc->nirqs; irq += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0);
gic_d_write_4(sc, GICD_IPRIORITYR(irq), 0);
/* Set all the interrupts to be in Group 0 (secure) */
for (irq = 0; GIC_SUPPORT_SECEXT(sc) && irq < sc->nirqs; irq += 32) {
gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0);
gic_d_write_4(sc, GICD_IGROUPR(irq), 0);
}
/* Enable CPU interface */
@ -276,11 +255,11 @@ arm_gic_init_secondary(device_t dev)
arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
for (i = 0; i < sc->nirqs; i += 4)
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
gic_d_write_4(sc, GICD_IPRIORITYR(i), 0);
/* Set all the interrupts to be in Group 0 (secure) */
for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
gic_d_write_4(sc, GICD_IGROUPR(i), 0);
}
/* Enable CPU interface */
@ -295,9 +274,9 @@ arm_gic_init_secondary(device_t dev)
/*
* Activate the timer interrupts: virtual, secure, and non-secure.
*/
gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(27), (1UL << (27 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(29), (1UL << (29 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(30), (1UL << (30 & 0x1F)));
}
#endif /* INTRNG */
#endif /* SMP */
@ -484,18 +463,19 @@ arm_gic_attach(device_t dev)
#endif
icciidr = gic_c_read_4(sc, GICC_IIDR);
device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
(icciidr & 0xfff), sc->nirqs);
device_printf(dev,
"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
GICD_IIDR_PROD(icciidr), GICD_IIDR_VAR(icciidr),
GICD_IIDR_REV(icciidr), GICD_IIDR_IMPL(icciidr), sc->nirqs);
/* Set all global interrupts to be level triggered, active low. */
for (i = 32; i < sc->nirqs; i += 16) {
gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT);
gic_d_write_4(sc, GICD_ICFGR(i), GIC_DEFAULT_ICFGR_INIT);
}
/* Disable all interrupts. */
for (i = 32; i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
gic_d_write_4(sc, GICD_ICENABLER(i), 0xFFFFFFFF);
}
/* Find the current cpu mask */
@ -507,15 +487,15 @@ arm_gic_attach(device_t dev)
mask |= mask << 16;
for (i = 0; i < sc->nirqs; i += 4) {
gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
gic_d_write_4(sc, GICD_IPRIORITYR(i), 0);
if (i > 32) {
gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
gic_d_write_4(sc, GICD_ITARGETSR(i), mask);
}
}
/* Set all the interrupts to be in Group 0 (secure) */
for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
gic_d_write_4(sc, GICD_IGROUPR(i), 0);
}
/* Enable CPU interface */
@ -725,7 +705,7 @@ gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig,
mtx_lock_spin(&sc->mutex);
reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
reg = gic_d_read_4(sc, GICD_ICFGR(irq));
mask = (reg >> 2*(irq % 16)) & 0x3;
if (pol == INTR_POLARITY_LOW) {
@ -747,7 +727,7 @@ gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig,
/* Set mask */
reg = reg & ~(0x3 << 2*(irq % 16));
reg = reg | (mask << 2*(irq % 16));
gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
gic_d_write_4(sc, GICD_ICFGR(irq), reg);
mtx_unlock_spin(&sc->mutex);
}
@ -1089,7 +1069,7 @@ arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
if (CPU_ISSET(i, &cpus))
val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq);
gic_d_write_4(sc, GICD_SGIR, val | gi->gi_irq);
}
static int
@ -1157,7 +1137,7 @@ arm_gic_config(device_t dev, int irq, enum intr_trigger trig,
mtx_lock_spin(&sc->mutex);
reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
reg = gic_d_read_4(sc, GICD_ICFGR(irq));
mask = (reg >> 2*(irq % 16)) & 0x3;
if (pol == INTR_POLARITY_LOW) {
@ -1179,7 +1159,7 @@ arm_gic_config(device_t dev, int irq, enum intr_trigger trig,
/* Set mask */
reg = reg & ~(0x3 << 2*(irq % 16));
reg = reg | (mask << 2*(irq % 16));
gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
gic_d_write_4(sc, GICD_ICFGR(irq), reg);
mtx_unlock_spin(&sc->mutex);
@ -1196,7 +1176,7 @@ arm_gic_mask(device_t dev, int irq)
{
struct arm_gic_softc *sc = device_get_softc(dev);
gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
gic_d_write_4(sc, GICD_ICENABLER(irq), (1UL << (irq & 0x1F)));
gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */
}
@ -1208,7 +1188,7 @@ arm_gic_unmask(device_t dev, int irq)
if (irq > GIC_LAST_SGI)
arm_irq_memory_barrier(irq);
gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(irq), (1UL << (irq & 0x1F)));
}
#ifdef SMP
@ -1222,7 +1202,7 @@ arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
if (CPU_ISSET(i, &cpus))
val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
gic_d_write_4(sc, GICD_SGIR, val | ipi);
}
static int

75
sys/arm/arm/gic_common.h Normal file
View file

@ -0,0 +1,75 @@
/*-
* Copyright (c) 2016 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Andrew Turner under
* the sponsorship of the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _GIC_COMMON_H_
#define _GIC_COMMON_H_
/* Common register values */
#define GICD_CTLR 0x0000 /* v1 ICDDCR */
#define GICD_TYPER 0x0004 /* v1 ICDICTR */
#define GICD_IIDR 0x0008 /* v1 ICDIIDR */
#define GICD_IIDR_PROD_SHIFT 24
#define GICD_IIDR_PROD_MASK 0xff000000
#define GICD_IIDR_PROD(x) \
(((x) & GICD_IIDR_PROD_MASK) >> GICD_IIDR_PROD_SHIFT)
#define GICD_IIDR_VAR_SHIFT 16
#define GICD_IIDR_VAR_MASK 0x000f0000
#define GICD_IIDR_VAR(x) \
(((x) & GICD_IIDR_VAR_MASK) >> GICD_IIDR_VAR_SHIFT)
#define GICD_IIDR_REV_SHIFT 12
#define GICD_IIDR_REV_MASK 0x0000f000
#define GICD_IIDR_REV(x) \
(((x) & GICD_IIDR_REV_MASK) >> GICD_IIDR_REV_SHIFT)
#define GICD_IIDR_IMPL_SHIFT 0
#define GICD_IIDR_IMPL_MASK 0x00000fff
#define GICD_IIDR_IMPL(x) \
(((x) & GICD_IIDR_IMPL_MASK) >> GICD_IIDR_IMPL_SHIFT)
#define GICD_IGROUPR(n) (0x0080 + (((n) >> 5) * 4)) /* v1 ICDISER */
#define GICD_ISENABLER(n) (0x0100 + (((n) >> 5) * 4)) /* v1 ICDISER */
#define GICD_ICENABLER(n) (0x0180 + (((n) >> 5) * 4)) /* v1 ICDICER */
#define GICD_ISPENDR(n) (0x0200 + (((n) >> 5) * 4)) /* v1 ICDISPR */
#define GICD_ICPENDR(n) (0x0280 + (((n) >> 5) * 4)) /* v1 ICDICPR */
#define GICD_ICACTIVER(n) (0x0380 + (((n) >> 5) * 4)) /* v1 ICDABR */
#define GICD_IPRIORITYR(n) (0x0400 + (((n) >> 2) * 4)) /* v1 ICDIPR */
#define GICD_ITARGETSR(n) (0x0800 + (((n) >> 2) * 4)) /* v1 ICDIPTR */
#define GICD_ICFGR(n) (0x0C00 + (((n) >> 4) * 4)) /* v1 ICDICFR */
/* First bit is a polarity bit (0 - low, 1 - high) */
#define GICD_ICFGR_POL_LOW (0 << 0)
#define GICD_ICFGR_POL_HIGH (1 << 0)
#define GICD_ICFGR_POL_MASK 0x1
/* Second bit is a trigger bit (0 - level, 1 - edge) */
#define GICD_ICFGR_TRIG_LVL (0 << 1)
#define GICD_ICFGR_TRIG_EDGE (1 << 1)
#define GICD_ICFGR_TRIG_MASK 0x2
#define GICD_SGIR 0x0F00 /* v1 ICDSGIR */
#define GICD_SGI_TARGET_SHIFT 16
#endif /* _GIC_COMMON_H_ */