summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-10-26 03:52:45 +0000
committerian <ian@FreeBSD.org>2014-10-26 03:52:45 +0000
commit839e78bb760f69a2429364064c3b8ebd4715c08f (patch)
treed2b9d0b3fe940305fc8d2c8a024e08664c3e607f
parent1ede59bf75201fe38de6e2eb3f949289e699f83b (diff)
downloadFreeBSD-src-839e78bb760f69a2429364064c3b8ebd4715c08f.zip
FreeBSD-src-839e78bb760f69a2429364064c3b8ebd4715c08f.tar.gz
MFC r271595, r271601, r271607, r271630:
Add compat strings for all the flavors of GIC this driver should support. Also allow the driver to attach to ofwbus as well as simplebus, some FDT data puts the root interrupt controller on the root bus. Add a common routine for parsing FDT data describing an ARM GIC interrupt. Use gic_decode_fdt() rather than a local routine to parse fdt interrupt properties. Move fdt_pic_table and fdt_fixup_table into imx6_machdep.c, which means imx6 doesn't need imx_common.c anymore. The private peripheral interrupts start at offset 16, not 0. Also, use names rather than inline mystery constants for these offsets.
-rw-r--r--sys/arm/arm/gic.c66
-rw-r--r--sys/arm/freescale/imx/files.imx61
-rw-r--r--sys/arm/freescale/imx/imx6_machdep.c13
-rw-r--r--sys/arm/include/intr.h2
4 files changed, 79 insertions, 3 deletions
diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c
index 49d3c62..265c6e7 100644
--- a/sys/arm/arm/gic.c
+++ b/sys/arm/arm/gic.c
@@ -83,7 +83,11 @@ __FBSDID("$FreeBSD$");
#define GICC_ABPR 0x001C /* v1 ICCABPR */
#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
-#define GIC_LAST_IPI 15 /* Irqs 0-15 are IPIs. */
+#define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
+#define GIC_LAST_IPI 15
+#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
+#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
+#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
/* First bit is a polarity bit (0 - low, 1 - high) */
#define GICD_ICFGR_POL_LOW (0 << 0)
@@ -127,6 +131,17 @@ static int gic_config_irq(int irq, enum intr_trigger trig,
enum intr_polarity pol);
static void gic_post_filter(void *);
+static struct ofw_compat_data compat_data[] = {
+ {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */
+ {"arm,gic-400", true},
+ {"arm,cortex-a15-gic", true},
+ {"arm,cortex-a9-gic", true},
+ {"arm,cortex-a7-gic", true},
+ {"arm,arm11mp-gic", true},
+ {"brcm,brahma-b15-gic", true},
+ {NULL, false}
+};
+
static int
arm_gic_probe(device_t dev)
{
@@ -134,7 +149,7 @@ arm_gic_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "arm,gic"))
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
return (ENXIO);
device_set_desc(dev, "ARM Generic Interrupt Controller");
return (BUS_PROBE_DEFAULT);
@@ -170,6 +185,51 @@ gic_init_secondary(void)
gic_d_write_4(GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
}
+int
+gic_decode_fdt(uint32_t iparent, uint32_t *intr, int *interrupt,
+ int *trig, int *pol)
+{
+ static u_int num_intr_cells;
+
+ if (num_intr_cells == 0) {
+ if (OF_searchencprop(OF_node_from_xref(iparent),
+ "#interrupt-cells", &num_intr_cells,
+ sizeof(num_intr_cells)) == -1) {
+ num_intr_cells = 1;
+ }
+ }
+
+ if (num_intr_cells == 1) {
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+ } else {
+ if (intr[0] == 0)
+ *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI;
+ else
+ *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI;
+ /*
+ * In intr[2], bits[3:0] are trigger type and level flags.
+ * 1 = low-to-high edge triggered
+ * 2 = high-to-low edge triggered
+ * 4 = active high level-sensitive
+ * 8 = active low level-sensitive
+ * The hardware only supports active-high-level or rising-edge.
+ */
+ if (intr[2] & 0x0a) {
+ printf("unsupported trigger/polarity configuration "
+ "0x%2x\n", intr[2] & 0x0f);
+ return (ENOTSUP);
+ }
+ *pol = INTR_POLARITY_CONFORM;
+ if (intr[2] & 0x01)
+ *trig = INTR_TRIGGER_EDGE;
+ else
+ *trig = INTR_TRIGGER_LEVEL;
+ }
+ return (0);
+}
+
static int
arm_gic_attach(device_t dev)
{
@@ -265,6 +325,8 @@ static devclass_t arm_gic_devclass;
EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0,
BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
+EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
static void
gic_post_filter(void *arg)
diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6
index 03c2f7e..351da22 100644
--- a/sys/arm/freescale/imx/files.imx6
+++ b/sys/arm/freescale/imx/files.imx6
@@ -23,7 +23,6 @@ arm/freescale/imx/imx6_ccm.c standard
arm/freescale/imx/imx6_machdep.c standard
arm/freescale/imx/imx6_mp.c optional smp
arm/freescale/imx/imx6_pl310.c standard
-arm/freescale/imx/imx_common.c standard
arm/freescale/imx/imx_iomux.c standard
arm/freescale/imx/imx_machdep.c standard
arm/freescale/imx/imx_gpt.c standard
diff --git a/sys/arm/freescale/imx/imx6_machdep.c b/sys/arm/freescale/imx/imx6_machdep.c
index 3a01cd8..be0ae67 100644
--- a/sys/arm/freescale/imx/imx6_machdep.c
+++ b/sys/arm/freescale/imx/imx6_machdep.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/devmap.h>
+#include <machine/intr.h>
#include <machine/machdep.h>
#include <arm/arm/mpcore_timervar.h>
@@ -45,6 +46,18 @@ __FBSDID("$FreeBSD$");
#include <arm/freescale/imx/imx6_anatopvar.h>
#include <arm/freescale/imx/imx_machdep.h>
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+fdt_pic_decode_t fdt_pic_table[] = {
+ &gic_decode_fdt,
+ NULL
+};
+
vm_offset_t
initarm_lastaddr(void)
{
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index e2d0feb..96ce2e0 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -82,5 +82,7 @@ extern int (*arm_config_irq)(int irq, enum intr_trigger trig,
void arm_irq_memory_barrier(uintptr_t);
void gic_init_secondary(void);
+int gic_decode_fdt(uint32_t iparentnode, uint32_t *intrcells, int *interrupt,
+ int *trig, int *pol);
#endif /* _MACHINE_INTR_H */
OpenPOWER on IntegriCloud