1 /* $NetBSD: stp4020.c,v 1.11 2000/07/09 20:57:44 pk 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/errno.h> 47 #include <sys/malloc.h> 48 #include <sys/proc.h> 49 #include <sys/kernel.h> 50 #include <sys/kthread.h> 51 #include <sys/device.h> 52 53 #include <dev/pcmcia/pcmciareg.h> 54 #include <dev/pcmcia/pcmciavar.h> 55 #include <dev/pcmcia/pcmciachip.h> 56 57 #include <machine/bus.h> 58 #include <machine/intr.h> 59 60 #include <dev/sbus/sbusvar.h> 61 #include <dev/sbus/stp4020reg.h> 62 63 #define STP4020_DEBUG 1 /* XXX-temp */ 64 65 #if defined(STP4020_DEBUG) 66 int stp4020_debug = 0; 67 #define DPRINTF(x) do { if (stp4020_debug) printf x; } while(0) 68 #else 69 #define DPRINTF(x) 70 #endif 71 72 /* 73 * Event queue; events detected in an interrupt context go here 74 * awaiting attention from our event handling thread. 75 */ 76 struct stp4020_event { 77 SIMPLEQ_ENTRY(stp4020_event) se_q; 78 int se_type; 79 int se_sock; 80 }; 81 /* Defined event types */ 82 #define STP4020_EVENT_INSERTION 0 83 #define STP4020_EVENT_REMOVAL 1 84 85 /* 86 * Per socket data. 87 */ 88 struct stp4020_socket { 89 struct stp4020_softc *sc; /* Back link */ 90 int flags; 91 #define STP4020_SOCKET_BUSY 0x0001 92 #define STP4020_SOCKET_SHUTDOWN 0x0002 93 int sock; /* Socket number (0 or 1) */ 94 bus_space_tag_t tag; /* socket control space */ 95 bus_space_handle_t regs; /* */ 96 struct device *pcmcia; /* Associated PCMCIA device */ 97 int (*intrhandler) /* Card driver interrupt handler */ 98 __P((void *)); 99 void *intrarg; /* Card interrupt handler argument */ 100 int ipl; /* Interrupt level suggested by card */ 101 int winalloc; /* Windows allocated (bitmask) */ 102 struct { 103 bus_space_handle_t winaddr;/* this window's address */ 104 } windows[STP4020_NWIN]; 105 106 }; 107 108 struct stp4020_softc { 109 struct device sc_dev; /* Base device */ 110 struct sbusdev sc_sd; /* SBus device */ 111 bus_space_tag_t sc_bustag; 112 bus_dma_tag_t sc_dmatag; 113 pcmcia_chipset_tag_t sc_pct; /* Chipset methods */ 114 115 struct proc *event_thread; /* event handling thread */ 116 SIMPLEQ_HEAD(, stp4020_event) events; /* Pending events for thread */ 117 118 struct stp4020_socket sc_socks[STP4020_NSOCK]; 119 }; 120 121 122 static int stp4020print __P((void *, const char *)); 123 static int stp4020match __P((struct device *, struct cfdata *, void *)); 124 static void stp4020attach __P((struct device *, struct device *, void *)); 125 static int stp4020_iointr __P((void *)); 126 static int stp4020_statintr __P((void *)); 127 128 struct cfattach nell_ca = { 129 sizeof(struct stp4020_softc), stp4020match, stp4020attach 130 }; 131 132 #ifdef STP4020_DEBUG 133 static void stp4020_dump_regs __P((struct stp4020_socket *)); 134 #endif 135 136 static int stp4020_rd_sockctl __P((struct stp4020_socket *, int)); 137 static void stp4020_wr_sockctl __P((struct stp4020_socket *, int, int)); 138 static int stp4020_rd_winctl __P((struct stp4020_socket *, int, int)); 139 static void stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int)); 140 141 void stp4020_delay __P((unsigned int)); 142 void stp4020_attach_socket __P((struct stp4020_socket *)); 143 void stp4020_create_event_thread __P((void *)); 144 void stp4020_event_thread __P((void *)); 145 void stp4020_queue_event __P((struct stp4020_softc *, int, int)); 146 147 int stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t, 148 struct pcmcia_mem_handle *)); 149 void stp4020_chip_mem_free __P((pcmcia_chipset_handle_t, 150 struct pcmcia_mem_handle *)); 151 int stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, 152 bus_size_t, struct pcmcia_mem_handle *, 153 bus_addr_t *, int *)); 154 void stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int)); 155 156 int stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t, 157 bus_addr_t, bus_size_t, bus_size_t, 158 struct pcmcia_io_handle *)); 159 void stp4020_chip_io_free __P((pcmcia_chipset_handle_t, 160 struct pcmcia_io_handle *)); 161 int stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t, 162 bus_size_t, struct pcmcia_io_handle *, int *)); 163 void stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int)); 164 165 void stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t)); 166 void stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t)); 167 void *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t, 168 struct pcmcia_function *, int, 169 int (*) __P((void *)), void *)); 170 void stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *)); 171 172 173 /* Our PCMCIA chipset methods */ 174 static struct pcmcia_chip_functions stp4020_functions = { 175 stp4020_chip_mem_alloc, 176 stp4020_chip_mem_free, 177 stp4020_chip_mem_map, 178 stp4020_chip_mem_unmap, 179 180 stp4020_chip_io_alloc, 181 stp4020_chip_io_free, 182 stp4020_chip_io_map, 183 stp4020_chip_io_unmap, 184 185 stp4020_chip_intr_establish, 186 stp4020_chip_intr_disestablish, 187 188 stp4020_chip_socket_enable, 189 stp4020_chip_socket_disable 190 }; 191 192 193 static __inline__ int 194 stp4020_rd_sockctl(h, idx) 195 struct stp4020_socket *h; 196 int idx; 197 { 198 int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx); 199 return (bus_space_read_2(h->tag, h->regs, o)); 200 } 201 202 static __inline__ void 203 stp4020_wr_sockctl(h, idx, v) 204 struct stp4020_socket *h; 205 int idx; 206 int v; 207 { 208 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx; 209 bus_space_write_2(h->tag, h->regs, o, v); 210 } 211 212 static __inline__ int 213 stp4020_rd_winctl(h, win, idx) 214 struct stp4020_socket *h; 215 int win; 216 int idx; 217 { 218 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 219 (STP4020_WINREGS_SIZE * win) + idx; 220 return (bus_space_read_2(h->tag, h->regs, o)); 221 } 222 223 static __inline__ void 224 stp4020_wr_winctl(h, win, idx, v) 225 struct stp4020_socket *h; 226 int win; 227 int idx; 228 int v; 229 { 230 int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + 231 (STP4020_WINREGS_SIZE * win) + idx; 232 233 bus_space_write_2(h->tag, h->regs, o, v); 234 } 235 236 237 int 238 stp4020print(aux, busname) 239 void *aux; 240 const char *busname; 241 { 242 struct pcmciabus_attach_args *paa = aux; 243 struct stp4020_socket *h = paa->pch; 244 245 printf(" socket %d", h->sock); 246 return (UNCONF); 247 } 248 249 int 250 stp4020match(parent, cf, aux) 251 struct device *parent; 252 struct cfdata *cf; 253 void *aux; 254 { 255 struct sbus_attach_args *sa = aux; 256 257 return (strcmp("SUNW,pcmcia", sa->sa_name) == 0); 258 } 259 260 /* 261 * Attach all the sub-devices we can find 262 */ 263 void 264 stp4020attach(parent, self, aux) 265 struct device *parent, *self; 266 void *aux; 267 { 268 struct sbus_attach_args *sa = aux; 269 struct stp4020_softc *sc = (void *)self; 270 int node, rev; 271 int i; 272 bus_space_handle_t bh; 273 274 node = sa->sa_node; 275 276 /* Transfer bus tags */ 277 sc->sc_bustag = sa->sa_bustag; 278 sc->sc_dmatag = sa->sa_dmatag; 279 280 /* Set up per-socket static initialization */ 281 sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc; 282 sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag; 283 284 if (sa->sa_nreg < 8) { 285 printf("%s: only %d register sets\n", 286 self->dv_xname, sa->sa_nreg); 287 return; 288 } 289 290 if (sa->sa_nintr != 2) { 291 printf("%s: expect 2 interrupt Sbus levels; got %d\n", 292 self->dv_xname, sa->sa_nintr); 293 return; 294 } 295 296 #define STP4020_BANK_PROM 0 297 #define STP4020_BANK_CTRL 4 298 for (i = 0; i < 8; i++) { 299 300 /* 301 * STP4020 Register address map: 302 * bank 0: Forth PROM 303 * banks 1-3: socket 0, windows 0-2 304 * bank 4: control registers 305 * banks 5-7: socket 1, windows 0-2 306 */ 307 308 if (i == STP4020_BANK_PROM) 309 /* Skip the PROM */ 310 continue; 311 312 if (sbus_bus_map(sa->sa_bustag, 313 sa->sa_reg[i].sbr_slot, 314 sa->sa_reg[i].sbr_offset, 315 sa->sa_reg[i].sbr_size, 316 BUS_SPACE_MAP_LINEAR, 0, 317 &bh) != 0) { 318 printf("%s: attach: cannot map registers\n", 319 self->dv_xname); 320 return; 321 } 322 323 if (i == STP4020_BANK_CTRL) { 324 /* 325 * Copy tag and handle to both socket structures 326 * for easy access in control/status IO functions. 327 */ 328 sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh; 329 } else if (i < STP4020_BANK_CTRL) { 330 /* banks 1-3 */ 331 sc->sc_socks[0].windows[i-1].winaddr = bh; 332 } else { 333 /* banks 5-7 */ 334 sc->sc_socks[1].windows[i-5].winaddr = bh; 335 } 336 } 337 338 sbus_establish(&sc->sc_sd, &sc->sc_dev); 339 340 /* 341 * We get to use two SBus interrupt levels. 342 * The higher level we use for status change interrupts; 343 * the lower level for PC card I/O. 344 */ 345 if (sa->sa_nintr != 0) { 346 bus_intr_establish(sa->sa_bustag, sa->sa_intr[1].sbi_pri, 347 IPL_NONE, 0, stp4020_statintr, sc); 348 349 bus_intr_establish(sa->sa_bustag, sa->sa_intr[0].sbi_pri, 350 IPL_NONE, 0, stp4020_iointr, sc); 351 } 352 353 rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) & 354 STP4020_ISR1_REV_M; 355 printf(": rev %x\n", rev); 356 357 sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions; 358 359 /* 360 * Arrange that a kernel thread be created to handle 361 * insert/removal events. 362 */ 363 SIMPLEQ_INIT(&sc->events); 364 kthread_create(stp4020_create_event_thread, sc); 365 366 for (i = 0; i < STP4020_NSOCK; i++) { 367 struct stp4020_socket *h = &sc->sc_socks[i]; 368 h->sock = i; 369 h->sc = sc; 370 #ifdef STP4020_DEBUG 371 stp4020_dump_regs(h); 372 #endif 373 stp4020_attach_socket(h); 374 } 375 } 376 377 void 378 stp4020_attach_socket(h) 379 struct stp4020_socket *h; 380 { 381 struct pcmciabus_attach_args paa; 382 int v; 383 384 /* Initialize the rest of the handle */ 385 h->winalloc = 0; 386 387 /* Configure one pcmcia device per socket */ 388 paa.paa_busname = "pcmcia"; 389 paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct; 390 paa.pch = (pcmcia_chipset_handle_t)h; 391 paa.iobase = 0; 392 paa.iosize = 0; 393 394 h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print); 395 396 if (h->pcmcia == NULL) 397 return; 398 399 /* 400 * There's actually a pcmcia bus attached; initialize the slot. 401 */ 402 403 /* 404 * Enable socket status change interrupts. 405 * We use SB_INT[1] for status change interrupts. 406 */ 407 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 408 v |= STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1; 409 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 410 411 /* Get live status bits from ISR0 */ 412 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 413 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0) 414 return; 415 416 pcmcia_card_attach(h->pcmcia); 417 h->flags |= STP4020_SOCKET_BUSY; 418 } 419 420 421 /* 422 * Deferred thread creation callback. 423 */ 424 void 425 stp4020_create_event_thread(arg) 426 void *arg; 427 { 428 struct stp4020_softc *sc = arg; 429 const char *name = sc->sc_dev.dv_xname; 430 431 if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread, 432 "%s", name)) { 433 panic("%s: unable to create event thread", name); 434 } 435 } 436 437 /* 438 * The actual event handling thread. 439 */ 440 void 441 stp4020_event_thread(arg) 442 void *arg; 443 { 444 struct stp4020_softc *sc = arg; 445 struct stp4020_event *e; 446 int s; 447 448 while (1) { 449 struct stp4020_socket *h; 450 int n; 451 452 s = splhigh(); 453 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) { 454 splx(s); 455 (void)tsleep(&sc->events, PWAIT, "pcicev", 0); 456 continue; 457 } 458 SIMPLEQ_REMOVE_HEAD(&sc->events, e, se_q); 459 splx(s); 460 461 n = e->se_sock; 462 if (n < 0 || n >= STP4020_NSOCK) 463 panic("stp4020_event_thread: wayward socket number %d", 464 n); 465 466 h = &sc->sc_socks[n]; 467 switch (e->se_type) { 468 case STP4020_EVENT_INSERTION: 469 pcmcia_card_attach(h->pcmcia); 470 break; 471 case STP4020_EVENT_REMOVAL: 472 pcmcia_card_detach(h->pcmcia, DETACH_FORCE); 473 break; 474 default: 475 panic("stp4020_event_thread: unknown event type %d", 476 e->se_type); 477 } 478 free(e, M_TEMP); 479 } 480 } 481 482 void 483 stp4020_queue_event(sc, sock, event) 484 struct stp4020_softc *sc; 485 int sock, event; 486 { 487 struct stp4020_event *e; 488 int s; 489 490 e = malloc(sizeof(*e), M_TEMP, M_NOWAIT); 491 if (e == NULL) 492 panic("stp4020_queue_event: can't allocate event"); 493 494 e->se_type = event; 495 e->se_sock = sock; 496 s = splhigh(); 497 SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q); 498 splx(s); 499 wakeup(&sc->events); 500 } 501 502 int 503 stp4020_statintr(arg) 504 void *arg; 505 { 506 struct stp4020_softc *sc = arg; 507 int i, r = 0; 508 509 /* 510 * Check each socket for pending requests. 511 */ 512 for (i = 0 ; i < STP4020_NSOCK; i++) { 513 struct stp4020_socket *h; 514 int v; 515 516 h = &sc->sc_socks[i]; 517 518 /* Read socket's ISR0 for the interrupt status bits */ 519 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 520 521 #ifdef STP4020_DEBUG 522 if (stp4020_debug != 0) { 523 char bits[64]; 524 bitmask_snprintf(v, STP4020_ISR0_IOBITS, 525 bits, sizeof(bits)); 526 printf("stp4020_statintr: ISR0=%s\n", bits); 527 } 528 #endif 529 530 /* Ack all interrupts at once */ 531 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 532 STP4020_ISR0_ALL_STATUS_IRQ); 533 534 if ((v & STP4020_ISR0_CDCHG) != 0) { 535 /* 536 * Card status change detect 537 */ 538 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) != 0){ 539 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 540 stp4020_queue_event(sc, i, 541 STP4020_EVENT_INSERTION); 542 h->flags |= STP4020_SOCKET_BUSY; 543 } 544 } 545 if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){ 546 if ((h->flags & STP4020_SOCKET_BUSY) != 0) { 547 stp4020_queue_event(sc, i, 548 STP4020_EVENT_REMOVAL); 549 h->flags &= ~STP4020_SOCKET_BUSY; 550 } 551 } 552 } 553 554 /* XXX - a bunch of unhandled conditions */ 555 if ((v & STP4020_ISR0_BVD1CHG) != 0) { 556 printf("stp4020[%d]: Battery change 1\n", h->sock); 557 } 558 559 if ((v & STP4020_ISR0_BVD2CHG) != 0) { 560 printf("stp4020[%d]: Battery change 2\n", h->sock); 561 } 562 563 if ((v & STP4020_ISR0_RDYCHG) != 0) { 564 printf("stp4020[%d]: Ready/Busy change\n", h->sock); 565 } 566 567 if ((v & STP4020_ISR0_WPCHG) != 0) { 568 printf("stp4020[%d]: Write protect change\n", h->sock); 569 } 570 571 if ((v & STP4020_ISR0_PCTO) != 0) { 572 printf("stp4020[%d]: Card access timeout\n", h->sock); 573 } 574 } 575 576 return (r); 577 } 578 579 int 580 stp4020_iointr(arg) 581 void *arg; 582 { 583 struct stp4020_softc *sc = arg; 584 int i, r = 0; 585 586 /* 587 * Check each socket for pending requests. 588 */ 589 for (i = 0 ; i < STP4020_NSOCK; i++) { 590 struct stp4020_socket *h; 591 int v; 592 593 h = &sc->sc_socks[i]; 594 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 595 596 if ((v & STP4020_ISR0_IOINT) != 0) { 597 /* It's a card interrupt */ 598 if ((h->flags & STP4020_SOCKET_BUSY) == 0) { 599 printf("stp4020[%d]: spurious interrupt?\n", 600 h->sock); 601 continue; 602 } 603 /* Call card handler, if any */ 604 if (h->intrhandler != NULL) 605 r |= (*h->intrhandler)(h->intrarg); 606 } 607 608 } 609 610 return (r); 611 } 612 613 int 614 stp4020_chip_mem_alloc(pch, size, pcmhp) 615 pcmcia_chipset_handle_t pch; 616 bus_size_t size; 617 struct pcmcia_mem_handle *pcmhp; 618 { 619 struct stp4020_socket *h = (struct stp4020_socket *)pch; 620 int i, win; 621 622 /* 623 * Allocate a window. 624 */ 625 if (size > STP4020_WINDOW_SIZE) 626 return (1); 627 628 for (win = -1, i = 0; i < STP4020_NWIN; i++) { 629 if ((h->winalloc & (1 << i)) == 0) { 630 win = i; 631 h->winalloc |= (1 << i); 632 break; 633 } 634 } 635 636 if (win == -1) 637 return (1); 638 639 pcmhp->memt = 0; 640 pcmhp->memh = h->windows[win].winaddr; 641 pcmhp->addr = 0; /* What is it used for? */ 642 pcmhp->size = size; 643 pcmhp->mhandle = win; /* Use our window number as a handle */ 644 pcmhp->realsize = STP4020_WINDOW_SIZE; 645 646 return (0); 647 } 648 649 void 650 stp4020_chip_mem_free(pch, pcmhp) 651 pcmcia_chipset_handle_t pch; 652 struct pcmcia_mem_handle *pcmhp; 653 { 654 655 return; 656 } 657 658 int 659 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp) 660 pcmcia_chipset_handle_t pch; 661 int kind; 662 bus_addr_t card_addr; 663 bus_size_t size; 664 struct pcmcia_mem_handle *pcmhp; 665 bus_addr_t *offsetp; 666 int *windowp; 667 { 668 struct stp4020_socket *h = (struct stp4020_socket *)pch; 669 bus_addr_t offset; 670 int win, v; 671 672 int mem8 = (kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8; 673 kind &= ~PCMCIA_WIDTH_MEM_MASK; 674 675 if(mem8) { 676 /* XXX Fix 8-bit memory accesses (can this be done at all?) */ 677 #ifdef DIAGNOSTIC 678 printf("stp4020_chip_mem_map: can't handle 8-bit memory\n"); 679 #endif 680 return (-1); 681 } 682 683 win = pcmhp->mhandle; 684 *windowp = win; 685 686 /* 687 * Compute the address offset to the pcmcia address space 688 * for the window. 689 */ 690 offset = card_addr & -STP4020_WINDOW_SIZE; 691 card_addr -= offset; 692 *offsetp = offset; 693 694 /* 695 * Fill in the Address Space Select and Base Address 696 * fields of this windows control register 0. 697 */ 698 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX); 699 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M); 700 v |= (kind == PCMCIA_MEM_ATTR) 701 ? STP4020_WCR0_ASPSEL_AM 702 : STP4020_WCR0_ASPSEL_CM; 703 v |= (STP4020_ADDR2PAGE(card_addr) & STP4020_WCR0_BASE_M); 704 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 705 706 return (0); 707 } 708 709 void 710 stp4020_chip_mem_unmap(pch, win) 711 pcmcia_chipset_handle_t pch; 712 int win; 713 { 714 struct stp4020_socket *h = (struct stp4020_socket *)pch; 715 716 #ifdef DIAGNOSTIC 717 if (win < 0 || win > 2) 718 panic("stp4020_chip_mem_unmap: window (%d) out of range", win); 719 #endif 720 h->winalloc &= ~(1 << win); 721 /* 722 * If possible, invalidate hardware mapping here; but 723 * I don't think the stp4020 has provided for that. 724 */ 725 } 726 727 int 728 stp4020_chip_io_alloc(pch, start, size, align, pcihp) 729 pcmcia_chipset_handle_t pch; 730 bus_addr_t start; 731 bus_size_t size; 732 bus_size_t align; 733 struct pcmcia_io_handle *pcihp; 734 { 735 struct stp4020_socket *h = (struct stp4020_socket *)pch; 736 737 if (start) { 738 /* How on earth can `start' be interpreted?? 739 WHERE DOES THE CARD DRIVER GET IT FROM? 740 */ 741 } 742 743 pcihp->iot = h->tag; 744 pcihp->ioh = 0; 745 pcihp->addr = 0; 746 pcihp->size = size; 747 pcihp->flags = 0; 748 749 return (0); 750 } 751 752 void 753 stp4020_chip_io_free(pch, pcihp) 754 pcmcia_chipset_handle_t pch; 755 struct pcmcia_io_handle *pcihp; 756 { 757 758 return; 759 } 760 761 int 762 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp) 763 pcmcia_chipset_handle_t pch; 764 int width; 765 bus_addr_t offset; 766 bus_size_t size; 767 struct pcmcia_io_handle *pcihp; 768 int *windowp; 769 { 770 struct stp4020_socket *h = (struct stp4020_socket *)pch; 771 int i, win, v; 772 773 /* 774 * Allocate a window. 775 */ 776 if (size > STP4020_WINDOW_SIZE) 777 return (1); 778 779 for (win = -1, i = 0; i < STP4020_NWIN; i++) { 780 if ((h->winalloc & (1 << i)) == 0) { 781 win = i; 782 h->winalloc |= (1 << i); 783 break; 784 } 785 } 786 787 if (win == -1) 788 return (1); 789 790 *windowp = win; 791 792 /* 793 * Fill in the Address Space Select and Base Address 794 * fields of this windows control register 0. 795 */ 796 v = stp4020_rd_winctl(h, win, STP4020_WCR0_IDX); 797 v &= (STP4020_WCR0_ASPSEL_M | STP4020_WCR0_BASE_M); 798 v |= STP4020_WCR0_ASPSEL_IO; 799 v |= (STP4020_ADDR2PAGE(pcihp->addr+offset) & STP4020_WCR0_BASE_M); 800 stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v); 801 802 return (0); 803 } 804 805 void 806 stp4020_chip_io_unmap(pch, win) 807 pcmcia_chipset_handle_t pch; 808 int win; 809 { 810 struct stp4020_socket *h = (struct stp4020_socket *)pch; 811 812 #ifdef DIAGNOSTIC 813 if (win < 0 || win > 2) 814 panic("stp4020_chip_io_unmap: window (%d) out of range", win); 815 #endif 816 817 h->winalloc &= ~(1 << win); 818 } 819 820 void 821 stp4020_chip_socket_enable(pch) 822 pcmcia_chipset_handle_t pch; 823 { 824 struct stp4020_socket *h = (struct stp4020_socket *)pch; 825 int i, v, cardtype; 826 827 /* this bit is mostly stolen from pcic_attach_card */ 828 829 /* Power down the socket to reset it, clear the card reset pin */ 830 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX); 831 v &= ~STP4020_ICR1_MSTPWR; 832 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 833 834 /* 835 * wait 300ms until power fails (Tpf). Then, wait 100ms since 836 * we are changing Vcc (Toff). 837 */ 838 stp4020_delay((300 + 100) * 1000); 839 840 /* Power up the socket */ 841 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX); 842 v |= STP4020_ICR1_MSTPWR; 843 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 844 845 /* 846 * wait 100ms until power raise (Tpr) and 20ms to become 847 * stable (Tsu(Vcc)). 848 */ 849 stp4020_delay((100 + 20) * 1000); 850 851 v |= STP4020_ICR1_PCIFOE; 852 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 853 854 /* 855 * hold RESET at least 10us. 856 */ 857 delay(10); 858 859 /* Clear reset flag */ 860 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 861 v &= ~STP4020_ICR0_RESET; 862 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 863 864 /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */ 865 stp4020_delay(20000); 866 867 /* Wait for the chip to finish initializing (5 seconds max) */ 868 for (i = 10000; i > 0; i--) { 869 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX); 870 if ((v & STP4020_ISR0_RDYST) != 0) 871 break; 872 delay(500); 873 } 874 if (i <= 0) { 875 char bits[64]; 876 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 877 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 878 printf("stp4020_chip_socket_enable: not ready: status %s\n", 879 bits); 880 return; 881 } 882 883 /* Set the card type */ 884 cardtype = pcmcia_card_gettype(h->pcmcia); 885 886 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 887 v &= ~STP4020_ICR0_IFTYPE; 888 v |= (cardtype == PCMCIA_IFTYPE_IO) 889 ? STP4020_ICR0_IFTYPE_IO 890 : STP4020_ICR0_IFTYPE_MEM; 891 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 892 893 DPRINTF(("%s: stp4020_chip_socket_enable %02x cardtype %s\n", 894 h->sc->sc_dev.dv_xname, h->sock, 895 ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"))); 896 897 /* 898 * Enable socket I/O interrupts. 899 * We use level SB_INT[0] for I/O interrupts. 900 */ 901 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 902 v &= ~STP4020_ICR0_IOILVL; 903 v |= STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL_SB0; 904 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 905 906 #if 0 907 /* Reinstall all the memory and io mappings */ 908 for (win = 0; win < STP4020_NWIN; win++) 909 if (h->winalloc & (1 << win)) 910 ___chip_mem_map(h, win); 911 912 #endif 913 } 914 915 void 916 stp4020_chip_socket_disable(pch) 917 pcmcia_chipset_handle_t pch; 918 { 919 struct stp4020_socket *h = (struct stp4020_socket *)pch; 920 int v; 921 922 DPRINTF(("stp4020_chip_socket_disable\n")); 923 924 /* 925 * Disable socket I/O interrupts. 926 */ 927 v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX); 928 v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL); 929 stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v); 930 931 /* Power down the socket */ 932 v = stp4020_rd_sockctl(h, STP4020_ICR1_IDX); 933 v &= ~STP4020_ICR1_MSTPWR; 934 stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v); 935 936 /* 937 * wait 300ms until power fails (Tpf). 938 */ 939 stp4020_delay(300 * 1000); 940 } 941 942 void * 943 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg) 944 pcmcia_chipset_handle_t pch; 945 struct pcmcia_function *pf; 946 int ipl; 947 int (*handler) __P((void *)); 948 void *arg; 949 { 950 struct stp4020_socket *h = (struct stp4020_socket *)pch; 951 952 h->intrhandler = handler; 953 h->intrarg = arg; 954 h->ipl = ipl; 955 return (NULL); 956 } 957 958 void 959 stp4020_chip_intr_disestablish(pch, ih) 960 pcmcia_chipset_handle_t pch; 961 void *ih; 962 { 963 struct stp4020_socket *h = (struct stp4020_socket *)pch; 964 965 h->intrhandler = NULL; 966 h->intrarg = NULL; 967 } 968 969 /* 970 * Delay and possibly yield CPU. 971 * XXX - assumes a context 972 */ 973 void 974 stp4020_delay(ms) 975 unsigned int ms; 976 { 977 unsigned int ticks; 978 extern int cold; 979 980 /* Convert to ticks */ 981 ticks = (ms * hz ) / 1000000; 982 983 if (cold || ticks == 0) { 984 delay(ms); 985 return; 986 } 987 988 #ifdef DIAGNOSTIC 989 if (ticks > 60*hz) 990 panic("stp4020: preposterous delay: %u", ticks); 991 #endif 992 tsleep(&ticks, 0, "stp4020_delay", ticks); 993 } 994 995 #ifdef STP4020_DEBUG 996 void 997 stp4020_dump_regs(h) 998 struct stp4020_socket *h; 999 { 1000 char bits[64]; 1001 /* 1002 * Dump control and status registers. 1003 */ 1004 printf("socket[%d] registers:\n", h->sock); 1005 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX), 1006 STP4020_ICR0_BITS, bits, sizeof(bits)); 1007 printf("\tICR0=%s\n", bits); 1008 1009 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX), 1010 STP4020_ICR1_BITS, bits, sizeof(bits)); 1011 printf("\tICR1=%s\n", bits); 1012 1013 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX), 1014 STP4020_ISR0_IOBITS, bits, sizeof(bits)); 1015 printf("\tISR0=%s\n", bits); 1016 1017 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX), 1018 STP4020_ISR1_BITS, bits, sizeof(bits)); 1019 printf("\tISR1=%s\n", bits); 1020 } 1021 #endif /* STP4020_DEBUG */ 1022