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