xref: /freebsd/sys/arm/allwinner/aw_nmi.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
130c05743SEmmanuel Vadot /*-
230c05743SEmmanuel Vadot  * Copyright (c) 2016 Emmanuel Vadot <manu@freebsd.org>
330c05743SEmmanuel Vadot  *
430c05743SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
530c05743SEmmanuel Vadot  * modification, are permitted provided that the following conditions
630c05743SEmmanuel Vadot  * are met:
730c05743SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
830c05743SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
930c05743SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
1030c05743SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
1130c05743SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
1230c05743SEmmanuel Vadot  *
1330c05743SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1430c05743SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1530c05743SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1630c05743SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1730c05743SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1830c05743SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1930c05743SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2030c05743SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2130c05743SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2230c05743SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2330c05743SEmmanuel Vadot  * SUCH DAMAGE.
2430c05743SEmmanuel Vadot  */
2530c05743SEmmanuel Vadot 
2630c05743SEmmanuel Vadot #include <sys/cdefs.h>
2730c05743SEmmanuel Vadot #include "opt_platform.h"
2830c05743SEmmanuel Vadot 
2930c05743SEmmanuel Vadot #include <sys/param.h>
3030c05743SEmmanuel Vadot #include <sys/systm.h>
3130c05743SEmmanuel Vadot #include <sys/bus.h>
3230c05743SEmmanuel Vadot #include <sys/kernel.h>
3330c05743SEmmanuel Vadot #include <sys/module.h>
3430c05743SEmmanuel Vadot #include <sys/proc.h>
352274551aSJared McNeill #include <sys/rman.h>
3630c05743SEmmanuel Vadot #include <machine/bus.h>
3730c05743SEmmanuel Vadot #include <machine/intr.h>
3830c05743SEmmanuel Vadot 
39f1ae17fbSAndrew Turner #include <dev/fdt/fdt_intr.h>
4030c05743SEmmanuel Vadot #include <dev/ofw/openfirm.h>
4130c05743SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
4230c05743SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
4330c05743SEmmanuel Vadot 
4430c05743SEmmanuel Vadot #include "pic_if.h"
4530c05743SEmmanuel Vadot 
4630c05743SEmmanuel Vadot #define	NMI_IRQ_CTRL_REG	0x0
4730c05743SEmmanuel Vadot #define	 NMI_IRQ_LOW_LEVEL	0x0
4830c05743SEmmanuel Vadot #define	 NMI_IRQ_LOW_EDGE	0x1
4930c05743SEmmanuel Vadot #define	 NMI_IRQ_HIGH_LEVEL	0x2
5030c05743SEmmanuel Vadot #define	 NMI_IRQ_HIGH_EDGE	0x3
5130c05743SEmmanuel Vadot #define	NMI_IRQ_PENDING_REG	0x4
5230c05743SEmmanuel Vadot #define	 NMI_IRQ_ACK		(1U << 0)
5330c05743SEmmanuel Vadot #define	A20_NMI_IRQ_ENABLE_REG	0x8
5430c05743SEmmanuel Vadot #define	A31_NMI_IRQ_ENABLE_REG	0x34
5530c05743SEmmanuel Vadot #define	 NMI_IRQ_ENABLE		(1U << 0)
5630c05743SEmmanuel Vadot 
57c4717ac0SKyle Evans #define	R_NMI_IRQ_CTRL_REG	0x0c
58c4717ac0SKyle Evans #define	R_NMI_IRQ_PENDING_REG	0x10
59c4717ac0SKyle Evans #define	R_NMI_IRQ_ENABLE_REG	0x40
60c4717ac0SKyle Evans 
6130c05743SEmmanuel Vadot #define	SC_NMI_READ(_sc, _reg)		bus_read_4(_sc->res[0], _reg)
6230c05743SEmmanuel Vadot #define	SC_NMI_WRITE(_sc, _reg, _val)	bus_write_4(_sc->res[0], _reg, _val)
6330c05743SEmmanuel Vadot 
6430c05743SEmmanuel Vadot static struct resource_spec aw_nmi_res_spec[] = {
6530c05743SEmmanuel Vadot 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
6630c05743SEmmanuel Vadot 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
6730c05743SEmmanuel Vadot 	{ -1,			0,	0 }
6830c05743SEmmanuel Vadot };
6930c05743SEmmanuel Vadot 
7030c05743SEmmanuel Vadot struct aw_nmi_intr {
7130c05743SEmmanuel Vadot 	struct intr_irqsrc	isrc;
7230c05743SEmmanuel Vadot 	u_int			irq;
7330c05743SEmmanuel Vadot 	enum intr_polarity	pol;
7430c05743SEmmanuel Vadot 	enum intr_trigger	tri;
7530c05743SEmmanuel Vadot };
7630c05743SEmmanuel Vadot 
77c4717ac0SKyle Evans struct aw_nmi_reg_cfg {
78c4717ac0SKyle Evans 	uint8_t			ctrl_reg;
79c4717ac0SKyle Evans 	uint8_t			pending_reg;
80c4717ac0SKyle Evans 	uint8_t			enable_reg;
81c4717ac0SKyle Evans };
82c4717ac0SKyle Evans 
8330c05743SEmmanuel Vadot struct aw_nmi_softc {
8430c05743SEmmanuel Vadot 	device_t		dev;
8530c05743SEmmanuel Vadot 	struct resource *	res[2];
8630c05743SEmmanuel Vadot 	void *			intrcookie;
8730c05743SEmmanuel Vadot 	struct aw_nmi_intr	intr;
88c4717ac0SKyle Evans 	struct aw_nmi_reg_cfg *	cfg;
8930c05743SEmmanuel Vadot };
9030c05743SEmmanuel Vadot 
91c4717ac0SKyle Evans static struct aw_nmi_reg_cfg a20_nmi_cfg = {
92c4717ac0SKyle Evans 	.ctrl_reg =	NMI_IRQ_CTRL_REG,
93c4717ac0SKyle Evans 	.pending_reg =	NMI_IRQ_PENDING_REG,
94c4717ac0SKyle Evans 	.enable_reg =	A20_NMI_IRQ_ENABLE_REG,
95c4717ac0SKyle Evans };
96c4717ac0SKyle Evans 
97c4717ac0SKyle Evans static struct aw_nmi_reg_cfg a31_nmi_cfg = {
98c4717ac0SKyle Evans 	.ctrl_reg =	NMI_IRQ_CTRL_REG,
99c4717ac0SKyle Evans 	.pending_reg =	NMI_IRQ_PENDING_REG,
100c4717ac0SKyle Evans 	.enable_reg =	A31_NMI_IRQ_ENABLE_REG,
101c4717ac0SKyle Evans };
102c4717ac0SKyle Evans 
103c4717ac0SKyle Evans static struct aw_nmi_reg_cfg a83t_r_nmi_cfg = {
104c4717ac0SKyle Evans 	.ctrl_reg =	R_NMI_IRQ_CTRL_REG,
105c4717ac0SKyle Evans 	.pending_reg =	R_NMI_IRQ_PENDING_REG,
106c4717ac0SKyle Evans 	.enable_reg =	R_NMI_IRQ_ENABLE_REG,
107c4717ac0SKyle Evans };
10830c05743SEmmanuel Vadot 
10930c05743SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
110c4717ac0SKyle Evans 	{"allwinner,sun7i-a20-sc-nmi", (uintptr_t)&a20_nmi_cfg},
111c4717ac0SKyle Evans 	{"allwinner,sun6i-a31-sc-nmi", (uintptr_t)&a31_nmi_cfg},
112c4717ac0SKyle Evans 	{"allwinner,sun6i-a31-r-intc", (uintptr_t)&a83t_r_nmi_cfg},
113c4717ac0SKyle Evans 	{"allwinner,sun8i-a83t-r-intc", (uintptr_t)&a83t_r_nmi_cfg},
11430c05743SEmmanuel Vadot 	{NULL, 0},
11530c05743SEmmanuel Vadot };
11630c05743SEmmanuel Vadot 
11730c05743SEmmanuel Vadot static int
aw_nmi_intr(void * arg)11830c05743SEmmanuel Vadot aw_nmi_intr(void *arg)
11930c05743SEmmanuel Vadot {
12030c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
12130c05743SEmmanuel Vadot 
12230c05743SEmmanuel Vadot 	sc = arg;
12330c05743SEmmanuel Vadot 
124c4717ac0SKyle Evans 	if (SC_NMI_READ(sc, sc->cfg->pending_reg) == 0) {
12530c05743SEmmanuel Vadot 		device_printf(sc->dev, "Spurious interrupt\n");
12630c05743SEmmanuel Vadot 		return (FILTER_HANDLED);
12730c05743SEmmanuel Vadot 	}
12830c05743SEmmanuel Vadot 
12930c05743SEmmanuel Vadot 	if (intr_isrc_dispatch(&sc->intr.isrc, curthread->td_intr_frame) != 0) {
1301c62664fSEmmanuel Vadot 		SC_NMI_WRITE(sc, sc->cfg->enable_reg, ~NMI_IRQ_ENABLE);
13130c05743SEmmanuel Vadot 		device_printf(sc->dev, "Stray interrupt, NMI disabled\n");
13230c05743SEmmanuel Vadot 	}
13330c05743SEmmanuel Vadot 
13430c05743SEmmanuel Vadot 	return (FILTER_HANDLED);
13530c05743SEmmanuel Vadot }
13630c05743SEmmanuel Vadot 
13730c05743SEmmanuel Vadot static void
aw_nmi_enable_intr(device_t dev,struct intr_irqsrc * isrc)13830c05743SEmmanuel Vadot aw_nmi_enable_intr(device_t dev, struct intr_irqsrc *isrc)
13930c05743SEmmanuel Vadot {
14030c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
14130c05743SEmmanuel Vadot 
14230c05743SEmmanuel Vadot 	sc = device_get_softc(dev);
14330c05743SEmmanuel Vadot 
144c4717ac0SKyle Evans 	SC_NMI_WRITE(sc, sc->cfg->enable_reg, NMI_IRQ_ENABLE);
14530c05743SEmmanuel Vadot }
14630c05743SEmmanuel Vadot 
14730c05743SEmmanuel Vadot static void
aw_nmi_disable_intr(device_t dev,struct intr_irqsrc * isrc)14830c05743SEmmanuel Vadot aw_nmi_disable_intr(device_t dev, struct intr_irqsrc *isrc)
14930c05743SEmmanuel Vadot {
15030c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
15130c05743SEmmanuel Vadot 
15230c05743SEmmanuel Vadot 	sc = device_get_softc(dev);
15330c05743SEmmanuel Vadot 
1541c62664fSEmmanuel Vadot 	SC_NMI_WRITE(sc, sc->cfg->enable_reg, ~NMI_IRQ_ENABLE);
15530c05743SEmmanuel Vadot }
15630c05743SEmmanuel Vadot 
15730c05743SEmmanuel Vadot static int
aw_nmi_map_fdt(device_t dev,u_int ncells,pcell_t * cells,u_int * irqp,enum intr_polarity * polp,enum intr_trigger * trigp)15830c05743SEmmanuel Vadot aw_nmi_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp,
15930c05743SEmmanuel Vadot     enum intr_polarity *polp, enum intr_trigger *trigp)
16030c05743SEmmanuel Vadot {
16130c05743SEmmanuel Vadot 	u_int irq, tripol;
16230c05743SEmmanuel Vadot 	enum intr_polarity pol;
16330c05743SEmmanuel Vadot 	enum intr_trigger trig;
16430c05743SEmmanuel Vadot 
16530c05743SEmmanuel Vadot 	if (ncells != 2) {
16630c05743SEmmanuel Vadot 		device_printf(dev, "Invalid #interrupt-cells\n");
16730c05743SEmmanuel Vadot 		return (EINVAL);
16830c05743SEmmanuel Vadot 	}
16930c05743SEmmanuel Vadot 
17030c05743SEmmanuel Vadot 	irq = cells[0];
17130c05743SEmmanuel Vadot 	if (irq != 0) {
17230c05743SEmmanuel Vadot 		device_printf(dev, "Controller only support irq 0\n");
17330c05743SEmmanuel Vadot 		return (EINVAL);
17430c05743SEmmanuel Vadot 	}
17530c05743SEmmanuel Vadot 
17630c05743SEmmanuel Vadot 	tripol = cells[1];
17730c05743SEmmanuel Vadot 
17830c05743SEmmanuel Vadot 	switch (tripol) {
179f1ae17fbSAndrew Turner 	case FDT_INTR_EDGE_RISING:
18030c05743SEmmanuel Vadot 		trig = INTR_TRIGGER_EDGE;
18130c05743SEmmanuel Vadot 		pol  = INTR_POLARITY_HIGH;
18230c05743SEmmanuel Vadot 		break;
183f1ae17fbSAndrew Turner 	case FDT_INTR_EDGE_FALLING:
18430c05743SEmmanuel Vadot 		trig = INTR_TRIGGER_EDGE;
18530c05743SEmmanuel Vadot 		pol  = INTR_POLARITY_LOW;
18630c05743SEmmanuel Vadot 		break;
187f1ae17fbSAndrew Turner 	case FDT_INTR_LEVEL_HIGH:
18830c05743SEmmanuel Vadot 		trig = INTR_TRIGGER_LEVEL;
18930c05743SEmmanuel Vadot 		pol  = INTR_POLARITY_HIGH;
19030c05743SEmmanuel Vadot 		break;
191f1ae17fbSAndrew Turner 	case FDT_INTR_LEVEL_LOW:
19230c05743SEmmanuel Vadot 		trig = INTR_TRIGGER_LEVEL;
19330c05743SEmmanuel Vadot 		pol  = INTR_POLARITY_LOW;
19430c05743SEmmanuel Vadot 		break;
19530c05743SEmmanuel Vadot 	default:
19630c05743SEmmanuel Vadot 		device_printf(dev, "unsupported trigger/polarity 0x%2x\n",
19730c05743SEmmanuel Vadot 		    tripol);
19830c05743SEmmanuel Vadot 		return (ENOTSUP);
19930c05743SEmmanuel Vadot 	}
20030c05743SEmmanuel Vadot 
20130c05743SEmmanuel Vadot 	*irqp = irq;
20230c05743SEmmanuel Vadot 	if (polp != NULL)
20330c05743SEmmanuel Vadot 		*polp = pol;
20430c05743SEmmanuel Vadot 	if (trigp != NULL)
20530c05743SEmmanuel Vadot 		*trigp = trig;
20630c05743SEmmanuel Vadot 	return (0);
20730c05743SEmmanuel Vadot }
20830c05743SEmmanuel Vadot 
20930c05743SEmmanuel Vadot static int
aw_nmi_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)21030c05743SEmmanuel Vadot aw_nmi_map_intr(device_t dev, struct intr_map_data *data,
21130c05743SEmmanuel Vadot     struct intr_irqsrc **isrcp)
21230c05743SEmmanuel Vadot {
213cd642c88SSvatopluk Kraus 	struct intr_map_data_fdt *daf;
21430c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
21530c05743SEmmanuel Vadot 	int error;
21630c05743SEmmanuel Vadot 	u_int irq;
21730c05743SEmmanuel Vadot 
21830c05743SEmmanuel Vadot 	if (data->type != INTR_MAP_DATA_FDT)
21930c05743SEmmanuel Vadot 		return (ENOTSUP);
22030c05743SEmmanuel Vadot 
221cd642c88SSvatopluk Kraus 	sc = device_get_softc(dev);
222cd642c88SSvatopluk Kraus 	daf = (struct intr_map_data_fdt *)data;
223cd642c88SSvatopluk Kraus 
224cd642c88SSvatopluk Kraus 	error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, NULL, NULL);
22530c05743SEmmanuel Vadot 	if (error == 0)
22630c05743SEmmanuel Vadot 		*isrcp = &sc->intr.isrc;
22730c05743SEmmanuel Vadot 
22830c05743SEmmanuel Vadot 	return (error);
22930c05743SEmmanuel Vadot }
23030c05743SEmmanuel Vadot 
23130c05743SEmmanuel Vadot static int
aw_nmi_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)23230c05743SEmmanuel Vadot aw_nmi_setup_intr(device_t dev, struct intr_irqsrc *isrc,
23330c05743SEmmanuel Vadot     struct resource *res, struct intr_map_data *data)
23430c05743SEmmanuel Vadot {
235cd642c88SSvatopluk Kraus 	struct intr_map_data_fdt *daf;
23630c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
23730c05743SEmmanuel Vadot 	struct aw_nmi_intr *nmi_intr;
23830c05743SEmmanuel Vadot 	int error, icfg;
23930c05743SEmmanuel Vadot 	u_int irq;
24030c05743SEmmanuel Vadot 	enum intr_trigger trig;
24130c05743SEmmanuel Vadot 	enum intr_polarity pol;
24230c05743SEmmanuel Vadot 
24330c05743SEmmanuel Vadot 	/* Get config for interrupt. */
24430c05743SEmmanuel Vadot 	if (data == NULL || data->type != INTR_MAP_DATA_FDT)
24530c05743SEmmanuel Vadot 		return (ENOTSUP);
246cd642c88SSvatopluk Kraus 
247cd642c88SSvatopluk Kraus 	sc = device_get_softc(dev);
248cd642c88SSvatopluk Kraus 	nmi_intr = (struct aw_nmi_intr *)isrc;
249cd642c88SSvatopluk Kraus 	daf = (struct intr_map_data_fdt *)data;
250cd642c88SSvatopluk Kraus 
251cd642c88SSvatopluk Kraus 	error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, &trig);
25230c05743SEmmanuel Vadot 	if (error != 0)
25330c05743SEmmanuel Vadot 		return (error);
25430c05743SEmmanuel Vadot 	if (nmi_intr->irq != irq)
25530c05743SEmmanuel Vadot 		return (EINVAL);
25630c05743SEmmanuel Vadot 
25730c05743SEmmanuel Vadot 	/* Compare config if this is not first setup. */
25830c05743SEmmanuel Vadot 	if (isrc->isrc_handlers != 0) {
25930c05743SEmmanuel Vadot 		if (pol != nmi_intr->pol || trig != nmi_intr->tri)
26030c05743SEmmanuel Vadot 			return (EINVAL);
26130c05743SEmmanuel Vadot 		else
26230c05743SEmmanuel Vadot 			return (0);
26330c05743SEmmanuel Vadot 	}
26430c05743SEmmanuel Vadot 
26530c05743SEmmanuel Vadot 	nmi_intr->pol = pol;
26630c05743SEmmanuel Vadot 	nmi_intr->tri = trig;
26730c05743SEmmanuel Vadot 
26830c05743SEmmanuel Vadot 	if (trig == INTR_TRIGGER_LEVEL) {
26930c05743SEmmanuel Vadot 		if (pol == INTR_POLARITY_LOW)
27030c05743SEmmanuel Vadot 			icfg = NMI_IRQ_LOW_LEVEL;
27130c05743SEmmanuel Vadot 		else
27230c05743SEmmanuel Vadot 			icfg = NMI_IRQ_HIGH_LEVEL;
27330c05743SEmmanuel Vadot 	} else {
27430c05743SEmmanuel Vadot 		if (pol == INTR_POLARITY_HIGH)
27530c05743SEmmanuel Vadot 			icfg = NMI_IRQ_HIGH_EDGE;
27630c05743SEmmanuel Vadot 		else
27730c05743SEmmanuel Vadot 			icfg = NMI_IRQ_LOW_EDGE;
27830c05743SEmmanuel Vadot 	}
27930c05743SEmmanuel Vadot 
280c4717ac0SKyle Evans 	SC_NMI_WRITE(sc, sc->cfg->ctrl_reg, icfg);
28130c05743SEmmanuel Vadot 
28230c05743SEmmanuel Vadot 	return (0);
28330c05743SEmmanuel Vadot }
28430c05743SEmmanuel Vadot 
28530c05743SEmmanuel Vadot static int
aw_nmi_teardown_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)28630c05743SEmmanuel Vadot aw_nmi_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
28730c05743SEmmanuel Vadot     struct resource *res, struct intr_map_data *data)
28830c05743SEmmanuel Vadot {
28930c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
29030c05743SEmmanuel Vadot 
29130c05743SEmmanuel Vadot 	sc = device_get_softc(dev);
29230c05743SEmmanuel Vadot 
29330c05743SEmmanuel Vadot 	if (isrc->isrc_handlers == 0) {
29430c05743SEmmanuel Vadot 		sc->intr.pol = INTR_POLARITY_CONFORM;
29530c05743SEmmanuel Vadot 		sc->intr.tri = INTR_TRIGGER_CONFORM;
29630c05743SEmmanuel Vadot 
2971c62664fSEmmanuel Vadot 		SC_NMI_WRITE(sc, sc->cfg->enable_reg, ~NMI_IRQ_ENABLE);
29830c05743SEmmanuel Vadot 	}
29930c05743SEmmanuel Vadot 
30030c05743SEmmanuel Vadot 	return (0);
30130c05743SEmmanuel Vadot }
30230c05743SEmmanuel Vadot 
30330c05743SEmmanuel Vadot static void
aw_nmi_pre_ithread(device_t dev,struct intr_irqsrc * isrc)30430c05743SEmmanuel Vadot aw_nmi_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
30530c05743SEmmanuel Vadot {
30622d63659SEmmanuel Vadot 	struct aw_nmi_softc *sc;
30730c05743SEmmanuel Vadot 
30822d63659SEmmanuel Vadot 	sc = device_get_softc(dev);
30930c05743SEmmanuel Vadot 	aw_nmi_disable_intr(dev, isrc);
310c4717ac0SKyle Evans 	SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK);
31130c05743SEmmanuel Vadot }
31230c05743SEmmanuel Vadot 
31330c05743SEmmanuel Vadot static void
aw_nmi_post_ithread(device_t dev,struct intr_irqsrc * isrc)31430c05743SEmmanuel Vadot aw_nmi_post_ithread(device_t dev, struct intr_irqsrc *isrc)
31530c05743SEmmanuel Vadot {
31630c05743SEmmanuel Vadot 
31730c05743SEmmanuel Vadot 	arm_irq_memory_barrier(0);
31830c05743SEmmanuel Vadot 	aw_nmi_enable_intr(dev, isrc);
31930c05743SEmmanuel Vadot }
32030c05743SEmmanuel Vadot 
32130c05743SEmmanuel Vadot static void
aw_nmi_post_filter(device_t dev,struct intr_irqsrc * isrc)32230c05743SEmmanuel Vadot aw_nmi_post_filter(device_t dev, struct intr_irqsrc *isrc)
32330c05743SEmmanuel Vadot {
32430c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
32530c05743SEmmanuel Vadot 
32630c05743SEmmanuel Vadot 	sc = device_get_softc(dev);
32730c05743SEmmanuel Vadot 
32830c05743SEmmanuel Vadot 	arm_irq_memory_barrier(0);
329c4717ac0SKyle Evans 	SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK);
33030c05743SEmmanuel Vadot }
33130c05743SEmmanuel Vadot 
33230c05743SEmmanuel Vadot static int
aw_nmi_probe(device_t dev)33330c05743SEmmanuel Vadot aw_nmi_probe(device_t dev)
33430c05743SEmmanuel Vadot {
33530c05743SEmmanuel Vadot 
33630c05743SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
33730c05743SEmmanuel Vadot 		return (ENXIO);
33830c05743SEmmanuel Vadot 
33930c05743SEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
34030c05743SEmmanuel Vadot 		return (ENXIO);
34130c05743SEmmanuel Vadot 	device_set_desc(dev, "Allwinner NMI Controller");
34230c05743SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
34330c05743SEmmanuel Vadot }
34430c05743SEmmanuel Vadot 
34530c05743SEmmanuel Vadot static int
aw_nmi_attach(device_t dev)34630c05743SEmmanuel Vadot aw_nmi_attach(device_t dev)
34730c05743SEmmanuel Vadot {
34830c05743SEmmanuel Vadot 	struct aw_nmi_softc *sc;
34930c05743SEmmanuel Vadot 	phandle_t xref;
35030c05743SEmmanuel Vadot 
35130c05743SEmmanuel Vadot 	sc = device_get_softc(dev);
35230c05743SEmmanuel Vadot 	sc->dev = dev;
353c4717ac0SKyle Evans 	sc->cfg = (struct aw_nmi_reg_cfg *)
354c4717ac0SKyle Evans 	    ofw_bus_search_compatible(dev, compat_data)->ocd_data;
35530c05743SEmmanuel Vadot 
35630c05743SEmmanuel Vadot 	if (bus_alloc_resources(dev, aw_nmi_res_spec, sc->res) != 0) {
35730c05743SEmmanuel Vadot 		device_printf(dev, "can't allocate device resources\n");
35830c05743SEmmanuel Vadot 		return (ENXIO);
35930c05743SEmmanuel Vadot 	}
36030c05743SEmmanuel Vadot 	if ((bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC,
36130c05743SEmmanuel Vadot 	    aw_nmi_intr, NULL, sc, &sc->intrcookie))) {
36230c05743SEmmanuel Vadot 		device_printf(dev, "unable to register interrupt handler\n");
36330c05743SEmmanuel Vadot 		bus_release_resources(dev, aw_nmi_res_spec, sc->res);
36430c05743SEmmanuel Vadot 		return (ENXIO);
36530c05743SEmmanuel Vadot 	}
36630c05743SEmmanuel Vadot 
36730c05743SEmmanuel Vadot 	/* Disable and clear interrupts */
3681c62664fSEmmanuel Vadot 	SC_NMI_WRITE(sc, sc->cfg->enable_reg, ~NMI_IRQ_ENABLE);
369c4717ac0SKyle Evans 	SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK);
37030c05743SEmmanuel Vadot 
37130c05743SEmmanuel Vadot 	xref = OF_xref_from_node(ofw_bus_get_node(dev));
37230c05743SEmmanuel Vadot 	/* Register our isrc */
37330c05743SEmmanuel Vadot 	sc->intr.irq = 0;
37430c05743SEmmanuel Vadot 	sc->intr.pol = INTR_POLARITY_CONFORM;
37530c05743SEmmanuel Vadot 	sc->intr.tri = INTR_TRIGGER_CONFORM;
37630c05743SEmmanuel Vadot 	if (intr_isrc_register(&sc->intr.isrc, sc->dev, 0, "%s,%u",
37730c05743SEmmanuel Vadot 	      device_get_nameunit(sc->dev), sc->intr.irq) != 0)
37830c05743SEmmanuel Vadot 		goto error;
37930c05743SEmmanuel Vadot 
3809346e913SAndrew Turner 	if (intr_pic_register(dev, (intptr_t)xref) == NULL) {
38130c05743SEmmanuel Vadot 		device_printf(dev, "could not register pic\n");
38230c05743SEmmanuel Vadot 		goto error;
38330c05743SEmmanuel Vadot 	}
38430c05743SEmmanuel Vadot 	return (0);
38530c05743SEmmanuel Vadot 
38630c05743SEmmanuel Vadot error:
38730c05743SEmmanuel Vadot 	bus_teardown_intr(dev, sc->res[1], sc->intrcookie);
38830c05743SEmmanuel Vadot 	bus_release_resources(dev, aw_nmi_res_spec, sc->res);
38930c05743SEmmanuel Vadot 	return (ENXIO);
39030c05743SEmmanuel Vadot }
39130c05743SEmmanuel Vadot 
39230c05743SEmmanuel Vadot static device_method_t aw_nmi_methods[] = {
39330c05743SEmmanuel Vadot 	DEVMETHOD(device_probe,		aw_nmi_probe),
39430c05743SEmmanuel Vadot 	DEVMETHOD(device_attach,	aw_nmi_attach),
39530c05743SEmmanuel Vadot 
39630c05743SEmmanuel Vadot 	/* Interrupt controller interface */
39730c05743SEmmanuel Vadot 	DEVMETHOD(pic_disable_intr,	aw_nmi_disable_intr),
39830c05743SEmmanuel Vadot 	DEVMETHOD(pic_enable_intr,	aw_nmi_enable_intr),
39930c05743SEmmanuel Vadot 	DEVMETHOD(pic_map_intr,		aw_nmi_map_intr),
40030c05743SEmmanuel Vadot 	DEVMETHOD(pic_setup_intr,	aw_nmi_setup_intr),
40130c05743SEmmanuel Vadot 	DEVMETHOD(pic_teardown_intr,	aw_nmi_teardown_intr),
40230c05743SEmmanuel Vadot 	DEVMETHOD(pic_post_filter,	aw_nmi_post_filter),
40330c05743SEmmanuel Vadot 	DEVMETHOD(pic_post_ithread,	aw_nmi_post_ithread),
40430c05743SEmmanuel Vadot 	DEVMETHOD(pic_pre_ithread,	aw_nmi_pre_ithread),
40530c05743SEmmanuel Vadot 
40630c05743SEmmanuel Vadot 	{0, 0},
40730c05743SEmmanuel Vadot };
40830c05743SEmmanuel Vadot 
40930c05743SEmmanuel Vadot static driver_t aw_nmi_driver = {
41030c05743SEmmanuel Vadot 	"aw_nmi",
41130c05743SEmmanuel Vadot 	aw_nmi_methods,
41230c05743SEmmanuel Vadot 	sizeof(struct aw_nmi_softc),
41330c05743SEmmanuel Vadot };
41430c05743SEmmanuel Vadot 
415*7e1e2ba1SJohn Baldwin EARLY_DRIVER_MODULE(aw_nmi, simplebus, aw_nmi_driver, 0, 0,
416*7e1e2ba1SJohn Baldwin     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
417