1 /* $NetBSD: plumicu.c,v 1.10 2005/12/24 23:24:00 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: plumicu.c,v 1.10 2005/12/24 23:24:00 perry Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 46 #include <machine/bus.h> 47 #include <machine/intr.h> 48 49 #include <hpcmips/tx/tx39var.h> 50 #include <hpcmips/dev/plumvar.h> 51 #include <hpcmips/dev/plumicuvar.h> 52 #include <hpcmips/dev/plumicureg.h> 53 54 #ifdef PLUMICUDEBUG 55 #define DPRINTF(arg) printf arg 56 #else 57 #define DPRINTF(arg) 58 #endif 59 60 int plumicu_match(struct device *, struct cfdata *, void *); 61 void plumicu_attach(struct device *, struct device *, void *); 62 int plumicu_intr(void *); 63 64 static inline void plum_di(plum_chipset_tag_t); 65 static inline void plum_ei(plum_chipset_tag_t); 66 67 const struct plum_intr_ctrl { 68 plumreg_t ic_ackpat1; 69 plumreg_t ic_ackpat2; int ic_ackreg2; 70 plumreg_t ic_ienpat; int ic_ienreg; 71 plumreg_t ic_senpat; int ic_senreg; 72 } pi_ctrl[PLUM_INTR_MAX] = { 73 [PLUM_INT_C1IO] = {PLUM_INT_INTSTA_PCCINT, 74 PLUM_INT_PCCINTS_C1IO, PLUM_INT_PCCINTS_REG, 75 PLUM_INT_PCCIEN_IENC1IO, PLUM_INT_PCCIEN_REG, 76 PLUM_INT_PCCIEN_SENC1IO, PLUM_INT_PCCIEN_REG 77 }, 78 [PLUM_INT_C1RI] = {PLUM_INT_INTSTA_PCCINT, 79 PLUM_INT_PCCINTS_C1RI, PLUM_INT_PCCINTS_REG, 80 PLUM_INT_PCCIEN_IENC1RI, PLUM_INT_PCCIEN_REG, 81 PLUM_INT_PCCIEN_SENC1RI, PLUM_INT_PCCIEN_REG 82 }, 83 [PLUM_INT_C1SC] = {PLUM_INT_INTSTA_C1SCINT, 0, 0, 0, 0, 0, 0}, 84 [PLUM_INT_C2IO] = {PLUM_INT_INTSTA_PCCINT, 85 PLUM_INT_PCCINTS_C2IO, PLUM_INT_PCCINTS_REG, 86 PLUM_INT_PCCIEN_IENC2IO, PLUM_INT_PCCIEN_REG, 87 PLUM_INT_PCCIEN_SENC2IO, PLUM_INT_PCCIEN_REG 88 }, 89 [PLUM_INT_C2RI] = {PLUM_INT_INTSTA_PCCINT, 90 PLUM_INT_PCCINTS_C2RI, PLUM_INT_PCCINTS_REG, 91 PLUM_INT_PCCIEN_IENC2RI, PLUM_INT_PCCIEN_REG, 92 PLUM_INT_PCCIEN_SENC2RI, PLUM_INT_PCCIEN_REG 93 }, 94 [PLUM_INT_C2SC] = {PLUM_INT_INTSTA_C2SCINT, 0, 0, 0, 0, 0, 0}, 95 [PLUM_INT_DISP] = {PLUM_INT_INTSTA_DISPINT, 0, 0, 0, 0, 0, 0}, 96 [PLUM_INT_USB] = {PLUM_INT_INTSTA_USBINT, 97 0, 0, 98 PLUM_INT_USBINTEN_IEN, PLUM_INT_USBINTEN_REG, 99 0, 0 100 }, 101 [PLUM_INT_USBWAKE] = {PLUM_INT_INTSTA_USBWAKE, 102 0, 0, 103 PLUM_INT_USBINTEN_WIEN, PLUM_INT_USBINTEN_REG, 104 0, 0 105 }, 106 [PLUM_INT_SM] = {PLUM_INT_INTSTA_SMINT, 107 0, 0, 108 PLUM_INT_SMIEN, PLUM_INT_SMIEN_REG, 109 0, 0 110 }, 111 [PLUM_INT_EXT5IO0] = {PLUM_INT_INTSTA_EXTINT, 112 PLUM_INT_EXTINTS_IO5INT0, PLUM_INT_EXTINTS_REG, 113 PLUM_INT_EXTIEN_IENIO5INT0, PLUM_INT_EXTIEN_REG, 114 PLUM_INT_EXTIEN_SENIO5INT0, PLUM_INT_EXTIEN_REG, 115 }, 116 [PLUM_INT_EXT5IO1] = {PLUM_INT_INTSTA_EXTINT, 117 PLUM_INT_EXTINTS_IO5INT1, PLUM_INT_EXTINTS_REG, 118 PLUM_INT_EXTIEN_IENIO5INT1, PLUM_INT_EXTIEN_REG, 119 PLUM_INT_EXTIEN_SENIO5INT1, PLUM_INT_EXTIEN_REG, 120 }, 121 [PLUM_INT_EXT5IO2] = {PLUM_INT_INTSTA_EXTINT, 122 PLUM_INT_EXTINTS_IO5INT2, PLUM_INT_EXTINTS_REG, 123 PLUM_INT_EXTIEN_IENIO5INT2, PLUM_INT_EXTIEN_REG, 124 PLUM_INT_EXTIEN_SENIO5INT2, PLUM_INT_EXTIEN_REG, 125 }, 126 [PLUM_INT_EXT5IO3] = {PLUM_INT_INTSTA_EXTINT, 127 PLUM_INT_EXTINTS_IO5INT3, PLUM_INT_EXTINTS_REG, 128 PLUM_INT_EXTIEN_IENIO5INT0, PLUM_INT_EXTIEN_REG, 129 PLUM_INT_EXTIEN_SENIO5INT0, PLUM_INT_EXTIEN_REG, 130 }, 131 [PLUM_INT_EXT3IO0] = {PLUM_INT_INTSTA_EXTINT, 132 PLUM_INT_EXTINTS_IO3INT0, PLUM_INT_EXTINTS_REG, 133 PLUM_INT_EXTIEN_IENIO3INT0, PLUM_INT_EXTIEN_REG, 134 PLUM_INT_EXTIEN_SENIO3INT0, PLUM_INT_EXTIEN_REG, 135 }, 136 [PLUM_INT_EXT3IO1] = {PLUM_INT_INTSTA_EXTINT, 137 PLUM_INT_EXTINTS_IO3INT1, PLUM_INT_EXTINTS_REG, 138 PLUM_INT_EXTIEN_IENIO3INT1, PLUM_INT_EXTIEN_REG, 139 PLUM_INT_EXTIEN_SENIO3INT1, PLUM_INT_EXTIEN_REG, 140 } 141 }; 142 143 struct plum_intr_entry { 144 int pi_enabled; 145 int pi_line; 146 int (*pi_fun)(void *); 147 void *pi_arg; 148 const struct plum_intr_ctrl *pi_ctrl; 149 }; 150 151 struct plumicu_softc { 152 struct device sc_dev; 153 plum_chipset_tag_t sc_pc; 154 bus_space_tag_t sc_regt; 155 bus_space_handle_t sc_regh; 156 void *sc_ih; 157 int sc_enable_count; 158 struct plum_intr_entry sc_intr[PLUM_INTR_MAX]; 159 }; 160 161 CFATTACH_DECL(plumicu, sizeof(struct plumicu_softc), 162 plumicu_match, plumicu_attach, NULL, NULL); 163 164 #ifdef PLUMICUDEBUG 165 void plumicu_dump(struct plumicu_softc *); 166 #endif 167 168 int 169 plumicu_match(struct device *parent, struct cfdata *cf, void *aux) 170 { 171 172 return (2); /* 1st attach group */ 173 } 174 175 void 176 plumicu_attach(struct device *parent, struct device *self, void *aux) 177 { 178 struct plum_attach_args *pa = aux; 179 struct plumicu_softc *sc = (void*)self; 180 const struct plum_intr_ctrl *pic; 181 bus_space_tag_t regt; 182 bus_space_handle_t regh; 183 plumreg_t reg; 184 int i; 185 186 sc->sc_pc = pa->pa_pc; 187 sc->sc_regt = pa->pa_regt; 188 189 /* map plum2 interrupt controller register space */ 190 if (bus_space_map(sc->sc_regt, PLUM_INT_REGBASE, 191 PLUM_INT_REGSIZE, 0, &sc->sc_regh)) { 192 printf(":interrupt register map failed\n"); 193 return; 194 } 195 #ifdef PLUMICUDEBUG 196 plumicu_dump(sc); 197 #endif 198 /* disable all interrupt */ 199 regt = sc->sc_regt; 200 regh = sc->sc_regh; 201 for (i = 0; i < PLUM_INTR_MAX; i++) { 202 pic = &pi_ctrl[i]; 203 if (pic->ic_ienreg) { 204 reg = plum_conf_read(regt, regh, pic->ic_ienreg); 205 reg &= ~pic->ic_ienpat; 206 plum_conf_write(regt, regh, pic->ic_ienreg, reg); 207 } 208 if (pic->ic_senreg) { 209 reg = plum_conf_read(regt, regh, pic->ic_senreg); 210 reg &= ~pic->ic_senpat; 211 plum_conf_write(regt, regh, pic->ic_senreg, reg); 212 } 213 } 214 215 /* register handle to plum_chipset_tag */ 216 plum_conf_register_intr(sc->sc_pc, (void*)sc); 217 218 /* disable interrupt redirect to TX39 core */ 219 plum_di(sc->sc_pc); 220 221 if (!(sc->sc_ih = tx_intr_establish(sc->sc_pc->pc_tc, pa->pa_irq, 222 IST_EDGE, IPL_BIO, 223 plumicu_intr, sc))) { 224 printf(": can't establish interrupt\n"); 225 } 226 printf("\n"); 227 } 228 229 inline void 230 plum_di(plum_chipset_tag_t pc) 231 { 232 struct plumicu_softc *sc = pc->pc_intrt; 233 234 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG, 0); 235 } 236 237 inline void 238 plum_ei(plum_chipset_tag_t pc) 239 { 240 struct plumicu_softc *sc = pc->pc_intrt; 241 242 plum_conf_write(sc->sc_regt, sc->sc_regh, PLUM_INT_INTIEN_REG, 243 PLUM_INT_INTIEN); 244 } 245 246 void* 247 plum_intr_establish(plum_chipset_tag_t pc, int line, int mode, int level, 248 int (*ih_fun)(void *), void *ih_arg) 249 { 250 struct plumicu_softc *sc = pc->pc_intrt; 251 bus_space_tag_t regt = sc->sc_regt; 252 bus_space_handle_t regh = sc->sc_regh; 253 plumreg_t reg; 254 struct plum_intr_entry *pi; 255 256 if (!LEGAL_PRUM_INTR(line)) { 257 panic("plum_intr_establish: bogus interrupt line"); 258 } 259 260 pi = &sc->sc_intr[line]; 261 pi->pi_line = line; 262 pi->pi_fun = ih_fun; 263 pi->pi_arg = ih_arg; 264 pi->pi_ctrl = &pi_ctrl[line]; 265 266 /* Enable interrupt */ 267 268 /* status enable */ 269 if (pi->pi_ctrl->ic_senreg) { 270 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg); 271 reg |= pi->pi_ctrl->ic_senpat; 272 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg); 273 } 274 /* interrupt enable */ 275 if (pi->pi_ctrl->ic_ienreg) { 276 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg); 277 reg |= pi->pi_ctrl->ic_ienpat; 278 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg); 279 } 280 281 /* Enable redirect to TX39 core */ 282 DPRINTF(("plum_intr_establish: %d (count=%d)\n", line, 283 sc->sc_enable_count)); 284 285 if (sc->sc_enable_count++ == 0) 286 plum_ei(pc); 287 288 pi->pi_enabled = 1; 289 290 return (ih_fun); 291 } 292 293 void 294 plum_intr_disestablish(plum_chipset_tag_t pc, void *arg) 295 { 296 struct plumicu_softc *sc = pc->pc_intrt; 297 bus_space_tag_t regt = sc->sc_regt; 298 bus_space_handle_t regh = sc->sc_regh; 299 plumreg_t reg; 300 struct plum_intr_entry *pi; 301 int i; 302 303 sc = pc->pc_intrt; 304 305 for (i = 0; i < PLUM_INTR_MAX; i++) { 306 pi = &sc->sc_intr[i]; 307 if (pi->pi_fun != arg) 308 continue; 309 DPRINTF(("plum_intr_disestablish: %d (count=%d)\n", 310 pi->pi_line, sc->sc_enable_count - 1)); 311 goto found; 312 } 313 panic("plum_intr_disestablish: can't find entry."); 314 /* NOTREACHED */ 315 found: 316 pi->pi_enabled = 0; 317 /* Disable interrupt */ 318 if (pi->pi_ctrl->ic_ienreg) { 319 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_ienreg); 320 reg &= ~(pi->pi_ctrl->ic_ienpat); 321 plum_conf_write(regt, regh, pi->pi_ctrl->ic_ienreg, reg); 322 } 323 if (pi->pi_ctrl->ic_senreg) { 324 reg = plum_conf_read(regt, regh, pi->pi_ctrl->ic_senreg); 325 reg &= ~(pi->pi_ctrl->ic_senpat); 326 plum_conf_write(regt, regh, pi->pi_ctrl->ic_senreg, reg); 327 } 328 329 /* Disable/Enable interrupt redirect to TX39 core */ 330 if (--sc->sc_enable_count == 0) 331 plum_di(pc); 332 } 333 334 int 335 plumicu_intr(void *arg) 336 { 337 struct plumicu_softc *sc = arg; 338 bus_space_tag_t regt = sc->sc_regt; 339 bus_space_handle_t regh = sc->sc_regh; 340 plumreg_t reg1, reg2, reg_ext, reg_pccard; 341 int i; 342 343 plum_di(sc->sc_pc); 344 /* read level 1 status */ 345 reg1 = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG); 346 347 /* read level 2 status and acknowledge */ 348 reg_ext = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG); 349 plum_conf_write(regt, regh, PLUM_INT_EXTINTS_REG, reg_ext); 350 351 reg_pccard = plum_conf_read(regt, regh, PLUM_INT_PCCINTS_REG); 352 plum_conf_write(regt, regh, PLUM_INT_PCCINTS_REG, reg_pccard); 353 354 for (i = 0; i < PLUM_INTR_MAX; i++) { 355 register struct plum_intr_entry *pi; 356 register const struct plum_intr_ctrl *pic = &pi_ctrl[i]; 357 358 if (!(pic->ic_ackpat1 & reg1)) 359 continue; 360 361 pi = &sc->sc_intr[i]; 362 if (!pi->pi_enabled) 363 continue; 364 365 if (pic->ic_ackreg2 == 0) { 366 (*pi->pi_fun)(pi->pi_arg); 367 continue; 368 } 369 370 reg2 = pic->ic_ackreg2 == PLUM_INT_PCCINTS_REG 371 ? reg_pccard : reg_ext; 372 373 if (pic->ic_ackpat2 & reg2) 374 (*pi->pi_fun)(pi->pi_arg); 375 } 376 plum_ei(sc->sc_pc); 377 378 return (0); 379 } 380 381 #ifdef PLUMICUDEBUG 382 void 383 plumicu_dump(struct plumicu_softc *sc) 384 { 385 bus_space_tag_t regt = sc->sc_regt; 386 bus_space_handle_t regh = sc->sc_regh; 387 plumreg_t reg; 388 389 printf("status:"); 390 reg = plum_conf_read(regt, regh, PLUM_INT_INTSTA_REG); 391 dbg_bit_print(reg); 392 printf("ExtIO\n"); 393 printf("status:"); 394 reg = plum_conf_read(regt, regh, PLUM_INT_EXTINTS_REG); 395 dbg_bit_print(reg); 396 printf("enable:"); 397 reg = plum_conf_read(regt, regh, PLUM_INT_EXTIEN_REG); 398 dbg_bit_print(reg); 399 400 } 401 #endif /* PLUMICUDEBUG */ 402