1 1.26 riastrad /* $NetBSD: pxa2x0_intr.c,v 1.26 2023/07/13 19:42:24 riastradh Exp $ */ 2 1.1 bsh 3 1.1 bsh /* 4 1.1 bsh * Copyright (c) 2002 Genetec Corporation. All rights reserved. 5 1.1 bsh * Written by Hiroyuki Bessho for Genetec Corporation. 6 1.1 bsh * 7 1.1 bsh * Redistribution and use in source and binary forms, with or without 8 1.1 bsh * modification, are permitted provided that the following conditions 9 1.1 bsh * are met: 10 1.1 bsh * 1. Redistributions of source code must retain the above copyright 11 1.1 bsh * notice, this list of conditions and the following disclaimer. 12 1.1 bsh * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 bsh * notice, this list of conditions and the following disclaimer in the 14 1.1 bsh * documentation and/or other materials provided with the distribution. 15 1.1 bsh * 3. All advertising materials mentioning features or use of this software 16 1.1 bsh * must display the following acknowledgement: 17 1.1 bsh * This product includes software developed for the NetBSD Project by 18 1.1 bsh * Genetec Corporation. 19 1.23 skrll * 4. The name of Genetec Corporation may not be used to endorse or 20 1.1 bsh * promote products derived from this software without specific prior 21 1.1 bsh * written permission. 22 1.1 bsh * 23 1.1 bsh * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 24 1.1 bsh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 1.1 bsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 1.1 bsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 27 1.1 bsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.1 bsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.1 bsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 1.1 bsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 1.1 bsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 1.1 bsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 1.1 bsh * POSSIBILITY OF SUCH DAMAGE. 34 1.1 bsh */ 35 1.1 bsh 36 1.1 bsh /* 37 1.1 bsh * IRQ handler for the Intel PXA2X0 processor. 38 1.1 bsh * It has integrated interrupt controller. 39 1.1 bsh */ 40 1.5 lukem 41 1.5 lukem #include <sys/cdefs.h> 42 1.26 riastrad __KERNEL_RCSID(0, "$NetBSD: pxa2x0_intr.c,v 1.26 2023/07/13 19:42:24 riastradh Exp $"); 43 1.5 lukem 44 1.1 bsh #include <sys/param.h> 45 1.1 bsh #include <sys/systm.h> 46 1.3 scw 47 1.19 dyoung #include <sys/bus.h> 48 1.26 riastrad #include <sys/bitops.h> 49 1.26 riastrad 50 1.1 bsh #include <machine/intr.h> 51 1.3 scw #include <machine/lock.h> 52 1.1 bsh 53 1.6 bsh #include <arm/xscale/pxa2x0cpu.h> 54 1.1 bsh #include <arm/xscale/pxa2x0reg.h> 55 1.1 bsh #include <arm/xscale/pxa2x0var.h> 56 1.3 scw #include <arm/xscale/pxa2x0_intr.h> 57 1.1 bsh #include <arm/sa11x0/sa11x0_var.h> 58 1.3 scw 59 1.3 scw /* 60 1.3 scw * INTC autoconf glue 61 1.3 scw */ 62 1.18 matt static int pxaintc_match(device_t, cfdata_t, void *); 63 1.18 matt static void pxaintc_attach(device_t, device_t, void *); 64 1.3 scw 65 1.18 matt CFATTACH_DECL_NEW(pxaintc, 0, 66 1.3 scw pxaintc_match, pxaintc_attach, NULL, NULL); 67 1.3 scw 68 1.3 scw static int pxaintc_attached; 69 1.3 scw 70 1.3 scw static int stray_interrupt(void *); 71 1.3 scw static void init_interrupt_masks(void); 72 1.1 bsh 73 1.1 bsh /* 74 1.23 skrll * interrupt dispatch table. 75 1.1 bsh */ 76 1.1 bsh #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ 77 1.1 bsh struct intrhand { 78 1.1 bsh TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ 79 1.1 bsh int (*ih_func)(void *); /* handler */ 80 1.1 bsh void *ih_arg; /* arg for handler */ 81 1.1 bsh }; 82 1.1 bsh #endif 83 1.1 bsh 84 1.11 peter static struct intrhandler { 85 1.1 bsh #ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ 86 1.1 bsh TAILQ_HEAD(,intrhand) list; 87 1.1 bsh #else 88 1.1 bsh pxa2x0_irq_handler_t func; 89 1.1 bsh #endif 90 1.1 bsh void *cookie; /* NULL for stackframe */ 91 1.1 bsh /* struct evbnt ev; */ 92 1.1 bsh } handler[ICU_LEN]; 93 1.1 bsh 94 1.20 matt vaddr_t pxaic_base; 95 1.8 perry volatile int softint_pending; 96 1.8 perry volatile int intr_mask; 97 1.1 bsh /* interrupt masks for each level */ 98 1.1 bsh int pxa2x0_imask[NIPL]; 99 1.1 bsh static int extirq_level[ICU_LEN]; 100 1.1 bsh 101 1.3 scw 102 1.3 scw static int 103 1.18 matt pxaintc_match(device_t parent, cfdata_t cf, void *aux) 104 1.3 scw { 105 1.3 scw struct pxaip_attach_args *pxa = aux; 106 1.3 scw 107 1.3 scw if (pxaintc_attached || pxa->pxa_addr != PXA2X0_INTCTL_BASE) 108 1.3 scw return (0); 109 1.3 scw 110 1.3 scw return (1); 111 1.3 scw } 112 1.3 scw 113 1.3 scw void 114 1.18 matt pxaintc_attach(device_t parent, device_t self, void *args) 115 1.3 scw { 116 1.3 scw int i; 117 1.3 scw 118 1.3 scw pxaintc_attached = 1; 119 1.3 scw 120 1.3 scw aprint_normal(": Interrupt Controller\n"); 121 1.3 scw 122 1.3 scw #define SAIPIC_ICCR 0x14 123 1.3 scw 124 1.3 scw write_icu(SAIPIC_ICCR, 1); 125 1.3 scw write_icu(SAIPIC_MR, 0); 126 1.3 scw 127 1.3 scw for(i = 0; i < sizeof handler / sizeof handler[0]; ++i){ 128 1.3 scw handler[i].func = stray_interrupt; 129 1.3 scw handler[i].cookie = (void *)(intptr_t) i; 130 1.3 scw extirq_level[i] = IPL_SERIAL; 131 1.3 scw } 132 1.3 scw 133 1.3 scw init_interrupt_masks(); 134 1.3 scw 135 1.3 scw _splraise(IPL_SERIAL); 136 1.3 scw enable_interrupts(I32_bit); 137 1.3 scw } 138 1.3 scw 139 1.3 scw /* 140 1.3 scw * Invoked very early on from the board-specific initarm(), in order to 141 1.3 scw * inform us the virtual address of the interrupt controller's registers. 142 1.3 scw */ 143 1.3 scw void 144 1.3 scw pxa2x0_intr_bootstrap(vaddr_t addr) 145 1.3 scw { 146 1.3 scw 147 1.3 scw pxaic_base = addr; 148 1.3 scw } 149 1.3 scw 150 1.1 bsh /* 151 1.1 bsh * called from irq_entry. 152 1.1 bsh */ 153 1.1 bsh void 154 1.3 scw pxa2x0_irq_handler(void *arg) 155 1.1 bsh { 156 1.3 scw struct clockframe *frame = arg; 157 1.1 bsh uint32_t irqbits; 158 1.1 bsh int irqno; 159 1.1 bsh int saved_spl_level; 160 1.1 bsh 161 1.14 matt saved_spl_level = curcpu()->ci_cpl; 162 1.1 bsh 163 1.1 bsh /* get pending IRQs */ 164 1.1 bsh irqbits = read_icu(SAIPIC_IP); 165 1.1 bsh 166 1.26 riastrad while ((irqno = fls32(irqbits) - 1) >= 0) { 167 1.25 andvar /* XXX: Should we handle IRQs in priority order? */ 168 1.1 bsh 169 1.1 bsh /* raise spl to stop interrupts of lower priorities */ 170 1.3 scw if (saved_spl_level < extirq_level[irqno]) 171 1.1 bsh pxa2x0_setipl(extirq_level[irqno]); 172 1.1 bsh 173 1.1 bsh #ifdef notyet 174 1.1 bsh /* Enable interrupt */ 175 1.1 bsh #endif 176 1.1 bsh #ifndef MULTIPLE_HANDLERS_ON_ONE_IRQ 177 1.23 skrll (* handler[irqno].func)( 178 1.1 bsh handler[irqno].cookie == 0 179 1.1 bsh ? frame : handler[irqno].cookie ); 180 1.1 bsh #else 181 1.1 bsh /* process all handlers for this interrupt. 182 1.1 bsh XXX not yet */ 183 1.1 bsh #endif 184 1.23 skrll 185 1.1 bsh #ifdef notyet 186 1.1 bsh /* Disable interrupt */ 187 1.1 bsh #endif 188 1.1 bsh 189 1.1 bsh irqbits &= ~(1<<irqno); 190 1.1 bsh } 191 1.1 bsh 192 1.1 bsh /* restore spl to that was when this interrupt happen */ 193 1.1 bsh pxa2x0_setipl(saved_spl_level); 194 1.13 ad 195 1.14 matt #ifdef __HAVE_FAST_SOFTINTS 196 1.14 matt cpu_dosoftints(); 197 1.14 matt #endif 198 1.1 bsh } 199 1.1 bsh 200 1.1 bsh static int 201 1.3 scw stray_interrupt(void *cookie) 202 1.1 bsh { 203 1.1 bsh int irqno = (int)cookie; 204 1.15 rafal int irqmin = CPU_IS_PXA250 ? PXA250_IRQ_MIN : PXA270_IRQ_MIN; 205 1.15 rafal 206 1.3 scw printf("stray interrupt %d\n", irqno); 207 1.1 bsh 208 1.15 rafal if (irqmin <= irqno && irqno < ICU_LEN){ 209 1.1 bsh int save = disable_interrupts(I32_bit); 210 1.3 scw write_icu(SAIPIC_MR, 211 1.3 scw read_icu(SAIPIC_MR) & ~(1U<<irqno)); 212 1.1 bsh restore_interrupts(save); 213 1.1 bsh } 214 1.1 bsh 215 1.1 bsh return 0; 216 1.1 bsh } 217 1.1 bsh 218 1.1 bsh 219 1.1 bsh 220 1.1 bsh /* 221 1.1 bsh * Interrupt Mask Handling 222 1.1 bsh */ 223 1.1 bsh 224 1.1 bsh void 225 1.3 scw pxa2x0_update_intr_masks(int irqno, int level) 226 1.1 bsh { 227 1.1 bsh int mask = 1U<<irqno; 228 1.1 bsh int psw = disable_interrupts(I32_bit); 229 1.1 bsh int i; 230 1.1 bsh 231 1.3 scw for(i = 0; i < level; ++i) 232 1.3 scw pxa2x0_imask[i] |= mask; /* Enable interrupt at lower level */ 233 1.1 bsh 234 1.3 scw for( ; i < NIPL-1; ++i) 235 1.17 tsutsui pxa2x0_imask[i] &= ~mask; /* Disable interrupt at upper level */ 236 1.1 bsh 237 1.1 bsh /* 238 1.10 wiz * Enforce a hierarchy that gives "slow" device (or devices with 239 1.1 bsh * limited input buffer space/"real-time" requirements) a better 240 1.1 bsh * chance at not dropping data. 241 1.1 bsh */ 242 1.12 ad pxa2x0_imask[IPL_SCHED] &= pxa2x0_imask[IPL_VM]; 243 1.12 ad pxa2x0_imask[IPL_HIGH] &= pxa2x0_imask[IPL_SCHED]; 244 1.1 bsh 245 1.14 matt write_icu(SAIPIC_MR, pxa2x0_imask[curcpu()->ci_cpl]); 246 1.1 bsh 247 1.1 bsh restore_interrupts(psw); 248 1.1 bsh } 249 1.1 bsh 250 1.1 bsh 251 1.1 bsh static void 252 1.1 bsh init_interrupt_masks(void) 253 1.1 bsh { 254 1.1 bsh 255 1.3 scw /* 256 1.22 skrll * disable all interrupts until handlers are installed. 257 1.3 scw */ 258 1.16 bsh memset(pxa2x0_imask, 0, sizeof(pxa2x0_imask)); 259 1.1 bsh 260 1.1 bsh } 261 1.1 bsh 262 1.1 bsh #undef splx 263 1.1 bsh void 264 1.1 bsh splx(int ipl) 265 1.1 bsh { 266 1.1 bsh pxa2x0_splx(ipl); 267 1.1 bsh } 268 1.1 bsh 269 1.1 bsh #undef _splraise 270 1.1 bsh int 271 1.1 bsh _splraise(int ipl) 272 1.1 bsh { 273 1.1 bsh return pxa2x0_splraise(ipl); 274 1.1 bsh } 275 1.1 bsh 276 1.1 bsh #undef _spllower 277 1.1 bsh int 278 1.1 bsh _spllower(int ipl) 279 1.1 bsh { 280 1.1 bsh return pxa2x0_spllower(ipl); 281 1.1 bsh } 282 1.1 bsh 283 1.1 bsh void * 284 1.1 bsh pxa2x0_intr_establish(int irqno, int level, 285 1.3 scw int (*func)(void *), void *cookie) 286 1.1 bsh { 287 1.1 bsh int psw; 288 1.6 bsh int irqmin = CPU_IS_PXA250 ? PXA250_IRQ_MIN : PXA270_IRQ_MIN; 289 1.1 bsh 290 1.6 bsh if (irqno < irqmin || irqno >= ICU_LEN) 291 1.1 bsh panic("intr_establish: bogus irq number %d", irqno); 292 1.1 bsh 293 1.1 bsh psw = disable_interrupts(I32_bit); 294 1.1 bsh 295 1.1 bsh handler[irqno].cookie = cookie; 296 1.1 bsh handler[irqno].func = func; 297 1.1 bsh extirq_level[irqno] = level; 298 1.3 scw pxa2x0_update_intr_masks(irqno, level); 299 1.1 bsh 300 1.14 matt intr_mask = pxa2x0_imask[curcpu()->ci_cpl]; 301 1.11 peter 302 1.1 bsh restore_interrupts(psw); 303 1.1 bsh 304 1.3 scw return (&handler[irqno]); 305 1.1 bsh } 306 1.1 bsh 307 1.11 peter void 308 1.11 peter pxa2x0_intr_disestablish(void *cookie) 309 1.11 peter { 310 1.11 peter struct intrhandler *lhandler = cookie, *ih; 311 1.11 peter int irqmin = CPU_IS_PXA250 ? PXA250_IRQ_MIN : PXA270_IRQ_MIN; 312 1.11 peter int irqno = lhandler - handler; 313 1.11 peter int psw; 314 1.11 peter 315 1.11 peter if (irqno < irqmin || irqno >= ICU_LEN) 316 1.11 peter panic("intr_disestablish: bogus irq number %d", irqno); 317 1.11 peter 318 1.11 peter psw = disable_interrupts(I32_bit); 319 1.11 peter 320 1.11 peter ih = &handler[irqno]; 321 1.11 peter ih->func = stray_interrupt; 322 1.11 peter ih->cookie = (void *)(intptr_t)irqno; 323 1.11 peter extirq_level[irqno] = IPL_SERIAL; 324 1.11 peter pxa2x0_update_intr_masks(irqno, IPL_SERIAL); 325 1.11 peter 326 1.11 peter restore_interrupts(psw); 327 1.11 peter } 328 1.11 peter 329 1.1 bsh /* 330 1.1 bsh * Glue for drivers of sa11x0 compatible integrated logics. 331 1.1 bsh */ 332 1.1 bsh void * 333 1.1 bsh sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, 334 1.3 scw int (*ih_fun)(void *), void *ih_arg) 335 1.1 bsh { 336 1.3 scw 337 1.3 scw return pxa2x0_intr_establish(irq, level, ih_fun, ih_arg); 338 1.1 bsh } 339