1 /* $NetBSD: vrgiu.c,v 1.35 2002/05/03 07:31:25 takemura Exp $ */ 2 /*- 3 * Copyright (c) 1999-2001 4 * Shin Takemura and PocketBSD Project. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the PocketBSD project 17 * and its contributors. 18 * 4. Neither the name of the project nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/queue.h> 41 #include <sys/reboot.h> 42 43 #include <mips/cpuregs.h> 44 #include <machine/bus.h> 45 #include <machine/config_hook.h> 46 #include <machine/debug.h> 47 48 #include <dev/hpc/hpciovar.h> 49 50 #include "opt_vr41xx.h" 51 #include <hpcmips/vr/vrcpudef.h> 52 #include <hpcmips/vr/vripif.h> 53 #include <hpcmips/vr/vripreg.h> 54 #include <hpcmips/vr/vrgiureg.h> 55 56 #include "locators.h" 57 58 /* 59 * constant and macro definitions 60 */ 61 #define VRGIUDEBUG 62 #ifdef VRGIUDEBUG 63 #define DEBUG_IO 1 64 #define DEBUG_INTR 2 65 #ifndef VRGIUDEBUG_CONF 66 #define VRGIUDEBUG_CONF 0 67 #endif /* VRGIUDEBUG_CONF */ 68 int vrgiu_debug = VRGIUDEBUG_CONF; 69 #define DPRINTF(flag, arg) if (vrgiu_debug & flag) printf arg; 70 #define DDUMP_IO(flag, sc) if (vrgiu_debug & flag) vrgiu_dump_io(sc); 71 #define DDUMP_IOSETTING(flag, sc) \ 72 if (vrgiu_debug & flag) vrgiu_dump_iosetting(sc); 73 #define VPRINTF(flag, arg) \ 74 if (bootverbose || vrgiu_debug & flag) printf arg; 75 #define VDUMP_IO(flag, sc) \ 76 if (bootverbose || vrgiu_debug & flag) vrgiu_dump_io(sc); 77 #define VDUMP_IOSETTING(flag, sc) \ 78 if (bootverbose || vrgiu_debug & flag) vrgiu_dump_iosetting(sc); 79 #else 80 #define DPRINTF(flag, arg) 81 #define DDUMP_IO(flag, sc) 82 #define DDUMP_IOSETTING(flag, sc) 83 #define VPRINTF(flag, arg) if (bootverbose) printf arg; 84 #define VDUMP_IO(flag, sc) if (bootverbose) vrgiu_dump_io(sc); 85 #define VDUMP_IOSETTING(flag, sc) \ 86 if (bootverbose) vrgiu_dump_iosetting(sc); 87 #endif 88 89 #ifdef VRGIU_INTR_NOLED 90 int vrgiu_intr_led = 0; 91 #else /* VRGIU_INTR_NOLED */ 92 int vrgiu_intr_led = 1; 93 #endif /* VRGIU_INTR_NOLED */ 94 95 #define MAX_GPIO_OUT 50 /* port 32:49 are output only port */ 96 #define MAX_GPIO_INOUT 32 /* input/output port(0:31) */ 97 98 #define LEGAL_INTR_PORT(x) ((x) >= 0 && (x) < MAX_GPIO_INOUT) 99 #define LEGAL_OUT_PORT(x) ((x) >= 0 && (x) < MAX_GPIO_OUT) 100 101 /* 102 * type declarations 103 */ 104 struct vrgiu_intr_entry { 105 int ih_port; 106 int (*ih_fun)(void *); 107 void *ih_arg; 108 TAILQ_ENTRY(vrgiu_intr_entry) ih_link; 109 }; 110 111 struct vrgiu_softc { 112 struct device sc_dev; 113 bus_space_tag_t sc_iot; 114 bus_space_handle_t sc_ioh; 115 /* Interrupt */ 116 vrip_chipset_tag_t sc_vc; 117 void *sc_ih; 118 u_int32_t sc_intr_mask; 119 u_int32_t sc_intr_mode[MAX_GPIO_INOUT]; 120 TAILQ_HEAD(, vrgiu_intr_entry) sc_intr_head[MAX_GPIO_INOUT]; 121 struct hpcio_chip sc_iochip; 122 #ifndef SINGLE_VRIP_BASE 123 int sc_useupdn_reg, sc_termupdn_reg; 124 #endif /* SINGLE_VRIP_BASE */ 125 }; 126 127 #ifndef SINGLE_VRIP_BASE 128 #define GIUUSEUPDN_REG_W (sc->sc_useupdn_reg) 129 #define GIUTERMUPDN_REG_W (sc->sc_termupdn_reg) 130 #endif /* SINGLE_VRIP_BASE */ 131 132 /* 133 * prototypes 134 */ 135 int vrgiu_match(struct device*, struct cfdata*, void*); 136 void vrgiu_attach(struct device*, struct device*, void*); 137 int vrgiu_intr(void*); 138 int vrgiu_print(void*, const char*); 139 void vrgiu_callback(struct device*); 140 141 void vrgiu_dump_regs(struct vrgiu_softc *); 142 void vrgiu_dump_io(struct vrgiu_softc *); 143 void vrgiu_diff_io(void); 144 void vrgiu_dump_iosetting(struct vrgiu_softc *); 145 void vrgiu_diff_iosetting(void); 146 u_int32_t vrgiu_regread_4(struct vrgiu_softc *, bus_addr_t); 147 u_int16_t vrgiu_regread(struct vrgiu_softc *, bus_addr_t); 148 void vrgiu_regwrite_4(struct vrgiu_softc *, bus_addr_t, u_int32_t); 149 void vrgiu_regwrite(struct vrgiu_softc *, bus_addr_t, u_int16_t); 150 151 static int vrgiu_port_read(hpcio_chip_t, int); 152 static void vrgiu_port_write(hpcio_chip_t, int, int); 153 static void *vrgiu_intr_establish(hpcio_chip_t, int, int, int (*)(void *), void*); 154 static void vrgiu_intr_disestablish(hpcio_chip_t, void*); 155 static void vrgiu_intr_clear(hpcio_chip_t, void*); 156 static void vrgiu_register_iochip(hpcio_chip_t, hpcio_chip_t); 157 static void vrgiu_update(hpcio_chip_t); 158 static void vrgiu_dump(hpcio_chip_t); 159 static hpcio_chip_t vrgiu_getchip(void*, int); 160 161 /* 162 * variables 163 */ 164 static struct hpcio_chip vrgiu_iochip = { 165 .hc_portread = vrgiu_port_read, 166 .hc_portwrite = vrgiu_port_write, 167 .hc_intr_establish = vrgiu_intr_establish, 168 .hc_intr_disestablish = vrgiu_intr_disestablish, 169 .hc_intr_clear = vrgiu_intr_clear, 170 .hc_register_iochip = vrgiu_register_iochip, 171 .hc_update = vrgiu_update, 172 .hc_dump = vrgiu_dump, 173 }; 174 175 struct cfattach vrgiu_ca = { 176 sizeof(struct vrgiu_softc), vrgiu_match, vrgiu_attach 177 }; 178 179 struct vrgiu_softc *this_giu; 180 181 /* 182 * function bodies 183 */ 184 int 185 vrgiu_match(struct device *parent, struct cfdata *cf, void *aux) 186 { 187 188 return (2); /* 1st attach group of vrip */ 189 } 190 191 void 192 vrgiu_attach(struct device *parent, struct device *self, void *aux) 193 { 194 struct vrip_attach_args *va = aux; 195 struct vrgiu_softc *sc = (void*)self; 196 struct hpcio_attach_args haa; 197 int i; 198 199 #ifndef SINGLE_VRIP_BASE 200 if (va->va_addr == VR4102_GIU_ADDR) { 201 sc->sc_useupdn_reg = VR4102_GIUUSEUPDN_REG_W; 202 sc->sc_termupdn_reg = VR4102_GIUTERMUPDN_REG_W; 203 } else 204 if (va->va_addr == VR4122_GIU_ADDR) { 205 sc->sc_useupdn_reg = VR4122_GIUUSEUPDN_REG_W; 206 sc->sc_termupdn_reg = VR4122_GIUTERMUPDN_REG_W; 207 } else { 208 panic("%s: unknown base address 0x%lx\n", 209 sc->sc_dev.dv_xname, va->va_addr); 210 } 211 #endif /* SINGLE_VRIP_BASE */ 212 213 this_giu = sc; 214 sc->sc_vc = va->va_vc; 215 sc->sc_iot = va->va_iot; 216 bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 217 0 /* no cache */, &sc->sc_ioh); 218 /* 219 * Disable all interrupts. 220 */ 221 sc->sc_intr_mask = 0; 222 printf("\n"); 223 #ifdef WINCE_DEFAULT_SETTING 224 #warning WINCE_DEFAULT_SETTING 225 #else 226 VPRINTF(DEBUG_IO, (" " 227 " 3 2 1\n")); 228 VPRINTF(DEBUG_IO, (" " 229 "10987654321098765432109876543210\n")); 230 VPRINTF(DEBUG_IO, ("WIN setting: ")); 231 VDUMP_IOSETTING(DEBUG_IO, sc); 232 VPRINTF(DEBUG_IO, ("\n")); 233 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 234 #endif 235 236 for (i = 0; i < MAX_GPIO_INOUT; i++) 237 TAILQ_INIT(&sc->sc_intr_head[i]); 238 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_unit, 0, 239 IPL_BIO, vrgiu_intr, sc))) { 240 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 241 return; 242 } 243 /* 244 * fill hpcio_chip structure 245 */ 246 sc->sc_iochip = vrgiu_iochip; /* structure copy */ 247 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VRGIU; 248 sc->sc_iochip.hc_name = sc->sc_dev.dv_xname; 249 sc->sc_iochip.hc_sc = sc; 250 /* Register functions to upper interface */ 251 vrip_register_gpio(va->va_vc, &sc->sc_iochip); 252 253 /* Display port status (Input/Output) for debugging */ 254 VPRINTF(DEBUG_IO, ("I/O setting: ")); 255 VDUMP_IOSETTING(DEBUG_IO, sc); 256 VPRINTF(DEBUG_IO, ("\n")); 257 VPRINTF(DEBUG_IO, (" data:")); 258 VDUMP_IO(DEBUG_IO, sc); 259 260 /* 261 * hpcio I/F 262 */ 263 haa.haa_busname = HPCIO_BUSNAME; 264 haa.haa_sc = sc; 265 haa.haa_getchip = vrgiu_getchip; 266 haa.haa_iot = sc->sc_iot; 267 while (config_found(self, &haa, vrgiu_print)) ; 268 /* 269 * GIU-ISA bridge 270 */ 271 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/ 272 config_defer(self, vrgiu_callback); 273 #else 274 vrgiu_callback(self); 275 #endif 276 } 277 278 void 279 vrgiu_callback(struct device *self) 280 { 281 struct vrgiu_softc *sc = (void*)self; 282 struct hpcio_attach_args haa; 283 284 haa.haa_busname = "vrisab"; 285 haa.haa_sc = sc; 286 haa.haa_getchip = vrgiu_getchip; 287 haa.haa_iot = sc->sc_iot; 288 config_found(self, &haa, vrgiu_print); 289 } 290 291 int 292 vrgiu_print(void *aux, const char *pnp) 293 { 294 if (pnp) 295 return (QUIET); 296 return (UNCONF); 297 } 298 299 void 300 vrgiu_dump_iosetting(struct vrgiu_softc *sc) 301 { 302 long iosel, inten, useupdn, termupdn, edge, hold, level; 303 u_int32_t m; 304 char syms[] = "iiiiiiiilhLHeeEEoooooooooooooooo" 305 "DDDDDDDDDDDDDDDDUUUUUUUUUUUUUUUU"; 306 307 iosel= vrgiu_regread_4(sc, GIUIOSEL_REG); 308 inten= vrgiu_regread_4(sc, GIUINTEN_REG); 309 edge = vrgiu_regread_4(sc, GIUINTTYP_REG); 310 hold = vrgiu_regread_4(sc, GIUINTHTSEL_REG); 311 level = vrgiu_regread_4(sc, GIUINTALSEL_REG); 312 313 if (GIUUSEUPDN_REG_W == GIU_NO_REG_W) 314 useupdn = 0; 315 else 316 useupdn = vrgiu_regread(sc, GIUUSEUPDN_REG_W); 317 if (GIUTERMUPDN_REG_W == GIU_NO_REG_W) 318 termupdn = 0; 319 else 320 termupdn = vrgiu_regread(sc, GIUTERMUPDN_REG_W); 321 for (m = 0x80000000; m; m >>=1) 322 printf ("%c", syms[ 323 ((useupdn&m) ? 32 : 0) + 324 ((iosel&m) ? 16 : 0) + ((termupdn&m) ? 16 : 0) + 325 ((inten&m) ? 8 : 0) + 326 ((edge&m) ? 4 : 0) + 327 ((hold&m) ? 2 : 0) + 328 ((level&m) ? 1 : 0)]); 329 } 330 331 void 332 vrgiu_diff_iosetting() 333 { 334 struct vrgiu_softc *sc = this_giu; 335 static long oiosel = 0, ointen = 0, ouseupdn = 0, otermupdn = 0; 336 long iosel, inten, useupdn, termupdn; 337 u_int32_t m; 338 339 iosel= vrgiu_regread_4(sc, GIUIOSEL_REG); 340 inten= vrgiu_regread_4(sc, GIUINTEN_REG); 341 if (GIUUSEUPDN_REG_W == GIU_NO_REG_W) 342 useupdn = 0; 343 else 344 useupdn = vrgiu_regread(sc, GIUUSEUPDN_REG_W); 345 if (GIUTERMUPDN_REG_W == GIU_NO_REG_W) 346 termupdn = 0; 347 else 348 termupdn = vrgiu_regread(sc, GIUTERMUPDN_REG_W); 349 if (oiosel != iosel || ointen != inten || 350 ouseupdn != useupdn || otermupdn != termupdn) { 351 for (m = 0x80000000; m; m >>=1) 352 printf ("%c" , (useupdn&m) ? 353 ((termupdn&m) ? 'U' : 'D') : 354 ((iosel&m) ? 'o' : ((inten&m)?'I':'i'))); 355 } 356 oiosel = iosel; 357 ointen = inten; 358 ouseupdn = useupdn; 359 otermupdn = termupdn; 360 } 361 362 void 363 vrgiu_dump_io(struct vrgiu_softc *sc) 364 { 365 366 dbg_bit_display(vrgiu_regread_4(sc, GIUPODAT_REG)); 367 dbg_bit_display(vrgiu_regread_4(sc, GIUPIOD_REG)); 368 printf("\n"); 369 } 370 371 void 372 vrgiu_diff_io() 373 { 374 struct vrgiu_softc *sc = this_giu; 375 static u_int32_t opreg[2] = {0, 0}; 376 u_int32_t preg[2]; 377 378 preg[0] = vrgiu_regread_4(sc, GIUPIOD_REG); 379 preg[1] = vrgiu_regread_4(sc, GIUPODAT_REG); 380 381 if (opreg[0] != preg[0] || opreg[1] != preg[1]) { 382 printf("giu data: "); 383 dbg_bit_display(preg[1]); 384 dbg_bit_display(preg[0]); 385 printf("\n"); 386 } 387 opreg[0] = preg[0]; 388 opreg[1] = preg[1]; 389 } 390 391 void 392 vrgiu_dump_regs(struct vrgiu_softc *sc) 393 { 394 395 if (sc == NULL) { 396 panic("%s(%d): VRGIU device not initialized\n", 397 __FILE__, __LINE__); 398 } 399 printf(" IOSEL: %08x\n", vrgiu_regread_4(sc, GIUIOSEL_REG)); 400 printf(" PIOD: %08x\n", vrgiu_regread_4(sc, GIUPIOD_REG)); 401 printf(" PODAT: %08x\n", vrgiu_regread_4(sc, GIUPODAT_REG)); 402 printf(" INTSTAT: %08x\n", vrgiu_regread_4(sc, GIUINTSTAT_REG)); 403 printf(" INTEN: %08x\n", vrgiu_regread_4(sc, GIUINTEN_REG)); 404 printf(" INTTYP: %08x\n", vrgiu_regread_4(sc, GIUINTTYP_REG)); 405 printf(" INTALSEL: %08x\n", vrgiu_regread_4(sc, GIUINTALSEL_REG)); 406 printf(" INTHTSEL: %08x\n", vrgiu_regread_4(sc, GIUINTHTSEL_REG)); 407 } 408 /* 409 * GIU regster access method. 410 */ 411 u_int32_t 412 vrgiu_regread_4(struct vrgiu_softc *sc, bus_addr_t offs) 413 { 414 u_int16_t reg[2]; 415 416 bus_space_read_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 417 418 return (reg[0] | (reg[1] << 16)); 419 } 420 421 u_int16_t 422 vrgiu_regread(struct vrgiu_softc *sc, bus_addr_t off) 423 { 424 425 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, off)); 426 } 427 428 void 429 vrgiu_regwrite_4(struct vrgiu_softc *sc, bus_addr_t offs, u_int32_t data) 430 { 431 u_int16_t reg[2]; 432 433 reg[0] = data & 0xffff; 434 reg[1] = (data>>16)&0xffff; 435 bus_space_write_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 436 } 437 438 void 439 vrgiu_regwrite(struct vrgiu_softc *sc, bus_addr_t off, u_int16_t data) 440 { 441 442 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, data); 443 } 444 445 /* 446 * PORT 447 */ 448 int 449 vrgiu_port_read(hpcio_chip_t hc, int port) 450 { 451 struct vrgiu_softc *sc = hc->hc_sc; 452 int on; 453 454 if (!LEGAL_OUT_PORT(port)) 455 panic("vrgiu_port_read: illegal gpio port"); 456 457 if (port < 32) 458 on = (vrgiu_regread_4(sc, GIUPIOD_REG) & (1 << port)); 459 else 460 on = (vrgiu_regread_4(sc, GIUPODAT_REG) & (1 << (port - 32))); 461 462 return (on ? 1 : 0); 463 } 464 465 void 466 vrgiu_port_write(hpcio_chip_t hc, int port, int onoff) 467 { 468 struct vrgiu_softc *sc = hc->hc_sc; 469 u_int32_t reg[2]; 470 int bank; 471 472 if (!LEGAL_OUT_PORT(port)) 473 panic("vrgiu_port_write: illegal gpio port"); 474 475 reg[0] = vrgiu_regread_4(sc, GIUPIOD_REG); 476 reg[1] = vrgiu_regread_4(sc, GIUPODAT_REG); 477 bank = port < 32 ? 0 : 1; 478 if (bank == 1) 479 port -= 32; 480 481 if (onoff) 482 reg[bank] |= (1<<port); 483 else 484 reg[bank] &= ~(1<<port); 485 vrgiu_regwrite_4(sc, GIUPIOD_REG, reg[0]); 486 vrgiu_regwrite_4(sc, GIUPODAT_REG, reg[1]); 487 } 488 489 static void 490 vrgiu_update(hpcio_chip_t hc) 491 { 492 } 493 494 static void 495 vrgiu_dump(hpcio_chip_t hc) 496 { 497 } 498 499 static hpcio_chip_t 500 vrgiu_getchip(void* scx, int chipid) 501 { 502 struct vrgiu_softc *sc = scx; 503 504 return (&sc->sc_iochip); 505 } 506 507 /* 508 * Interrupt staff 509 */ 510 void * 511 vrgiu_intr_establish( 512 hpcio_chip_t hc, 513 int port, /* GPIO pin # */ 514 int mode, /* GIU trigger setting */ 515 int (*ih_fun)(void *), 516 void *ih_arg) 517 { 518 struct vrgiu_softc *sc = hc->hc_sc; 519 int s; 520 u_int32_t reg, mask; 521 struct vrgiu_intr_entry *ih; 522 523 if (!LEGAL_INTR_PORT(port)) 524 panic ("vrgiu_intr_establish: bogus interrupt line."); 525 if (sc->sc_intr_mode[port] && mode != sc->sc_intr_mode[port]) 526 panic ("vrgiu_intr_establish: bogus interrupt type."); 527 else 528 sc->sc_intr_mode[port] = mode; 529 mask = (1 << port); 530 531 s = splhigh(); 532 533 if (!(ih = malloc(sizeof(struct vrgiu_intr_entry), M_DEVBUF, M_NOWAIT))) 534 panic ("vrgiu_intr_establish: no memory."); 535 536 DPRINTF(DEBUG_INTR, ("%s: port %d ", sc->sc_dev.dv_xname, port)); 537 ih->ih_port = port; 538 ih->ih_fun = ih_fun; 539 ih->ih_arg = ih_arg; 540 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link); 541 #ifdef WINCE_DEFAULT_SETTING 542 #warning WINCE_DEFAULT_SETTING 543 #else 544 /* 545 * Setup registers 546 */ 547 /* Input mode */ 548 reg = vrgiu_regread_4(sc, GIUIOSEL_REG); 549 reg &= ~mask; 550 vrgiu_regwrite_4(sc, GIUIOSEL_REG, reg); 551 552 /* interrupt type */ 553 reg = vrgiu_regread_4(sc, GIUINTTYP_REG); 554 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "edge" : "level")); 555 if (mode & HPCIO_INTR_EDGE) { 556 DPRINTF(DEBUG_INTR, ("edge]")); 557 reg |= mask; /* edge */ 558 } else { 559 DPRINTF(DEBUG_INTR, ("level]")); 560 reg &= ~mask; /* level */ 561 } 562 vrgiu_regwrite_4(sc, GIUINTTYP_REG, reg); 563 564 /* interrupt level */ 565 if (!(mode & HPCIO_INTR_EDGE)) { 566 reg = vrgiu_regread_4(sc, GIUINTALSEL_REG); 567 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "high" : "low")); 568 if (mode & HPCIO_INTR_HIGH) { 569 DPRINTF(DEBUG_INTR, ("high]")); 570 reg |= mask; /* high */ 571 } else { 572 DPRINTF(DEBUG_INTR, ("low]")); 573 reg &= ~mask; /* low */ 574 } 575 vrgiu_regwrite_4(sc, GIUINTALSEL_REG, reg); 576 } 577 /* hold or through */ 578 reg = vrgiu_regread_4(sc, GIUINTHTSEL_REG); 579 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "hold" : "through")); 580 if (mode & HPCIO_INTR_HOLD) { 581 DPRINTF(DEBUG_INTR, ("hold]")); 582 reg |= mask; /* hold */ 583 } else { 584 DPRINTF(DEBUG_INTR, ("through]")); 585 reg &= ~mask; /* through */ 586 } 587 vrgiu_regwrite_4(sc, GIUINTHTSEL_REG, reg); 588 #endif 589 /* 590 * clear interrupt status 591 */ 592 reg = vrgiu_regread_4(sc, GIUINTSTAT_REG); 593 reg &= ~mask; 594 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, reg); 595 /* 596 * enable interrupt 597 */ 598 #ifdef WINCE_DEFAULT_SETTING 599 #warning WINCE_DEFAULT_SETTING 600 #else 601 sc->sc_intr_mask |= mask; 602 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 603 /* Unmask GIU level 2 mask register */ 604 vrip_intr_setmask2(sc->sc_vc, sc->sc_ih, (1<<port), 1); 605 #endif 606 splx(s); 607 608 DPRINTF(DEBUG_INTR, ("\n")); 609 610 return (ih); 611 } 612 613 void 614 vrgiu_intr_disestablish(hpcio_chip_t hc, void *arg) 615 { 616 struct vrgiu_intr_entry *ihe = arg; 617 struct vrgiu_softc *sc = hc->hc_sc; 618 int port = ihe->ih_port; 619 struct vrgiu_intr_entry *ih; 620 int s; 621 622 s = splhigh(); 623 TAILQ_FOREACH(ih, &sc->sc_intr_head[port], ih_link) { 624 if (ih == ihe) { 625 TAILQ_REMOVE(&sc->sc_intr_head[port], ih, ih_link); 626 free(ih, M_DEVBUF); 627 if (TAILQ_EMPTY(&sc->sc_intr_head[port])) { 628 /* Disable interrupt */ 629 #ifdef WINCE_DEFAULT_SETTING 630 #warning WINCE_DEFAULT_SETTING 631 #else 632 sc->sc_intr_mask &= ~(1<<port); 633 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 634 #endif 635 } 636 splx(s); 637 return; 638 } 639 } 640 panic("vrgiu_intr_disetablish: no such a handle."); 641 /* NOTREACHED */ 642 } 643 644 /* Clear interrupt */ 645 void 646 vrgiu_intr_clear(hpcio_chip_t hc, void *arg) 647 { 648 struct vrgiu_softc *sc = hc->hc_sc; 649 struct vrgiu_intr_entry *ihe = arg; 650 u_int32_t reg; 651 652 reg = vrgiu_regread_4(sc, GIUINTSTAT_REG); 653 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, reg & ~(1 << ihe->ih_port)); 654 } 655 656 static void 657 vrgiu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip) 658 { 659 struct vrgiu_softc *sc = hc->hc_sc; 660 661 vrip_register_gpio(sc->sc_vc, iochip); 662 } 663 664 /* interrupt handler */ 665 int 666 vrgiu_intr(void *arg) 667 { 668 #ifdef DUMP_GIU_LEVEL2_INTR 669 #warning DUMP_GIU_LEVEL2_INTR 670 static u_int32_t oreg; 671 #endif 672 struct vrgiu_softc *sc = arg; 673 int i; 674 u_int32_t reg; 675 int ledvalue = CONFIG_HOOK_LED_FLASH; 676 677 /* Get Level 2 interrupt status */ 678 vrip_intr_getstatus2 (sc->sc_vc, sc->sc_ih, ®); 679 #ifdef DUMP_GIU_LEVEL2_INTR 680 #warning DUMP_GIU_LEVEL2_INTR 681 { 682 u_int32_t uedge, dedge, j; 683 for (j = 0x80000000; j > 0; j >>=1) 684 printf ("%c" , reg&j ? '|' : '.'); 685 uedge = (reg ^ oreg) & reg; 686 dedge = (reg ^ oreg) & ~reg; 687 if (uedge || dedge) { 688 for (j = 0; j < 32; j++) { 689 if (uedge & (1 << j)) 690 printf ("+%d", j); 691 else if (dedge & (1 << j)) 692 printf ("-%d", j); 693 } 694 } 695 oreg = reg; 696 printf ("\n"); 697 } 698 #endif 699 /* Clear interrupt */ 700 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, vrgiu_regread_4(sc, GIUINTSTAT_REG)); 701 702 /* Dispatch handler */ 703 for (i = 0; i < MAX_GPIO_INOUT; i++) { 704 if (reg & (1 << i)) { 705 register struct vrgiu_intr_entry *ih; 706 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) { 707 ih->ih_fun(ih->ih_arg); 708 } 709 } 710 } 711 712 if (vrgiu_intr_led) 713 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_LED, 714 (void *)&ledvalue); 715 return (0); 716 } 717