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