Module Name: src
Committed By: jmcneill
Date: Sun Nov 7 17:13:38 UTC 2021
Modified Files:
src/sys/arch/arm/sunxi: sunxi_nmi.c
Log Message:
sunxi: nmi: add support for #interrupt-cells 3 bindings
To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/arm/sunxi/sunxi_nmi.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/sunxi/sunxi_nmi.c
diff -u src/sys/arch/arm/sunxi/sunxi_nmi.c:1.11 src/sys/arch/arm/sunxi/sunxi_nmi.c:1.12
--- src/sys/arch/arm/sunxi/sunxi_nmi.c:1.11 Wed Jan 27 03:10:20 2021
+++ src/sys/arch/arm/sunxi/sunxi_nmi.c Sun Nov 7 17:13:38 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_nmi.c,v 1.11 2021/01/27 03:10:20 thorpej Exp $ */
+/* $NetBSD: sunxi_nmi.c,v 1.12 2021/11/07 17:13:38 jmcneill Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <[email protected]>
@@ -29,7 +29,7 @@
#define _INTR_PRIVATE
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_nmi.c,v 1.11 2021/01/27 03:10:20 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_nmi.c,v 1.12 2021/11/07 17:13:38 jmcneill Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@@ -105,6 +105,9 @@ struct sunxi_nmi_softc {
bus_space_handle_t sc_bsh;
int sc_phandle;
+ u_int sc_intr_nmi;
+ u_int sc_intr_cells;
+
kmutex_t sc_intr_lock;
const struct sunxi_nmi_config *sc_config;
@@ -177,22 +180,54 @@ sunxi_nmi_fdt_establish(device_t dev, u_
int (*func)(void *), void *arg, const char *xname)
{
struct sunxi_nmi_softc * const sc = device_private(dev);
- u_int irq_type;
+ u_int irq_type, irq, pol;
int ist;
- /* 1st cell is the interrupt number */
- const u_int irq = be32toh(specifier[0]);
- /* 2nd cell is polarity */
- const u_int pol = be32toh(specifier[1]);
+ if (sc->sc_intr_cells == 2) {
+ /* 1st cell is the interrupt number */
+ irq = be32toh(specifier[0]);
+ /* 2nd cell is polarity */
+ pol = be32toh(specifier[1]);
+ } else {
+ /* 1st cell is the GIC interrupt type and must be GIC_SPI */
+ if (be32toh(specifier[0]) != 0) {
+#ifdef DIAGNOSTIC
+ device_printf(dev, "GIC intr type %u is invalid\n",
+ be32toh(specifier[0]));
+#endif
+ return NULL;
+ }
+ /* 2nd cell is the interrupt number */
+ irq = be32toh(specifier[1]);
+ /* 3rd cell is polarity */
+ pol = be32toh(specifier[2]);
+ }
- if (irq != 0) {
+ if (sc->sc_intr_cells == 3 && irq != sc->sc_intr_nmi) {
+ /*
+ * Driver is requesting a wakeup irq, which we don't
+ * support today. Just pass it through to the parent
+ * interrupt controller.
+ */
+ const int ihandle = fdtbus_intr_parent(sc->sc_phandle);
+ if (ihandle == -1) {
+#ifdef DIAGNOSTIC
+ device_printf(dev, "couldn't find interrupt parent\n");
+#endif
+ return NULL;
+ }
+ return fdtbus_intr_establish_raw(ihandle, specifier, ipl,
+ flags, func, arg, xname);
+ }
+
+ if (sc->sc_intr_cells == 2 && irq != 0) {
#ifdef DIAGNOSTIC
device_printf(dev, "IRQ %u is invalid\n", irq);
#endif
return NULL;
}
- switch (pol & 0x7) {
+ switch (pol & 0xf) {
case 1: /* IRQ_TYPE_EDGE_RISING */
irq_type = NMI_CTRL_IRQ_HIGH_EDGE;
ist = IST_EDGE;
@@ -201,11 +236,11 @@ sunxi_nmi_fdt_establish(device_t dev, u_
irq_type = NMI_CTRL_IRQ_LOW_EDGE;
ist = IST_EDGE;
break;
- case 3: /* IRQ_TYPE_LEVEL_HIGH */
+ case 4: /* IRQ_TYPE_LEVEL_HIGH */
irq_type = NMI_CTRL_IRQ_HIGH_LEVEL;
ist = IST_LEVEL;
break;
- case 4: /* IRQ_TYPE_LEVEL_LOW */
+ case 8: /* IRQ_TYPE_LEVEL_LOW */
irq_type = NMI_CTRL_IRQ_LOW_LEVEL;
ist = IST_LEVEL;
break;
@@ -296,6 +331,18 @@ sunxi_nmi_fdt_intrstr(device_t dev, u_in
{
struct sunxi_nmi_softc * const sc = device_private(dev);
+ if (sc->sc_intr_cells == 3) {
+ const u_int irq = be32toh(specifier[1]);
+ if (irq != sc->sc_intr_nmi) {
+ const int ihandle = fdtbus_intr_parent(sc->sc_phandle);
+ if (ihandle == -1) {
+ return false;
+ }
+ return fdtbus_intr_str_raw(ihandle, specifier, buf,
+ buflen);
+ }
+ }
+
snprintf(buf, buflen, "%s", sc->sc_config->name);
return true;
@@ -323,9 +370,10 @@ sunxi_nmi_attach(device_t parent, device
struct sunxi_nmi_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
+ const u_int *interrupts;
bus_addr_t addr;
bus_size_t size;
- int error;
+ int error, len;
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
aprint_error(": couldn't get registers\n");
@@ -341,8 +389,18 @@ sunxi_nmi_attach(device_t parent, device
return;
}
+ of_getprop_uint32(phandle, "#interrupt-cells", &sc->sc_intr_cells);
+ interrupts = fdtbus_get_prop(phandle, "interrupts", &len);
+ if (interrupts == NULL || len != 12 ||
+ be32toh(interrupts[0]) != 0 /* GIC_SPI */ ||
+ be32toh(interrupts[2]) != 4 /* IRQ_TYPE_LEVEL_HIGH */) {
+ aprint_error(": couldn't find GIC SPI for NMI\n");
+ return;
+ }
+ sc->sc_intr_nmi = be32toh(interrupts[1]);
+
aprint_naive("\n");
- aprint_normal(": %s\n", sc->sc_config->name);
+ aprint_normal(": %s, NMI IRQ %u\n", sc->sc_config->name, sc->sc_intr_nmi);
mutex_init(&sc->sc_intr_lock, MUTEX_SPIN, IPL_HIGH);