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