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