summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arm/include/intr.h7
-rw-r--r--sys/arm/mv/mpic.c129
-rw-r--r--sys/arm/mv/mvvar.h2
-rw-r--r--sys/boot/fdt/dts/db78460.dts2
4 files changed, 120 insertions, 20 deletions
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index 4cd2651..ce681aa 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -55,7 +55,12 @@
#elif defined(CPU_ARM11)
#define NIRQ 128
#elif defined(SOC_MV_ARMADAXP)
-#define NIRQ 148
+#define MAIN_IRQ_NUM 116
+#define ERR_IRQ_NUM 32
+#define ERR_IRQ (MAIN_IRQ_NUM)
+#define MSI_IRQ_NUM 32
+#define MSI_IRQ (ERR_IRQ + ERR_IRQ_NUM)
+#define NIRQ (MAIN_IRQ_NUM + ERR_IRQ_NUM + MSI_IRQ_NUM)
#else
#define NIRQ 32
#endif
diff --git a/sys/arm/mv/mpic.c b/sys/arm/mv/mpic.c
index ba8dde0..0a1be1d 100644
--- a/sys/arm/mv/mpic.c
+++ b/sys/arm/mv/mpic.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2006 Benno Rice.
* Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
+ * Copyright (c) 2012 Semihalf.
* All rights reserved.
*
* Developed by Semihalf.
@@ -46,23 +47,34 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/smp.h>
+#include <arm/mv/mvvar.h>
+
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/fdt/fdt_common.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
+ printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
-#define IRQ_ERR 4
-#define MAIN_IRQS 116
+#define MPIC_INT_ERR 4
+#define MPIC_INT_MSI 96
#define IRQ_MASK 0x3ff
#define MPIC_CTRL 0x0
#define MPIC_SOFT_INT 0x4
+#define MPIC_SOFT_INT_DRBL1 (1 << 5)
#define MPIC_ERR_CAUSE 0x20
#define MPIC_ISE 0x30
#define MPIC_ICE 0x34
-#define MPIC_IN_DOORBELL 0x78
-#define MPIC_IN_DOORBELL_MASK 0x7c
+#define MPIC_IN_DRBL 0x78
+#define MPIC_IN_DRBL_MASK 0x7c
#define MPIC_CTP 0xb0
#define MPIC_CTP 0xb0
#define MPIC_IIACK 0xb4
@@ -71,16 +83,20 @@ __FBSDID("$FreeBSD$");
#define MPIC_ERR_MASK 0xec0
struct mv_mpic_softc {
- struct resource * mpic_res[2];
+ device_t sc_dev;
+ struct resource * mpic_res[3];
bus_space_tag_t mpic_bst;
bus_space_handle_t mpic_bsh;
bus_space_tag_t cpu_bst;
bus_space_handle_t cpu_bsh;
+ bus_space_tag_t drbl_bst;
+ bus_space_handle_t drbl_bsh;
};
static struct resource_spec mv_mpic_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE },
{ -1, 0 }
};
@@ -92,14 +108,21 @@ static int mv_mpic_probe(device_t);
static int mv_mpic_attach(device_t);
uint32_t mv_mpic_get_cause(void);
uint32_t mv_mpic_get_cause_err(void);
+uint32_t mv_mpic_get_msi(void);
static void arm_mask_irq_err(uintptr_t);
static void arm_unmask_irq_err(uintptr_t);
+static void arm_unmask_msi(void);
#define MPIC_CPU_WRITE(softc, reg, val) \
bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
#define MPIC_CPU_READ(softc, reg) \
bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg))
+#define MPIC_DRBL_WRITE(softc, reg, val) \
+ bus_space_write_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg), (val))
+#define MPIC_DRBL_READ(softc, reg) \
+ bus_space_read_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg))
+
static int
mv_mpic_probe(device_t dev)
{
@@ -123,6 +146,8 @@ mv_mpic_attach(device_t dev)
return (ENXIO);
mv_mpic_sc = sc;
+ sc->sc_dev = dev;
+
error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
if (error) {
device_printf(dev, "could not allocate resources\n");
@@ -135,10 +160,15 @@ mv_mpic_attach(device_t dev)
sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]);
sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]);
+ sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]);
+ sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]);
+
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
MPIC_CTRL, 1);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
+ arm_unmask_msi();
+
return (0);
}
@@ -167,8 +197,10 @@ arm_get_next_irq(int last)
CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq);
if (irq != IRQ_MASK) {
- if (irq == IRQ_ERR)
+ if (irq == MPIC_INT_ERR)
irq = mv_mpic_get_cause_err();
+ if (irq == MPIC_INT_MSI)
+ irq = mv_mpic_get_msi();
next = irq;
}
@@ -186,11 +218,11 @@ arm_mask_irq(uintptr_t nb)
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1);
- if (nb < MAIN_IRQS) {
+ if (nb < ERR_IRQ) {
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
MPIC_ICE, nb);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
- } else
+ } else if (nb < MSI_IRQ)
arm_mask_irq_err(nb);
}
@@ -201,7 +233,7 @@ arm_mask_irq_err(uintptr_t nb)
uint32_t mask;
uint8_t bit_off;
- bit_off = nb - MAIN_IRQS;
+ bit_off = nb - ERR_IRQ;
mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
mask &= ~(1 << bit_off);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
@@ -213,15 +245,15 @@ arm_unmask_irq(uintptr_t nb)
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
- if (nb < MAIN_IRQS) {
+ if (nb < ERR_IRQ) {
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
MPIC_ISE, nb);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
- } else
+ } else if (nb < MSI_IRQ)
arm_unmask_irq_err(nb);
if (nb == 0)
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL_MASK, 0xffffffff);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
}
void
@@ -231,15 +263,22 @@ arm_unmask_irq_err(uintptr_t nb)
uint8_t bit_off;
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
- MPIC_ISE, IRQ_ERR);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, IRQ_ERR);
+ MPIC_ISE, MPIC_INT_ERR);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, MPIC_INT_ERR);
- bit_off = nb - MAIN_IRQS;
+ bit_off = nb - ERR_IRQ;
mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
mask |= (1 << bit_off);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
}
+static void
+arm_unmask_msi(void)
+{
+
+ arm_unmask_irq(MPIC_INT_MSI);
+}
+
uint32_t
mv_mpic_get_cause(void)
{
@@ -260,7 +299,61 @@ mv_mpic_get_cause_err(void)
bit_off = ffs(err_cause) - 1;
else
return (-1);
- return (MAIN_IRQS + bit_off);
+
+ debugf("%s: irq:%x cause:%x\n", __func__, bit_off, err_cause);
+ return (ERR_IRQ + bit_off);
+}
+
+uint32_t
+mv_mpic_get_msi(void)
+{
+ uint32_t cause;
+ uint8_t bit_off;
+
+ cause = MPIC_DRBL_READ(mv_mpic_sc, 0);
+
+ if (cause)
+ bit_off = ffs(cause) - 1;
+ else
+ return (-1);
+
+ debugf("%s: irq:%x cause:%x\n", __func__, bit_off, cause);
+
+ cause &= ~(1 << bit_off);
+ MPIC_DRBL_WRITE(mv_mpic_sc, 0, cause);
+
+ return (MSI_IRQ + bit_off);
+}
+
+int
+mv_msi_data(int irq, uint64_t *addr, uint32_t *data)
+{
+ u_long phys, base, size;
+ phandle_t node;
+ int error;
+
+ node = ofw_bus_get_node(mv_mpic_sc->sc_dev);
+
+ /* Get physical addres of register space */
+ error = fdt_get_range(OF_parent(node), 0, &phys, &size);
+ if (error) {
+ printf("%s: Cannot get register physical address, err:%d",
+ __func__, error);
+ return (error);
+ }
+
+ /* Get offset of MPIC register space */
+ error = fdt_regsize(node, &base, &size);
+ if (error) {
+ printf("%s: Cannot get MPIC register offset, err:%d",
+ __func__, error);
+ return (error);
+ }
+
+ *addr = phys + base + MPIC_SOFT_INT;
+ *data = MPIC_SOFT_INT_DRBL1 | irq;
+
+ return (0);
}
#if defined(SMP)
@@ -283,7 +376,7 @@ pic_ipi_get(int i __unused)
{
uint32_t val;
- val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DOORBELL);
+ val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DRBL);
if (val)
return (ffs(val) - 1);
@@ -296,7 +389,7 @@ pic_ipi_clear(int ipi)
uint32_t val;
val = ~(1 << ipi);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL, val);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL, val);
}
#endif
diff --git a/sys/arm/mv/mvvar.h b/sys/arm/mv/mvvar.h
index 4a2c87d..002640c 100644
--- a/sys/arm/mv/mvvar.h
+++ b/sys/arm/mv/mvvar.h
@@ -134,4 +134,6 @@ uint32_t mv_drbl_get_cause(int dir, int unit);
void mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit);
uint32_t mv_drbl_get_msg(int mnr, int dir, int unit);
+int mv_msi_data(int irq, uint64_t *addr, uint32_t *data);
+
#endif /* _MVVAR_H_ */
diff --git a/sys/boot/fdt/dts/db78460.dts b/sys/boot/fdt/dts/db78460.dts
index 2db9a99..45a13c3 100644
--- a/sys/boot/fdt/dts/db78460.dts
+++ b/sys/boot/fdt/dts/db78460.dts
@@ -75,7 +75,7 @@
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
- reg = <0x20a00 0x500 0x21000 0x800>;
+ reg = <0x20a00 0x500 0x21000 0x800 0x20400 0x100>;
compatible = "mrvl,mpic";
};
OpenPOWER on IntegriCloud