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