1 /* $NetBSD: vrgiu.c,v 1.4 1999/12/23 06:26:10 takemura Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 5 * Shin Takemura and PocketBSD Project. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the PocketBSD project 18 * and its contributors. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/queue.h> 42 #define TAILQ_FOREACH(var, head, field) \ 43 for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field)) 44 #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 45 46 #include <mips/cpuregs.h> 47 #include <machine/bus.h> 48 49 #include <hpcmips/vr/vripreg.h> 50 #include <hpcmips/vr/vripvar.h> 51 #include <hpcmips/vr/vrgiureg.h> 52 53 #include "locators.h" 54 55 #define VRGIUDEBUG 56 #ifdef VRGIUDEBUG 57 #define DEBUG_IO 1 58 #define DEBUG_INTR 2 59 int vrgiu_debug = 1; 60 #define DPRINTF(flag, arg) if (vrgiu_debug & flag) printf arg; 61 #else 62 #define DPRINTF(flag, arg) 63 #endif 64 65 #define LEGAL_INTR_PORT(x) ((x) >= 0 && (x) < MAX_GPIO_INOUT) 66 #define LEGAL_OUT_PORT(x) ((x) >= 0 && (x) < MAX_GPIO_OUT) 67 68 int vrgiu_match __P((struct device*, struct cfdata*, void*)); 69 void vrgiu_attach __P((struct device*, struct device*, void*)); 70 int vrgiu_intr __P((void*)); 71 int vrgiu_print __P((void*, const char*)); 72 void vrgiu_callback __P((struct device*)); 73 74 void vrgiu_dump_regs(struct vrgiu_softc *sc); 75 void vrgiu_dump_iosetting(struct vrgiu_softc *sc); 76 u_int32_t vrgiu_regread_4 __P((vrgiu_chipset_tag_t, bus_addr_t)); 77 u_int16_t vrgiu_regread __P((vrgiu_chipset_tag_t, bus_addr_t)); 78 void vrgiu_regwrite_4 __P((vrgiu_chipset_tag_t, bus_addr_t, u_int32_t)); 79 void vrgiu_regwrite __P((vrgiu_chipset_tag_t, bus_addr_t, u_int16_t)); 80 81 int vrgiu_port_read __P((vrgiu_chipset_tag_t, int)); 82 int vrgiu_port_write __P((vrgiu_chipset_tag_t, int, int)); 83 84 void *vrgiu_intr_establish __P((vrgiu_chipset_tag_t, int, int, int, int (*)(void *), void*)); 85 void vrgiu_intr_disestablish __P((vrgiu_chipset_tag_t, void*)); 86 87 struct vrgiu_function_tag vrgiu_functions = { 88 vrgiu_port_read, 89 vrgiu_port_write, 90 vrgiu_regread_4, 91 vrgiu_regwrite_4, 92 vrgiu_intr_establish, 93 vrgiu_intr_disestablish 94 }; 95 96 struct cfattach vrgiu_ca = { 97 sizeof(struct vrgiu_softc), vrgiu_match, vrgiu_attach 98 }; 99 100 int 101 vrgiu_match(parent, cf, aux) 102 struct device *parent; 103 struct cfdata *cf; 104 void *aux; 105 { 106 return 2; /* 1st attach group of vrip */ 107 } 108 109 void 110 vrgiu_attach(parent, self, aux) 111 struct device *parent; 112 struct device *self; 113 void *aux; 114 { 115 struct vrip_attach_args *va = aux; 116 struct vrgiu_softc *sc = (void*)self; 117 struct gpbus_attach_args gpa; 118 int i; 119 120 sc->sc_vc = va->va_vc; 121 sc->sc_iot = va->va_iot; 122 bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 123 0 /* no cache */, &sc->sc_ioh); 124 /* 125 * Disable all interrupts. 126 */ 127 sc->sc_intr_mask = 0; 128 #ifdef WINCE_DEFAULT_SETTING 129 #warning WINCE_DEFAULT_SETTING 130 #else 131 #ifdef VRGIUDEBUG 132 if (vrgiu_debug & DEBUG_IO) { 133 printf("\nWIN setting: "); 134 vrgiu_dump_iosetting(sc); 135 printf("\n"); 136 } 137 #endif /* VRGIUDEBUG */ 138 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 139 #endif 140 141 for (i = 0; i < MAX_GPIO_INOUT; i++) 142 TAILQ_INIT(&sc->sc_intr_head[i]); 143 if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_intr, IPL_BIO, 144 vrgiu_intr, sc))) { 145 printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); 146 return; 147 } 148 vrgiu_functions.gf_intr_establish = vrgiu_intr_establish; 149 vrgiu_functions.gf_intr_disestablish = vrgiu_intr_disestablish; 150 /* 151 * Register functions to upper interface. 152 */ 153 vrip_giu_function_register(va->va_vc, &vrgiu_functions, self); 154 #ifdef VRGIUDEBUG 155 /* Display port status (Input/Output) for debugging */ 156 if (vrgiu_debug & DEBUG_IO) { 157 u_int32_t preg[2]; 158 printf("I/O setting: "); 159 vrgiu_dump_iosetting(sc); 160 printf("\n"); 161 162 printf(" data:"); 163 bitdisp64(preg); 164 } 165 #endif /* VRGIUDEBUG */ 166 /* 167 * General purpose bus 168 */ 169 gpa.gpa_busname = "gpbus"; 170 gpa.gpa_gc = sc; 171 gpa.gpa_gf = &vrgiu_functions; 172 while (config_found(self, &gpa, vrgiu_print)) ; 173 /* 174 * GIU-ISA bridge 175 */ 176 #if 1 /* XXX Sometimes mounting root device failed. Why? XXX*/ 177 config_defer(self, vrgiu_callback); 178 #else 179 vrgiu_callback(self); 180 #endif 181 } 182 183 void 184 vrgiu_callback(self) 185 struct device *self; 186 { 187 struct vrgiu_softc *sc = (void*)self; 188 struct gpbus_attach_args gpa; 189 190 gpa.gpa_busname = "vrisab"; 191 gpa.gpa_gc = sc; 192 gpa.gpa_gf = &vrgiu_functions; 193 config_found(self, &gpa, vrgiu_print); 194 } 195 196 int 197 vrgiu_print(aux, pnp) 198 void *aux; 199 const char *pnp; 200 { 201 if (pnp) 202 return (QUIET); 203 return (UNCONF); 204 } 205 206 void 207 vrgiu_dump_iosetting(sc) 208 struct vrgiu_softc *sc; 209 { 210 long iosel, inten, useupdn, termupdn; 211 u_int32_t m; 212 iosel= vrgiu_regread_4(sc, GIUIOSEL_REG); 213 inten= vrgiu_regread_4(sc, GIUINTEN_REG); 214 useupdn = vrgiu_regread(sc, GIUUSEUPDN_REG_W); 215 termupdn = vrgiu_regread(sc, GIUTERMUPDN_REG_W); 216 for (m = 0x80000000; m; m >>=1) 217 printf ("%c" , (useupdn&m) ? 218 ((termupdn&m) ? 'U' : 'D') : 219 ((iosel&m) ? 'o' : ((inten&m)?'I':'i'))); 220 } 221 222 void 223 vrgiu_dump_regs(sc) 224 struct vrgiu_softc *sc; 225 { 226 if (sc == NULL) { 227 panic("%s(%d): VRGIU device not initialized\n", 228 __FILE__, __LINE__); 229 } 230 printf(" IOSEL: %08x\n", vrgiu_regread_4(sc, GIUIOSEL_REG)); 231 printf(" PIOD: %08x\n", vrgiu_regread_4(sc, GIUPIOD_REG)); 232 printf(" PODAT: %08x\n", vrgiu_regread_4(sc, GIUPODAT_REG)); 233 printf(" INTSTAT: %08x\n", vrgiu_regread_4(sc, GIUINTSTAT_REG)); 234 printf(" INTEN: %08x\n", vrgiu_regread_4(sc, GIUINTEN_REG)); 235 printf(" INTTYP: %08x\n", vrgiu_regread_4(sc, GIUINTTYP_REG)); 236 printf(" INTALSEL: %08x\n", vrgiu_regread_4(sc, GIUINTALSEL_REG)); 237 printf(" INTHTSEL: %08x\n", vrgiu_regread_4(sc, GIUINTHTSEL_REG)); 238 } 239 /* 240 * GIU regster access method. 241 */ 242 u_int32_t 243 vrgiu_regread_4(vc, offs) 244 vrgiu_chipset_tag_t vc; 245 bus_addr_t offs; 246 { 247 struct vrgiu_softc *sc = (void*)vc; 248 u_int16_t reg[2]; 249 bus_space_read_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 250 return reg[0]|(reg[1]<<16); 251 } 252 253 u_int16_t 254 vrgiu_regread(vc, off) 255 vrgiu_chipset_tag_t vc; 256 bus_addr_t off; 257 { 258 struct vrgiu_softc *sc = (void*)vc; 259 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, off); 260 } 261 262 void 263 vrgiu_regwrite_4(vc, offs, data) 264 vrgiu_chipset_tag_t vc; 265 bus_addr_t offs; 266 u_int32_t data; 267 { 268 struct vrgiu_softc *sc = (void*)vc; 269 270 u_int16_t reg[2]; 271 reg[0] = data & 0xffff; 272 reg[1] = (data>>16)&0xffff; 273 bus_space_write_region_2 (sc->sc_iot, sc->sc_ioh, offs, reg, 2); 274 } 275 276 void 277 vrgiu_regwrite(vc, off, data) 278 vrgiu_chipset_tag_t vc; 279 bus_addr_t off; 280 u_int16_t data; 281 { 282 struct vrgiu_softc *sc = (void*)vc; 283 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, data); 284 } 285 286 /* 287 * PORT 288 */ 289 int 290 vrgiu_port_read(vc, port) 291 vrgiu_chipset_tag_t vc; 292 int port; 293 { 294 struct vrgiu_softc *sc = (void*)vc; 295 int on; 296 297 if (!LEGAL_OUT_PORT(port)) 298 panic("vrgiu_port_read: illegal gpio port"); 299 300 if (port < 32) 301 on = (vrgiu_regread_4(vc, GIUPIOD_REG) & (1 << port)); 302 else 303 on = (vrgiu_regread_4(vc, GIUPODAT_REG) & (1 << (port - 32))); 304 305 return (on ? 1 : 0); 306 } 307 308 int 309 vrgiu_port_write(vc, port, onoff) 310 vrgiu_chipset_tag_t vc; 311 int port; 312 int onoff; 313 { 314 u_int32_t reg[2]; 315 int bank; 316 317 if (!LEGAL_OUT_PORT(port)) 318 panic("vrgiu_port_write: illegal gpio port"); 319 320 reg[0] = vrgiu_regread_4(vc, GIUPIOD_REG); 321 reg[1] = vrgiu_regread_4(vc, GIUPODAT_REG); 322 bank = port < 32 ? 0 : 1; 323 if (bank == 1) 324 port -= 32; 325 326 if (onoff) 327 reg[bank] |= (1<<port); 328 else 329 reg[bank] &= ~(1<<port); 330 vrgiu_regwrite_4(vc, GIUPIOD_REG, reg[0]); 331 vrgiu_regwrite_4(vc, GIUPODAT_REG, reg[1]); 332 333 return 0; 334 } 335 /* 336 * For before autoconfiguration. 337 */ 338 void 339 __vrgiu_out(port, data) 340 int port; 341 int data; 342 { 343 u_int16_t reg; 344 u_int32_t addr; 345 int offs; 346 347 if (!LEGAL_OUT_PORT(port)) 348 panic("__vrgiu_out: illegal gpio port"); 349 if (port < 16) { 350 addr = MIPS_PHYS_TO_KSEG1((VRIP_GIU_ADDR + GIUPIOD_L_REG_W)); 351 offs = port; 352 } else if (port < 32) { 353 addr = MIPS_PHYS_TO_KSEG1((VRIP_GIU_ADDR + GIUPIOD_H_REG_W)); 354 offs = port - 16; 355 } else if (port < 48) { 356 addr = MIPS_PHYS_TO_KSEG1((VRIP_GIU_ADDR + GIUPODAT_L_REG_W)); 357 offs = port - 32; 358 } else { 359 addr = MIPS_PHYS_TO_KSEG1((VRIP_GIU_ADDR + GIUPODAT_H_REG_W)); 360 offs = port - 48; 361 panic ("__vrgiu_out: not coded yet."); 362 } 363 printf ("__vrgiu_out: addr %08x bit %d\n", addr, offs); 364 365 wbflush(); 366 reg = *((volatile u_int16_t*)addr); 367 if (data) { 368 reg |= (1 << offs); 369 } else { 370 reg &= ~(1 << offs); 371 } 372 *((volatile u_int16_t*)addr) = reg; 373 wbflush(); 374 } 375 /* 376 * Interrupt staff 377 */ 378 void * 379 vrgiu_intr_establish(ic, port, mode, level, ih_fun, ih_arg) 380 vrgiu_chipset_tag_t ic; 381 int port; /* GPIO pin # */ 382 int mode; /* GIU trigger setting */ 383 int level; /* XXX not yet */ 384 int (*ih_fun) __P((void*)); 385 void *ih_arg; 386 { 387 struct vrgiu_softc *sc = (void*)ic; 388 int s; 389 u_int32_t reg, mask; 390 struct vrgiu_intr_entry *ih; 391 392 if (!LEGAL_INTR_PORT(port)) 393 panic ("vrgiu_intr_establish: bogus interrupt line."); 394 if (sc->sc_intr_mode[port] && mode != sc->sc_intr_mode[port]) 395 panic ("vrgiu_intr_establish: bogus interrupt type."); 396 else 397 sc->sc_intr_mode[port] = mode; 398 mask = (1 << port); 399 400 s = splhigh(); 401 402 if (!(ih = malloc(sizeof(struct vrgiu_intr_entry), M_DEVBUF, M_NOWAIT))) 403 panic ("vrgiu_intr_establish: no memory."); 404 405 ih->ih_port = port; 406 ih->ih_fun = ih_fun; 407 ih->ih_arg = ih_arg; 408 TAILQ_INSERT_TAIL(&sc->sc_intr_head[port], ih, ih_link); 409 #ifdef WINCE_DEFAULT_SETTING 410 #warning WINCE_DEFAULT_SETTING 411 #else 412 /* 413 * Setup registers 414 */ 415 /* Input mode */ 416 reg = vrgiu_regread_4(sc, GIUIOSEL_REG); 417 reg &= ~mask; 418 vrgiu_regwrite_4(sc, GIUIOSEL_REG, reg); 419 420 /* interrupt type */ 421 reg = vrgiu_regread_4(sc, GIUINTTYP_REG); 422 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "edge" : "level")); 423 if (mode & VRGIU_INTR_EDGE) { 424 DPRINTF(DEBUG_INTR, ("edge]")); 425 reg |= mask; /* edge */ 426 } else { 427 DPRINTF(DEBUG_INTR, ("level]")); 428 reg &= ~mask; /* level */ 429 } 430 vrgiu_regwrite_4(sc, GIUINTTYP_REG, reg); 431 432 /* interrupt level */ 433 if (!(mode & VRGIU_INTR_EDGE)) { 434 reg = vrgiu_regread_4(sc, GIUINTALSEL_REG); 435 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "high" : "low")); 436 if (mode & VRGIU_INTR_HIGH) { 437 DPRINTF(DEBUG_INTR, ("high]")); 438 reg |= mask; /* high */ 439 } else { 440 DPRINTF(DEBUG_INTR, ("low]")); 441 reg &= ~mask; /* low */ 442 } 443 vrgiu_regwrite_4(sc, GIUINTALSEL_REG, reg); 444 } 445 /* hold or through */ 446 reg = vrgiu_regread_4(sc, GIUINTHTSEL_REG); 447 DPRINTF(DEBUG_INTR, ("[%s->",reg & mask ? "hold" : "through")); 448 if (mode & VRGIU_INTR_HOLD) { 449 DPRINTF(DEBUG_INTR, ("hold]")); 450 reg |= mask; /* hold */ 451 } else { 452 DPRINTF(DEBUG_INTR, ("through]")); 453 reg &= ~mask; /* through */ 454 } 455 vrgiu_regwrite_4(sc, GIUINTHTSEL_REG, reg); 456 #endif 457 /* 458 * clear interrupt status 459 */ 460 reg = vrgiu_regread_4(sc, GIUINTSTAT_REG); 461 reg &= ~mask; 462 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, reg); 463 /* 464 * enable interrupt 465 */ 466 #ifdef WINCE_DEFAULT_SETTING 467 #warning WINCE_DEFAULT_SETTING 468 #else 469 sc->sc_intr_mask |= mask; 470 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 471 /* Unmask GIU level 2 mask register */ 472 vrip_intr_setmask2(sc->sc_vc, sc->sc_ih, (1<<port), 1); 473 #endif 474 splx(s); 475 476 DPRINTF(DEBUG_INTR, ("\n")); 477 #if 0 && defined VRGIUDEBUG 478 vrgiu_dump_regs(sc); 479 #endif 480 481 return ih; 482 } 483 484 void 485 vrgiu_intr_disestablish(ic, arg) 486 vrgiu_chipset_tag_t ic; 487 void *arg; 488 { 489 struct vrgiu_intr_entry *ihe = arg; 490 struct vrgiu_softc *sc = (void*)ic; 491 int port = ihe->ih_port; 492 struct vrgiu_intr_entry *ih; 493 int s; 494 495 s = splhigh(); 496 TAILQ_FOREACH(ih, &sc->sc_intr_head[port], ih_link) { 497 if (ih == ihe) { 498 TAILQ_REMOVE(&sc->sc_intr_head[port], ih, ih_link); 499 free(ih, M_DEVBUF); 500 if (TAILQ_EMPTY(&sc->sc_intr_head[port])) { 501 /* Disable interrupt */ 502 #ifdef WINCE_DEFAULT_SETTING 503 #warning WINCE_DEFAULT_SETTING 504 #else 505 sc->sc_intr_mask &= ~(1<<port); 506 vrgiu_regwrite_4(sc, GIUINTEN_REG, sc->sc_intr_mask); 507 #endif 508 } 509 splx(s); 510 return; 511 } 512 } 513 panic("vrgiu_intr_disetablish: no such a handle."); 514 /* NOTREACHED */ 515 } 516 517 int 518 vrgiu_intr(arg) 519 void *arg; 520 { 521 #ifdef DUMP_GIU_LEVEL2_INTR 522 #warning DUMP_GIU_LEVEL2_INTR 523 static u_int32_t oreg; 524 #endif 525 struct vrgiu_softc *sc = arg; 526 int i; 527 u_int32_t reg; 528 /* Get Level 2 interrupt status */ 529 vrip_intr_get_status2 (sc->sc_vc, sc->sc_ih, ®); 530 #ifdef DUMP_GIU_LEVEL2_INTR 531 #warning DUMP_GIU_LEVEL2_INTR 532 { 533 u_int32_t uedge, dedge, j; 534 for (j = 0x80000000; j > 0; j >>=1) 535 printf ("%c" , reg&j ? '|' : '.'); 536 uedge = (reg ^ oreg) & reg; 537 dedge = (reg ^ oreg) & ~reg; 538 if (uedge || dedge) { 539 for (j = 0; j < 32; j++) { 540 if (uedge & (1 << j)) 541 printf ("+%d", j); 542 else if (dedge & (1 << j)) 543 printf ("-%d", j); 544 } 545 } 546 oreg = reg; 547 printf ("\n"); 548 } 549 #endif 550 /* Clear interrupt */ 551 vrgiu_regwrite_4(sc, GIUINTSTAT_REG, vrgiu_regread_4(sc, GIUINTSTAT_REG)); 552 553 /* Dispatch handler */ 554 for (i = 0; i < MAX_GPIO_INOUT; i++) { 555 if (reg & (1 << i)) { 556 register struct vrgiu_intr_entry *ih; 557 TAILQ_FOREACH(ih, &sc->sc_intr_head[i], ih_link) { 558 ih->ih_fun(ih->ih_arg); 559 } 560 } 561 } 562 563 return 0; 564 } 565