1 /* $NetBSD: stp4020.c,v 1.34 2003/01/07 20:39:19 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.34 2003/01/07 20:39:19 martin Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/errno.h> 49 #include <sys/malloc.h> 50 #include <sys/extent.h> 51 #include <sys/proc.h> 52 #include <sys/kernel.h> 53 #include <sys/kthread.h> 54 #include <sys/device.h> 55 56 #include <dev/pcmcia/pcmciareg.h> 57 #include <dev/pcmcia/pcmciavar.h> 58 #include <dev/pcmcia/pcmciachip.h> 59 60 #include <machine/bus.h> 61 #include <machine/intr.h> 62 63 #include <dev/sbus/sbusvar.h> 64 #include <dev/sbus/stp4020reg.h> 65 66 #define STP4020_DEBUG 1 /* XXX-temp */ 67 68 /* 69 * We use the three available windows per socket in a simple, fixed 70 * arrangement. Each window maps (at full 1 MB size) one of the pcmcia 71 * spaces into sbus space. 72 */ 73 #define STP_WIN_ATTR 0 /* index of the attribute memory space window */ 74 #define STP_WIN_MEM 1 /* index of the common memory space window */ 75 #define STP_WIN_IO 2 /* index of the io space window */ 76 77 78 #if defined(STP4020_DEBUG) 79 int stp4020_debug = 0; 80 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0) 81 #else 82 #define DPRINTF(x) 83 #endif 84 85 /* 86 * Event queue; events detected in an interrupt context go here 87 * awaiting attention from our event handling thread. 88 */ 89 struct stp4020_event { 90 SIMPLEQ_ENTRY(stp4020_event) se_q; 91 int se_type; 92 int se_sock; 93 }; 94 /* Defined event types */ 95 #define STP4020_EVENT_INSERTION 0 96 #define STP4020_EVENT_REMOVAL 1 97 98 /* 99 * Per socket data. 100 */ 101 struct stp4020_socket { 102 struct stp4020_softc *sc; /* Back link */ 103 int flags; 104 #define STP4020_SOCKET_BUSY 0x0001 105 #define STP4020_SOCKET_SHUTDOWN 0x0002 106 int sock; /* Socket number (0 or 1) */ 107 int sbus_intno; /* Do we use first (0) or second (1) 108 interrupt? */ 109 int int_enable; /* ICR0 value for interrupt enabled */ 110 int int_disable; /* ICR0 value for interrupt disabled */ 111 bus_space_tag_t tag; /* socket control io */ 112 bus_space_handle_t regs; /* space */ 113 bus_space_tag_t pcmciat; /* io space for pcmcia */ 114 struct device *pcmcia; /* Associated PCMCIA device */ 115 int (*intrhandler) /* Card driver interrupt handler */ 116 __P((void *)); 117 void *intrarg; /* Card interrupt handler argument */ 118 void *softint; /* cookie for the softintr */ 119 120 struct { 121 bus_space_handle_t winaddr;/* this window's address */ 122 } windows[STP4020_NWIN]; 123 124 }; 125 126 struct stp4020_softc { 127 struct device sc_dev; /* Base device */ 128 struct sbusdev sc_sd; /* SBus device */ 129 bus_space_tag_t sc_bustag; 130 pcmcia_chipset_tag_t sc_pct; /* Chipset methods */ 131 132 struct proc *event_thread; /* event handling thread */ 133 SIMPLEQ_HEAD(, stp4020_event) events; /* Pending events for thread */ 134 135 struct stp4020_socket sc_socks[STP4020_NSOCK]; 136 }; 137 138 139 static int stp4020print __P((void *, const char *)); 140 static int stp4020match __P((struct device *, struct cfdata *, void *)); 141 static void stp4020attach __P((struct device *, struct device *, void *)); 142 static int stp4020_intr __P((void *)); 143 static void stp4020_map_window(struct stp4020_socket *h, int win, int speed); 144 static void stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay); 145 static void stp4020_intr_dispatch(void *arg); 146 147 CFATTACH_DECL(nell, sizeof(struct stp4020_softc), 148 stp4020match, stp4020attach, NULL, NULL); 149 150 #ifdef STP4020_DEBUG 151 static void stp4020_dump_regs __P((struct stp4020_socket *)); 152 #endif 153 154 static int stp4020_rd_sockctl __P((struct stp4020_socket *, int)); 155 static void stp4020_wr_sockctl __P((struct stp4020_socket *, int, int)); 156 static int stp4020_rd_winctl __P((struct stp4020_socket *, int, int)); 157 static void stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int)); 158 159 void stp4020_delay __P((unsigned int)); 160 void stp4020_attach_socket __P((struct stp4020_socket *, int)); 161 void stp4020_create_event_thread __P((void *)); 162 void stp4020_event_thread __P((void *)); 163 void stp4020_queue_event __P((struct stp4020_softc *, int, int)); 164 165 int stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t, 166 struct pcmcia_mem_handle *)); 167 void stp4020_chip_mem_free __P((pcmcia_chipset_handle_t, 168 struct pcmcia_mem_handle *)); 169 int stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, 170 bus_size_t, struct pcmcia_mem_handle *, 171 bus_size_t *, int *)); 172 void stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int)); 173 174 int stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t, 175 bus_addr_t, bus_size_t, bus_size_t, 176 struct pcmcia_io_handle *)); 177 void stp4020_chip_io_free __P((pcmcia_chipset_handle_t, 178 struct pcmcia_io_handle *)); 179 int stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, 180 bus_size_t, struct pcmcia_io_handle *, int *)); 181 void stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int)); 182 183 void stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t)); 184 void stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t)); 185 void *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t, 186 struct pcmcia_function *, int, 187 int (*) __P((void *)), void *)); 188 void stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *)); 189 190 /* Our PCMCIA chipset methods */ 191 static struct pcmcia_chip_functions stp4020_functions = { 192 stp4020_chip_mem_alloc, 193 stp4020_chip_mem_free, 194 stp4020_chip_mem_map, 195 stp4020_chip_mem_unmap, 196 197 stp4020_chip_io_alloc, 198 stp4020_chip_io_free, 199 stp4020_chip_io_map, 200 stp4020_chip_io_unmap, 201 202 stp4020_chip_intr_establish, 203 stp4020_chip_intr_disestablish, 204 205 stp4020_chip_socket_enable, 206 stp4020_chip_socket_disable 207 }; 208 209 210 static __inline__ int 211 stp4020_rd_sockctl(h, idx) 212 struct stp4020_socket *h; 213 int idx; 214 { 215 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx); 216 return (bus_space_read_2(h->tag, h->regs, o)); 217 } 218 219 static __inline__ void 220 stp4020_wr_sockctl(h, idx, v) 221 struct stp4020_socket *h; 222 int idx; 223 int v; 224 { 225 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx; 226 bus_space_write_2(h->tag, h->regs, o, v); 227 } 228 229 static __inline__ int 230 stp4020_rd_winctl(h, win, idx) 231 struct stp4020_socket *h; 232 int win; 233 int idx; 234 { 235 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 236 (STP4020_WINREGS_SIZE * win) + idx; 237 return (bus_space_read_2(h->tag, h->regs, o)); 238 } 239 240 static __inline__ void 241 stp4020_wr_winctl(h, win, idx, v) 242 struct stp4020_socket *h; 243 int win; 244 int idx; 245 int v; 246 { 247 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 248 (STP4020_WINREGS_SIZE * win) + idx; 249 250 bus_space_write_2(h->tag, h->regs, o, v); 251 } 252 253 #ifndef SUN4U /* XXX - move to SBUS machdep function? */ 254 255 #if !__FULL_SPARC_BUS_SPACE 256 #error "stp4020 (nell) needs __FULL_SPARC_BUS_SPACE defined as well" 257 #else 258 static u_int16_t stp4020_read_2(bus_space_tag_t, 259 bus_space_handle_t, 260 bus_size_t); 261 static u_int32_t stp4020_read_4(bus_space_tag_t, 262 bus_space_handle_t, 263 bus_size_t); 264 static u_int64_t stp4020_read_8(bus_space_tag_t, 265 bus_space_handle_t, 266 bus_size_t); 267 static void stp4020_write_2(bus_space_tag_t, 268 bus_space_handle_t, 269 bus_size_t, 270 u_int16_t); 271 static void stp4020_write_4(bus_space_tag_t, 272 bus_space_handle_t, 273 bus_size_t, 274 u_int32_t); 275 static void stp4020_write_8(bus_space_tag_t, 276 bus_space_handle_t, 277 bus_size_t, 278 u_int64_t); 279 280 static u_int16_t 281 stp4020_read_2(space, handle, offset) 282 bus_space_tag_t space; 283 bus_space_handle_t handle; 284 bus_size_t offset; 285 { 286 return (le16toh(*(volatile u_int16_t *)(handle + offset))); 287 } 288 289 static u_int32_t 290 stp4020_read_4(space, handle, offset) 291 bus_space_tag_t space; 292 bus_space_handle_t handle; 293 bus_size_t offset; 294 { 295 return (le32toh(*(volatile u_int32_t *)(handle + offset))); 296 } 297 298 static u_int64_t 299 stp4020_read_8(space, handle, offset) 300 bus_space_tag_t space; 301 bus_space_handle_t handle; 302 bus_size_t offset; 303 { 304 return (le64toh(*(volatile u_int64_t *)(handle + offset))); 305 } 306 307 static void 308 stp4020_write_2(space, handle, offset, value) 309 bus_space_tag_t space; 310 bus_space_handle_t handle; 311 bus_size_t offset; 312 u_int16_t value; 313 { 314 (*(volatile u_int16_t *)(handle + offset)) = htole16(value); 315 } 316 317 static void 318 stp4020_write_4(space, handle, offset, value) 319 bus_space_tag_t space; 320 bus_space_handle_t handle; 321 bus_size_t offset; 322 u_int32_t value; 323 { 324 (*(volatile u_int32_t *)(handle + offset)) = htole32(value); 325 } 326 327 static void 328 stp4020_write_8(space, handle, offset, value) 329 bus_space_tag_t space; 330 bus_space_handle_t handle; 331 bus_size_t offset; 332 u_int64_t value; 333 { 334 (*(volatile u_int64_t *)(handle + offset)) = htole64(value); 335 } 336 #endif /* __FULL_SPARC_BUS_SPACE */ 337 #endif /* SUN4U */ 338 339 int 340 stp4020print(aux, busname) 341 void *aux; 342 const char *busname; 343 { 344 struct pcmciabus_attach_args *paa = aux; 345 struct stp4020_socket *h = paa->pch; 346 347 aprint_normal(" socket %d", h->sock); 348 return (UNCONF); 349 } 350 351 int 352 stp4020match(parent, cf, aux) 353 struct device *parent; 354 struct cfdata *cf; 355 void *aux; 356 { 357 struct sbus_attach_args *sa = aux; 358 359 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0); 360 } 361 362 /* 363 * Attach all the sub-devices we can find 364 */ 365 void 366 stp4020attach(parent, self, aux) 367 struct device *parent, *self; 368 void *aux; 369 { 370 struct sbus_attach_args *sa = aux; 371 struct stp4020_softc *sc = (void *)self; 372 bus_space_tag_t tag; 373 int rev; 374 int i, sbus_intno; 375 bus_space_handle_t bh; 376 377 /* lsb of our config flags decides which interrupt we use */ 378 sbus_intno = sc->sc_dev.dv_cfdata->cf_flags & 1; 379 380 /* Transfer bus tags */ 381 #if __FULL_SPARC_BUS_SPACE 382 tag = (bus_space_tag_t) 383 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT); 384 *tag = *sa->sa_bustag; 385 tag->sparc_read_2 = stp4020_read_2; 386 tag->sparc_read_4 = stp4020_read_4; 387 tag->sparc_read_8 = stp4020_read_8; 388 tag->sparc_write_2 = stp4020_write_2; 389 tag->sparc_write_4 = stp4020_write_4; 390 tag->sparc_write_8 = stp4020_write_8; 391 #else 392 tag = sa->sa_bustag; 393 #endif /* __FULL_SPARC_BUS_SPACE */ 394 sc->sc_bustag = tag; 395 396 /* Set up per-socket static initialization */ 397 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc; 398 sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag; 399 /* 400 * XXX we rely on "tag" accepting the same handle-domain 401 * as sa->sa_bustag. 402 */ 403 sc->sc_socks[0].pcmciat = sc->sc_socks[1].pcmciat = tag; 404 sc->sc_socks[0].sbus_intno = 405 sc->sc_socks[1].sbus_intno = sbus_intno; 406 407 if (sa->sa_nreg < 8) { 408 printf("%s: only %d register sets\n", 409 self->dv_xname, sa->sa_nreg); 410 return; 411 } 412 413 if (sa->sa_nintr != 2) { 414 printf("%s: expect 2 interrupt Sbus levels; got %d\n", 415 self->dv_xname, sa->sa_nintr); 416 return; 417 } 418 419 #define STP4020_BANK_PROM 0 420 #define STP4020_BANK_CTRL 4 421 for (i = 0; i < 8; i++) { 422 423 /* 424 * STP4020 Register address map: 425 * bank 0: Forth PROM 426 * banks 1-3: socket 0, windows 0-2 427 * bank 4: control registers 428 * banks 5-7: socket 1, windows 0-2 429 */ 430 431 if (i == STP4020_BANK_PROM) 432 /* Skip the PROM */ 433 continue; 434 435 if (sbus_bus_map(sa->sa_bustag, 436 sa->sa_reg[i].oa_space, 437 sa->sa_reg[i].oa_base, 438 sa->sa_reg[i].oa_size, 439 0, &bh) != 0) { 440 printf("%s: attach: cannot map registers\n", 441 self->dv_xname); 442 return; 443 } 444 445 if (i == STP4020_BANK_CTRL) { 446 /* 447 * Copy tag and handle to both socket structures 448 * for easy access in control/status IO functions. 449 */ 450 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh; 451 } else if (i < STP4020_BANK_CTRL) { 452 /* banks 1-3 */ 453 sc->sc_socks[0].windows[i-1].winaddr = bh; 454 } else { 455 /* banks 5-7 */ 456 sc->sc_socks[1].windows[i-5].winaddr = bh; 457 } 458 } 459 460 sbus_establish(&sc->sc_sd, &sc->sc_dev); 461 462 /* We only use one interrupt level. */ 463 if (sa->sa_nintr > sbus_intno) { 464 bus_intr_establish(sa->sa_bustag, 465 sa->sa_intr[sbus_intno].oi_pri, 466 IPL_NONE, stp4020_intr, sc); 467 } 468 469 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) & 470 STP4020_ISR1_REV_M; 471 printf(": rev %x\n", rev); 472 473 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions; 474 475 /* 476 * Arrange that a kernel thread be created to handle 477 * insert/removal events. 478 */ 479 SIMPLEQ_INIT(&sc->events); 480 kthread_create(stp4020_create_event_thread, sc); 481 482 for (i = 0; i < STP4020_NSOCK; i++) { 483 struct stp4020_socket *h = &sc->sc_socks[i]; 484 h->sock = i; 485 h->sc = sc; 486 #ifdef STP4020_DEBUG 487 if (stp4020_debug) 488 stp4020_dump_regs(h); 489 #endif 490 stp4020_attach_socket(h, sa->sa_frequency); 491 } 492 } 493 494 void 495 stp4020_attach_socket(h, speed) 496 struct stp4020_socket *h; 497 int speed; 498 { 499 struct pcmciabus_attach_args paa; 500 int v; 501 502 /* no interrupt handlers yet */ 503 h->intrhandler = NULL; 504 h->intrarg = NULL; 505 h->softint = NULL; 506 h->int_enable = 0; 507 h->int_disable = 0; 508 509 /* Map all three windows */ 510 stp4020_map_window(h, STP_WIN_ATTR, speed); 511 stp4020_map_window(h, STP_WIN_MEM, speed); 512 stp4020_map_window(h, STP_WIN_IO, speed); 513 514 /* Configure one pcmcia device per socket */ 515 paa.paa_busname = "pcmcia"; 516 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct; 517 paa.pch = (pcmcia_chipset_handle_t)h; 518 paa.iobase = 0; 519 paa.iosize = STP4020_WINDOW_SIZE; 520 521 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print); 522 523 if (h->pcmcia == NULL) 524 return; 525 526 /* 527 * There's actually a pcmcia bus attached; initialize the slot. 528 */ 529 530 /* 531 * Clear things up before we enable status change interrupts. 532 * This seems to not be fully initialized by the PROM. 533 */ 534 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 535 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0); 536 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff); 537 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff); 538 539 /* 540 * Enable socket status change interrupts. 541 * We only use one common interrupt for status change 542 * and IO, to avoid locking issues. 543 */ 544 v = STP4020_ICR0_ALL_STATUS_IE 545 | (h->sbus_intno ? STP4020_ICR0_SCILVL_SB1 546 : STP4020_ICR0_SCILVL_SB0); 547 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 548 549 /* Get live status bits from ISR0 */ 550 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 551 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0) 552 return; 553 554 pcmcia_card_attach(h->pcmcia); 555 h->flags |= STP4020_SOCKET_BUSY; 556 } 557 558 559 /* 560 * Deferred thread creation callback. 561 */ 562 void 563 stp4020_create_event_thread(arg) 564 void *arg; 565 { 566 struct stp4020_softc *sc = arg; 567 const char *name = sc->sc_dev.dv_xname; 568 569 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread, 570 "%s", name)) { 571 panic("%s: unable to create event thread", name); 572 } 573 } 574 575 /* 576 * The actual event handling thread. 577 */ 578 void 579 stp4020_event_thread(arg) 580 void *arg; 581 { 582 struct stp4020_softc *sc = arg; 583 struct stp4020_event *e; 584 int s; 585 586 while (1) { 587 struct stp4020_socket *h; 588 int n; 589 590 s = splhigh(); 591 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) { 592 splx(s); 593 (void)tsleep(&sc->events, PWAIT, "pcicev", 0); 594 continue; 595 } 596 SIMPLEQ_REMOVE_HEAD(&sc->events, se_q); 597 splx(s); 598 599 n = e->se_sock; 600 if (n < 0 || n >= STP4020_NSOCK) 601 panic("stp4020_event_thread: wayward socket number %d", 602 n); 603 604 h = &sc->sc_socks[n]; 605 switch (e->se_type) { 606 case STP4020_EVENT_INSERTION: 607 pcmcia_card_attach(h->pcmcia); 608 break; 609 case STP4020_EVENT_REMOVAL: 610 pcmcia_card_detach(h->pcmcia, DETACH_FORCE); 611 break; 612 default: 613 panic("stp4020_event_thread: unknown event type %d", 614 e->se_type); 615 } 616 free(e, M_TEMP); 617 } 618 } 619 620 void 621 stp4020_queue_event(sc, sock, event) 622 struct stp4020_softc *sc; 623 int sock, event; 624 { 625 struct stp4020_event *e; 626 int s; 627 628 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT); 629 if (e == NULL) 630 panic("stp4020_queue_event: can't allocate event"); 631 632 e->se_type = event; 633 e->se_sock = sock; 634 s = splhigh(); 635 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q); 636 splx(s); 637 wakeup(&sc->events); 638 } 639 640 /* 641 * Softinterrupt called to invoke the real driver interrupt handler. 642 */ 643 static void 644 stp4020_intr_dispatch(arg) 645 void *arg; 646 { 647 struct stp4020_socket *h = arg; 648 int s; 649 650 /* invoke driver handler */ 651 h->intrhandler(h->intrarg); 652 653 /* enable SBUS interrupts for pcmcia interrupts again */ 654 s = splhigh(); 655 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable); 656 splx(s); 657 } 658 659 int 660 stp4020_intr(arg) 661 void *arg; 662 { 663 struct stp4020_softc *sc = arg; 664 int i, s, r = 0, cd_change = 0; 665 666 667 /* protect hardware access by splhigh against softint */ 668 s = splhigh(); 669 670 /* 671 * Check each socket for pending requests. 672 */ 673 for (i = 0 ; i < STP4020_NSOCK; i++) { 674 struct stp4020_socket *h; 675 int v; 676 677 h = &sc->sc_socks[i]; 678 679 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 680 681 /* Ack all interrupts at once. */ 682 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 683 STP4020_ISR0_ALL_STATUS_IRQ); 684 685 #ifdef STP4020_DEBUG 686 if (stp4020_debug != 0) { 687 char bits[64]; 688 bitmask_snprintf(v, STP4020_ISR0_IOBITS, 689 bits, sizeof(bits)); 690 printf("stp4020_statintr: ISR0=%s\n", bits); 691 } 692 #endif 693 694 if ((v & STP4020_ISR0_CDCHG) != 0) { 695 /* 696 * Card status change detect 697 */ 698 cd_change = 1; 699 r = 1; 700 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){ 701 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 702 stp4020_queue_event(sc, i, 703 STP4020_EVENT_INSERTION); 704 h->flags |= STP4020_SOCKET_BUSY; 705 } 706 } 707 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){ 708 if ((h->flags & STP4020_SOCKET_BUSY) != 0) { 709 stp4020_queue_event(sc, i, 710 STP4020_EVENT_REMOVAL); 711 h->flags &= ~STP4020_SOCKET_BUSY; 712 } 713 } 714 } 715 716 if ((v & STP4020_ISR0_IOINT) != 0) { 717 /* we can not deny this is ours, no matter what the 718 card driver says. */ 719 r = 1; 720 721 /* It's a card interrupt */ 722 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 723 printf("stp4020[%d]: spurious interrupt?\n", 724 h->sock); 725 continue; 726 } 727 728 /* 729 * Schedule softint to invoke driver interrupt 730 * handler 731 */ 732 if (h->softint != NULL) 733 softintr_schedule(h->softint); 734 /* 735 * Disable this sbus interrupt, until the soft-int 736 * handler had a chance to run 737 */ 738 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable); 739 } 740 741 /* informational messages */ 742 if ((v & STP4020_ISR0_BVD1CHG) != 0) { 743 /* ignore if this is caused by insert or removal */ 744 if (!cd_change) 745 printf("stp4020[%d]: Battery change 1\n", h->sock); 746 r = 1; 747 } 748 749 if ((v & STP4020_ISR0_BVD2CHG) != 0) { 750 /* ignore if this is caused by insert or removal */ 751 if (!cd_change) 752 printf("stp4020[%d]: Battery change 2\n", h->sock); 753 r = 1; 754 } 755 756 if ((v & STP4020_ISR0_RDYCHG) != 0) { 757 DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock)); 758 r = 1; 759 } 760 761 if ((v & STP4020_ISR0_WPCHG) != 0) { 762 DPRINTF(("stp4020[%d]: Write protect change\n", h->sock)); 763 r = 1; 764 } 765 766 if ((v & STP4020_ISR0_PCTO) != 0) { 767 DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock)); 768 r = 1; 769 } 770 771 } 772 splx(s); 773 774 return (r); 775 } 776 777 /* 778 * The function gets the sbus speed and a access time and calculates 779 * values for the CMDLNG and CMDDLAY registers. 780 */ 781 static void 782 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay) 783 { 784 int result; 785 786 if (ns < STP4020_MEM_SPEED_MIN) 787 ns = STP4020_MEM_SPEED_MIN; 788 else if (ns > STP4020_MEM_SPEED_MAX) 789 ns = STP4020_MEM_SPEED_MAX; 790 result = ns*(bus_speed/1000); 791 if (result % 1000000) 792 result = result/1000000 + 1; 793 else 794 result /= 1000000; 795 *length = result; 796 797 /* the sbus frequency range is limited, so we can keep this simple */ 798 *delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2; 799 } 800 801 static void 802 stp4020_map_window(struct stp4020_socket *h, int win, int speed) 803 { 804 int v, length, delay; 805 806 /* 807 * According to the PC Card standard 300ns access timing should be 808 * used for attribute memory access. Our pcmcia framework does not 809 * seem to propagate timing information, so we use that 810 * everywhere. 811 */ 812 stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &delay); 813 814 /* 815 * Fill in the Address Space Select and Base Address 816 * fields of this windows control register 0. 817 */ 818 v = ((delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M) 819 | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M); 820 switch (win) { 821 case STP_WIN_ATTR: 822 v |= STP4020_WCR0_ASPSEL_AM; 823 break; 824 case STP_WIN_MEM: 825 v |= STP4020_WCR0_ASPSEL_CM; 826 break; 827 case STP_WIN_IO: 828 v |= STP4020_WCR0_ASPSEL_IO; 829 break; 830 } 831 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M); 832 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 833 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S); 834 } 835 836 int 837 stp4020_chip_mem_alloc(pch, size, pcmhp) 838 pcmcia_chipset_handle_t pch; 839 bus_size_t size; 840 struct pcmcia_mem_handle *pcmhp; 841 { 842 struct stp4020_socket *h = (struct stp4020_socket *)pch; 843 844 /* we can not do much here, defere work to _mem_map */ 845 pcmhp->memt = h->pcmciat; 846 pcmhp->size = size; 847 pcmhp->addr = 0; 848 pcmhp->mhandle = 0; 849 pcmhp->realsize = size; 850 851 return (0); 852 } 853 854 void 855 stp4020_chip_mem_free(pch, pcmhp) 856 pcmcia_chipset_handle_t pch; 857 struct pcmcia_mem_handle *pcmhp; 858 { 859 } 860 861 int 862 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) 863 pcmcia_chipset_handle_t pch; 864 int kind; 865 bus_addr_t card_addr; 866 bus_size_t size; 867 struct pcmcia_mem_handle *pcmhp; 868 bus_size_t *offsetp; 869 int *windowp; 870 { 871 struct stp4020_socket *h = (struct stp4020_socket *)pch; 872 int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM; 873 874 pcmhp->memt = h->pcmciat; 875 bus_space_subregion(h->pcmciat, h->windows[win].winaddr, card_addr, size, &pcmhp->memh); 876 #ifdef SUN4U 877 if ((u_int8_t)pcmhp->memh._asi == ASI_PHYS_NON_CACHED) 878 pcmhp->memh._asi = ASI_PHYS_NON_CACHED_LITTLE; 879 else if ((u_int8_t)pcmhp->memh._asi == ASI_PRIMARY) 880 pcmhp->memh._asi = ASI_PRIMARY_LITTLE; 881 #endif 882 pcmhp->size = size; 883 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr; 884 *offsetp = 0; 885 *windowp = 0; 886 887 return (0); 888 } 889 890 void 891 stp4020_chip_mem_unmap(pch, win) 892 pcmcia_chipset_handle_t pch; 893 int win; 894 { 895 } 896 897 int 898 stp4020_chip_io_alloc(pch, start, size, align, pcihp) 899 pcmcia_chipset_handle_t pch; 900 bus_addr_t start; 901 bus_size_t size; 902 bus_size_t align; 903 struct pcmcia_io_handle *pcihp; 904 { 905 struct stp4020_socket *h = (struct stp4020_socket *)pch; 906 907 pcihp->iot = h->pcmciat; 908 pcihp->ioh = h->windows[STP_WIN_IO].winaddr; 909 return 0; 910 } 911 912 void 913 stp4020_chip_io_free(pch, pcihp) 914 pcmcia_chipset_handle_t pch; 915 struct pcmcia_io_handle *pcihp; 916 { 917 } 918 919 int 920 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp) 921 pcmcia_chipset_handle_t pch; 922 int width; 923 bus_addr_t offset; 924 bus_size_t size; 925 struct pcmcia_io_handle *pcihp; 926 int *windowp; 927 { 928 struct stp4020_socket *h = (struct stp4020_socket *)pch; 929 930 pcihp->iot = h->pcmciat; 931 bus_space_subregion(h->pcmciat, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh); 932 #ifdef SUN4U 933 if ((u_int8_t)pcihp->ioh._asi == ASI_PHYS_NON_CACHED) 934 pcihp->ioh._asi = ASI_PHYS_NON_CACHED_LITTLE; 935 else if ((u_int8_t)pcihp->ioh._asi == ASI_PRIMARY) 936 pcihp->ioh._asi = ASI_PRIMARY_LITTLE; 937 #endif 938 *windowp = 0; 939 return 0; 940 } 941 942 void 943 stp4020_chip_io_unmap(pch, win) 944 pcmcia_chipset_handle_t pch; 945 int win; 946 { 947 } 948 949 void 950 stp4020_chip_socket_enable(pch) 951 pcmcia_chipset_handle_t pch; 952 { 953 struct stp4020_socket *h = (struct stp4020_socket *)pch; 954 int i, v; 955 956 /* this bit is mostly stolen from pcic_attach_card */ 957 958 /* Power down the socket to reset it, clear the card reset pin */ 959 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 960 961 /* 962 * wait 300ms until power fails (Tpf). Then, wait 100ms since 963 * we are changing Vcc (Toff). 964 */ 965 stp4020_delay((300 + 100) * 1000); 966 967 /* Power up the socket */ 968 v = STP4020_ICR1_MSTPWR; 969 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 970 971 /* 972 * wait 100ms until power raise (Tpr) and 20ms to become 973 * stable (Tsu(Vcc)). 974 */ 975 stp4020_delay((100 + 20) * 1000); 976 977 v |= STP4020_ICR1_PCIFOE|STP4020_ICR1_VPP1_VCC; 978 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 979 980 /* 981 * hold RESET at least 10us. 982 */ 983 delay(10); 984 985 /* Clear reset flag */ 986 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 987 v &= ~STP4020_ICR0_RESET; 988 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 989 990 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 991 stp4020_delay(20000); 992 993 /* Wait for the chip to finish initializing (5 seconds max) */ 994 for (i = 10000; i > 0; i--) { 995 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 996 if ((v & STP4020_ISR0_RDYST) != 0) 997 break; 998 delay(500); 999 } 1000 if (i <= 0) { 1001 char bits[64]; 1002 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 1003 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 1004 printf("stp4020_chip_socket_enable: not ready: status %s\n", 1005 bits); 1006 return; 1007 } 1008 1009 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 1010 1011 /* 1012 * Check the card type. 1013 * Enable socket I/O interrupts for IO cards. 1014 * We use level SB_INT[0] for I/O interrupts. 1015 */ 1016 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) { 1017 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE); 1018 v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE 1019 |STP4020_ICR0_SPKREN; 1020 v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1 1021 : STP4020_ICR0_IOILVL_SB0; 1022 h->int_enable = v; 1023 h->int_disable = v & ~STP4020_ICR0_IOIE; 1024 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname)); 1025 } else { 1026 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE 1027 |STP4020_ICR0_SPKREN); 1028 v |= STP4020_ICR0_IFTYPE_MEM; 1029 DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname)); 1030 } 1031 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 1032 } 1033 1034 void 1035 stp4020_chip_socket_disable(pch) 1036 pcmcia_chipset_handle_t pch; 1037 { 1038 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1039 int v; 1040 1041 /* 1042 * Disable socket I/O interrupts. 1043 */ 1044 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 1045 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL); 1046 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 1047 1048 /* Power down the socket */ 1049 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 1050 1051 /* 1052 * wait 300ms until power fails (Tpf). 1053 */ 1054 stp4020_delay(300 * 1000); 1055 } 1056 1057 void * 1058 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg) 1059 pcmcia_chipset_handle_t pch; 1060 struct pcmcia_function *pf; 1061 int ipl; 1062 int (*handler) __P((void *)); 1063 void *arg; 1064 { 1065 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1066 1067 /* only one interrupt handler per slot */ 1068 if (h->intrhandler != NULL) return NULL; 1069 1070 h->intrhandler = handler; 1071 h->intrarg = arg; 1072 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h); 1073 return h->softint; 1074 } 1075 1076 void 1077 stp4020_chip_intr_disestablish(pch, ih) 1078 pcmcia_chipset_handle_t pch; 1079 void *ih; 1080 { 1081 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1082 1083 h->intrhandler = NULL; 1084 h->intrarg = NULL; 1085 if (h->softint) { 1086 softintr_disestablish(h->softint); 1087 h->softint = NULL; 1088 } 1089 } 1090 1091 /* 1092 * Delay and possibly yield CPU. 1093 * XXX - assumes a context 1094 */ 1095 void 1096 stp4020_delay(ms) 1097 unsigned int ms; 1098 { 1099 unsigned int ticks; 1100 1101 /* Convert to ticks */ 1102 ticks = (ms * hz ) / 1000000; 1103 1104 if (cold || ticks == 0) { 1105 delay(ms); 1106 return; 1107 } 1108 1109 #ifdef DIAGNOSTIC 1110 if (ticks > 60*hz) 1111 panic("stp4020: preposterous delay: %u", ticks); 1112 #endif 1113 tsleep(&ticks, 0, "stp4020_delay", ticks); 1114 } 1115 1116 #ifdef STP4020_DEBUG 1117 void 1118 stp4020_dump_regs(h) 1119 struct stp4020_socket *h; 1120 { 1121 char bits[64]; 1122 /* 1123 * Dump control and status registers. 1124 */ 1125 printf("socket[%d] registers:\n", h->sock); 1126 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX), 1127 STP4020_ICR0_BITS, bits, sizeof(bits)); 1128 printf("\tICR0=%s\n", bits); 1129 1130 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX), 1131 STP4020_ICR1_BITS, bits, sizeof(bits)); 1132 printf("\tICR1=%s\n", bits); 1133 1134 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 1135 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 1136 printf("\tISR0=%s\n", bits); 1137 1138 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX), 1139 STP4020_ISR1_BITS, bits, sizeof(bits)); 1140 printf("\tISR1=%s\n", bits); 1141 } 1142 #endif /* STP4020_DEBUG */ 1143