1 /* $OpenBSD: stp4020.c,v 1.19 2016/03/19 11:34:22 mpi Exp $ */ 2 /* $NetBSD: stp4020.c,v 1.23 2002/06/01 23:51:03 lukem Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Paul Kranenburg. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * STP4020: SBus/PCMCIA bridge supporting one Type-3 PCMCIA card, or up to 35 * two Type-1 and Type-2 PCMCIA cards.. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/errno.h> 41 #include <sys/extent.h> 42 #include <sys/proc.h> 43 #include <sys/kernel.h> 44 #include <sys/kthread.h> 45 #include <sys/device.h> 46 47 #include <dev/pcmcia/pcmciareg.h> 48 #include <dev/pcmcia/pcmciavar.h> 49 #include <dev/pcmcia/pcmciachip.h> 50 51 #include <machine/bus.h> 52 #include <machine/intr.h> 53 54 #include <dev/sbus/stp4020reg.h> 55 #include <dev/sbus/stp4020var.h> 56 57 /* 58 * We use the three available windows per socket in a simple, fixed 59 * arrangement. Each window maps (at full 1 MB size) one of the pcmcia 60 * spaces into sbus space. 61 */ 62 #define STP_WIN_ATTR 0 /* index of the attribute memory space window */ 63 #define STP_WIN_MEM 1 /* index of the common memory space window */ 64 #define STP_WIN_IO 2 /* index of the io space window */ 65 66 #ifdef STP4020_DEBUG 67 int stp4020_debug = 0; 68 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0) 69 #else 70 #define DPRINTF(x) 71 #endif 72 73 int stp4020print(void *, const char *); 74 void stp4020_map_window(struct stp4020_socket *, int, int); 75 void stp4020_calc_speed(int, int, int *, int *); 76 void stp4020_intr_dispatch(void *); 77 78 struct cfdriver stp_cd = { 79 NULL, "stp", DV_DULL 80 }; 81 82 #ifdef STP4020_DEBUG 83 static void stp4020_dump_regs(struct stp4020_socket *); 84 #endif 85 86 static u_int16_t stp4020_rd_sockctl(struct stp4020_socket *, int); 87 static void stp4020_wr_sockctl(struct stp4020_socket *, int, u_int16_t); 88 static u_int16_t stp4020_rd_winctl(struct stp4020_socket *, int, int); 89 static void stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t); 90 91 void stp4020_delay(unsigned int); 92 void stp4020_attach_socket(struct stp4020_socket *, int); 93 void stp4020_create_event_thread(void *); 94 void stp4020_event_thread(void *); 95 void stp4020_queue_event(struct stp4020_softc *, int); 96 97 int stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t, 98 struct pcmcia_mem_handle *); 99 void stp4020_chip_mem_free(pcmcia_chipset_handle_t, 100 struct pcmcia_mem_handle *); 101 int stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t, 102 bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *); 103 void stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int); 104 105 int stp4020_chip_io_alloc(pcmcia_chipset_handle_t, 106 bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *); 107 void stp4020_chip_io_free(pcmcia_chipset_handle_t, 108 struct pcmcia_io_handle *); 109 int stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t, 110 bus_size_t, struct pcmcia_io_handle *, int *); 111 void stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int); 112 113 void stp4020_chip_socket_enable(pcmcia_chipset_handle_t); 114 void stp4020_chip_socket_disable(pcmcia_chipset_handle_t); 115 void *stp4020_chip_intr_establish(pcmcia_chipset_handle_t, 116 struct pcmcia_function *, int, int (*) (void *), void *, char *); 117 void stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *); 118 const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *); 119 120 /* Our PCMCIA chipset methods */ 121 static struct pcmcia_chip_functions stp4020_functions = { 122 stp4020_chip_mem_alloc, 123 stp4020_chip_mem_free, 124 stp4020_chip_mem_map, 125 stp4020_chip_mem_unmap, 126 127 stp4020_chip_io_alloc, 128 stp4020_chip_io_free, 129 stp4020_chip_io_map, 130 stp4020_chip_io_unmap, 131 132 stp4020_chip_intr_establish, 133 stp4020_chip_intr_disestablish, 134 stp4020_chip_intr_string, 135 136 stp4020_chip_socket_enable, 137 stp4020_chip_socket_disable 138 }; 139 140 141 static __inline__ u_int16_t 142 stp4020_rd_sockctl(h, idx) 143 struct stp4020_socket *h; 144 int idx; 145 { 146 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx); 147 return (bus_space_read_2(h->tag, h->regs, o)); 148 } 149 150 static __inline__ void 151 stp4020_wr_sockctl(h, idx, v) 152 struct stp4020_socket *h; 153 int idx; 154 u_int16_t v; 155 { 156 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx; 157 bus_space_write_2(h->tag, h->regs, o, v); 158 } 159 160 static __inline__ u_int16_t 161 stp4020_rd_winctl(h, win, idx) 162 struct stp4020_socket *h; 163 int win; 164 int idx; 165 { 166 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 167 (STP4020_WINREGS_SIZE * win) + idx; 168 return (bus_space_read_2(h->tag, h->regs, o)); 169 } 170 171 static __inline__ void 172 stp4020_wr_winctl(h, win, idx, v) 173 struct stp4020_socket *h; 174 int win; 175 int idx; 176 u_int16_t v; 177 { 178 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 179 (STP4020_WINREGS_SIZE * win) + idx; 180 bus_space_write_2(h->tag, h->regs, o, v); 181 } 182 183 184 int 185 stp4020print(aux, busname) 186 void *aux; 187 const char *busname; 188 { 189 struct pcmciabus_attach_args *paa = aux; 190 struct stp4020_socket *h = paa->pch; 191 192 printf(" socket %d", h->sock); 193 return (UNCONF); 194 } 195 196 /* 197 * Attach all the sub-devices we can find 198 */ 199 void 200 stpattach_common(struct stp4020_softc *sc, int clockfreq) 201 { 202 int i, rev; 203 204 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) & 205 STP4020_ISR1_REV_M; 206 printf(": rev %x\n", rev); 207 208 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions; 209 210 /* 211 * Arrange that a kernel thread be created to handle 212 * insert/removal events. 213 */ 214 sc->events = 0; 215 kthread_create_deferred(stp4020_create_event_thread, sc); 216 217 for (i = 0; i < STP4020_NSOCK; i++) { 218 struct stp4020_socket *h = &sc->sc_socks[i]; 219 h->sock = i; 220 h->sc = sc; 221 #ifdef STP4020_DEBUG 222 if (stp4020_debug) 223 stp4020_dump_regs(h); 224 #endif 225 stp4020_attach_socket(h, clockfreq); 226 } 227 } 228 229 void 230 stp4020_attach_socket(h, speed) 231 struct stp4020_socket *h; 232 int speed; 233 { 234 struct pcmciabus_attach_args paa; 235 int v; 236 237 /* no interrupt handlers yet */ 238 h->intrhandler = NULL; 239 h->intrarg = NULL; 240 h->softint = NULL; 241 h->int_enable = h->int_disable = 0; 242 243 /* Map all three windows */ 244 stp4020_map_window(h, STP_WIN_ATTR, speed); 245 stp4020_map_window(h, STP_WIN_MEM, speed); 246 stp4020_map_window(h, STP_WIN_IO, speed); 247 248 /* Configure one pcmcia device per socket */ 249 paa.paa_busname = "pcmcia"; 250 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct; 251 paa.pch = (pcmcia_chipset_handle_t)h; 252 paa.iobase = 0; 253 paa.iosize = STP4020_WINDOW_SIZE; 254 255 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print); 256 257 if (h->pcmcia == NULL) 258 return; 259 260 /* 261 * There's actually a pcmcia bus attached; initialize the slot. 262 */ 263 264 /* 265 * Clear things up before we enable status change interrupts. 266 * This seems to not be fully initialized by the PROM. 267 */ 268 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 269 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0); 270 stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff); 271 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff); 272 273 /* 274 * Enable socket status change interrupts. 275 * We use SB_INT[1] for status change interrupts. 276 */ 277 v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1; 278 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 279 280 /* Get live status bits from ISR0 */ 281 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 282 h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST); 283 if (h->sense != 0) { 284 h->flags |= STP4020_SOCKET_BUSY; 285 pcmcia_card_attach(h->pcmcia); 286 } 287 } 288 289 290 /* 291 * Deferred thread creation callback. 292 */ 293 void 294 stp4020_create_event_thread(arg) 295 void *arg; 296 { 297 struct stp4020_softc *sc = arg; 298 299 if (kthread_create(stp4020_event_thread, sc, &sc->event_thread, 300 sc->sc_dev.dv_xname)) { 301 panic("%s: unable to create event thread", sc->sc_dev.dv_xname); 302 } 303 } 304 305 /* 306 * The actual event handling thread. 307 */ 308 void 309 stp4020_event_thread(arg) 310 void *arg; 311 { 312 struct stp4020_softc *sc = arg; 313 int s, sense; 314 unsigned int socket; 315 316 for (;;) { 317 struct stp4020_socket *h; 318 319 s = splhigh(); 320 if ((socket = ffs(sc->events)) == 0) { 321 splx(s); 322 (void)tsleep(&sc->events, PWAIT, "stp4020_ev", 0); 323 continue; 324 } 325 socket--; 326 sc->events &= ~(1 << socket); 327 splx(s); 328 329 if (socket >= STP4020_NSOCK) { 330 #ifdef DEBUG 331 printf("stp4020_event_thread: wayward socket number %d\n", 332 socket); 333 #endif 334 continue; 335 } 336 337 h = &sc->sc_socks[socket]; 338 339 /* Read socket's ISR0 for the interrupt status bits */ 340 sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) & 341 (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST); 342 343 if (sense > h->sense) { 344 /* 345 * If at least one more sensor is asserted, this is 346 * a card insertion. 347 */ 348 h->sense = sense; 349 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 350 h->flags |= STP4020_SOCKET_BUSY; 351 pcmcia_card_attach(h->pcmcia); 352 } 353 } else if (sense < h->sense) { 354 /* 355 * If at least one less sensor is asserted, this is 356 * a card removal. 357 */ 358 h->sense = sense; 359 if (h->flags & STP4020_SOCKET_BUSY) { 360 h->flags &= ~STP4020_SOCKET_BUSY; 361 pcmcia_card_detach(h->pcmcia, DETACH_FORCE); 362 } 363 } 364 } 365 } 366 367 void 368 stp4020_queue_event(sc, sock) 369 struct stp4020_softc *sc; 370 int sock; 371 { 372 int s; 373 374 s = splhigh(); 375 sc->events |= (1 << sock); 376 splx(s); 377 wakeup(&sc->events); 378 } 379 380 /* 381 * Software interrupt called to invoke the real driver interrupt handler. 382 */ 383 void 384 stp4020_intr_dispatch(void *arg) 385 { 386 struct stp4020_socket *h = (struct stp4020_socket *)arg; 387 int s; 388 389 /* invoke driver handler */ 390 h->intrhandler(h->intrarg); 391 392 /* enable SBUS interrupts for PCMCIA interrupts again */ 393 s = splhigh(); 394 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable); 395 splx(s); 396 } 397 398 int 399 stp4020_statintr(arg) 400 void *arg; 401 { 402 struct stp4020_softc *sc = arg; 403 int i, sense, r = 0; 404 int s; 405 406 /* protect hardware access against soft interrupts */ 407 s = splhigh(); 408 409 /* 410 * Check each socket for pending requests. 411 */ 412 for (i = 0 ; i < STP4020_NSOCK; i++) { 413 struct stp4020_socket *h; 414 int v; 415 416 h = &sc->sc_socks[i]; 417 418 /* Read socket's ISR0 for the interrupt status bits */ 419 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 420 sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST); 421 422 #ifdef STP4020_DEBUG 423 if (stp4020_debug != 0) 424 printf("stp4020_statintr: ISR0=%b\n", 425 v, STP4020_ISR0_IOBITS); 426 #endif 427 428 /* Ack all interrupts at once */ 429 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 430 STP4020_ISR0_ALL_STATUS_IRQ); 431 432 if ((v & STP4020_ISR0_CDCHG) != 0) { 433 r = 1; 434 435 /* 436 * Card detect status changed. In an ideal world, 437 * both card detect sensors should be set if a card 438 * is in the slot, and clear if it is not. 439 * 440 * Unfortunately, it turns out that we can get the 441 * notification before both sensors are set (or 442 * clear). 443 * 444 * This can be very funny if only one sensor is set. 445 * Is this a removal or an insertion operation? 446 * Defer appropriate action to the worker thread. 447 */ 448 if (sense != h->sense) 449 stp4020_queue_event(sc, i); 450 451 } 452 453 /* informational messages */ 454 if ((v & STP4020_ISR0_BVD1CHG) != 0) { 455 DPRINTF(("stp4020[%d]: Battery change 1\n", 456 h->sock)); 457 r = 1; 458 } 459 460 if ((v & STP4020_ISR0_BVD2CHG) != 0) { 461 DPRINTF(("stp4020[%d]: Battery change 2\n", 462 h->sock)); 463 r = 1; 464 } 465 466 if ((v & STP4020_ISR0_RDYCHG) != 0) { 467 DPRINTF(("stp4020[%d]: Ready/Busy change\n", 468 h->sock)); 469 r = 1; 470 } 471 472 if ((v & STP4020_ISR0_WPCHG) != 0) { 473 DPRINTF(("stp4020[%d]: Write protect change\n", 474 h->sock)); 475 r = 1; 476 } 477 478 if ((v & STP4020_ISR0_PCTO) != 0) { 479 DPRINTF(("stp4020[%d]: Card access timeout\n", 480 h->sock)); 481 r = 1; 482 } 483 484 if ((v & STP4020_ISR0_SCINT) != 0) { 485 DPRINTF(("stp4020[%d]: Status change\n", 486 h->sock)); 487 r = 1; 488 } 489 490 /* 491 * Not interrupts flag per se, but interrupts can occur when 492 * they are asserted, at least during our slot enable routine. 493 */ 494 if ((h->flags & STP4020_SOCKET_ENABLING) && 495 (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON))) 496 r = 1; 497 } 498 499 splx(s); 500 501 return (r); 502 } 503 504 int 505 stp4020_iointr(arg) 506 void *arg; 507 { 508 struct stp4020_softc *sc = arg; 509 int i, r = 0; 510 int s; 511 512 /* protect hardware access against soft interrupts */ 513 s = splhigh(); 514 515 /* 516 * Check each socket for pending requests. 517 */ 518 for (i = 0 ; i < STP4020_NSOCK; i++) { 519 struct stp4020_socket *h; 520 int v; 521 522 h = &sc->sc_socks[i]; 523 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 524 525 if ((v & STP4020_ISR0_IOINT) != 0) { 526 /* we can not deny this is ours, no matter what the 527 card driver says. */ 528 r = 1; 529 530 /* ack interrupt */ 531 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v); 532 533 /* It's a card interrupt */ 534 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 535 printf("stp4020[%d]: spurious interrupt?\n", 536 h->sock); 537 continue; 538 } 539 /* Call card handler, if any */ 540 if (h->softint != NULL) { 541 softintr_schedule(h->softint); 542 543 /* 544 * Disable this sbus interrupt, until the 545 * softintr handler had a chance to run. 546 */ 547 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 548 h->int_disable); 549 } 550 } 551 552 } 553 554 splx(s); 555 556 return (r); 557 } 558 559 /* 560 * The function gets the sbus speed and a access time and calculates 561 * values for the CMDLNG and CMDDLAY registers. 562 */ 563 void 564 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay) 565 { 566 int result; 567 568 if (ns < STP4020_MEM_SPEED_MIN) 569 ns = STP4020_MEM_SPEED_MIN; 570 else if (ns > STP4020_MEM_SPEED_MAX) 571 ns = STP4020_MEM_SPEED_MAX; 572 result = ns * (bus_speed / 1000); 573 if (result % 1000000) 574 result = result / 1000000 + 1; 575 else 576 result /= 1000000; 577 *length = result; 578 579 /* the sbus frequency range is limited, so we can keep this simple */ 580 *delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2; 581 } 582 583 void 584 stp4020_map_window(struct stp4020_socket *h, int win, int speed) 585 { 586 int v, length, delay; 587 588 /* 589 * According to the PC Card standard 300ns access timing should be 590 * used for attribute memory access. Our pcmcia framework does not 591 * seem to propagate timing information, so we use that 592 * everywhere. 593 */ 594 stp4020_calc_speed(speed, 300, &length, &delay); 595 596 /* 597 * Fill in the Address Space Select and Base Address 598 * fields of this windows control register 0. 599 */ 600 v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) | 601 ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M); 602 switch (win) { 603 case STP_WIN_ATTR: 604 v |= STP4020_WCR0_ASPSEL_AM; 605 break; 606 case STP_WIN_MEM: 607 v |= STP4020_WCR0_ASPSEL_CM; 608 break; 609 case STP_WIN_IO: 610 v |= STP4020_WCR0_ASPSEL_IO; 611 break; 612 } 613 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M); 614 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 615 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 616 1 << STP4020_WCR1_WAITREQ_S); 617 } 618 619 int 620 stp4020_chip_mem_alloc(pch, size, pcmhp) 621 pcmcia_chipset_handle_t pch; 622 bus_size_t size; 623 struct pcmcia_mem_handle *pcmhp; 624 { 625 struct stp4020_socket *h = (struct stp4020_socket *)pch; 626 627 /* we can not do much here, defere work to _mem_map */ 628 pcmhp->memt = h->wintag; 629 pcmhp->size = size; 630 pcmhp->addr = 0; 631 pcmhp->mhandle = 0; 632 pcmhp->realsize = size; 633 634 return (0); 635 } 636 637 void 638 stp4020_chip_mem_free(pch, pcmhp) 639 pcmcia_chipset_handle_t pch; 640 struct pcmcia_mem_handle *pcmhp; 641 { 642 } 643 644 int 645 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) 646 pcmcia_chipset_handle_t pch; 647 int kind; 648 bus_addr_t card_addr; 649 bus_size_t size; 650 struct pcmcia_mem_handle *pcmhp; 651 bus_size_t *offsetp; 652 int *windowp; 653 { 654 struct stp4020_socket *h = (struct stp4020_socket *)pch; 655 int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM; 656 657 pcmhp->memt = h->wintag; 658 bus_space_subregion(h->wintag, h->windows[win].winaddr, 659 card_addr, size, &pcmhp->memh); 660 pcmhp->size = size; 661 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr; 662 *offsetp = 0; 663 *windowp = win; 664 665 return (0); 666 } 667 668 void 669 stp4020_chip_mem_unmap(pch, win) 670 pcmcia_chipset_handle_t pch; 671 int win; 672 { 673 } 674 675 int 676 stp4020_chip_io_alloc(pch, start, size, align, pcihp) 677 pcmcia_chipset_handle_t pch; 678 bus_addr_t start; 679 bus_size_t size; 680 bus_size_t align; 681 struct pcmcia_io_handle *pcihp; 682 { 683 struct stp4020_socket *h = (struct stp4020_socket *)pch; 684 685 pcihp->iot = h->wintag; 686 pcihp->ioh = h->windows[STP_WIN_IO].winaddr; 687 pcihp->size = size; 688 return (0); 689 } 690 691 void 692 stp4020_chip_io_free(pch, pcihp) 693 pcmcia_chipset_handle_t pch; 694 struct pcmcia_io_handle *pcihp; 695 { 696 } 697 698 int 699 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp) 700 pcmcia_chipset_handle_t pch; 701 int width; 702 bus_addr_t offset; 703 bus_size_t size; 704 struct pcmcia_io_handle *pcihp; 705 int *windowp; 706 { 707 struct stp4020_socket *h = (struct stp4020_socket *)pch; 708 709 pcihp->iot = h->wintag; 710 bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr, 711 offset, size, &pcihp->ioh); 712 *windowp = 0; 713 return (0); 714 } 715 716 void 717 stp4020_chip_io_unmap(pch, win) 718 pcmcia_chipset_handle_t pch; 719 int win; 720 { 721 } 722 723 void 724 stp4020_chip_socket_enable(pch) 725 pcmcia_chipset_handle_t pch; 726 { 727 struct stp4020_socket *h = (struct stp4020_socket *)pch; 728 int i, v; 729 730 h->flags |= STP4020_SOCKET_ENABLING; 731 732 /* this bit is mostly stolen from pcic_attach_card */ 733 734 /* Power down the socket to reset it, clear the card reset pin */ 735 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 736 737 /* 738 * wait 300ms until power fails (Tpf). Then, wait 100ms since 739 * we are changing Vcc (Toff). 740 */ 741 stp4020_delay((300 + 100) * 1000); 742 743 /* Power up the socket */ 744 v = STP4020_ICR1_MSTPWR; 745 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 746 747 /* 748 * wait 100ms until power raise (Tpr) and 20ms to become 749 * stable (Tsu(Vcc)). 750 * 751 * some machines require some more time to be settled 752 * (another 200ms is added here). 753 */ 754 stp4020_delay((100 + 20 + 200) * 1000); 755 756 v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC; 757 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 758 759 /* 760 * hold RESET at least 20us. 761 */ 762 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 763 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET); 764 delay(20); 765 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 766 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET); 767 768 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 769 stp4020_delay(20000); 770 771 /* Wait for the chip to finish initializing (5 seconds max) */ 772 for (i = 10000; i > 0; i--) { 773 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 774 /* If the card has been removed, abort */ 775 if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) { 776 h->flags &= ~STP4020_SOCKET_ENABLING; 777 return; 778 } 779 if ((v & STP4020_ISR0_RDYST) != 0) 780 break; 781 delay(500); 782 } 783 if (i <= 0) { 784 #ifdef STP4020_DEBUG 785 printf("stp4020_chip_socket_enable: not ready: status %b\n", 786 v, STP4020_ISR0_IOBITS); 787 #endif 788 h->flags &= ~STP4020_SOCKET_ENABLING; 789 return; 790 } 791 792 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 793 794 /* 795 * Check the card type. 796 * Enable socket I/O interrupts for IO cards. 797 * We use level SB_INT[0] for I/O interrupts. 798 */ 799 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) { 800 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE); 801 v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE | 802 STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN; 803 h->int_enable = v; 804 h->int_disable = v & ~STP4020_ICR0_IOIE; 805 DPRINTF(("%s: configuring card for IO usage\n", 806 h->sc->sc_dev.dv_xname)); 807 } else { 808 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 809 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE); 810 v |= STP4020_ICR0_IFTYPE_MEM; 811 h->int_enable = h->int_disable = v; 812 DPRINTF(("%s: configuring card for MEM ONLY usage\n", 813 h->sc->sc_dev.dv_xname)); 814 } 815 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 816 817 h->flags &= ~STP4020_SOCKET_ENABLING; 818 } 819 820 void 821 stp4020_chip_socket_disable(pch) 822 pcmcia_chipset_handle_t pch; 823 { 824 struct stp4020_socket *h = (struct stp4020_socket *)pch; 825 int v; 826 827 /* 828 * Disable socket I/O interrupts. 829 */ 830 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 831 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 832 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE); 833 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 834 835 /* Power down the socket */ 836 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 837 838 /* 839 * wait 300ms until power fails (Tpf). 840 */ 841 stp4020_delay(300 * 1000); 842 } 843 844 void * 845 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname) 846 pcmcia_chipset_handle_t pch; 847 struct pcmcia_function *pf; 848 int ipl; 849 int (*handler) (void *); 850 void *arg; 851 char *xname; 852 { 853 struct stp4020_socket *h = (struct stp4020_socket *)pch; 854 855 /* 856 * Note that this code relies on softintr_establish() to be 857 * used with real, hardware ipl values. All platforms with 858 * SBus support support this. 859 */ 860 h->intrhandler = handler; 861 h->intrarg = arg; 862 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h); 863 864 return h->softint != NULL ? h : NULL; 865 } 866 867 void 868 stp4020_chip_intr_disestablish(pch, ih) 869 pcmcia_chipset_handle_t pch; 870 void *ih; 871 { 872 struct stp4020_socket *h = (struct stp4020_socket *)pch; 873 874 if (h->softint != NULL) { 875 softintr_disestablish(h->softint); 876 h->softint = NULL; 877 } 878 h->intrhandler = NULL; 879 h->intrarg = NULL; 880 } 881 882 const char * 883 stp4020_chip_intr_string(pch, ih) 884 pcmcia_chipset_handle_t pch; 885 void *ih; 886 { 887 if (ih == NULL) 888 return ("couldn't establish interrupt"); 889 else 890 return (""); /* nothing for now */ 891 } 892 893 /* 894 * Delay and possibly yield CPU. 895 * XXX - assumes a context 896 */ 897 void 898 stp4020_delay(ms) 899 unsigned int ms; 900 { 901 unsigned int nticks; 902 903 /* Convert to nticks */ 904 nticks = (ms * hz) / 1000000; 905 906 if (cold || nticks == 0) { 907 delay(ms); 908 return; 909 } 910 911 #ifdef DEBUG 912 if (nticks > 60 * hz) 913 panic("stp4020: preposterous delay: %u", nticks); 914 #endif 915 tsleep(&nticks, 0, "stp4020_delay", nticks); 916 } 917 918 #ifdef STP4020_DEBUG 919 void 920 stp4020_dump_regs(h) 921 struct stp4020_socket *h; 922 { 923 /* 924 * Dump control and status registers. 925 */ 926 printf("socket[%d] registers:\n" 927 "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock, 928 stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS, 929 stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS, 930 stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS, 931 stp4020_rd_sockctl(h, STP4020_ISR1_IDX)); 932 } 933 #endif /* STP4020_DEBUG */ 934