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