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