1 /* $NetBSD: stp4020.c,v 1.49 2006/12/11 11:42:48 jdc 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.49 2006/12/11 11:42:48 jdc 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 NULL 208 }; 209 210 211 static inline int 212 stp4020_rd_sockctl(h, idx) 213 struct stp4020_socket *h; 214 int idx; 215 { 216 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx); 217 return (bus_space_read_2(h->tag, h->regs, o)); 218 } 219 220 static inline void 221 stp4020_wr_sockctl(h, idx, v) 222 struct stp4020_socket *h; 223 int idx; 224 int v; 225 { 226 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx; 227 bus_space_write_2(h->tag, h->regs, o, v); 228 } 229 230 static inline int 231 stp4020_rd_winctl(h, win, idx) 232 struct stp4020_socket *h; 233 int win; 234 int idx; 235 { 236 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 237 (STP4020_WINREGS_SIZE * win) + idx; 238 return (bus_space_read_2(h->tag, h->regs, o)); 239 } 240 241 static inline void 242 stp4020_wr_winctl(h, win, idx, v) 243 struct stp4020_socket *h; 244 int win; 245 int idx; 246 int v; 247 { 248 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 249 (STP4020_WINREGS_SIZE * win) + idx; 250 251 bus_space_write_2(h->tag, h->regs, o, v); 252 } 253 254 #ifndef SUN4U /* XXX - move to SBUS machdep function? */ 255 256 static u_int16_t stp4020_read_2(bus_space_tag_t, 257 bus_space_handle_t, 258 bus_size_t); 259 static u_int32_t stp4020_read_4(bus_space_tag_t, 260 bus_space_handle_t, 261 bus_size_t); 262 static u_int64_t stp4020_read_8(bus_space_tag_t, 263 bus_space_handle_t, 264 bus_size_t); 265 static void stp4020_write_2(bus_space_tag_t, 266 bus_space_handle_t, 267 bus_size_t, 268 u_int16_t); 269 static void stp4020_write_4(bus_space_tag_t, 270 bus_space_handle_t, 271 bus_size_t, 272 u_int32_t); 273 static void stp4020_write_8(bus_space_tag_t, 274 bus_space_handle_t, 275 bus_size_t, 276 u_int64_t); 277 278 static u_int16_t 279 stp4020_read_2(space, handle, offset) 280 bus_space_tag_t space; 281 bus_space_handle_t handle; 282 bus_size_t offset; 283 { 284 return (le16toh(*(volatile u_int16_t *)(handle + offset))); 285 } 286 287 static u_int32_t 288 stp4020_read_4(space, handle, offset) 289 bus_space_tag_t space; 290 bus_space_handle_t handle; 291 bus_size_t offset; 292 { 293 return (le32toh(*(volatile u_int32_t *)(handle + offset))); 294 } 295 296 static u_int64_t 297 stp4020_read_8(space, handle, offset) 298 bus_space_tag_t space; 299 bus_space_handle_t handle; 300 bus_size_t offset; 301 { 302 return (le64toh(*(volatile u_int64_t *)(handle + offset))); 303 } 304 305 static void 306 stp4020_write_2(space, handle, offset, value) 307 bus_space_tag_t space; 308 bus_space_handle_t handle; 309 bus_size_t offset; 310 u_int16_t value; 311 { 312 (*(volatile u_int16_t *)(handle + offset)) = htole16(value); 313 } 314 315 static void 316 stp4020_write_4(space, handle, offset, value) 317 bus_space_tag_t space; 318 bus_space_handle_t handle; 319 bus_size_t offset; 320 u_int32_t value; 321 { 322 (*(volatile u_int32_t *)(handle + offset)) = htole32(value); 323 } 324 325 static void 326 stp4020_write_8(space, handle, offset, value) 327 bus_space_tag_t space; 328 bus_space_handle_t handle; 329 bus_size_t offset; 330 u_int64_t value; 331 { 332 (*(volatile u_int64_t *)(handle + offset)) = htole64(value); 333 } 334 #endif /* SUN4U */ 335 336 int 337 stp4020print(aux, busname) 338 void *aux; 339 const char *busname; 340 { 341 struct pcmciabus_attach_args *paa = aux; 342 struct stp4020_socket *h = paa->pch; 343 344 aprint_normal(" socket %d", h->sock); 345 return (UNCONF); 346 } 347 348 int 349 stp4020match(parent, cf, aux) 350 struct device *parent; 351 struct cfdata *cf; 352 void *aux; 353 { 354 struct sbus_attach_args *sa = aux; 355 356 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0); 357 } 358 359 /* 360 * Attach all the sub-devices we can find 361 */ 362 void 363 stp4020attach(parent, self, aux) 364 struct device *parent, *self; 365 void *aux; 366 { 367 struct sbus_attach_args *sa = aux; 368 struct stp4020_softc *sc = (void *)self; 369 bus_space_tag_t tag; 370 int rev; 371 int i, sbus_intno; 372 bus_space_handle_t bh; 373 374 /* lsb of our config flags decides which interrupt we use */ 375 sbus_intno = device_cfdata(&sc->sc_dev)->cf_flags & 1; 376 377 /* Transfer bus tags */ 378 #ifdef SUN4U 379 tag = sa->sa_bustag; 380 #else 381 tag = bus_space_tag_alloc(sa->sa_bustag, sc); 382 if (tag == NULL) { 383 printf("%s: attach: out of memory\n", self->dv_xname); 384 return; 385 } 386 tag->sparc_read_2 = stp4020_read_2; 387 tag->sparc_read_4 = stp4020_read_4; 388 tag->sparc_read_8 = stp4020_read_8; 389 tag->sparc_write_2 = stp4020_write_2; 390 tag->sparc_write_4 = stp4020_write_4; 391 tag->sparc_write_8 = stp4020_write_8; 392 #endif /* SUN4U */ 393 394 /* Set up per-socket static initialization */ 395 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc; 396 sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag; 397 /* 398 * XXX we rely on "tag" accepting the same handle-domain 399 * as sa->sa_bustag. 400 */ 401 sc->sc_socks[0].pcmciat = sc->sc_socks[1].pcmciat = tag; 402 sc->sc_socks[0].sbus_intno = 403 sc->sc_socks[1].sbus_intno = sbus_intno; 404 405 if (sa->sa_nreg < 8) { 406 printf("%s: only %d register sets\n", 407 self->dv_xname, sa->sa_nreg); 408 return; 409 } 410 411 if (sa->sa_nintr != 2) { 412 printf("%s: expect 2 interrupt Sbus levels; got %d\n", 413 self->dv_xname, sa->sa_nintr); 414 return; 415 } 416 417 #define STP4020_BANK_PROM 0 418 #define STP4020_BANK_CTRL 4 419 for (i = 0; i < 8; i++) { 420 421 /* 422 * STP4020 Register address map: 423 * bank 0: Forth PROM 424 * banks 1-3: socket 0, windows 0-2 425 * bank 4: control registers 426 * banks 5-7: socket 1, windows 0-2 427 */ 428 429 if (i == STP4020_BANK_PROM) 430 /* Skip the PROM */ 431 continue; 432 433 if (sbus_bus_map(sa->sa_bustag, 434 sa->sa_reg[i].oa_space, 435 sa->sa_reg[i].oa_base, 436 sa->sa_reg[i].oa_size, 437 0, &bh) != 0) { 438 printf("%s: attach: cannot map registers\n", 439 self->dv_xname); 440 return; 441 } 442 443 if (i == STP4020_BANK_CTRL) { 444 /* 445 * Copy tag and handle to both socket structures 446 * for easy access in control/status IO functions. 447 */ 448 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh; 449 } else if (i < STP4020_BANK_CTRL) { 450 /* banks 1-3 */ 451 sc->sc_socks[0].windows[i-1].winaddr = bh; 452 } else { 453 /* banks 5-7 */ 454 sc->sc_socks[1].windows[i-5].winaddr = bh; 455 } 456 } 457 458 sbus_establish(&sc->sc_sd, &sc->sc_dev); 459 460 /* We only use one interrupt level. */ 461 if (sa->sa_nintr > sbus_intno) { 462 bus_intr_establish(sa->sa_bustag, 463 sa->sa_intr[sbus_intno].oi_pri, 464 IPL_NONE, stp4020_intr, sc); 465 } 466 467 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) & 468 STP4020_ISR1_REV_M; 469 printf(": rev %x\n", rev); 470 471 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions; 472 473 /* 474 * Arrange that a kernel thread be created to handle 475 * insert/removal events. 476 */ 477 SIMPLEQ_INIT(&sc->events); 478 kthread_create(stp4020_create_event_thread, sc); 479 480 for (i = 0; i < STP4020_NSOCK; i++) { 481 struct stp4020_socket *h = &sc->sc_socks[i]; 482 h->sock = i; 483 h->sc = sc; 484 #ifdef STP4020_DEBUG 485 if (stp4020_debug) 486 stp4020_dump_regs(h); 487 #endif 488 stp4020_attach_socket(h, sa->sa_frequency); 489 } 490 } 491 492 void 493 stp4020_attach_socket(h, speed) 494 struct stp4020_socket *h; 495 int speed; 496 { 497 struct pcmciabus_attach_args paa; 498 int v; 499 500 /* no interrupt handlers yet */ 501 h->intrhandler = NULL; 502 h->intrarg = NULL; 503 h->softint = NULL; 504 h->int_enable = 0; 505 h->int_disable = 0; 506 507 /* Map all three windows */ 508 stp4020_map_window(h, STP_WIN_ATTR, speed); 509 stp4020_map_window(h, STP_WIN_MEM, speed); 510 stp4020_map_window(h, STP_WIN_IO, speed); 511 512 /* Configure one pcmcia device per socket */ 513 paa.paa_busname = "pcmcia"; 514 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct; 515 paa.pch = (pcmcia_chipset_handle_t)h; 516 paa.iobase = 0; 517 paa.iosize = STP4020_WINDOW_SIZE; 518 519 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print); 520 521 if (h->pcmcia == NULL) 522 return; 523 524 /* 525 * There's actually a pcmcia bus attached; initialize the slot. 526 */ 527 528 /* 529 * Clear things up before we enable status change interrupts. 530 * This seems to not be fully initialized by the PROM. 531 */ 532 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 533 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0); 534 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff); 535 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff); 536 537 /* 538 * Enable socket status change interrupts. 539 * We only use one common interrupt for status change 540 * and IO, to avoid locking issues. 541 */ 542 v = STP4020_ICR0_ALL_STATUS_IE 543 | (h->sbus_intno ? STP4020_ICR0_SCILVL_SB1 544 : STP4020_ICR0_SCILVL_SB0); 545 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 546 547 /* Get live status bits from ISR0 and clear pending interrupts */ 548 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 549 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v); 550 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, "nellevt", 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, v); 683 684 #ifdef STP4020_DEBUG 685 if (stp4020_debug != 0) { 686 char bits[64]; 687 bitmask_snprintf(v, STP4020_ISR0_IOBITS, 688 bits, sizeof(bits)); 689 printf("stp4020_statintr: ISR0=%s\n", bits); 690 } 691 #endif 692 693 if ((v & STP4020_ISR0_CDCHG) != 0) { 694 /* 695 * Card status change detect 696 */ 697 cd_change = 1; 698 r = 1; 699 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){ 700 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 701 stp4020_queue_event(sc, i, 702 STP4020_EVENT_INSERTION); 703 h->flags |= STP4020_SOCKET_BUSY; 704 } 705 } 706 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){ 707 if ((h->flags & STP4020_SOCKET_BUSY) != 0) { 708 stp4020_queue_event(sc, i, 709 STP4020_EVENT_REMOVAL); 710 h->flags &= ~STP4020_SOCKET_BUSY; 711 } 712 } 713 } 714 715 if ((v & STP4020_ISR0_IOINT) != 0) { 716 /* we can not deny this is ours, no matter what the 717 card driver says. */ 718 r = 1; 719 720 /* It's a card interrupt */ 721 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 722 printf("stp4020[%d]: spurious interrupt?\n", 723 h->sock); 724 continue; 725 } 726 727 /* 728 * Schedule softint to invoke driver interrupt 729 * handler 730 */ 731 if (h->softint != NULL) 732 softintr_schedule(h->softint); 733 /* 734 * Disable this sbus interrupt, until the soft-int 735 * handler had a chance to run 736 */ 737 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable); 738 } 739 740 /* informational messages */ 741 if ((v & STP4020_ISR0_BVD1CHG) != 0) { 742 /* ignore if this is caused by insert or removal */ 743 if (!cd_change) 744 printf("stp4020[%d]: Battery change 1\n", h->sock); 745 r = 1; 746 } 747 748 if ((v & STP4020_ISR0_BVD2CHG) != 0) { 749 /* ignore if this is caused by insert or removal */ 750 if (!cd_change) 751 printf("stp4020[%d]: Battery change 2\n", h->sock); 752 r = 1; 753 } 754 755 if ((v & STP4020_ISR0_SCINT) != 0) { 756 DPRINTF(("stp4020[%d]: status change\n", h->sock)); 757 r = 1; 758 } 759 760 if ((v & STP4020_ISR0_RDYCHG) != 0) { 761 DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock)); 762 r = 1; 763 } 764 765 if ((v & STP4020_ISR0_WPCHG) != 0) { 766 DPRINTF(("stp4020[%d]: Write protect change\n", h->sock)); 767 r = 1; 768 } 769 770 if ((v & STP4020_ISR0_PCTO) != 0) { 771 DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock)); 772 r = 1; 773 } 774 775 if ((v & ~STP4020_ISR0_LIVE) && r == 0) 776 printf("stp4020[%d]: unhandled interrupt: 0x%x\n", h->sock, v); 777 778 } 779 splx(s); 780 781 return (r); 782 } 783 784 /* 785 * The function gets the sbus speed and a access time and calculates 786 * values for the CMDLNG and CMDDLAY registers. 787 */ 788 static void 789 stp4020_calc_speed(int bus_speed, int ns, int *length, int *cmd_delay) 790 { 791 int result; 792 793 if (ns < STP4020_MEM_SPEED_MIN) 794 ns = STP4020_MEM_SPEED_MIN; 795 else if (ns > STP4020_MEM_SPEED_MAX) 796 ns = STP4020_MEM_SPEED_MAX; 797 result = ns*(bus_speed/1000); 798 if (result % 1000000) 799 result = result/1000000 + 1; 800 else 801 result /= 1000000; 802 *length = result; 803 804 /* the sbus frequency range is limited, so we can keep this simple */ 805 *cmd_delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2; 806 } 807 808 static void 809 stp4020_map_window(struct stp4020_socket *h, int win, int speed) 810 { 811 int v, length, cmd_delay; 812 813 /* 814 * According to the PC Card standard 300ns access timing should be 815 * used for attribute memory access. Our pcmcia framework does not 816 * seem to propagate timing information, so we use that 817 * everywhere. 818 */ 819 stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &cmd_delay); 820 821 /* 822 * Fill in the Address Space Select and Base Address 823 * fields of this windows control register 0. 824 */ 825 v = ((cmd_delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M) 826 | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M); 827 switch (win) { 828 case STP_WIN_ATTR: 829 v |= STP4020_WCR0_ASPSEL_AM; 830 break; 831 case STP_WIN_MEM: 832 v |= STP4020_WCR0_ASPSEL_CM; 833 break; 834 case STP_WIN_IO: 835 v |= STP4020_WCR0_ASPSEL_IO; 836 break; 837 } 838 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M); 839 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 840 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S); 841 } 842 843 int 844 stp4020_chip_mem_alloc(pch, size, pcmhp) 845 pcmcia_chipset_handle_t pch; 846 bus_size_t size; 847 struct pcmcia_mem_handle *pcmhp; 848 { 849 struct stp4020_socket *h = (struct stp4020_socket *)pch; 850 851 /* we can not do much here, defere work to _mem_map */ 852 pcmhp->memt = h->pcmciat; 853 pcmhp->size = size; 854 pcmhp->addr = 0; 855 pcmhp->mhandle = 0; 856 pcmhp->realsize = size; 857 858 return (0); 859 } 860 861 void 862 stp4020_chip_mem_free(pch, pcmhp) 863 pcmcia_chipset_handle_t pch; 864 struct pcmcia_mem_handle *pcmhp; 865 { 866 } 867 868 int 869 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) 870 pcmcia_chipset_handle_t pch; 871 int kind; 872 bus_addr_t card_addr; 873 bus_size_t size; 874 struct pcmcia_mem_handle *pcmhp; 875 bus_size_t *offsetp; 876 int *windowp; 877 { 878 struct stp4020_socket *h = (struct stp4020_socket *)pch; 879 int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM; 880 881 pcmhp->memt = h->pcmciat; 882 bus_space_subregion(h->pcmciat, h->windows[win].winaddr, card_addr, size, &pcmhp->memh); 883 #ifdef SUN4U 884 if ((u_int8_t)pcmhp->memh._asi == ASI_PHYS_NON_CACHED) 885 pcmhp->memh._asi = ASI_PHYS_NON_CACHED_LITTLE; 886 else if ((u_int8_t)pcmhp->memh._asi == ASI_PRIMARY) 887 pcmhp->memh._asi = ASI_PRIMARY_LITTLE; 888 #endif 889 pcmhp->size = size; 890 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr; 891 *offsetp = 0; 892 *windowp = 0; 893 894 return (0); 895 } 896 897 void 898 stp4020_chip_mem_unmap(pch, win) 899 pcmcia_chipset_handle_t pch; 900 int win; 901 { 902 } 903 904 int 905 stp4020_chip_io_alloc(pch, start, size, align, pcihp) 906 pcmcia_chipset_handle_t pch; 907 bus_addr_t start; 908 bus_size_t size; 909 bus_size_t align; 910 struct pcmcia_io_handle *pcihp; 911 { 912 struct stp4020_socket *h = (struct stp4020_socket *)pch; 913 914 pcihp->iot = h->pcmciat; 915 pcihp->ioh = h->windows[STP_WIN_IO].winaddr; 916 return 0; 917 } 918 919 void 920 stp4020_chip_io_free(pch, pcihp) 921 pcmcia_chipset_handle_t pch; 922 struct pcmcia_io_handle *pcihp; 923 { 924 } 925 926 int 927 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp) 928 pcmcia_chipset_handle_t pch; 929 int width; 930 bus_addr_t offset; 931 bus_size_t size; 932 struct pcmcia_io_handle *pcihp; 933 int *windowp; 934 { 935 struct stp4020_socket *h = (struct stp4020_socket *)pch; 936 937 pcihp->iot = h->pcmciat; 938 bus_space_subregion(h->pcmciat, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh); 939 #ifdef SUN4U 940 if ((u_int8_t)pcihp->ioh._asi == ASI_PHYS_NON_CACHED) 941 pcihp->ioh._asi = ASI_PHYS_NON_CACHED_LITTLE; 942 else if ((u_int8_t)pcihp->ioh._asi == ASI_PRIMARY) 943 pcihp->ioh._asi = ASI_PRIMARY_LITTLE; 944 #endif 945 *windowp = 0; 946 return 0; 947 } 948 949 void 950 stp4020_chip_io_unmap(pch, win) 951 pcmcia_chipset_handle_t pch; 952 int win; 953 { 954 } 955 956 void 957 stp4020_chip_socket_enable(pch) 958 pcmcia_chipset_handle_t pch; 959 { 960 struct stp4020_socket *h = (struct stp4020_socket *)pch; 961 int i, v; 962 963 /* this bit is mostly stolen from pcic_attach_card */ 964 965 /* Power down the socket to reset it, clear the card reset pin */ 966 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 967 968 /* 969 * wait 300ms until power fails (Tpf). Then, wait 100ms since 970 * we are changing Vcc (Toff). 971 */ 972 stp4020_delay(h->sc, 300 + 100); 973 974 /* Power up the socket */ 975 v = STP4020_ICR1_MSTPWR; 976 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 977 978 /* 979 * wait 100ms until power raise (Tpr) and 20ms to become 980 * stable (Tsu(Vcc)). 981 */ 982 stp4020_delay(h->sc, 100 + 20); 983 984 v |= STP4020_ICR1_PCIFOE|STP4020_ICR1_VPP1_VCC; 985 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 986 987 /* 988 * hold RESET at least 10us. 989 */ 990 delay(10); 991 992 /* Clear reset flag, set to memory mode */ 993 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 994 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 995 STP4020_ICR0_SPKREN); 996 v &= ~STP4020_ICR0_RESET; 997 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 998 999 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 1000 stp4020_delay(h->sc, 20); 1001 1002 /* Wait for the chip to finish initializing (5 seconds max) */ 1003 for (i = 10000; i > 0; i--) { 1004 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 1005 if ((v & STP4020_ISR0_RDYST) != 0) 1006 break; 1007 delay(500); 1008 } 1009 if (i <= 0) { 1010 char bits[64]; 1011 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 1012 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 1013 printf("stp4020_chip_socket_enable: not ready: status %s\n", 1014 bits); 1015 return; 1016 } 1017 } 1018 1019 void 1020 stp4020_chip_socket_settype(pch, type) 1021 pcmcia_chipset_handle_t pch; 1022 int type; 1023 { 1024 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1025 int v; 1026 1027 /* 1028 * Check the card type. 1029 * Enable socket I/O interrupts for IO cards. 1030 */ 1031 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 1032 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 1033 STP4020_ICR0_SPKREN); 1034 if (type == PCMCIA_IFTYPE_IO) { 1035 v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE 1036 |STP4020_ICR0_SPKREN; 1037 v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1 1038 : STP4020_ICR0_IOILVL_SB0; 1039 h->int_enable = v; 1040 h->int_disable = v & ~STP4020_ICR0_IOIE; 1041 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname)); 1042 } else { 1043 v |= STP4020_ICR0_IFTYPE_MEM; 1044 h->int_enable = h->int_disable = v; 1045 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname)); 1046 DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname)); 1047 } 1048 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 1049 } 1050 1051 void 1052 stp4020_chip_socket_disable(pch) 1053 pcmcia_chipset_handle_t pch; 1054 { 1055 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1056 int v; 1057 1058 /* 1059 * Disable socket I/O interrupts. 1060 */ 1061 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 1062 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 1063 STP4020_ICR0_SPKREN); 1064 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 1065 1066 /* Power down the socket */ 1067 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 1068 1069 /* 1070 * wait 300ms until power fails (Tpf). 1071 */ 1072 stp4020_delay(h->sc, 300); 1073 } 1074 1075 void * 1076 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg) 1077 pcmcia_chipset_handle_t pch; 1078 struct pcmcia_function *pf; 1079 int ipl; 1080 int (*handler)(void *); 1081 void *arg; 1082 { 1083 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1084 1085 /* only one interrupt handler per slot */ 1086 if (h->intrhandler != NULL) return NULL; 1087 1088 h->intrhandler = handler; 1089 h->intrarg = arg; 1090 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h); 1091 return h->softint; 1092 } 1093 1094 void 1095 stp4020_chip_intr_disestablish(pch, ih) 1096 pcmcia_chipset_handle_t pch; 1097 void *ih; 1098 { 1099 struct stp4020_socket *h = (struct stp4020_socket *)pch; 1100 1101 h->intrhandler = NULL; 1102 h->intrarg = NULL; 1103 if (h->softint) { 1104 softintr_disestablish(h->softint); 1105 h->softint = NULL; 1106 } 1107 } 1108 1109 /* 1110 * Delay and possibly yield CPU. 1111 * XXX - assumes a context 1112 */ 1113 void 1114 stp4020_delay(sc, ms) 1115 struct stp4020_softc *sc; 1116 unsigned int ms; 1117 { 1118 unsigned int ticks = mstohz(ms); 1119 1120 if (cold || ticks == 0) { 1121 delay(ms); 1122 return; 1123 } 1124 1125 #ifdef DIAGNOSTIC 1126 if (ticks > 60*hz) 1127 panic("stp4020: preposterous delay: %u", ticks); 1128 #endif 1129 tsleep(sc, 0, "nelldel", ticks); 1130 } 1131 1132 #ifdef STP4020_DEBUG 1133 void 1134 stp4020_dump_regs(h) 1135 struct stp4020_socket *h; 1136 { 1137 char bits[64]; 1138 /* 1139 * Dump control and status registers. 1140 */ 1141 printf("socket[%d] registers:\n", h->sock); 1142 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX), 1143 STP4020_ICR0_BITS, bits, sizeof(bits)); 1144 printf("\tICR0=%s\n", bits); 1145 1146 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX), 1147 STP4020_ICR1_BITS, bits, sizeof(bits)); 1148 printf("\tICR1=%s\n", bits); 1149 1150 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 1151 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 1152 printf("\tISR0=%s\n", bits); 1153 1154 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX), 1155 STP4020_ISR1_BITS, bits, sizeof(bits)); 1156 printf("\tISR1=%s\n", bits); 1157 } 1158 #endif /* STP4020_DEBUG */ 1159