1 /* $OpenBSD: stp4020.c,v 1.16 2009/04/10 20:54:58 miod 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 const char *name = sc->sc_dev.dv_xname; 299 300 if (kthread_create(stp4020_event_thread, sc, &sc->event_thread, 301 "%s", name)) { 302 panic("%s: unable to create event thread", name); 303 } 304 } 305 306 /* 307 * The actual event handling thread. 308 */ 309 void 310 stp4020_event_thread(arg) 311 void *arg; 312 { 313 struct stp4020_softc *sc = arg; 314 int s, sense; 315 unsigned int socket; 316 317 for (;;) { 318 struct stp4020_socket *h; 319 320 s = splhigh(); 321 if ((socket = ffs(sc->events)) == 0) { 322 splx(s); 323 (void)tsleep(&sc->events, PWAIT, "stp4020_ev", 0); 324 continue; 325 } 326 socket--; 327 sc->events &= ~(1 << socket); 328 splx(s); 329 330 if (socket >= STP4020_NSOCK) { 331 #ifdef DEBUG 332 printf("stp4020_event_thread: wayward socket number %d\n", 333 socket); 334 #endif 335 continue; 336 } 337 338 h = &sc->sc_socks[socket]; 339 340 /* Read socket's ISR0 for the interrupt status bits */ 341 sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) & 342 (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST); 343 344 if (sense > h->sense) { 345 /* 346 * If at least one more sensor is asserted, this is 347 * a card insertion. 348 */ 349 h->sense = sense; 350 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 351 h->flags |= STP4020_SOCKET_BUSY; 352 pcmcia_card_attach(h->pcmcia); 353 } 354 } else if (sense < h->sense) { 355 /* 356 * If at least one less sensor is asserted, this is 357 * a card removal. 358 */ 359 h->sense = sense; 360 if (h->flags & STP4020_SOCKET_BUSY) { 361 h->flags &= ~STP4020_SOCKET_BUSY; 362 pcmcia_card_detach(h->pcmcia, DETACH_FORCE); 363 } 364 } 365 } 366 } 367 368 void 369 stp4020_queue_event(sc, sock) 370 struct stp4020_softc *sc; 371 int sock; 372 { 373 int s; 374 375 s = splhigh(); 376 sc->events |= (1 << sock); 377 splx(s); 378 wakeup(&sc->events); 379 } 380 381 /* 382 * Software interrupt called to invoke the real driver interrupt handler. 383 */ 384 void 385 stp4020_intr_dispatch(void *arg) 386 { 387 struct stp4020_socket *h = (struct stp4020_socket *)arg; 388 int s; 389 390 /* invoke driver handler */ 391 h->intrhandler(h->intrarg); 392 393 /* enable SBUS interrupts for PCMCIA interrupts again */ 394 s = splhigh(); 395 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable); 396 splx(s); 397 } 398 399 int 400 stp4020_statintr(arg) 401 void *arg; 402 { 403 struct stp4020_softc *sc = arg; 404 int i, sense, r = 0; 405 int s; 406 407 /* protect hardware access against soft interrupts */ 408 s = splhigh(); 409 410 /* 411 * Check each socket for pending requests. 412 */ 413 for (i = 0 ; i < STP4020_NSOCK; i++) { 414 struct stp4020_socket *h; 415 int v; 416 417 h = &sc->sc_socks[i]; 418 419 /* Read socket's ISR0 for the interrupt status bits */ 420 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 421 sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST); 422 423 #ifdef STP4020_DEBUG 424 if (stp4020_debug != 0) 425 printf("stp4020_statintr: ISR0=%b\n", 426 v, STP4020_ISR0_IOBITS); 427 #endif 428 429 /* Ack all interrupts at once */ 430 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 431 STP4020_ISR0_ALL_STATUS_IRQ); 432 433 if ((v & STP4020_ISR0_CDCHG) != 0) { 434 r = 1; 435 436 /* 437 * Card detect status changed. In an ideal world, 438 * both card detect sensors should be set if a card 439 * is in the slot, and clear if it is not. 440 * 441 * Unfortunately, it turns out that we can get the 442 * notification before both sensors are set (or 443 * clear). 444 * 445 * This can be very funny if only one sensor is set. 446 * Is this a removal or an insertion operation? 447 * Defer appropriate action to the worker thread. 448 */ 449 if (sense != h->sense) 450 stp4020_queue_event(sc, i); 451 452 } 453 454 /* informational messages */ 455 if ((v & STP4020_ISR0_BVD1CHG) != 0) { 456 DPRINTF(("stp4020[%d]: Battery change 1\n", 457 h->sock)); 458 r = 1; 459 } 460 461 if ((v & STP4020_ISR0_BVD2CHG) != 0) { 462 DPRINTF(("stp4020[%d]: Battery change 2\n", 463 h->sock)); 464 r = 1; 465 } 466 467 if ((v & STP4020_ISR0_RDYCHG) != 0) { 468 DPRINTF(("stp4020[%d]: Ready/Busy change\n", 469 h->sock)); 470 r = 1; 471 } 472 473 if ((v & STP4020_ISR0_WPCHG) != 0) { 474 DPRINTF(("stp4020[%d]: Write protect change\n", 475 h->sock)); 476 r = 1; 477 } 478 479 if ((v & STP4020_ISR0_PCTO) != 0) { 480 DPRINTF(("stp4020[%d]: Card access timeout\n", 481 h->sock)); 482 r = 1; 483 } 484 485 if ((v & STP4020_ISR0_SCINT) != 0) { 486 DPRINTF(("stp4020[%d]: Status change\n", 487 h->sock)); 488 r = 1; 489 } 490 491 /* 492 * Not interrupts flag per se, but interrupts can occur when 493 * they are asserted, at least during our slot enable routine. 494 */ 495 if ((h->flags & STP4020_SOCKET_ENABLING) && 496 (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON))) 497 r = 1; 498 } 499 500 splx(s); 501 502 return (r); 503 } 504 505 int 506 stp4020_iointr(arg) 507 void *arg; 508 { 509 struct stp4020_softc *sc = arg; 510 int i, r = 0; 511 int s; 512 513 /* protect hardware access against soft interrupts */ 514 s = splhigh(); 515 516 /* 517 * Check each socket for pending requests. 518 */ 519 for (i = 0 ; i < STP4020_NSOCK; i++) { 520 struct stp4020_socket *h; 521 int v; 522 523 h = &sc->sc_socks[i]; 524 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 525 526 if ((v & STP4020_ISR0_IOINT) != 0) { 527 /* we can not deny this is ours, no matter what the 528 card driver says. */ 529 r = 1; 530 531 /* ack interrupt */ 532 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v); 533 534 /* It's a card interrupt */ 535 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 536 printf("stp4020[%d]: spurious interrupt?\n", 537 h->sock); 538 continue; 539 } 540 /* Call card handler, if any */ 541 if (h->softint != NULL) { 542 softintr_schedule(h->softint); 543 544 /* 545 * Disable this sbus interrupt, until the 546 * softintr handler had a chance to run. 547 */ 548 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 549 h->int_disable); 550 } 551 } 552 553 } 554 555 splx(s); 556 557 return (r); 558 } 559 560 /* 561 * The function gets the sbus speed and a access time and calculates 562 * values for the CMDLNG and CMDDLAY registers. 563 */ 564 void 565 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay) 566 { 567 int result; 568 569 if (ns < STP4020_MEM_SPEED_MIN) 570 ns = STP4020_MEM_SPEED_MIN; 571 else if (ns > STP4020_MEM_SPEED_MAX) 572 ns = STP4020_MEM_SPEED_MAX; 573 result = ns * (bus_speed / 1000); 574 if (result % 1000000) 575 result = result / 1000000 + 1; 576 else 577 result /= 1000000; 578 *length = result; 579 580 /* the sbus frequency range is limited, so we can keep this simple */ 581 *delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2; 582 } 583 584 void 585 stp4020_map_window(struct stp4020_socket *h, int win, int speed) 586 { 587 int v, length, delay; 588 589 /* 590 * According to the PC Card standard 300ns access timing should be 591 * used for attribute memory access. Our pcmcia framework does not 592 * seem to propagate timing information, so we use that 593 * everywhere. 594 */ 595 stp4020_calc_speed(speed, 300, &length, &delay); 596 597 /* 598 * Fill in the Address Space Select and Base Address 599 * fields of this windows control register 0. 600 */ 601 v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) | 602 ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M); 603 switch (win) { 604 case STP_WIN_ATTR: 605 v |= STP4020_WCR0_ASPSEL_AM; 606 break; 607 case STP_WIN_MEM: 608 v |= STP4020_WCR0_ASPSEL_CM; 609 break; 610 case STP_WIN_IO: 611 v |= STP4020_WCR0_ASPSEL_IO; 612 break; 613 } 614 v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M); 615 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 616 stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 617 1 << STP4020_WCR1_WAITREQ_S); 618 } 619 620 int 621 stp4020_chip_mem_alloc(pch, size, pcmhp) 622 pcmcia_chipset_handle_t pch; 623 bus_size_t size; 624 struct pcmcia_mem_handle *pcmhp; 625 { 626 struct stp4020_socket *h = (struct stp4020_socket *)pch; 627 628 /* we can not do much here, defere work to _mem_map */ 629 pcmhp->memt = h->wintag; 630 pcmhp->size = size; 631 pcmhp->addr = 0; 632 pcmhp->mhandle = 0; 633 pcmhp->realsize = size; 634 635 return (0); 636 } 637 638 void 639 stp4020_chip_mem_free(pch, pcmhp) 640 pcmcia_chipset_handle_t pch; 641 struct pcmcia_mem_handle *pcmhp; 642 { 643 } 644 645 int 646 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) 647 pcmcia_chipset_handle_t pch; 648 int kind; 649 bus_addr_t card_addr; 650 bus_size_t size; 651 struct pcmcia_mem_handle *pcmhp; 652 bus_size_t *offsetp; 653 int *windowp; 654 { 655 struct stp4020_socket *h = (struct stp4020_socket *)pch; 656 int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM; 657 658 pcmhp->memt = h->wintag; 659 bus_space_subregion(h->wintag, h->windows[win].winaddr, 660 card_addr, size, &pcmhp->memh); 661 pcmhp->size = size; 662 pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr; 663 *offsetp = 0; 664 *windowp = win; 665 666 return (0); 667 } 668 669 void 670 stp4020_chip_mem_unmap(pch, win) 671 pcmcia_chipset_handle_t pch; 672 int win; 673 { 674 } 675 676 int 677 stp4020_chip_io_alloc(pch, start, size, align, pcihp) 678 pcmcia_chipset_handle_t pch; 679 bus_addr_t start; 680 bus_size_t size; 681 bus_size_t align; 682 struct pcmcia_io_handle *pcihp; 683 { 684 struct stp4020_socket *h = (struct stp4020_socket *)pch; 685 686 pcihp->iot = h->wintag; 687 pcihp->ioh = h->windows[STP_WIN_IO].winaddr; 688 pcihp->size = size; 689 return (0); 690 } 691 692 void 693 stp4020_chip_io_free(pch, pcihp) 694 pcmcia_chipset_handle_t pch; 695 struct pcmcia_io_handle *pcihp; 696 { 697 } 698 699 int 700 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp) 701 pcmcia_chipset_handle_t pch; 702 int width; 703 bus_addr_t offset; 704 bus_size_t size; 705 struct pcmcia_io_handle *pcihp; 706 int *windowp; 707 { 708 struct stp4020_socket *h = (struct stp4020_socket *)pch; 709 710 pcihp->iot = h->wintag; 711 bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr, 712 offset, size, &pcihp->ioh); 713 *windowp = 0; 714 return (0); 715 } 716 717 void 718 stp4020_chip_io_unmap(pch, win) 719 pcmcia_chipset_handle_t pch; 720 int win; 721 { 722 } 723 724 void 725 stp4020_chip_socket_enable(pch) 726 pcmcia_chipset_handle_t pch; 727 { 728 struct stp4020_socket *h = (struct stp4020_socket *)pch; 729 int i, v; 730 731 h->flags |= STP4020_SOCKET_ENABLING; 732 733 /* this bit is mostly stolen from pcic_attach_card */ 734 735 /* Power down the socket to reset it, clear the card reset pin */ 736 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 737 738 /* 739 * wait 300ms until power fails (Tpf). Then, wait 100ms since 740 * we are changing Vcc (Toff). 741 */ 742 stp4020_delay((300 + 100) * 1000); 743 744 /* Power up the socket */ 745 v = STP4020_ICR1_MSTPWR; 746 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 747 748 /* 749 * wait 100ms until power raise (Tpr) and 20ms to become 750 * stable (Tsu(Vcc)). 751 * 752 * some machines require some more time to be settled 753 * (another 200ms is added here). 754 */ 755 stp4020_delay((100 + 20 + 200) * 1000); 756 757 v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC; 758 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 759 760 /* 761 * hold RESET at least 20us. 762 */ 763 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 764 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET); 765 delay(20); 766 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 767 stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET); 768 769 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 770 stp4020_delay(20000); 771 772 /* Wait for the chip to finish initializing (5 seconds max) */ 773 for (i = 10000; i > 0; i--) { 774 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 775 /* If the card has been removed, abort */ 776 if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) { 777 h->flags &= ~STP4020_SOCKET_ENABLING; 778 return; 779 } 780 if ((v & STP4020_ISR0_RDYST) != 0) 781 break; 782 delay(500); 783 } 784 if (i <= 0) { 785 #ifdef STP4020_DEBUG 786 printf("stp4020_chip_socket_enable: not ready: status %b\n", 787 v, STP4020_ISR0_IOBITS); 788 #endif 789 h->flags &= ~STP4020_SOCKET_ENABLING; 790 return; 791 } 792 793 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 794 795 /* 796 * Check the card type. 797 * Enable socket I/O interrupts for IO cards. 798 * We use level SB_INT[0] for I/O interrupts. 799 */ 800 if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) { 801 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE); 802 v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE | 803 STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN; 804 h->int_enable = v; 805 h->int_disable = v & ~STP4020_ICR0_IOIE; 806 DPRINTF(("%s: configuring card for IO usage\n", 807 h->sc->sc_dev.dv_xname)); 808 } else { 809 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 810 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE); 811 v |= STP4020_ICR0_IFTYPE_MEM; 812 h->int_enable = h->int_disable = v; 813 DPRINTF(("%s: configuring card for MEM ONLY usage\n", 814 h->sc->sc_dev.dv_xname)); 815 } 816 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 817 818 h->flags &= ~STP4020_SOCKET_ENABLING; 819 } 820 821 void 822 stp4020_chip_socket_disable(pch) 823 pcmcia_chipset_handle_t pch; 824 { 825 struct stp4020_socket *h = (struct stp4020_socket *)pch; 826 int v; 827 828 /* 829 * Disable socket I/O interrupts. 830 */ 831 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 832 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE | 833 STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE); 834 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 835 836 /* Power down the socket */ 837 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0); 838 839 /* 840 * wait 300ms until power fails (Tpf). 841 */ 842 stp4020_delay(300 * 1000); 843 } 844 845 void * 846 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname) 847 pcmcia_chipset_handle_t pch; 848 struct pcmcia_function *pf; 849 int ipl; 850 int (*handler) (void *); 851 void *arg; 852 char *xname; 853 { 854 struct stp4020_socket *h = (struct stp4020_socket *)pch; 855 856 /* 857 * Note that this code relies on softintr_establish() to be 858 * used with real, hardware ipl values. All platforms with 859 * SBus support support this. 860 */ 861 h->intrhandler = handler; 862 h->intrarg = arg; 863 h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h); 864 865 return h->softint != NULL ? h : NULL; 866 } 867 868 void 869 stp4020_chip_intr_disestablish(pch, ih) 870 pcmcia_chipset_handle_t pch; 871 void *ih; 872 { 873 struct stp4020_socket *h = (struct stp4020_socket *)pch; 874 875 if (h->softint != NULL) { 876 softintr_disestablish(h->softint); 877 h->softint = NULL; 878 } 879 h->intrhandler = NULL; 880 h->intrarg = NULL; 881 } 882 883 const char * 884 stp4020_chip_intr_string(pch, ih) 885 pcmcia_chipset_handle_t pch; 886 void *ih; 887 { 888 if (ih == NULL) 889 return ("couldn't establish interrupt"); 890 else 891 return (""); /* nothing for now */ 892 } 893 894 /* 895 * Delay and possibly yield CPU. 896 * XXX - assumes a context 897 */ 898 void 899 stp4020_delay(ms) 900 unsigned int ms; 901 { 902 unsigned int ticks; 903 904 /* Convert to ticks */ 905 ticks = (ms * hz) / 1000000; 906 907 if (cold || ticks == 0) { 908 delay(ms); 909 return; 910 } 911 912 #ifdef DEBUG 913 if (ticks > 60 * hz) 914 panic("stp4020: preposterous delay: %u", ticks); 915 #endif 916 tsleep(&ticks, 0, "stp4020_delay", ticks); 917 } 918 919 #ifdef STP4020_DEBUG 920 void 921 stp4020_dump_regs(h) 922 struct stp4020_socket *h; 923 { 924 /* 925 * Dump control and status registers. 926 */ 927 printf("socket[%d] registers:\n" 928 "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock, 929 stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS, 930 stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS, 931 stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS, 932 stp4020_rd_sockctl(h, STP4020_ISR1_IDX)); 933 } 934 #endif /* STP4020_DEBUG */ 935