1 /* $NetBSD: pic_uic.c,v 1.7 2020/07/06 10:35:28 rin Exp $ */ 2 3 /* 4 * Copyright 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: pic_uic.c,v 1.7 2020/07/06 10:35:28 rin Exp $"); 40 41 #ifdef _KERNEL_OPT 42 #include "opt_ppcarch.h" 43 #include "opt_uic.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/evcnt.h> 49 #include <sys/cpu.h> 50 51 #include <machine/intr.h> 52 #include <machine/psl.h> 53 54 #include <powerpc/spr.h> 55 #include <powerpc/ibm4xx/spr.h> 56 #include <powerpc/ibm4xx/cpu.h> 57 58 #include <powerpc/pic/picvar.h> 59 60 /* 61 * Number of interrupts (hard + soft), irq number legality test, 62 * mapping of irq number to mask and a way to pick irq number 63 * off a mask of active intrs. 64 */ 65 #define IRQ_TO_MASK(irq) (0x80000000UL >> ((irq) & 0x1f)) 66 #define IRQ_OF_MASK(mask) __builtin_clz(mask) 67 68 static void uic_enable_irq(struct pic_ops *, int, int); 69 static void uic_disable_irq(struct pic_ops *, int); 70 static int uic_get_irq(struct pic_ops *, int); 71 static void uic_ack_irq(struct pic_ops *, int); 72 static void uic_establish_irq(struct pic_ops *, int, int, int); 73 74 struct uic { 75 uint32_t uic_intr_enable; /* cached intr enable mask */ 76 uint32_t (*uic_mf_intr_status)(void); 77 uint32_t (*uic_mf_intr_enable)(void); 78 void (*uic_mt_intr_enable)(uint32_t); 79 void (*uic_mt_intr_ack)(uint32_t); 80 }; 81 82 /* 83 * Platform specific code may override any of the above. 84 */ 85 #ifdef PPC_IBM403 86 87 #include <powerpc/ibm4xx/dcr403cgx.h> 88 89 static uint32_t 90 uic403_mfdcr_intr_status(void) 91 { 92 return mfdcr(DCR_EXISR); 93 } 94 95 static uint32_t 96 uic403_mfdcr_intr_enable(void) 97 { 98 return mfdcr(DCR_EXIER); 99 } 100 101 static void 102 uic403_mtdcr_intr_ack(uint32_t v) 103 { 104 mtdcr(DCR_EXISR, v); 105 } 106 107 static void 108 uic403_mtdcr_intr_enable(uint32_t v) 109 { 110 mtdcr(DCR_EXIER, v); 111 } 112 113 struct uic uic403 = { 114 .uic_intr_enable = 0, 115 .uic_mf_intr_status = uic403_mfdcr_intr_status, 116 .uic_mf_intr_enable = uic403_mfdcr_intr_enable, 117 .uic_mt_intr_enable = uic403_mtdcr_intr_enable, 118 .uic_mt_intr_ack = uic403_mtdcr_intr_ack, 119 }; 120 121 struct pic_ops pic_uic403 = { 122 .pic_cookie = &uic403, 123 .pic_numintrs = 32, 124 .pic_enable_irq = uic_enable_irq, 125 .pic_reenable_irq = uic_enable_irq, 126 .pic_disable_irq = uic_disable_irq, 127 .pic_establish_irq = uic_establish_irq, 128 .pic_get_irq = uic_get_irq, 129 .pic_ack_irq = uic_ack_irq, 130 .pic_finish_setup = NULL, 131 .pic_name = "uic0" 132 }; 133 134 #else /* Generic 405/440/460 Universal Interrupt Controller */ 135 136 #include <powerpc/ibm4xx/dcr4xx.h> 137 138 #include "opt_uic.h" 139 140 /* 405EP/405GP/405GPr/Virtex-4 */ 141 142 static uint32_t 143 uic0_mfdcr_intr_status(void) 144 { 145 return mfdcr(DCR_UIC0_BASE + DCR_UIC_MSR); 146 } 147 148 static uint32_t 149 uic0_mfdcr_intr_enable(void) 150 { 151 return mfdcr(DCR_UIC0_BASE + DCR_UIC_ER); 152 } 153 154 static void 155 uic0_mtdcr_intr_ack(uint32_t v) 156 { 157 mtdcr(DCR_UIC0_BASE + DCR_UIC_SR, v); 158 } 159 160 static void 161 uic0_mtdcr_intr_enable(uint32_t v) 162 { 163 mtdcr(DCR_UIC0_BASE + DCR_UIC_ER, v); 164 } 165 166 struct uic uic0 = { 167 .uic_intr_enable = 0, 168 .uic_mf_intr_status = uic0_mfdcr_intr_status, 169 .uic_mf_intr_enable = uic0_mfdcr_intr_enable, 170 .uic_mt_intr_enable = uic0_mtdcr_intr_enable, 171 .uic_mt_intr_ack = uic0_mtdcr_intr_ack, 172 }; 173 174 struct pic_ops pic_uic0 = { 175 .pic_cookie = &uic0, 176 .pic_numintrs = 32, 177 .pic_enable_irq = uic_enable_irq, 178 .pic_reenable_irq = uic_enable_irq, 179 .pic_disable_irq = uic_disable_irq, 180 .pic_establish_irq = uic_establish_irq, 181 .pic_get_irq = uic_get_irq, 182 .pic_ack_irq = uic_ack_irq, 183 .pic_finish_setup = NULL, 184 .pic_name = "uic0" 185 }; 186 187 #ifdef MULTIUIC 188 189 /* 440EP/440GP/440SP/405EX/440SPe/440GX */ 190 191 static uint32_t 192 uic1_mfdcr_intr_status(void) 193 { 194 return mfdcr(DCR_UIC1_BASE + DCR_UIC_MSR); 195 } 196 197 static uint32_t 198 uic1_mfdcr_intr_enable(void) 199 { 200 return mfdcr(DCR_UIC1_BASE + DCR_UIC_ER); 201 } 202 203 static void 204 uic1_mtdcr_intr_ack(uint32_t v) 205 { 206 mtdcr(DCR_UIC1_BASE + DCR_UIC_SR, v); 207 } 208 209 static void 210 uic1_mtdcr_intr_enable(uint32_t v) 211 { 212 mtdcr(DCR_UIC1_BASE + DCR_UIC_ER, v); 213 } 214 215 extern struct pic_ops pic_uic1; 216 217 static void 218 uic1_finish_setup(struct pic_ops *pic) 219 { 220 intr_establish(30, IST_LEVEL, IPL_HIGH, pic_handle_intr, &pic_uic1); 221 } 222 223 struct uic uic1 = { 224 .uic_intr_enable = 0, 225 .uic_mf_intr_status = uic1_mfdcr_intr_status, 226 .uic_mf_intr_enable = uic1_mfdcr_intr_enable, 227 .uic_mt_intr_enable = uic1_mtdcr_intr_enable, 228 .uic_mt_intr_ack = uic1_mtdcr_intr_ack, 229 }; 230 231 struct pic_ops pic_uic1 = { 232 .pic_cookie = &uic1, 233 .pic_numintrs = 32, 234 .pic_enable_irq = uic_enable_irq, 235 .pic_reenable_irq = uic_enable_irq, 236 .pic_disable_irq = uic_disable_irq, 237 .pic_establish_irq = uic_establish_irq, 238 .pic_get_irq = uic_get_irq, 239 .pic_ack_irq = uic_ack_irq, 240 .pic_finish_setup = uic1_finish_setup, 241 .pic_name = "uic1" 242 }; 243 244 /* 440EP/440GP/440SP/405EX/440SPe */ 245 246 static uint32_t 247 uic2_mfdcr_intr_status(void) 248 { 249 return mfdcr(DCR_UIC2_BASE + DCR_UIC_MSR); 250 } 251 252 static uint32_t 253 uic2_mfdcr_intr_enable(void) 254 { 255 return mfdcr(DCR_UIC2_BASE + DCR_UIC_ER); 256 } 257 258 static void 259 uic2_mtdcr_intr_ack(uint32_t v) 260 { 261 mtdcr(DCR_UIC2_BASE + DCR_UIC_SR, v); 262 } 263 264 static void 265 uic2_mtdcr_intr_enable(uint32_t v) 266 { 267 mtdcr(DCR_UIC2_BASE + DCR_UIC_ER, v); 268 } 269 270 extern struct pic_ops pic_uic2; 271 272 static void 273 uic2_finish_setup(struct pic_ops *pic) 274 { 275 intr_establish(28, IST_LEVEL, IPL_HIGH, pic_handle_intr, &pic_uic2); 276 } 277 278 static struct uic uic2 = { 279 .uic_intr_enable = 0, 280 .uic_mf_intr_status = uic2_mfdcr_intr_status, 281 .uic_mf_intr_enable = uic2_mfdcr_intr_enable, 282 .uic_mt_intr_enable = uic2_mtdcr_intr_enable, 283 .uic_mt_intr_ack = uic2_mtdcr_intr_ack, 284 }; 285 286 struct pic_ops pic_uic2 = { 287 .pic_cookie = &uic2, 288 .pic_numintrs = 32, 289 .pic_enable_irq = uic_enable_irq, 290 .pic_reenable_irq = uic_enable_irq, 291 .pic_disable_irq = uic_disable_irq, 292 .pic_establish_irq = uic_establish_irq, 293 .pic_get_irq = uic_get_irq, 294 .pic_ack_irq = uic_ack_irq, 295 .pic_finish_setup = uic2_finish_setup, 296 .pic_name = "uic2" 297 }; 298 299 #endif /* MULTIUIC */ 300 #endif /* !PPC_IBM403 */ 301 302 /* 303 * Set up interrupt mapping array. 304 */ 305 void 306 intr_init(void) 307 { 308 #ifdef PPC_IBM403 309 struct pic_ops * const pic = &pic_uic403; 310 #else 311 struct pic_ops * const pic = &pic_uic0; 312 #endif 313 struct uic * const uic = pic->pic_cookie; 314 315 uic->uic_mt_intr_enable(0x00000000); /* mask all */ 316 uic->uic_mt_intr_ack(0xffffffff); /* acknowledge all */ 317 318 pic_add(pic); 319 } 320 321 static void 322 uic_disable_irq(struct pic_ops *pic, int irq) 323 { 324 struct uic * const uic = pic->pic_cookie; 325 const uint32_t irqmask = IRQ_TO_MASK(irq); 326 if ((uic->uic_intr_enable & irqmask) == 0) 327 return; 328 uic->uic_intr_enable ^= irqmask; 329 (*uic->uic_mt_intr_enable)(uic->uic_intr_enable); 330 #ifdef IRQ_DEBUG 331 printf("%s: %s: irq=%d, mask=%08x\n", __func__, 332 pic->pic_name, irq, irqmask); 333 #endif 334 } 335 336 static void 337 uic_enable_irq(struct pic_ops *pic, int irq, int type) 338 { 339 struct uic * const uic = pic->pic_cookie; 340 const uint32_t irqmask = IRQ_TO_MASK(irq); 341 if ((uic->uic_intr_enable & irqmask) != 0) 342 return; 343 uic->uic_intr_enable ^= irqmask; 344 (*uic->uic_mt_intr_enable)(uic->uic_intr_enable); 345 #ifdef IRQ_DEBUG 346 printf("%s: %s: irq=%d, mask=%08x\n", __func__, 347 pic->pic_name, irq, irqmask); 348 #endif 349 } 350 351 static void 352 uic_ack_irq(struct pic_ops *pic, int irq) 353 { 354 struct uic * const uic = pic->pic_cookie; 355 const uint32_t irqmask = IRQ_TO_MASK(irq); 356 357 (*uic->uic_mt_intr_ack)(irqmask); 358 } 359 360 static int 361 uic_get_irq(struct pic_ops *pic, int dummy) 362 { 363 struct uic * const uic = pic->pic_cookie; 364 365 const uint32_t irqmask = (*uic->uic_mf_intr_status)(); 366 if (irqmask == 0) 367 return 255; 368 return IRQ_OF_MASK(irqmask); 369 } 370 371 /* 372 * Register an interrupt handler. 373 */ 374 static void 375 uic_establish_irq(struct pic_ops *pic, int irq, int type, int ipl) 376 { 377 } 378