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