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 <jmcne...@invisible.ca>
@@ -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);
 

Reply via email to