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