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