1 /* $NetBSD: pic_uic.c,v 1.1 2011/06/20 17:44:33 matt 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.1 2011/06/20 17:44:33 matt Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/malloc.h> 43 #include <sys/kernel.h> 44 #include <sys/evcnt.h> 45 #include <sys/cpu.h> 46 47 #include <machine/intr.h> 48 #include <machine/psl.h> 49 50 #include <powerpc/spr.h> 51 #include <powerpc/ibm4xx/spr.h> 52 #include <powerpc/ibm4xx/cpu.h> 53 54 #include <powerpc/pic/picvar.h> 55 56 57 /* 58 * Number of interrupts (hard + soft), irq number legality test, 59 * mapping of irq number to mask and a way to pick irq number 60 * off a mask of active intrs. 61 */ 62 #define IRQ_TO_MASK(irq) (0x80000000UL >> ((irq) & 0x1f)) 63 #define IRQ_OF_MASK(mask) __builtin_clz(mask) 64 65 static void uic_enable_irq(struct pic_ops *, int, int); 66 static void uic_disable_irq(struct pic_ops *, int); 67 static int uic_get_irq(struct pic_ops *, int); 68 static void uic_ack_irq(struct pic_ops *, int); 69 static void uic_establish_irq(struct pic_ops *, int, int, int); 70 71 struct uic { 72 uint32_t uic_intr_enable; /* cached intr enable mask */ 73 uint32_t (*uic_mf_intr_status)(void); 74 uint32_t (*uic_mf_intr_enable)(void); 75 void (*uic_mt_intr_enable)(uint32_t); 76 void (*uic_mt_intr_ack)(uint32_t); 77 }; 78 79 /* 80 * Platform specific code may override any of the above. 81 */ 82 #ifdef PPC_IBM403 83 84 #include <powerpc/ibm4xx/dcr403cgx.h> 85 86 static uint32_t 87 uic403_mfdcr_intr_status(void) 88 { 89 return mfdcr(DCR_EXISR); 90 } 91 92 static uint32_t 93 uic403_mfdcr_intr_enable(void) 94 { 95 return mfdcr(DCR_EXIER); 96 } 97 98 static void 99 uic403_mtdcr_intr_ack(uint32_t v) 100 { 101 mtdcr(DCR_EXISR, v); 102 } 103 104 static void 105 uic403_mtdcr_intr_enable(uint32_t v) 106 { 107 mtdcr(DCR_EXIER, v); 108 } 109 110 struct uic uic403 = { 111 .uic_intr_enable = 0, 112 .uic_mf_intr_status = uic403_mfdcr_intr_status, 113 .uic_mf_intr_enable = uic403_mfdcr_intr_enable, 114 .uic_mt_intr_enable = uic403_mtdcr_intr_enable, 115 .uic_mt_intr_ack = uic403_mtdcr_intr_ack, 116 }; 117 118 struct pic_ops pic_uic403 = { 119 .pic_cookie = &uic403, 120 .pic_numintrs = 32, 121 .pic_enable_irq = uic_enable_irq, 122 .pic_reenable_irq = uic_enable_irq, 123 .pic_disable_irq = uic_disable_irq, 124 .pic_establish_irq = uic_establish_irq, 125 .pic_get_irq = uic_get_irq, 126 .pic_ack_irq = uic_ack_irq, 127 .pic_finish_setup = NULL, 128 .pic_name = "uic0" 129 }; 130 131 #else /* Generic 405/440/460 Universal Interrupt Controller */ 132 133 #include <powerpc/ibm4xx/dcr4xx.h> 134 135 #include "opt_uic.h" 136 137 /* 405EP/405GP/405GPr/Virtex-4 */ 138 139 static uint32_t 140 uic0_mfdcr_intr_status(void) 141 { 142 return mfdcr(DCR_UIC0_BASE + DCR_UIC_MSR); 143 } 144 145 static uint32_t 146 uic0_mfdcr_intr_enable(void) 147 { 148 return mfdcr(DCR_UIC0_BASE + DCR_UIC_ER); 149 } 150 151 static void 152 uic0_mtdcr_intr_ack(uint32_t v) 153 { 154 mtdcr(DCR_UIC0_BASE + DCR_UIC_SR, v); 155 } 156 157 static void 158 uic0_mtdcr_intr_enable(uint32_t v) 159 { 160 mtdcr(DCR_UIC0_BASE + DCR_UIC_ER, v); 161 } 162 163 struct uic uic0 = { 164 .uic_intr_enable = 0, 165 .uic_mf_intr_status = uic0_mfdcr_intr_status, 166 .uic_mf_intr_enable = uic0_mfdcr_intr_enable, 167 .uic_mt_intr_enable = uic0_mtdcr_intr_enable, 168 .uic_mt_intr_ack = uic0_mtdcr_intr_ack, 169 }; 170 171 struct pic_ops pic_uic0 = { 172 .pic_cookie = &uic0, 173 .pic_numintrs = 32, 174 .pic_enable_irq = uic_enable_irq, 175 .pic_reenable_irq = uic_enable_irq, 176 .pic_disable_irq = uic_disable_irq, 177 .pic_establish_irq = uic_establish_irq, 178 .pic_get_irq = uic_get_irq, 179 .pic_ack_irq = uic_ack_irq, 180 .pic_finish_setup = NULL, 181 .pic_name = "uic0" 182 }; 183 184 #ifdef MULTIUIC 185 186 /* 440EP/440GP/440SP/405EX/440SPe/440GX */ 187 188 static uint32_t 189 uic1_mfdcr_intr_status(void) 190 { 191 return mfdcr(DCR_UIC1_BASE + DCR_UIC_MSR); 192 } 193 194 static uint32_t 195 uic1_mfdcr_intr_enable(void) 196 { 197 return mfdcr(DCR_UIC1_BASE + DCR_UIC_ER); 198 } 199 200 static void 201 uic1_mtdcr_intr_ack(uint32_t v) 202 { 203 mtdcr(DCR_UIC1_BASE + DCR_UIC_SR, v); 204 } 205 206 static void 207 uic1_mtdcr_intr_enable(uint32_t v) 208 { 209 mtdcr(DCR_UIC1_BASE + DCR_UIC_ER, v); 210 } 211 212 extern struct pic_ops pic_uic1; 213 214 static void 215 uic1_finish_setup(struct pic_ops *pic) 216 { 217 intr_establish(30, IPL_NONE, IST_LEVEL, pic_handle_intr, &pic_uic1); 218 } 219 220 struct uic uic1 = { 221 .uic_intr_enable = 0, 222 .uic_mf_intr_status = uic1_mfdcr_intr_status, 223 .uic_mf_intr_enable = uic1_mfdcr_intr_enable, 224 .uic_mt_intr_enable = uic1_mtdcr_intr_enable, 225 .uic_mt_intr_ack = uic1_mtdcr_intr_ack, 226 }; 227 228 struct pic_ops pic_uic1 = { 229 .pic_cookie = &uic1, 230 .pic_numintrs = 32, 231 .pic_enable_irq = uic_enable_irq, 232 .pic_reenable_irq = uic_enable_irq, 233 .pic_disable_irq = uic_disable_irq, 234 .pic_establish_irq = uic_establish_irq, 235 .pic_get_irq = uic_get_irq, 236 .pic_ack_irq = uic_ack_irq, 237 .pic_finish_setup = uic1_finish_setup, 238 .pic_name = "uic1" 239 }; 240 241 /* 440EP/440GP/440SP/405EX/440SPe */ 242 243 static uint32_t 244 uic2_mfdcr_intr_status(void) 245 { 246 return mfdcr(DCR_UIC2_BASE + DCR_UIC_MSR); 247 } 248 249 static uint32_t 250 uic2_mfdcr_intr_enable(void) 251 { 252 return mfdcr(DCR_UIC2_BASE + DCR_UIC_ER); 253 } 254 255 static void 256 uic2_mtdcr_intr_ack(uint32_t v) 257 { 258 mtdcr(DCR_UIC2_BASE + DCR_UIC_SR, v); 259 } 260 261 static void 262 uic2_mtdcr_intr_enable(uint32_t v) 263 { 264 mtdcr(DCR_UIC2_BASE + DCR_UIC_ER, v); 265 } 266 267 extern struct pic_ops pic_uic2; 268 269 static void 270 uic2_finish_setup(struct pic_ops *pic) 271 { 272 intr_establish(28, IPL_NONE, IST_LEVEL, pic_handle_intr, &pic_uic2); 273 } 274 275 static struct uic uic2 = { 276 .uic_intr_enable = 0, 277 .uic_mf_intr_status = uic2_mfdcr_intr_status, 278 .uic_mf_intr_enable = uic2_mfdcr_intr_enable, 279 .uic_mt_intr_enable = uic2_mtdcr_intr_enable, 280 .uic_mt_intr_ack = uic2_mtdcr_intr_ack, 281 }; 282 283 struct pic_ops pic_uic2 = { 284 .pic_cookie = &uic2, 285 .pic_numintrs = 32, 286 .pic_enable_irq = uic_enable_irq, 287 .pic_reenable_irq = uic_enable_irq, 288 .pic_disable_irq = uic_disable_irq, 289 .pic_establish_irq = uic_establish_irq, 290 .pic_get_irq = uic_get_irq, 291 .pic_ack_irq = uic_ack_irq, 292 .pic_finish_setup = uic2_finish_setup, 293 .pic_name = "uic2" 294 }; 295 296 #endif /* MULTIUIC */ 297 #endif /* !PPC_IBM403 */ 298 299 /* Write External Enable Immediate */ 300 #define wrteei(en) __asm volatile ("wrteei %0" : : "K"(en)) 301 302 /* Enforce In Order Execution of I/O */ 303 #define eieio() __asm volatile ("eieio") 304 305 /* 306 * Set up interrupt mapping array. 307 */ 308 void 309 intr_init(void) 310 { 311 #ifdef PPC_IBM403 312 struct pic_ops * const pic = &pic_uic403; 313 #else 314 struct pic_ops * const pic = &pic_uic0; 315 #endif 316 struct uic * const uic = pic->pic_cookie; 317 318 uic->uic_mt_intr_enable(0x00000000); /* mask all */ 319 uic->uic_mt_intr_ack(0xffffffff); /* acknowledge all */ 320 321 pic_add(pic); 322 } 323 324 static void 325 uic_disable_irq(struct pic_ops *pic, int irq) 326 { 327 struct uic * const uic = pic->pic_cookie; 328 const uint32_t irqmask = IRQ_TO_MASK(irq); 329 if ((uic->uic_intr_enable & irqmask) == 0) 330 return; 331 uic->uic_intr_enable ^= irqmask; 332 (*uic->uic_mt_intr_enable)(uic->uic_intr_enable); 333 #ifdef IRQ_DEBUG 334 printf("%s: %s: irq=%d, mask=%08x\n", __func__, 335 pic->pic_name, irq, irqmask); 336 #endif 337 } 338 339 static void 340 uic_enable_irq(struct pic_ops *pic, int irq, int type) 341 { 342 struct uic * const uic = pic->pic_cookie; 343 const uint32_t irqmask = IRQ_TO_MASK(irq); 344 if ((uic->uic_intr_enable & irqmask) != 0) 345 return; 346 uic->uic_intr_enable ^= irqmask; 347 (*uic->uic_mt_intr_enable)(uic->uic_intr_enable); 348 #ifdef IRQ_DEBUG 349 printf("%s: %s: irq=%d, mask=%08x\n", __func__, 350 pic->pic_name, irq, irqmask); 351 #endif 352 } 353 354 static void 355 uic_ack_irq(struct pic_ops *pic, int irq) 356 { 357 struct uic * const uic = pic->pic_cookie; 358 const uint32_t irqmask = IRQ_TO_MASK(irq); 359 360 (*uic->uic_mt_intr_ack)(irqmask); 361 } 362 363 static int 364 uic_get_irq(struct pic_ops *pic, int dummy) 365 { 366 struct uic * const uic = pic->pic_cookie; 367 368 const uint32_t irqmask = (*uic->uic_mf_intr_status)(); 369 if (irqmask == 0) 370 return 255; 371 return IRQ_OF_MASK(irqmask); 372 } 373 374 /* 375 * Register an interrupt handler. 376 */ 377 static void 378 uic_establish_irq(struct pic_ops *pic, int irq, int type, int ipl) 379 { 380 } 381