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