xref: /openbsd/sys/arch/armv7/sunxi/sxiintc.c (revision 72784dda)
1*72784ddaSkettenis /*	$OpenBSD: sxiintc.c,v 1.6 2019/10/05 15:44:57 kettenis Exp $	*/
22b7dae4aSkettenis /*
32b7dae4aSkettenis  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
42b7dae4aSkettenis  * Copyright (c) 2013 Artturi Alm
52b7dae4aSkettenis  *
62b7dae4aSkettenis  * Permission to use, copy, modify, and distribute this software for any
72b7dae4aSkettenis  * purpose with or without fee is hereby granted, provided that the above
82b7dae4aSkettenis  * copyright notice and this permission notice appear in all copies.
92b7dae4aSkettenis  *
102b7dae4aSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112b7dae4aSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122b7dae4aSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132b7dae4aSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142b7dae4aSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152b7dae4aSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162b7dae4aSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172b7dae4aSkettenis  */
182b7dae4aSkettenis 
192b7dae4aSkettenis #include <sys/param.h>
202b7dae4aSkettenis #include <sys/systm.h>
212b7dae4aSkettenis #include <sys/queue.h>
222b7dae4aSkettenis #include <sys/malloc.h>
232b7dae4aSkettenis #include <sys/device.h>
242b7dae4aSkettenis #include <sys/evcount.h>
252b7dae4aSkettenis 
262b7dae4aSkettenis #include <machine/bus.h>
272b7dae4aSkettenis #include <machine/fdt.h>
282b7dae4aSkettenis 
290ea1c705Spatrick #include <dev/fdt/sunxireg.h>
302b7dae4aSkettenis #include <armv7/sunxi/sxiintc.h>
312b7dae4aSkettenis 
322b7dae4aSkettenis #include <dev/ofw/openfirm.h>
332b7dae4aSkettenis #include <dev/ofw/fdt.h>
342b7dae4aSkettenis 
352b7dae4aSkettenis #ifdef DEBUG_INTC
362b7dae4aSkettenis #define DPRINTF(x)	do { if (sxiintcdebug) printf x; } while (0)
372b7dae4aSkettenis #define DPRINTFN(n,x)	do { if (sxiintcdebug>(n)) printf x; } while (0)
382b7dae4aSkettenis int	sxiintcdebug = 10;
392b7dae4aSkettenis char *ipl_strtbl[NIPL] = {
402b7dae4aSkettenis 	"IPL_NONE",
412b7dae4aSkettenis 	"IPL_SOFT",
422b7dae4aSkettenis 	"IPL_SOFTCLOCK",
432b7dae4aSkettenis 	"IPL_SOFTNET",
442b7dae4aSkettenis 	"IPL_SOFTTTY",
452b7dae4aSkettenis 	"IPL_BIO|IPL_USB",
462b7dae4aSkettenis 	"IPL_NET",
472b7dae4aSkettenis 	"IPL_TTY",
482b7dae4aSkettenis 	"IPL_VM",
492b7dae4aSkettenis 	"IPL_AUDIO",
502b7dae4aSkettenis 	"IPL_CLOCK",
512b7dae4aSkettenis 	"IPL_STATCLOCK",
522b7dae4aSkettenis 	"IPL_SCHED|IPL_HIGH"
532b7dae4aSkettenis };
542b7dae4aSkettenis #else
552b7dae4aSkettenis #define DPRINTF(x)
562b7dae4aSkettenis #define DPRINTFN(n,x)
572b7dae4aSkettenis #endif
582b7dae4aSkettenis 
592b7dae4aSkettenis #define NIRQ			96
602b7dae4aSkettenis #define NBANKS			3
612b7dae4aSkettenis #define NIRQPRIOREGS		5
622b7dae4aSkettenis 
632b7dae4aSkettenis /* registers */
642b7dae4aSkettenis #define INTC_VECTOR_REG		0x00
652b7dae4aSkettenis #define INTC_BASE_ADR_REG	0x04
662b7dae4aSkettenis #define INTC_PROTECTION_REG	0x08
672b7dae4aSkettenis #define INTC_NMI_CTRL_REG	0x0c
682b7dae4aSkettenis 
692b7dae4aSkettenis #define INTC_IRQ_PENDING_REG0	0x10
702b7dae4aSkettenis #define INTC_IRQ_PENDING_REG1	0x14
712b7dae4aSkettenis #define INTC_IRQ_PENDING_REG2	0x18
722b7dae4aSkettenis 
732b7dae4aSkettenis #define INTC_SELECT_REG0	0x30
742b7dae4aSkettenis #define INTC_SELECT_REG1	0x34
752b7dae4aSkettenis #define INTC_SELECT_REG2	0x38
762b7dae4aSkettenis 
772b7dae4aSkettenis #define INTC_ENABLE_REG0	0x40
782b7dae4aSkettenis #define INTC_ENABLE_REG1	0x44
792b7dae4aSkettenis #define INTC_ENABLE_REG2	0x48
802b7dae4aSkettenis 
812b7dae4aSkettenis #define INTC_MASK_REG0		0x50
822b7dae4aSkettenis #define INTC_MASK_REG1		0x54
832b7dae4aSkettenis #define INTC_MASK_REG2		0x58
842b7dae4aSkettenis 
852b7dae4aSkettenis #define INTC_RESP_REG0		0x60
862b7dae4aSkettenis #define INTC_RESP_REG1		0x64
872b7dae4aSkettenis #define INTC_RESP_REG2		0x68
882b7dae4aSkettenis 
892b7dae4aSkettenis #define INTC_PRIO_REG0		0x80
902b7dae4aSkettenis #define INTC_PRIO_REG1		0x84
912b7dae4aSkettenis #define INTC_PRIO_REG2		0x88
922b7dae4aSkettenis #define INTC_PRIO_REG3		0x8c
932b7dae4aSkettenis #define INTC_PRIO_REG4		0x90
942b7dae4aSkettenis 
952b7dae4aSkettenis #define INTC_IRQ_PENDING_REG(_b)	(0x10 + ((_b) * 4))
962b7dae4aSkettenis #define INTC_FIQ_PENDING_REG(_b)	(0x20 + ((_b) * 4))
972b7dae4aSkettenis #define INTC_SELECT_REG(_b)		(0x30 + ((_b) * 4))
982b7dae4aSkettenis #define INTC_ENABLE_REG(_b)		(0x40 + ((_b) * 4))
992b7dae4aSkettenis #define INTC_MASK_REG(_b)		(0x50 + ((_b) * 4))
1002b7dae4aSkettenis #define INTC_RESP_REG(_b)		(0x60 + ((_b) * 4))
1012b7dae4aSkettenis #define INTC_PRIO_REG(_b)		(0x80 + ((_b) * 4))
1022b7dae4aSkettenis 
1032b7dae4aSkettenis #define IRQ2REG32(i)		(((i) >> 5) & 0x3)
1042b7dae4aSkettenis #define IRQ2BIT32(i)		((i) & 0x1f)
1052b7dae4aSkettenis 
1062b7dae4aSkettenis #define IRQ2REG16(i)		(((i) >> 4) & 0x5)
1072b7dae4aSkettenis #define IRQ2BIT16(i)		(((i) & 0x0f) * 2)
1082b7dae4aSkettenis 
1092b7dae4aSkettenis #define INTC_IRQ_HIPRIO		0x3
1102b7dae4aSkettenis #define INTC_IRQ_ENABLED	0x2
1112b7dae4aSkettenis #define INTC_IRQ_DISABLED	0x1
1122b7dae4aSkettenis #define INTC_IRQ_LOWPRIO	0x0
1132b7dae4aSkettenis #define INTC_PRIOCLEAR(i)	(~(INTC_IRQ_HIPRIO << IRQ2BIT16((i))))
1142b7dae4aSkettenis #define INTC_PRIOENABLE(i)	(INTC_IRQ_ENABLED << IRQ2BIT16((i)))
1152b7dae4aSkettenis #define INTC_PRIOHI(i)		(INTC_IRQ_HIPRIO << IRQ2BIT16((i)))
1162b7dae4aSkettenis 
1172b7dae4aSkettenis 
1182b7dae4aSkettenis struct intrhand {
1192b7dae4aSkettenis 	TAILQ_ENTRY(intrhand) ih_list;	/* link on intrq list */
1202b7dae4aSkettenis 	int (*ih_func)(void *);		/* handler */
1212b7dae4aSkettenis 	void *ih_arg;			/* arg for handler */
1222b7dae4aSkettenis 	int ih_ipl;			/* IPL_* */
1232b7dae4aSkettenis 	int ih_irq;			/* IRQ number */
1242b7dae4aSkettenis 	struct evcount	ih_count;
1252b7dae4aSkettenis 	char *ih_name;
1262b7dae4aSkettenis };
1272b7dae4aSkettenis 
1282b7dae4aSkettenis struct intrq {
1292b7dae4aSkettenis 	TAILQ_HEAD(, intrhand) iq_list;	/* handler list */
1302b7dae4aSkettenis 	int iq_irq;			/* IRQ to mask while handling */
1312b7dae4aSkettenis 	int iq_levels;			/* IPL_*'s this IRQ has */
1322b7dae4aSkettenis 	int iq_ist;			/* share type */
1332b7dae4aSkettenis };
1342b7dae4aSkettenis 
1352b7dae4aSkettenis volatile int a1xsoftint_pending;
1362b7dae4aSkettenis 
1372b7dae4aSkettenis struct intrq sxiintc_handler[NIRQ];
1382b7dae4aSkettenis u_int32_t sxiintc_smask[NIPL];
1392b7dae4aSkettenis u_int32_t sxiintc_imask[NBANKS][NIPL];
1402b7dae4aSkettenis struct interrupt_controller sxiintc_ic;
1412b7dae4aSkettenis 
1422b7dae4aSkettenis bus_space_tag_t		sxiintc_iot;
1432b7dae4aSkettenis bus_space_handle_t	sxiintc_ioh;
1442b7dae4aSkettenis int			sxiintc_nirq;
1452b7dae4aSkettenis 
1462b7dae4aSkettenis int	sxiintc_match(struct device *, void *, void *);
1472b7dae4aSkettenis void	sxiintc_attach(struct device *, struct device *, void *);
1482b7dae4aSkettenis int	sxiintc_spllower(int);
1492b7dae4aSkettenis int	sxiintc_splraise(int);
1502b7dae4aSkettenis void	sxiintc_setipl(int);
1512b7dae4aSkettenis void	sxiintc_calc_masks(void);
1522b7dae4aSkettenis void	*sxiintc_intr_establish_fdt(void *, int *, int, int (*)(void *),
1532b7dae4aSkettenis 	    void *, char *);
1542b7dae4aSkettenis 
1552b7dae4aSkettenis struct cfattach	sxiintc_ca = {
1562b7dae4aSkettenis 	sizeof (struct device), sxiintc_match, sxiintc_attach
1572b7dae4aSkettenis };
1582b7dae4aSkettenis 
1592b7dae4aSkettenis struct cfdriver sxiintc_cd = {
1602b7dae4aSkettenis 	NULL, "sxiintc", DV_DULL
1612b7dae4aSkettenis };
1622b7dae4aSkettenis 
1632b7dae4aSkettenis int sxiintc_attached = 0;
1642b7dae4aSkettenis 
1652b7dae4aSkettenis int
1662b7dae4aSkettenis sxiintc_match(struct device *parent, void *match, void *aux)
1672b7dae4aSkettenis {
1682b7dae4aSkettenis 	struct fdt_attach_args *faa = aux;
1692b7dae4aSkettenis 
1702b7dae4aSkettenis 	return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ic");
1712b7dae4aSkettenis }
1722b7dae4aSkettenis 
1732b7dae4aSkettenis void
1742b7dae4aSkettenis sxiintc_attach(struct device *parent, struct device *self, void *aux)
1752b7dae4aSkettenis {
1762b7dae4aSkettenis 	struct fdt_attach_args *faa = aux;
1772b7dae4aSkettenis 	int i, j;
1782b7dae4aSkettenis 
1792b7dae4aSkettenis 	sxiintc_iot = faa->fa_iot;
1802b7dae4aSkettenis 	if (bus_space_map(sxiintc_iot, faa->fa_reg[0].addr,
1812b7dae4aSkettenis 	    faa->fa_reg[0].size, 0, &sxiintc_ioh))
1822b7dae4aSkettenis 		panic("sxiintc_attach: bus_space_map failed!");
1832b7dae4aSkettenis 
1842b7dae4aSkettenis 	/* disable/mask/clear all interrupts */
1852b7dae4aSkettenis 	for (i = 0; i < NBANKS; i++) {
1862b7dae4aSkettenis 		bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_ENABLE_REG(i), 0);
1872b7dae4aSkettenis 		bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_MASK_REG(i), 0);
1882b7dae4aSkettenis 		bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_IRQ_PENDING_REG(i),
1892b7dae4aSkettenis 		    0xffffffff);
1902b7dae4aSkettenis 		for (j = 0; j < NIPL; j++)
1912b7dae4aSkettenis 			sxiintc_imask[i][j] = 0;
1922b7dae4aSkettenis 	}
1932b7dae4aSkettenis 
1942b7dae4aSkettenis 	/* XXX */
1952b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_PROTECTION_REG, 1);
1962b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_NMI_CTRL_REG, 0);
1972b7dae4aSkettenis 
1982b7dae4aSkettenis 	for (i = 0; i < NIRQ; i++)
1992b7dae4aSkettenis 		TAILQ_INIT(&sxiintc_handler[i].iq_list);
2002b7dae4aSkettenis 
2012b7dae4aSkettenis 	sxiintc_calc_masks();
2022b7dae4aSkettenis 
2032b7dae4aSkettenis 	arm_init_smask();
2042b7dae4aSkettenis 	sxiintc_attached = 1;
2052b7dae4aSkettenis 
2062b7dae4aSkettenis 	/* insert self as interrupt handler */
2072b7dae4aSkettenis 	arm_set_intr_handler(sxiintc_splraise, sxiintc_spllower, sxiintc_splx,
2082b7dae4aSkettenis 	    sxiintc_setipl,
2092b7dae4aSkettenis 	    sxiintc_intr_establish, sxiintc_intr_disestablish, sxiintc_intr_string,
2102b7dae4aSkettenis 	    sxiintc_irq_handler);
2112b7dae4aSkettenis 	sxiintc_setipl(IPL_HIGH);  /* XXX ??? */
2122b7dae4aSkettenis 	enable_interrupts(PSR_I);
2132b7dae4aSkettenis 	printf("\n");
2142b7dae4aSkettenis 
2152b7dae4aSkettenis 	sxiintc_ic.ic_node = faa->fa_node;
2162b7dae4aSkettenis 	sxiintc_ic.ic_establish = sxiintc_intr_establish_fdt;
2172b7dae4aSkettenis 	arm_intr_register_fdt(&sxiintc_ic);
2182b7dae4aSkettenis }
2192b7dae4aSkettenis 
2202b7dae4aSkettenis void
2212b7dae4aSkettenis sxiintc_calc_masks(void)
2222b7dae4aSkettenis {
2232b7dae4aSkettenis 	struct cpu_info *ci = curcpu();
2242b7dae4aSkettenis 	int irq;
2252b7dae4aSkettenis 	struct intrhand *ih;
2262b7dae4aSkettenis 	int i;
2272b7dae4aSkettenis 
2282b7dae4aSkettenis 	for (irq = 0; irq < NIRQ; irq++) {
2292b7dae4aSkettenis 		int max = IPL_NONE;
2302b7dae4aSkettenis 		int min = IPL_HIGH;
2312b7dae4aSkettenis 		TAILQ_FOREACH(ih, &sxiintc_handler[irq].iq_list, ih_list) {
2322b7dae4aSkettenis 			if (ih->ih_ipl > max)
2332b7dae4aSkettenis 				max = ih->ih_ipl;
2342b7dae4aSkettenis 			if (ih->ih_ipl < min)
2352b7dae4aSkettenis 				min = ih->ih_ipl;
2362b7dae4aSkettenis 		}
2372b7dae4aSkettenis 
2382b7dae4aSkettenis 		sxiintc_handler[irq].iq_irq = max;
2392b7dae4aSkettenis 
2402b7dae4aSkettenis 		if (max == IPL_NONE)
2412b7dae4aSkettenis 			min = IPL_NONE;
2422b7dae4aSkettenis 
2432b7dae4aSkettenis #ifdef DEBUG_INTC
2442b7dae4aSkettenis 		if (min != IPL_NONE) {
2452b7dae4aSkettenis 			printf("irq %d to block at %d %d reg %d bit %d\n",
2462b7dae4aSkettenis 			    irq, max, min, IRQ2REG32(irq),
2472b7dae4aSkettenis 			    IRQ2BIT32(irq));
2482b7dae4aSkettenis 		}
2492b7dae4aSkettenis #endif
2502b7dae4aSkettenis 		/* Enable interrupts at lower levels, clear -> enable */
2512b7dae4aSkettenis 		for (i = 0; i < min; i++)
2522b7dae4aSkettenis 			sxiintc_imask[IRQ2REG32(irq)][i] &=
2532b7dae4aSkettenis 			    ~(1 << IRQ2BIT32(irq));
2542b7dae4aSkettenis 		for (; i < NIPL; i++)
2552b7dae4aSkettenis 			sxiintc_imask[IRQ2REG32(irq)][i] |=
2562b7dae4aSkettenis 			    (1 << IRQ2BIT32(irq));
2572b7dae4aSkettenis 		/* XXX - set enable/disable, priority */
2582b7dae4aSkettenis 	}
2592b7dae4aSkettenis 
2602b7dae4aSkettenis 	sxiintc_setipl(ci->ci_cpl);
2612b7dae4aSkettenis }
2622b7dae4aSkettenis 
2632b7dae4aSkettenis void
2642b7dae4aSkettenis sxiintc_splx(int new)
2652b7dae4aSkettenis {
2662b7dae4aSkettenis 	struct cpu_info *ci = curcpu();
2672b7dae4aSkettenis 	sxiintc_setipl(new);
2682b7dae4aSkettenis 
2692b7dae4aSkettenis 	if (ci->ci_ipending & arm_smask[ci->ci_cpl])
2702b7dae4aSkettenis 		arm_do_pending_intr(ci->ci_cpl);
2712b7dae4aSkettenis }
2722b7dae4aSkettenis 
2732b7dae4aSkettenis int
2742b7dae4aSkettenis sxiintc_spllower(int new)
2752b7dae4aSkettenis {
2762b7dae4aSkettenis 	struct cpu_info *ci = curcpu();
2772b7dae4aSkettenis 	int old = ci->ci_cpl;
2782b7dae4aSkettenis 	sxiintc_splx(new);
2792b7dae4aSkettenis 	return (old);
2802b7dae4aSkettenis }
2812b7dae4aSkettenis 
2822b7dae4aSkettenis int
2832b7dae4aSkettenis sxiintc_splraise(int new)
2842b7dae4aSkettenis {
2852b7dae4aSkettenis 	struct cpu_info *ci = curcpu();
2862b7dae4aSkettenis 	int old;
2872b7dae4aSkettenis 	old = ci->ci_cpl;
2882b7dae4aSkettenis 
2892b7dae4aSkettenis 	/*
2902b7dae4aSkettenis 	 * setipl must always be called because there is a race window
2912b7dae4aSkettenis 	 * where the variable is updated before the mask is set
2922b7dae4aSkettenis 	 * an interrupt occurs in that window without the mask always
2932b7dae4aSkettenis 	 * being set, the hardware might not get updated on the next
2942b7dae4aSkettenis 	 * splraise completely messing up spl protection.
2952b7dae4aSkettenis 	 */
2962b7dae4aSkettenis 	if (old > new)
2972b7dae4aSkettenis 		new = old;
2982b7dae4aSkettenis 
2992b7dae4aSkettenis 	sxiintc_setipl(new);
3002b7dae4aSkettenis 
3012b7dae4aSkettenis 	return (old);
3022b7dae4aSkettenis }
3032b7dae4aSkettenis 
3042b7dae4aSkettenis void
3052b7dae4aSkettenis sxiintc_setipl(int new)
3062b7dae4aSkettenis {
3072b7dae4aSkettenis 	struct cpu_info *ci = curcpu();
3082b7dae4aSkettenis 	int i, psw;
3092b7dae4aSkettenis #if 1
3102b7dae4aSkettenis 	/*
3112b7dae4aSkettenis 	 * XXX not needed, because all interrupts are disabled
3122b7dae4aSkettenis 	 * by default, so touching maskregs has no effect, i hope.
3132b7dae4aSkettenis 	 */
3142b7dae4aSkettenis 	if (sxiintc_attached == 0) {
3152b7dae4aSkettenis 		ci->ci_cpl = new;
3162b7dae4aSkettenis 		return;
3172b7dae4aSkettenis 	}
3182b7dae4aSkettenis #endif
3192b7dae4aSkettenis 	psw = disable_interrupts(PSR_I);
3202b7dae4aSkettenis 	ci->ci_cpl = new;
3212b7dae4aSkettenis 	for (i = 0; i < NBANKS; i++)
3222b7dae4aSkettenis 		bus_space_write_4(sxiintc_iot, sxiintc_ioh,
3232b7dae4aSkettenis 		    INTC_MASK_REG(i), sxiintc_imask[i][new]);
3242b7dae4aSkettenis 	restore_interrupts(psw);
3252b7dae4aSkettenis }
3262b7dae4aSkettenis 
3272b7dae4aSkettenis void
3282b7dae4aSkettenis sxiintc_irq_handler(void *frame)
3292b7dae4aSkettenis {
3302b7dae4aSkettenis 	struct intrhand *ih;
3312b7dae4aSkettenis 	void *arg;
3322b7dae4aSkettenis 	uint32_t pr;
3332b7dae4aSkettenis 	int irq, prio, s;
3342b7dae4aSkettenis 
3352b7dae4aSkettenis 	irq = bus_space_read_4(sxiintc_iot, sxiintc_ioh, INTC_VECTOR_REG) >> 2;
3362b7dae4aSkettenis 	if (irq == 0)
3372b7dae4aSkettenis 		return;
3382b7dae4aSkettenis 
3392b7dae4aSkettenis 	prio = sxiintc_handler[irq].iq_irq;
3402b7dae4aSkettenis 	s = sxiintc_splraise(prio);
3412b7dae4aSkettenis 	splassert(prio);
3422b7dae4aSkettenis 
3432b7dae4aSkettenis 	pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
3442b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)));
3452b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh,
3462b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)),
3472b7dae4aSkettenis 	    pr & ~(1 << IRQ2BIT32(irq)));
3482b7dae4aSkettenis 
3492b7dae4aSkettenis 	/* clear pending */
3502b7dae4aSkettenis 	pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
3512b7dae4aSkettenis 	    INTC_IRQ_PENDING_REG(IRQ2REG32(irq)));
3522b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh,
3532b7dae4aSkettenis 	    INTC_IRQ_PENDING_REG(IRQ2REG32(irq)),
3542b7dae4aSkettenis 	    pr | (1 << IRQ2BIT32(irq)));
3552b7dae4aSkettenis 
3562b7dae4aSkettenis 	pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
3572b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)));
3582b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh,
3592b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)),
3602b7dae4aSkettenis 	    pr | (1 << IRQ2BIT32(irq)));
3612b7dae4aSkettenis 
3622b7dae4aSkettenis 	TAILQ_FOREACH(ih, &sxiintc_handler[irq].iq_list, ih_list) {
3632b7dae4aSkettenis 		if (ih->ih_arg != 0)
3642b7dae4aSkettenis 			arg = ih->ih_arg;
3652b7dae4aSkettenis 		else
3662b7dae4aSkettenis 			arg = frame;
3672b7dae4aSkettenis 
3682b7dae4aSkettenis 		if (ih->ih_func(arg))
3692b7dae4aSkettenis 			ih->ih_count.ec_count++;
3702b7dae4aSkettenis 	}
3712b7dae4aSkettenis 	sxiintc_splx(s);
3722b7dae4aSkettenis }
3732b7dae4aSkettenis 
3742b7dae4aSkettenis void *
3752b7dae4aSkettenis sxiintc_intr_establish(int irq, int level, int (*func)(void *),
3762b7dae4aSkettenis     void *arg, char *name)
3772b7dae4aSkettenis {
3782b7dae4aSkettenis 	int psw;
3792b7dae4aSkettenis 	struct intrhand *ih;
3802b7dae4aSkettenis 	uint32_t er;
3812b7dae4aSkettenis 
3822b7dae4aSkettenis 	if (irq <= 0 || irq >= NIRQ)
3832b7dae4aSkettenis 		panic("intr_establish: bogus irq %d %s\n", irq, name);
3842b7dae4aSkettenis 
3852b7dae4aSkettenis 	DPRINTF(("intr_establish: irq %d level %d [%s]\n", irq, level,
3862b7dae4aSkettenis 	    name != NULL ? name : "NULL"));
3872b7dae4aSkettenis 
3882b7dae4aSkettenis 	psw = disable_interrupts(PSR_I);
3892b7dae4aSkettenis 
390a8511e66Spatrick 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
3912b7dae4aSkettenis 	ih->ih_func = func;
3922b7dae4aSkettenis 	ih->ih_arg = arg;
393*72784ddaSkettenis 	ih->ih_ipl = level & IPL_IRQMASK;
3942b7dae4aSkettenis 	ih->ih_irq = irq;
3952b7dae4aSkettenis 	ih->ih_name = name;
3962b7dae4aSkettenis 
3972b7dae4aSkettenis 	TAILQ_INSERT_TAIL(&sxiintc_handler[irq].iq_list, ih, ih_list);
3982b7dae4aSkettenis 
3992b7dae4aSkettenis 	if (name != NULL)
4002b7dae4aSkettenis 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
4012b7dae4aSkettenis 
4022b7dae4aSkettenis 	er = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
4032b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)));
4042b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh,
4052b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)),
4062b7dae4aSkettenis 	    er | (1 << IRQ2BIT32(irq)));
4072b7dae4aSkettenis 
4082b7dae4aSkettenis 	sxiintc_calc_masks();
4092b7dae4aSkettenis 
4102b7dae4aSkettenis 	restore_interrupts(psw);
4112b7dae4aSkettenis 	return (ih);
4122b7dae4aSkettenis }
4132b7dae4aSkettenis 
4142b7dae4aSkettenis void *
4152b7dae4aSkettenis sxiintc_intr_establish_fdt(void *cookie, int *cell, int level,
4162b7dae4aSkettenis     int (*func)(void *), void *arg, char *name)
4172b7dae4aSkettenis {
4182b7dae4aSkettenis 	return sxiintc_intr_establish(cell[0], level, func, arg, name);
4192b7dae4aSkettenis }
4202b7dae4aSkettenis 
4212b7dae4aSkettenis void
4222b7dae4aSkettenis sxiintc_intr_disestablish(void *cookie)
4232b7dae4aSkettenis {
4242b7dae4aSkettenis 	struct intrhand *ih = cookie;
4252b7dae4aSkettenis 	int irq = ih->ih_irq;
4262b7dae4aSkettenis 	int psw;
4272b7dae4aSkettenis 	uint32_t er;
4282b7dae4aSkettenis 
4292b7dae4aSkettenis 	psw = disable_interrupts(PSR_I);
4302b7dae4aSkettenis 
4312b7dae4aSkettenis 	TAILQ_REMOVE(&sxiintc_handler[irq].iq_list, ih, ih_list);
4322b7dae4aSkettenis 
4332b7dae4aSkettenis 	if (ih->ih_name != NULL)
4342b7dae4aSkettenis 		evcount_detach(&ih->ih_count);
4352b7dae4aSkettenis 
4362b7dae4aSkettenis 	free(ih, M_DEVBUF, 0);
4372b7dae4aSkettenis 
4382b7dae4aSkettenis 	er = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
4392b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)));
4402b7dae4aSkettenis 	bus_space_write_4(sxiintc_iot, sxiintc_ioh,
4412b7dae4aSkettenis 	    INTC_ENABLE_REG(IRQ2REG32(irq)),
4422b7dae4aSkettenis 	    er & ~(1 << IRQ2BIT32(irq)));
4432b7dae4aSkettenis 
4442b7dae4aSkettenis 	sxiintc_calc_masks();
4452b7dae4aSkettenis 
4462b7dae4aSkettenis 	restore_interrupts(psw);
4472b7dae4aSkettenis }
4482b7dae4aSkettenis 
4492b7dae4aSkettenis const char *
4502b7dae4aSkettenis sxiintc_intr_string(void *cookie)
4512b7dae4aSkettenis {
4522b7dae4aSkettenis 	return "asd?";
4532b7dae4aSkettenis }
454