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