1 /* $NetBSD: vrgiu.c,v 1.38 2002/10/02 05:26:55 thorpej 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 CFATTACH_DECL(vrgiu, sizeof(struct vrgiu_softc), 176 vrgiu_match, vrgiu_attach, NULL, NULL); 177 178 struct vrgiu_softc *this_giu; 179 180 /* 181 * function bodies 182 */ 183 int 184 vrgiu_match(struct device *parent, struct cfdata *cf, void *aux) 185 { 186 187 return (2); /* 1st attach group of vrip */ 188 } 189 190 void 191 vrgiu_attach(struct device *parent, struct device *self, void *aux) 192 { 193 struct vrip_attach_args *va = aux; 194 struct vrgiu_softc *sc = (void*)self; 195 struct hpcio_attach_args haa; 196 int i; 197 198 #ifndef SINGLE_VRIP_BASE 199 if (va->va_addr == VR4102_GIU_ADDR) { 200 sc->sc_useupdn_reg = VR4102_GIUUSEUPDN_REG_W; 201 sc->sc_termupdn_reg = VR4102_GIUTERMUPDN_REG_W; 202 } else 203 if (va->va_addr == VR4122_GIU_ADDR) { 204 sc->sc_useupdn_reg = VR4122_GIUUSEUPDN_REG_W; 205 sc->sc_termupdn_reg = VR4122_GIUTERMUPDN_REG_W; 206 } else { 207 panic("%s: unknown base address 0x%lx", 208 sc->sc_dev.dv_xname, va->va_addr); 209 } 210 #endif /* SINGLE_VRIP_BASE */ 211 212 this_giu = sc; 213 sc->sc_vc = va->va_vc; 214 sc->sc_iot = va->va_iot; 215 bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 216 0 /* no cache */, &sc->sc_ioh); 217 /* 218 * Disable all interrupts. 219 */ 220 sc->sc_intr_mask = 0; 221 printf("\n"); 222 #ifdef WINCE_DEFAULT_SETTING 223 #warning WINCE_DEFAULT_SETTING 224 #else 225 VPRINTF(DEBUG_IO, (" " 226 " 3 2 1\n")); 227 VPRINTF(DEBUG_IO, (" " 228 "10987654321098765432109876543210\n")); 229 VPRINTF(DEBUG_IO, ("WIN setting: ")); 230 VDUMP_IOSETTING(DEBUG_IO, sc); 231 VPRINTF(DEBUG_IO, ("\n")); 232 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 233 #endif 234 235 for (i = 0; i < MAX_GPIO_INOUT; i++) 236 TAILQ_INIT(&sc->sc_intr_head[i]); 237 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_unit, 0, 238 IPL_BIO, vrgiu_intr, sc))) { 239 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 240 return; 241 } 242 /* 243 * fill hpcio_chip structure 244 */ 245 sc->sc_iochip = vrgiu_iochip; /* structure copy */ 246 sc->sc_iochip.hc_chipid = VRIP_IOCHIP_VRGIU; 247 sc->sc_iochip.hc_name = sc->sc_dev.dv_xname; 248 sc->sc_iochip.hc_sc = sc; 249 /* Register functions to upper interface */ 250 vrip_register_gpio(va->va_vc, &sc->sc_iochip); 251 252 /* Display port status (Input/Output) for debugging */ 253 VPRINTF(DEBUG_IO, ("I/O setting: ")); 254 VDUMP_IOSETTING(DEBUG_IO, sc); 255 VPRINTF(DEBUG_IO, ("\n")); 256 VPRINTF(DEBUG_IO, (" data:")); 257 VDUMP_IO(DEBUG_IO, sc); 258 259 /* 260 * hpcio I/F 261 */ 262 haa.haa_busname = HPCIO_BUSNAME; 263 haa.haa_sc = sc; 264 haa.haa_getchip = vrgiu_getchip; 265 haa.haa_iot = sc->sc_iot; 266 while (config_found(self, &haa, vrgiu_print)) ; 267 /* 268 * GIU-ISA bridge 269 */ 270 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/ 271 config_defer(self, vrgiu_callback); 272 #else 273 vrgiu_callback(self); 274 #endif 275 } 276 277 void 278 vrgiu_callback(struct device *self) 279 { 280 struct vrgiu_softc *sc = (void*)self; 281 struct hpcio_attach_args haa; 282 283 haa.haa_busname = "vrisab"; 284 haa.haa_sc = sc; 285 haa.haa_getchip = vrgiu_getchip; 286 haa.haa_iot = sc->sc_iot; 287 config_found(self, &haa, vrgiu_print); 288 } 289 290 int 291 vrgiu_print(void *aux, const char *pnp) 292 { 293 if (pnp) 294 return (QUIET); 295 return (UNCONF); 296 } 297 298 void 299 vrgiu_dump_iosetting(struct vrgiu_softc *sc) 300 { 301 long iosel, inten, useupdn, termupdn, edge, hold, level; 302 u_int32_t m; 303 char syms[] = "iiiiiiiilhLHeeEEoooooooooooooooo" 304 "DDDDDDDDDDDDDDDDUUUUUUUUUUUUUUUU"; 305 306 iosel= vrgiu_regread_4(sc, GIUIOSEL_REG); 307 inten= vrgiu_regread_4(sc, GIUINTEN_REG); 308 edge = vrgiu_regread_4(sc, GIUINTTYP_REG); 309 hold = vrgiu_regread_4(sc, GIUINTHTSEL_REG); 310 level = vrgiu_regread_4(sc, GIUINTALSEL_REG); 311 312 if (GIUUSEUPDN_REG_W == GIU_NO_REG_W) 313 useupdn = 0; 314 else 315 useupdn = vrgiu_regread(sc, GIUUSEUPDN_REG_W); 316 if (GIUTERMUPDN_REG_W == GIU_NO_REG_W) 317 termupdn = 0; 318 else 319 termupdn = vrgiu_regread(sc, GIUTERMUPDN_REG_W); 320 for (m = 0x80000000; m; m >>=1) 321 printf ("%c", syms[ 322 ((useupdn&m) ? 32 : 0) + 323 ((iosel&m) ? 16 : 0) + ((termupdn&m) ? 16 : 0) + 324 ((inten&m) ? 8 : 0) + 325 ((edge&m) ? 4 : 0) + 326 ((hold&m) ? 2 : 0) + 327 ((level&m) ? 1 : 0)]); 328 } 329 330 void 331 vrgiu_diff_iosetting() 332 { 333 struct vrgiu_softc *sc = this_giu; 334 static long oiosel = 0, ointen = 0, ouseupdn = 0, otermupdn = 0; 335 long iosel, inten, useupdn, termupdn; 336 u_int32_t m; 337 338 iosel= vrgiu_regread_4(sc, GIUIOSEL_REG); 339 inten= vrgiu_regread_4(sc, GIUINTEN_REG); 340 if (GIUUSEUPDN_REG_W == GIU_NO_REG_W) 341 useupdn = 0; 342 else 343 useupdn = vrgiu_regread(sc, GIUUSEUPDN_REG_W); 344 if (GIUTERMUPDN_REG_W == GIU_NO_REG_W) 345 termupdn = 0; 346 else 347 termupdn = vrgiu_regread(sc, GIUTERMUPDN_REG_W); 348 if (oiosel != iosel || ointen != inten || 349 ouseupdn != useupdn || otermupdn != termupdn) { 350 for (m = 0x80000000; m; m >>=1) 351 printf ("%c" , (useupdn&m) ? 352 ((termupdn&m) ? 'U' : 'D') : 353 ((iosel&m) ? 'o' : ((inten&m)?'I':'i'))); 354 } 355 oiosel = iosel; 356 ointen = inten; 357 ouseupdn = useupdn; 358 otermupdn = termupdn; 359 } 360 361 void 362 vrgiu_dump_io(struct vrgiu_softc *sc) 363 { 364 365 dbg_bit_display(vrgiu_regread_4(sc, GIUPODAT_REG)); 366 dbg_bit_display(vrgiu_regread_4(sc, GIUPIOD_REG)); 367 printf("\n"); 368 } 369 370 void 371 vrgiu_diff_io() 372 { 373 struct vrgiu_softc *sc = this_giu; 374 static u_int32_t opreg[2] = {0, 0}; 375 u_int32_t preg[2]; 376 377 preg[0] = vrgiu_regread_4(sc, GIUPIOD_REG); 378 preg[1] = vrgiu_regread_4(sc, GIUPODAT_REG); 379 380 if (opreg[0] != preg[0] || opreg[1] != preg[1]) { 381 printf("giu data: "); 382 dbg_bit_display(preg[1]); 383 dbg_bit_display(preg[0]); 384 printf("\n"); 385 } 386 opreg[0] = preg[0]; 387 opreg[1] = preg[1]; 388 } 389 390 void 391 vrgiu_dump_regs(struct vrgiu_softc *sc) 392 { 393 394 if (sc == NULL) { 395 panic("%s(%d): VRGIU device not initialized", 396 __FILE__, __LINE__); 397 } 398 printf(" IOSEL: %08x\n", vrgiu_regread_4(sc, GIUIOSEL_REG)); 399 printf(" PIOD: %08x\n", vrgiu_regread_4(sc, GIUPIOD_REG)); 400 printf(" PODAT: %08x\n", vrgiu_regread_4(sc, GIUPODAT_REG)); 401 printf(" INTSTAT: %08x\n", vrgiu_regread_4(sc, GIUINTSTAT_REG)); 402 printf(" INTEN: %08x\n", vrgiu_regread_4(sc, GIUINTEN_REG)); 403 printf(" INTTYP: %08x\n", vrgiu_regread_4(sc, GIUINTTYP_REG)); 404 printf(" INTALSEL: %08x\n", vrgiu_regread_4(sc, GIUINTALSEL_REG)); 405 printf(" INTHTSEL: %08x\n", vrgiu_regread_4(sc, GIUINTHTSEL_REG)); 406 } 407 /* 408 * GIU regster access method. 409 */ 410 u_int32_t 411 vrgiu_regread_4(struct vrgiu_softc *sc, bus_addr_t offs) 412 { 413 u_int16_t reg[2]; 414 415 bus_space_read_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 416 417 return (reg[0] | (reg[1] << 16)); 418 } 419 420 u_int16_t 421 vrgiu_regread(struct vrgiu_softc *sc, bus_addr_t off) 422 { 423 424 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, off)); 425 } 426 427 void 428 vrgiu_regwrite_4(struct vrgiu_softc *sc, bus_addr_t offs, u_int32_t data) 429 { 430 u_int16_t reg[2]; 431 432 reg[0] = data & 0xffff; 433 reg[1] = (data>>16)&0xffff; 434 bus_space_write_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 435 } 436 437 void 438 vrgiu_regwrite(struct vrgiu_softc *sc, bus_addr_t off, u_int16_t data) 439 { 440 441 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, data); 442 } 443 444 /* 445 * PORT 446 */ 447 int 448 vrgiu_port_read(hpcio_chip_t hc, int port) 449 { 450 struct vrgiu_softc *sc = hc->hc_sc; 451 int on; 452 453 if (!LEGAL_OUT_PORT(port)) 454 panic("vrgiu_port_read: illegal gpio port"); 455 456 if (port < 32) 457 on = (vrgiu_regread_4(sc, GIUPIOD_REG) & (1 << port)); 458 else 459 on = (vrgiu_regread_4(sc, GIUPODAT_REG) & (1 << (port - 32))); 460 461 return (on ? 1 : 0); 462 } 463 464 void 465 vrgiu_port_write(hpcio_chip_t hc, int port, int onoff) 466 { 467 struct vrgiu_softc *sc = hc->hc_sc; 468 u_int32_t reg[2]; 469 int bank; 470 471 if (!LEGAL_OUT_PORT(port)) 472 panic("vrgiu_port_write: illegal gpio port"); 473 474 reg[0] = vrgiu_regread_4(sc, GIUPIOD_REG); 475 reg[1] = vrgiu_regread_4(sc, GIUPODAT_REG); 476 bank = port < 32 ? 0 : 1; 477 if (bank == 1) 478 port -= 32; 479 480 if (onoff) 481 reg[bank] |= (1<<port); 482 else 483 reg[bank] &= ~(1<<port); 484 vrgiu_regwrite_4(sc, GIUPIOD_REG, reg[0]); 485 vrgiu_regwrite_4(sc, GIUPODAT_REG, reg[1]); 486 } 487 488 static void 489 vrgiu_update(hpcio_chip_t hc) 490 { 491 } 492 493 static void 494 vrgiu_dump(hpcio_chip_t hc) 495 { 496 } 497 498 static hpcio_chip_t 499 vrgiu_getchip(void* scx, int chipid) 500 { 501 struct vrgiu_softc *sc = scx; 502 503 return (&sc->sc_iochip); 504 } 505 506 /* 507 * Interrupt staff 508 */ 509 void * 510 vrgiu_intr_establish( 511 hpcio_chip_t hc, 512 int port, /* GPIO pin # */ 513 int mode, /* GIU trigger setting */ 514 int (*ih_fun)(void *), 515 void *ih_arg) 516 { 517 struct vrgiu_softc *sc = hc->hc_sc; 518 int s; 519 u_int32_t reg, mask; 520 struct vrgiu_intr_entry *ih; 521 522 if (!LEGAL_INTR_PORT(port)) 523 panic ("vrgiu_intr_establish: bogus interrupt line."); 524 if (sc->sc_intr_mode[port] && mode != sc->sc_intr_mode[port]) 525 panic ("vrgiu_intr_establish: bogus interrupt type."); 526 else 527 sc->sc_intr_mode[port] = mode; 528 mask = (1 << port); 529 530 s = splhigh(); 531 532 if (!(ih = malloc(sizeof(struct vrgiu_intr_entry), M_DEVBUF, M_NOWAIT))) 533 panic ("vrgiu_intr_establish: no memory."); 534 535 DPRINTF(DEBUG_INTR, ("%s: port %d ", sc->sc_dev.dv_xname, port)); 536 ih->ih_port = port; 537 ih->ih_fun = ih_fun; 538 ih->ih_arg = ih_arg; 539 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link); 540 #ifdef WINCE_DEFAULT_SETTING 541 #warning WINCE_DEFAULT_SETTING 542 #else 543 /* 544 * Setup registers 545 */ 546 /* Input mode */ 547 reg = vrgiu_regread_4(sc, GIUIOSEL_REG); 548 reg &= ~mask; 549 vrgiu_regwrite_4(sc, GIUIOSEL_REG, reg); 550 551 /* interrupt type */ 552 reg = vrgiu_regread_4(sc, GIUINTTYP_REG); 553 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "edge" : "level")); 554 if (mode & HPCIO_INTR_EDGE) { 555 DPRINTF(DEBUG_INTR, ("edge]")); 556 reg |= mask; /* edge */ 557 } else { 558 DPRINTF(DEBUG_INTR, ("level]")); 559 reg &= ~mask; /* level */ 560 } 561 vrgiu_regwrite_4(sc, GIUINTTYP_REG, reg); 562 563 /* interrupt level */ 564 if (!(mode & HPCIO_INTR_EDGE)) { 565 reg = vrgiu_regread_4(sc, GIUINTALSEL_REG); 566 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "high" : "low")); 567 if (mode & HPCIO_INTR_HIGH) { 568 DPRINTF(DEBUG_INTR, ("high]")); 569 reg |= mask; /* high */ 570 } else { 571 DPRINTF(DEBUG_INTR, ("low]")); 572 reg &= ~mask; /* low */ 573 } 574 vrgiu_regwrite_4(sc, GIUINTALSEL_REG, reg); 575 } 576 /* hold or through */ 577 reg = vrgiu_regread_4(sc, GIUINTHTSEL_REG); 578 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "hold" : "through")); 579 if (mode & HPCIO_INTR_HOLD) { 580 DPRINTF(DEBUG_INTR, ("hold]")); 581 reg |= mask; /* hold */ 582 } else { 583 DPRINTF(DEBUG_INTR, ("through]")); 584 reg &= ~mask; /* through */ 585 } 586 vrgiu_regwrite_4(sc, GIUINTHTSEL_REG, reg); 587 #endif 588 /* 589 * clear interrupt status 590 */ 591 reg = vrgiu_regread_4(sc, GIUINTSTAT_REG); 592 reg &= ~mask; 593 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, reg); 594 /* 595 * enable interrupt 596 */ 597 #ifdef WINCE_DEFAULT_SETTING 598 #warning WINCE_DEFAULT_SETTING 599 #else 600 sc->sc_intr_mask |= mask; 601 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 602 /* Unmask GIU level 2 mask register */ 603 vrip_intr_setmask2(sc->sc_vc, sc->sc_ih, (1<<port), 1); 604 #endif 605 splx(s); 606 607 DPRINTF(DEBUG_INTR, ("\n")); 608 609 return (ih); 610 } 611 612 void 613 vrgiu_intr_disestablish(hpcio_chip_t hc, void *arg) 614 { 615 struct vrgiu_intr_entry *ihe = arg; 616 struct vrgiu_softc *sc = hc->hc_sc; 617 int port = ihe->ih_port; 618 struct vrgiu_intr_entry *ih; 619 int s; 620 621 s = splhigh(); 622 TAILQ_FOREACH(ih, &sc->sc_intr_head[port], ih_link) { 623 if (ih == ihe) { 624 TAILQ_REMOVE(&sc->sc_intr_head[port], ih, ih_link); 625 free(ih, M_DEVBUF); 626 if (TAILQ_EMPTY(&sc->sc_intr_head[port])) { 627 /* Disable interrupt */ 628 #ifdef WINCE_DEFAULT_SETTING 629 #warning WINCE_DEFAULT_SETTING 630 #else 631 sc->sc_intr_mask &= ~(1<<port); 632 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 633 #endif 634 } 635 splx(s); 636 return; 637 } 638 } 639 panic("vrgiu_intr_disetablish: no such a handle."); 640 /* NOTREACHED */ 641 } 642 643 /* Clear interrupt */ 644 void 645 vrgiu_intr_clear(hpcio_chip_t hc, void *arg) 646 { 647 struct vrgiu_softc *sc = hc->hc_sc; 648 struct vrgiu_intr_entry *ihe = arg; 649 u_int32_t reg; 650 651 reg = vrgiu_regread_4(sc, GIUINTSTAT_REG); 652 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, reg & ~(1 << ihe->ih_port)); 653 } 654 655 static void 656 vrgiu_register_iochip(hpcio_chip_t hc, hpcio_chip_t iochip) 657 { 658 struct vrgiu_softc *sc = hc->hc_sc; 659 660 vrip_register_gpio(sc->sc_vc, iochip); 661 } 662 663 /* interrupt handler */ 664 int 665 vrgiu_intr(void *arg) 666 { 667 #ifdef DUMP_GIU_LEVEL2_INTR 668 #warning DUMP_GIU_LEVEL2_INTR 669 static u_int32_t oreg; 670 #endif 671 struct vrgiu_softc *sc = arg; 672 int i; 673 u_int32_t reg; 674 int ledvalue = CONFIG_HOOK_LED_FLASH; 675 676 /* Get Level 2 interrupt status */ 677 vrip_intr_getstatus2 (sc->sc_vc, sc->sc_ih, ®); 678 #ifdef DUMP_GIU_LEVEL2_INTR 679 #warning DUMP_GIU_LEVEL2_INTR 680 { 681 u_int32_t uedge, dedge, j; 682 for (j = 0x80000000; j > 0; j >>=1) 683 printf ("%c" , reg&j ? '|' : '.'); 684 uedge = (reg ^ oreg) & reg; 685 dedge = (reg ^ oreg) & ~reg; 686 if (uedge || dedge) { 687 for (j = 0; j < 32; j++) { 688 if (uedge & (1 << j)) 689 printf ("+%d", j); 690 else if (dedge & (1 << j)) 691 printf ("-%d", j); 692 } 693 } 694 oreg = reg; 695 printf ("\n"); 696 } 697 #endif 698 /* Clear interrupt */ 699 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, vrgiu_regread_4(sc, GIUINTSTAT_REG)); 700 701 /* Dispatch handler */ 702 for (i = 0; i < MAX_GPIO_INOUT; i++) { 703 if (reg & (1 << i)) { 704 register struct vrgiu_intr_entry *ih; 705 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) { 706 ih->ih_fun(ih->ih_arg); 707 } 708 } 709 } 710 711 if (vrgiu_intr_led) 712 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_LED, 713 (void *)&ledvalue); 714 return (0); 715 } 716