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