Annotation of sys/dev/ic/i82365.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: i82365.c,v 1.25 2005/11/23 11:39:37 mickey Exp $ */
! 2: /* $NetBSD: i82365.c,v 1.10 1998/06/09 07:36:55 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1997 Marc Horowitz. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Marc Horowitz.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: #include <sys/types.h>
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/device.h>
! 37: #include <sys/extent.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/malloc.h>
! 40: #include <sys/kthread.h>
! 41:
! 42: #include <uvm/uvm_extern.h>
! 43:
! 44: #include <machine/bus.h>
! 45: #include <machine/intr.h>
! 46:
! 47: #include <dev/pcmcia/pcmciareg.h>
! 48: #include <dev/pcmcia/pcmciavar.h>
! 49:
! 50: #include <dev/ic/i82365reg.h>
! 51: #include <dev/ic/i82365var.h>
! 52:
! 53: #ifdef PCICDEBUG
! 54: #define DPRINTF(arg) printf arg;
! 55: #else
! 56: #define DPRINTF(arg)
! 57: #endif
! 58:
! 59: #define PCIC_VENDOR_UNKNOWN 0
! 60: #define PCIC_VENDOR_I82365SLR0 1
! 61: #define PCIC_VENDOR_I82365SLR1 2
! 62: #define PCIC_VENDOR_I82365SLR2 3
! 63: #define PCIC_VENDOR_CIRRUS_PD6710 4
! 64: #define PCIC_VENDOR_CIRRUS_PD672X 5
! 65: #define PCIC_VENDOR_VADEM_VG468 6
! 66: #define PCIC_VENDOR_VADEM_VG469 7
! 67:
! 68: static char *pcic_vendor_to_string[] = {
! 69: "Unknown",
! 70: "Intel 82365SL rev 0",
! 71: "Intel 82365SL rev 1",
! 72: "Intel 82365SL rev 2",
! 73: "Cirrus PD6710",
! 74: "Cirrus PD672X",
! 75: "Vadem VG468",
! 76: "Vadem VG469",
! 77: };
! 78:
! 79: /*
! 80: * Individual drivers will allocate their own memory and io regions. Memory
! 81: * regions must be a multiple of 4k, aligned on a 4k boundary.
! 82: */
! 83:
! 84: #define PCIC_MEM_ALIGN PCIC_MEM_PAGESIZE
! 85:
! 86: void pcic_attach_socket(struct pcic_handle *);
! 87: void pcic_init_socket(struct pcic_handle *);
! 88:
! 89: int pcic_submatch(struct device *, void *, void *);
! 90: int pcic_print(void *arg, const char *pnp);
! 91: int pcic_intr_socket(struct pcic_handle *);
! 92:
! 93: void pcic_attach_card(struct pcic_handle *);
! 94: void pcic_detach_card(struct pcic_handle *, int);
! 95: void pcic_deactivate_card(struct pcic_handle *);
! 96:
! 97: void pcic_chip_do_mem_map(struct pcic_handle *, int);
! 98: void pcic_chip_do_io_map(struct pcic_handle *, int);
! 99:
! 100: void pcic_create_event_thread(void *);
! 101: void pcic_event_thread(void *);
! 102: void pcic_event_process(struct pcic_handle *, struct pcic_event *);
! 103: void pcic_queue_event(struct pcic_handle *, int);
! 104:
! 105: void pcic_wait_ready(struct pcic_handle *);
! 106:
! 107: u_int8_t st_pcic_read(struct pcic_handle *, int);
! 108: void st_pcic_write(struct pcic_handle *, int, int);
! 109:
! 110: struct cfdriver pcic_cd = {
! 111: NULL, "pcic", DV_DULL
! 112: };
! 113:
! 114: int
! 115: pcic_ident_ok(ident)
! 116: int ident;
! 117: {
! 118: /* this is very empirical and heuristic */
! 119:
! 120: if (ident == 0 || ident == 0xff || (ident & PCIC_IDENT_ZERO))
! 121: return (0);
! 122:
! 123: if ((ident & PCIC_IDENT_IFTYPE_MASK) != PCIC_IDENT_IFTYPE_MEM_AND_IO) {
! 124: #ifdef DIAGNOSTIC
! 125: printf("pcic: does not support memory and I/O cards, "
! 126: "ignored (ident=%0x)\n", ident);
! 127: #endif
! 128: return (0);
! 129: }
! 130: return (1);
! 131: }
! 132:
! 133: int
! 134: pcic_vendor(h)
! 135: struct pcic_handle *h;
! 136: {
! 137: int vendor, reg;
! 138:
! 139: /*
! 140: * the chip_id of the cirrus toggles between 11 and 00 after a write.
! 141: * weird.
! 142: */
! 143:
! 144: pcic_write(h, PCIC_CIRRUS_CHIP_INFO, 0);
! 145: reg = pcic_read(h, -1);
! 146:
! 147: if ((reg & PCIC_CIRRUS_CHIP_INFO_CHIP_ID) ==
! 148: PCIC_CIRRUS_CHIP_INFO_CHIP_ID) {
! 149: reg = pcic_read(h, -1);
! 150: if ((reg & PCIC_CIRRUS_CHIP_INFO_CHIP_ID) == 0) {
! 151: if (reg & PCIC_CIRRUS_CHIP_INFO_SLOTS)
! 152: return (PCIC_VENDOR_CIRRUS_PD672X);
! 153: else
! 154: return (PCIC_VENDOR_CIRRUS_PD6710);
! 155: }
! 156: }
! 157:
! 158: reg = pcic_read(h, PCIC_IDENT);
! 159:
! 160: switch (reg) {
! 161: case PCIC_IDENT_REV_I82365SLR0:
! 162: vendor = PCIC_VENDOR_I82365SLR0;
! 163: break;
! 164: case PCIC_IDENT_REV_I82365SLR1:
! 165: vendor = PCIC_VENDOR_I82365SLR1;
! 166: break;
! 167: case PCIC_IDENT_REV_I82365SLR2:
! 168: vendor = PCIC_VENDOR_I82365SLR2;
! 169: break;
! 170: default:
! 171: vendor = PCIC_VENDOR_UNKNOWN;
! 172: break;
! 173: }
! 174:
! 175: pcic_write(h, 0x0e, -1);
! 176: pcic_write(h, 0x37, -1);
! 177:
! 178: reg = pcic_read(h, PCIC_VG468_MISC);
! 179: reg |= PCIC_VG468_MISC_VADEMREV;
! 180: pcic_write(h, PCIC_VG468_MISC, reg);
! 181:
! 182: reg = pcic_read(h, PCIC_IDENT);
! 183:
! 184: if (reg & PCIC_IDENT_VADEM_MASK) {
! 185: if ((reg & 7) >= 4)
! 186: vendor = PCIC_VENDOR_VADEM_VG469;
! 187: else
! 188: vendor = PCIC_VENDOR_VADEM_VG468;
! 189:
! 190: reg = pcic_read(h, PCIC_VG468_MISC);
! 191: reg &= ~PCIC_VG468_MISC_VADEMREV;
! 192: pcic_write(h, PCIC_VG468_MISC, reg);
! 193: }
! 194:
! 195: return (vendor);
! 196: }
! 197:
! 198: void
! 199: pcic_attach(sc)
! 200: struct pcic_softc *sc;
! 201: {
! 202: int vendor, count, i, reg;
! 203:
! 204: /* now check for each controller/socket */
! 205:
! 206: /*
! 207: * this could be done with a loop, but it would violate the
! 208: * abstraction
! 209: */
! 210:
! 211: count = 0;
! 212:
! 213: DPRINTF(("pcic ident regs:"));
! 214:
! 215: sc->handle[0].ph_parent = (struct device *)sc;
! 216: sc->handle[0].sock = C0SA;
! 217: /* initialise pcic_read and pcic_write functions */
! 218: sc->handle[0].ph_read = st_pcic_read;
! 219: sc->handle[0].ph_write = st_pcic_write;
! 220: sc->handle[0].ph_bus_t = sc->iot;
! 221: sc->handle[0].ph_bus_h = sc->ioh;
! 222: if (pcic_ident_ok(reg = pcic_read(&sc->handle[0], PCIC_IDENT))) {
! 223: sc->handle[0].flags = PCIC_FLAG_SOCKETP;
! 224: count++;
! 225: } else {
! 226: sc->handle[0].flags = 0;
! 227: }
! 228: sc->handle[0].laststate = PCIC_LASTSTATE_EMPTY;
! 229:
! 230: DPRINTF((" 0x%02x", reg));
! 231:
! 232: sc->handle[1].ph_parent = (struct device *)sc;
! 233: sc->handle[1].sock = C0SB;
! 234: /* initialise pcic_read and pcic_write functions */
! 235: sc->handle[1].ph_read = st_pcic_read;
! 236: sc->handle[1].ph_write = st_pcic_write;
! 237: sc->handle[1].ph_bus_t = sc->iot;
! 238: sc->handle[1].ph_bus_h = sc->ioh;
! 239: if (pcic_ident_ok(reg = pcic_read(&sc->handle[1], PCIC_IDENT))) {
! 240: sc->handle[1].flags = PCIC_FLAG_SOCKETP;
! 241: count++;
! 242: } else {
! 243: sc->handle[1].flags = 0;
! 244: }
! 245: sc->handle[1].laststate = PCIC_LASTSTATE_EMPTY;
! 246:
! 247: DPRINTF((" 0x%02x", reg));
! 248:
! 249: /*
! 250: * The CL-PD6729 has only one controller and always returns 0
! 251: * if you try to read from the second one. Maybe pcic_ident_ok
! 252: * shouldn't accept 0?
! 253: */
! 254: sc->handle[2].ph_parent = (struct device *)sc;
! 255: sc->handle[2].sock = C1SA;
! 256: /* initialise pcic_read and pcic_write functions */
! 257: sc->handle[2].ph_read = st_pcic_read;
! 258: sc->handle[2].ph_write = st_pcic_write;
! 259: sc->handle[2].ph_bus_t = sc->iot;
! 260: sc->handle[2].ph_bus_h = sc->ioh;
! 261: if (pcic_vendor(&sc->handle[0]) != PCIC_VENDOR_CIRRUS_PD672X ||
! 262: pcic_read(&sc->handle[2], PCIC_IDENT) != 0) {
! 263: if (pcic_ident_ok(reg = pcic_read(&sc->handle[2],
! 264: PCIC_IDENT))) {
! 265: sc->handle[2].flags = PCIC_FLAG_SOCKETP;
! 266: count++;
! 267: } else {
! 268: sc->handle[2].flags = 0;
! 269: }
! 270: sc->handle[2].laststate = PCIC_LASTSTATE_EMPTY;
! 271:
! 272: DPRINTF((" 0x%02x", reg));
! 273:
! 274: sc->handle[3].ph_parent = (struct device *)sc;
! 275: sc->handle[3].sock = C1SB;
! 276: /* initialise pcic_read and pcic_write functions */
! 277: sc->handle[3].ph_read = st_pcic_read;
! 278: sc->handle[3].ph_write = st_pcic_write;
! 279: sc->handle[3].ph_bus_t = sc->iot;
! 280: sc->handle[3].ph_bus_h = sc->ioh;
! 281: if (pcic_ident_ok(reg = pcic_read(&sc->handle[3],
! 282: PCIC_IDENT))) {
! 283: sc->handle[3].flags = PCIC_FLAG_SOCKETP;
! 284: count++;
! 285: } else {
! 286: sc->handle[3].flags = 0;
! 287: }
! 288: sc->handle[3].laststate = PCIC_LASTSTATE_EMPTY;
! 289:
! 290: DPRINTF((" 0x%02x\n", reg));
! 291: } else {
! 292: sc->handle[2].flags = 0;
! 293: sc->handle[3].flags = 0;
! 294: }
! 295:
! 296: if (count == 0)
! 297: return;
! 298:
! 299: /* establish the interrupt */
! 300:
! 301: /* XXX block interrupts? */
! 302:
! 303: for (i = 0; i < PCIC_NSLOTS; i++) {
! 304: /*
! 305: * this should work, but w/o it, setting tty flags hangs at
! 306: * boot time.
! 307: */
! 308: if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
! 309: SIMPLEQ_INIT(&sc->handle[i].events);
! 310: pcic_write(&sc->handle[i], PCIC_CSC_INTR, 0);
! 311: pcic_read(&sc->handle[i], PCIC_CSC);
! 312: }
! 313: }
! 314:
! 315: for (i = 0; i < PCIC_NSLOTS; i += 2) {
! 316: if ((sc->handle[i+0].flags & PCIC_FLAG_SOCKETP) ||
! 317: (sc->handle[i+1].flags & PCIC_FLAG_SOCKETP)) {
! 318: vendor = pcic_vendor(&sc->handle[i]);
! 319:
! 320: printf("%s controller %d: <%s> has socket",
! 321: sc->dev.dv_xname, i/2,
! 322: pcic_vendor_to_string[vendor]);
! 323:
! 324: if ((sc->handle[i+0].flags & PCIC_FLAG_SOCKETP) &&
! 325: (sc->handle[i+1].flags & PCIC_FLAG_SOCKETP))
! 326: printf("s A and B\n");
! 327: else if (sc->handle[i+0].flags & PCIC_FLAG_SOCKETP)
! 328: printf(" A only\n");
! 329: else
! 330: printf(" B only\n");
! 331:
! 332: if (sc->handle[i+0].flags & PCIC_FLAG_SOCKETP)
! 333: sc->handle[i+0].vendor = vendor;
! 334: if (sc->handle[i+1].flags & PCIC_FLAG_SOCKETP)
! 335: sc->handle[i+1].vendor = vendor;
! 336: }
! 337: }
! 338: }
! 339:
! 340: void
! 341: pcic_attach_sockets(sc)
! 342: struct pcic_softc *sc;
! 343: {
! 344: int i;
! 345:
! 346: for (i = 0; i < PCIC_NSLOTS; i++)
! 347: if (sc->handle[i].flags & PCIC_FLAG_SOCKETP)
! 348: pcic_attach_socket(&sc->handle[i]);
! 349: }
! 350:
! 351: void
! 352: pcic_attach_socket(h)
! 353: struct pcic_handle *h;
! 354: {
! 355: struct pcmciabus_attach_args paa;
! 356: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 357:
! 358: /* initialize the rest of the handle */
! 359:
! 360: h->shutdown = 0;
! 361: h->memalloc = 0;
! 362: h->ioalloc = 0;
! 363: h->ih_irq = 0;
! 364:
! 365: /* now, config one pcmcia device per socket */
! 366:
! 367: paa.paa_busname = "pcmcia";
! 368: paa.pct = (pcmcia_chipset_tag_t) sc->pct;
! 369: paa.pch = (pcmcia_chipset_handle_t) h;
! 370: paa.iobase = sc->iobase;
! 371: paa.iosize = sc->iosize;
! 372:
! 373: h->pcmcia = config_found_sm(&sc->dev, &paa, pcic_print,
! 374: pcic_submatch);
! 375:
! 376: /* if there's actually a pcmcia device attached, initialize the slot */
! 377:
! 378: if (h->pcmcia)
! 379: pcic_init_socket(h);
! 380: else
! 381: h->flags &= ~PCIC_FLAG_SOCKETP;
! 382: }
! 383:
! 384: void
! 385: pcic_create_event_thread(arg)
! 386: void *arg;
! 387: {
! 388: struct pcic_handle *h = arg;
! 389: const char *cs;
! 390:
! 391: switch (h->sock) {
! 392: case C0SA:
! 393: cs = "0,0";
! 394: break;
! 395: case C0SB:
! 396: cs = "0,1";
! 397: break;
! 398: case C1SA:
! 399: cs = "1,0";
! 400: break;
! 401: case C1SB:
! 402: cs = "1,1";
! 403: break;
! 404: default:
! 405: panic("pcic_create_event_thread: unknown pcic socket");
! 406: }
! 407:
! 408: if (kthread_create(pcic_event_thread, h, &h->event_thread,
! 409: "%s,%s", h->ph_parent->dv_xname, cs)) {
! 410: printf("%s: unable to create event thread for sock 0x%02x\n",
! 411: h->ph_parent->dv_xname, h->sock);
! 412: panic("pcic_create_event_thread");
! 413: }
! 414: }
! 415:
! 416: void
! 417: pcic_event_thread(arg)
! 418: void *arg;
! 419: {
! 420: struct pcic_handle *h = arg;
! 421: struct pcic_event *pe;
! 422: int s;
! 423: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 424:
! 425: while (h->shutdown == 0) {
! 426: s = splhigh();
! 427: if ((pe = SIMPLEQ_FIRST(&h->events)) == NULL) {
! 428: splx(s);
! 429: (void) tsleep(&h->events, PWAIT, "pcicev", 0);
! 430: continue;
! 431: } else {
! 432: splx(s);
! 433: /* sleep .25s to be enqueued chatterling interrupts */
! 434: (void) tsleep((caddr_t)pcic_event_thread, PWAIT,
! 435: "pcicss", hz/4);
! 436: }
! 437: pcic_event_process(h, pe);
! 438: }
! 439:
! 440: h->event_thread = NULL;
! 441:
! 442: /* In case parent is waiting for us to exit. */
! 443: wakeup(sc);
! 444:
! 445: kthread_exit(0);
! 446: }
! 447:
! 448: void
! 449: pcic_event_process(h, pe)
! 450: struct pcic_handle *h;
! 451: struct pcic_event *pe;
! 452: {
! 453: int s;
! 454:
! 455: s = splhigh();
! 456: SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
! 457: splx(s);
! 458:
! 459: switch (pe->pe_type) {
! 460: case PCIC_EVENT_INSERTION:
! 461: s = splhigh();
! 462: while (1) {
! 463: struct pcic_event *pe1, *pe2;
! 464:
! 465: if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
! 466: break;
! 467: if (pe1->pe_type != PCIC_EVENT_REMOVAL)
! 468: break;
! 469: if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
! 470: break;
! 471: if (pe2->pe_type == PCIC_EVENT_INSERTION) {
! 472: SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
! 473: free(pe1, M_TEMP);
! 474: SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
! 475: free(pe2, M_TEMP);
! 476: }
! 477: }
! 478: splx(s);
! 479:
! 480: DPRINTF(("%s: insertion event\n", h->ph_parent->dv_xname));
! 481: pcic_attach_card(h);
! 482: break;
! 483:
! 484: case PCIC_EVENT_REMOVAL:
! 485: s = splhigh();
! 486: while (1) {
! 487: struct pcic_event *pe1, *pe2;
! 488:
! 489: if ((pe1 = SIMPLEQ_FIRST(&h->events)) == NULL)
! 490: break;
! 491: if (pe1->pe_type != PCIC_EVENT_INSERTION)
! 492: break;
! 493: if ((pe2 = SIMPLEQ_NEXT(pe1, pe_q)) == NULL)
! 494: break;
! 495: if (pe2->pe_type == PCIC_EVENT_REMOVAL) {
! 496: SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
! 497: free(pe1, M_TEMP);
! 498: SIMPLEQ_REMOVE_HEAD(&h->events, pe_q);
! 499: free(pe2, M_TEMP);
! 500: }
! 501: }
! 502: splx(s);
! 503:
! 504: DPRINTF(("%s: removal event\n", h->ph_parent->dv_xname));
! 505: pcic_detach_card(h, DETACH_FORCE);
! 506: break;
! 507:
! 508: default:
! 509: panic("pcic_event_thread: unknown event %d", pe->pe_type);
! 510: }
! 511: free(pe, M_TEMP);
! 512: }
! 513:
! 514: void
! 515: pcic_init_socket(h)
! 516: struct pcic_handle *h;
! 517: {
! 518: int reg;
! 519: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 520:
! 521: /*
! 522: * queue creation of a kernel thread to handle insert/removal events.
! 523: */
! 524: #ifdef DIAGNOSTIC
! 525: if (h->event_thread != NULL)
! 526: panic("pcic_attach_socket: event thread");
! 527: #endif
! 528: kthread_create_deferred(pcic_create_event_thread, h);
! 529:
! 530: /* set up the card to interrupt on card detect */
! 531:
! 532: pcic_write(h, PCIC_CSC_INTR, (sc->irq << PCIC_CSC_INTR_IRQ_SHIFT) |
! 533: PCIC_CSC_INTR_CD_ENABLE);
! 534: pcic_write(h, PCIC_INTR, 0);
! 535: pcic_read(h, PCIC_CSC);
! 536:
! 537: /* unsleep the cirrus controller */
! 538:
! 539: if ((h->vendor == PCIC_VENDOR_CIRRUS_PD6710) ||
! 540: (h->vendor == PCIC_VENDOR_CIRRUS_PD672X)) {
! 541: reg = pcic_read(h, PCIC_CIRRUS_MISC_CTL_2);
! 542: if (reg & PCIC_CIRRUS_MISC_CTL_2_SUSPEND) {
! 543: DPRINTF(("%s: socket %02x was suspended\n",
! 544: h->ph_parent->dv_xname, h->sock));
! 545: reg &= ~PCIC_CIRRUS_MISC_CTL_2_SUSPEND;
! 546: pcic_write(h, PCIC_CIRRUS_MISC_CTL_2, reg);
! 547: }
! 548: }
! 549: /* if there's a card there, then attach it. */
! 550:
! 551: reg = pcic_read(h, PCIC_IF_STATUS);
! 552:
! 553: if ((reg & PCIC_IF_STATUS_CARDDETECT_MASK) ==
! 554: PCIC_IF_STATUS_CARDDETECT_PRESENT) {
! 555: pcic_attach_card(h);
! 556: h->laststate = PCIC_LASTSTATE_PRESENT;
! 557: } else
! 558: h->laststate = PCIC_LASTSTATE_EMPTY;
! 559: }
! 560:
! 561: int
! 562: pcic_submatch(parent, match, aux)
! 563: struct device *parent;
! 564: void *match, *aux;
! 565: {
! 566: struct cfdata *cf = match;
! 567: struct pcmciabus_attach_args *paa = aux;
! 568: struct pcic_handle *h = (struct pcic_handle *) paa->pch;
! 569:
! 570: switch (h->sock) {
! 571: case C0SA:
! 572: if (cf->cf_loc[0 /* PCICCF_CONTROLLER */] !=
! 573: -1 /* PCICCF_CONTROLLER_DEFAULT */ &&
! 574: cf->cf_loc[0 /* PCICCF_CONTROLLER */] != 0)
! 575: return 0;
! 576: if (cf->cf_loc[1 /* PCICCF_SOCKET */] !=
! 577: -1 /* PCICCF_SOCKET_DEFAULT */ &&
! 578: cf->cf_loc[1 /* PCICCF_SOCKET */] != 0)
! 579: return 0;
! 580:
! 581: break;
! 582: case C0SB:
! 583: if (cf->cf_loc[0 /* PCICCF_CONTROLLER */] !=
! 584: -1 /* PCICCF_CONTROLLER_DEFAULT */ &&
! 585: cf->cf_loc[0 /* PCICCF_CONTROLLER */] != 0)
! 586: return 0;
! 587: if (cf->cf_loc[1 /* PCICCF_SOCKET */] !=
! 588: -1 /* PCICCF_SOCKET_DEFAULT */ &&
! 589: cf->cf_loc[1 /* PCICCF_SOCKET */] != 1)
! 590: return 0;
! 591:
! 592: break;
! 593: case C1SA:
! 594: if (cf->cf_loc[0 /* PCICCF_CONTROLLER */] !=
! 595: -1 /* PCICCF_CONTROLLER_DEFAULT */ &&
! 596: cf->cf_loc[0 /* PCICCF_CONTROLLER */] != 1)
! 597: return 0;
! 598: if (cf->cf_loc[1 /* PCICCF_SOCKET */] !=
! 599: -1 /* PCICCF_SOCKET_DEFAULT */ &&
! 600: cf->cf_loc[1 /* PCICCF_SOCKET */] != 0)
! 601: return 0;
! 602:
! 603: break;
! 604: case C1SB:
! 605: if (cf->cf_loc[0 /* PCICCF_CONTROLLER */] !=
! 606: -1 /* PCICCF_CONTROLLER_DEFAULT */ &&
! 607: cf->cf_loc[0 /* PCICCF_CONTROLLER */] != 1)
! 608: return 0;
! 609: if (cf->cf_loc[1 /* PCICCF_SOCKET */] !=
! 610: -1 /* PCICCF_SOCKET_DEFAULT */ &&
! 611: cf->cf_loc[1 /* PCICCF_SOCKET */] != 1)
! 612: return 0;
! 613:
! 614: break;
! 615: default:
! 616: panic("unknown pcic socket");
! 617: }
! 618:
! 619: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
! 620: }
! 621:
! 622: int
! 623: pcic_print(arg, pnp)
! 624: void *arg;
! 625: const char *pnp;
! 626: {
! 627: struct pcmciabus_attach_args *paa = arg;
! 628: struct pcic_handle *h = (struct pcic_handle *) paa->pch;
! 629:
! 630: /* Only "pcmcia"s can attach to "pcic"s... easy. */
! 631: if (pnp)
! 632: printf("pcmcia at %s", pnp);
! 633:
! 634: switch (h->sock) {
! 635: case C0SA:
! 636: printf(" controller 0 socket 0");
! 637: break;
! 638: case C0SB:
! 639: printf(" controller 0 socket 1");
! 640: break;
! 641: case C1SA:
! 642: printf(" controller 1 socket 0");
! 643: break;
! 644: case C1SB:
! 645: printf(" controller 1 socket 1");
! 646: break;
! 647: default:
! 648: panic("unknown pcic socket");
! 649: }
! 650:
! 651: return (UNCONF);
! 652: }
! 653:
! 654: int
! 655: pcic_intr(arg)
! 656: void *arg;
! 657: {
! 658: struct pcic_softc *sc = arg;
! 659: int i, ret = 0;
! 660:
! 661: DPRINTF(("%s: intr\n", sc->dev.dv_xname));
! 662:
! 663: for (i = 0; i < PCIC_NSLOTS; i++)
! 664: if (sc->handle[i].flags & PCIC_FLAG_SOCKETP)
! 665: ret += pcic_intr_socket(&sc->handle[i]);
! 666:
! 667: return (ret ? 1 : 0);
! 668: }
! 669:
! 670: void
! 671: pcic_poll_intr(arg)
! 672: void *arg;
! 673: {
! 674: struct pcic_softc *sc = arg;
! 675: int i, s;
! 676:
! 677: /*
! 678: * Since we're polling, we aren't in interrupt context, so block any
! 679: * actual interrupts coming from the pcic.
! 680: */
! 681: s = spltty();
! 682:
! 683: for (i = 0; i < PCIC_NSLOTS; i++)
! 684: if (sc->handle[i].flags & PCIC_FLAG_SOCKETP)
! 685: pcic_intr_socket(&sc->handle[i]);
! 686:
! 687: timeout_add(&sc->poll_timeout, hz / 2);
! 688:
! 689: splx(s);
! 690: }
! 691:
! 692: int
! 693: pcic_intr_socket(h)
! 694: struct pcic_handle *h;
! 695: {
! 696: int cscreg;
! 697:
! 698: cscreg = pcic_read(h, PCIC_CSC);
! 699:
! 700: cscreg &= (PCIC_CSC_GPI |
! 701: PCIC_CSC_CD |
! 702: PCIC_CSC_READY |
! 703: PCIC_CSC_BATTWARN |
! 704: PCIC_CSC_BATTDEAD);
! 705:
! 706: if (cscreg & PCIC_CSC_GPI) {
! 707: DPRINTF(("%s: %02x GPI\n", h->ph_parent->dv_xname, h->sock));
! 708: }
! 709: if (cscreg & PCIC_CSC_CD) {
! 710: int statreg;
! 711:
! 712: statreg = pcic_read(h, PCIC_IF_STATUS);
! 713:
! 714: DPRINTF(("%s: %02x CD %x\n", h->ph_parent->dv_xname, h->sock,
! 715: statreg));
! 716:
! 717: if ((statreg & PCIC_IF_STATUS_CARDDETECT_MASK) ==
! 718: PCIC_IF_STATUS_CARDDETECT_PRESENT) {
! 719: if (h->laststate != PCIC_LASTSTATE_PRESENT) {
! 720: DPRINTF(("%s: enqueing INSERTION event\n",
! 721: h->ph_parent->dv_xname));
! 722: pcic_queue_event(h, PCIC_EVENT_INSERTION);
! 723: }
! 724: h->laststate = PCIC_LASTSTATE_PRESENT;
! 725: } else {
! 726: if (h->laststate == PCIC_LASTSTATE_PRESENT) {
! 727: /* Deactivate the card now. */
! 728: DPRINTF(("%s: deactivating card\n",
! 729: h->ph_parent->dv_xname));
! 730: pcic_deactivate_card(h);
! 731:
! 732: DPRINTF(("%s: enqueing REMOVAL event\n",
! 733: h->ph_parent->dv_xname));
! 734: pcic_queue_event(h, PCIC_EVENT_REMOVAL);
! 735: }
! 736: h->laststate =
! 737: ((statreg & PCIC_IF_STATUS_CARDDETECT_MASK) == 0)
! 738: ? PCIC_LASTSTATE_EMPTY : PCIC_LASTSTATE_HALF;
! 739: }
! 740: }
! 741: if (cscreg & PCIC_CSC_READY) {
! 742: DPRINTF(("%s: %02x READY\n", h->ph_parent->dv_xname, h->sock));
! 743: /* shouldn't happen */
! 744: }
! 745: if (cscreg & PCIC_CSC_BATTWARN) {
! 746: DPRINTF(("%s: %02x BATTWARN\n", h->ph_parent->dv_xname,
! 747: h->sock));
! 748: }
! 749: if (cscreg & PCIC_CSC_BATTDEAD) {
! 750: DPRINTF(("%s: %02x BATTDEAD\n", h->ph_parent->dv_xname,
! 751: h->sock));
! 752: }
! 753: return (cscreg ? 1 : 0);
! 754: }
! 755:
! 756: void
! 757: pcic_queue_event(h, event)
! 758: struct pcic_handle *h;
! 759: int event;
! 760: {
! 761: struct pcic_event *pe;
! 762: int s;
! 763:
! 764: pe = malloc(sizeof(*pe), M_TEMP, M_NOWAIT);
! 765: if (pe == NULL)
! 766: panic("pcic_queue_event: can't allocate event");
! 767:
! 768: pe->pe_type = event;
! 769: s = splhigh();
! 770: SIMPLEQ_INSERT_TAIL(&h->events, pe, pe_q);
! 771: splx(s);
! 772: wakeup(&h->events);
! 773: }
! 774:
! 775: void
! 776: pcic_attach_card(h)
! 777: struct pcic_handle *h;
! 778: {
! 779: if (h->flags & PCIC_FLAG_CARDP)
! 780: panic("pcic_attach_card: already attached");
! 781:
! 782: /* call the MI attach function */
! 783: pcmcia_card_attach(h->pcmcia);
! 784:
! 785: h->flags |= PCIC_FLAG_CARDP;
! 786: }
! 787:
! 788: void
! 789: pcic_detach_card(h, flags)
! 790: struct pcic_handle *h;
! 791: int flags; /* DETACH_* */
! 792: {
! 793:
! 794: if (h->flags & PCIC_FLAG_CARDP) {
! 795: h->flags &= ~PCIC_FLAG_CARDP;
! 796:
! 797: /* call the MI detach function */
! 798: pcmcia_card_detach(h->pcmcia, flags);
! 799: } else {
! 800: DPRINTF(("pcic_detach_card: already detached"));
! 801: }
! 802: }
! 803:
! 804: void
! 805: pcic_deactivate_card(h)
! 806: struct pcic_handle *h;
! 807: {
! 808: struct device *dev = (struct device *)h->pcmcia;
! 809:
! 810: /*
! 811: * At suspend, apm deactivates any connected cards. If we've woken up
! 812: * to find a previously-connected device missing, and we're detaching
! 813: * it, we don't want to deactivate it again.
! 814: */
! 815: if (dev->dv_flags & DVF_ACTIVE)
! 816: pcmcia_card_deactivate(h->pcmcia);
! 817:
! 818: /* power down the socket */
! 819: pcic_write(h, PCIC_PWRCTL, 0);
! 820:
! 821: /* reset the socket */
! 822: pcic_write(h, PCIC_INTR, 0);
! 823: }
! 824:
! 825: /*
! 826: * The pcic_power() function must execute BEFORE the pcmcia_power() hooks.
! 827: * During suspend, a card may have been ejected. If so, we must detach it
! 828: * completely before pcmcia_power() tries to activate it. Attempting to
! 829: * activate a card that isn't there is bad news.
! 830: */
! 831: void
! 832: pcic_power(why, arg)
! 833: int why;
! 834: void *arg;
! 835: {
! 836: struct pcic_handle *h = (struct pcic_handle *)arg;
! 837: struct pcic_softc *sc = (struct pcic_softc *)h->ph_parent;
! 838: struct pcic_event *pe;
! 839:
! 840: if (why != PWR_RESUME) {
! 841: if (timeout_pending(&sc->poll_timeout))
! 842: timeout_del(&sc->poll_timeout);
! 843: }
! 844: else {
! 845: pcic_intr_socket(h);
! 846:
! 847: while ((pe = SIMPLEQ_FIRST(&h->events)))
! 848: pcic_event_process(h, pe);
! 849:
! 850: timeout_add(&sc->poll_timeout, hz / 2);
! 851: }
! 852: }
! 853:
! 854: int
! 855: pcic_chip_mem_alloc(pch, size, pcmhp)
! 856: pcmcia_chipset_handle_t pch;
! 857: bus_size_t size;
! 858: struct pcmcia_mem_handle *pcmhp;
! 859: {
! 860: struct pcic_handle *h = (struct pcic_handle *) pch;
! 861: bus_space_handle_t memh;
! 862: bus_addr_t addr;
! 863: bus_size_t sizepg;
! 864: int i, mask, mhandle;
! 865: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 866:
! 867: /* out of sc->memh, allocate as many pages as necessary */
! 868:
! 869: /* convert size to PCIC pages */
! 870: sizepg = (size + (PCIC_MEM_ALIGN - 1)) / PCIC_MEM_ALIGN;
! 871: if (sizepg > PCIC_MAX_MEM_PAGES)
! 872: return (1);
! 873:
! 874: mask = (1 << sizepg) - 1;
! 875:
! 876: addr = 0; /* XXX gcc -Wuninitialized */
! 877: mhandle = 0; /* XXX gcc -Wuninitialized */
! 878:
! 879: for (i = 0; i <= PCIC_MAX_MEM_PAGES - sizepg; i++) {
! 880: if ((sc->subregionmask & (mask << i)) == (mask << i)) {
! 881: if (bus_space_subregion(sc->memt, sc->memh,
! 882: i * PCIC_MEM_PAGESIZE,
! 883: sizepg * PCIC_MEM_PAGESIZE, &memh))
! 884: return (1);
! 885: mhandle = mask << i;
! 886: addr = sc->membase + (i * PCIC_MEM_PAGESIZE);
! 887: sc->subregionmask &= ~(mhandle);
! 888: pcmhp->memt = sc->memt;
! 889: pcmhp->memh = memh;
! 890: pcmhp->addr = addr;
! 891: pcmhp->size = size;
! 892: pcmhp->mhandle = mhandle;
! 893: pcmhp->realsize = sizepg * PCIC_MEM_PAGESIZE;
! 894:
! 895: DPRINTF(("pcic_chip_mem_alloc bus addr 0x%lx+0x%lx\n",
! 896: (u_long) addr, (u_long) size));
! 897:
! 898: return (0);
! 899: }
! 900: }
! 901:
! 902: return (1);
! 903: }
! 904:
! 905: void
! 906: pcic_chip_mem_free(pch, pcmhp)
! 907: pcmcia_chipset_handle_t pch;
! 908: struct pcmcia_mem_handle *pcmhp;
! 909: {
! 910: struct pcic_handle *h = (struct pcic_handle *) pch;
! 911: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 912:
! 913: sc->subregionmask |= pcmhp->mhandle;
! 914: }
! 915:
! 916: static struct mem_map_index_st {
! 917: int sysmem_start_lsb;
! 918: int sysmem_start_msb;
! 919: int sysmem_stop_lsb;
! 920: int sysmem_stop_msb;
! 921: int cardmem_lsb;
! 922: int cardmem_msb;
! 923: int memenable;
! 924: } mem_map_index[] = {
! 925: {
! 926: PCIC_SYSMEM_ADDR0_START_LSB,
! 927: PCIC_SYSMEM_ADDR0_START_MSB,
! 928: PCIC_SYSMEM_ADDR0_STOP_LSB,
! 929: PCIC_SYSMEM_ADDR0_STOP_MSB,
! 930: PCIC_CARDMEM_ADDR0_LSB,
! 931: PCIC_CARDMEM_ADDR0_MSB,
! 932: PCIC_ADDRWIN_ENABLE_MEM0,
! 933: },
! 934: {
! 935: PCIC_SYSMEM_ADDR1_START_LSB,
! 936: PCIC_SYSMEM_ADDR1_START_MSB,
! 937: PCIC_SYSMEM_ADDR1_STOP_LSB,
! 938: PCIC_SYSMEM_ADDR1_STOP_MSB,
! 939: PCIC_CARDMEM_ADDR1_LSB,
! 940: PCIC_CARDMEM_ADDR1_MSB,
! 941: PCIC_ADDRWIN_ENABLE_MEM1,
! 942: },
! 943: {
! 944: PCIC_SYSMEM_ADDR2_START_LSB,
! 945: PCIC_SYSMEM_ADDR2_START_MSB,
! 946: PCIC_SYSMEM_ADDR2_STOP_LSB,
! 947: PCIC_SYSMEM_ADDR2_STOP_MSB,
! 948: PCIC_CARDMEM_ADDR2_LSB,
! 949: PCIC_CARDMEM_ADDR2_MSB,
! 950: PCIC_ADDRWIN_ENABLE_MEM2,
! 951: },
! 952: {
! 953: PCIC_SYSMEM_ADDR3_START_LSB,
! 954: PCIC_SYSMEM_ADDR3_START_MSB,
! 955: PCIC_SYSMEM_ADDR3_STOP_LSB,
! 956: PCIC_SYSMEM_ADDR3_STOP_MSB,
! 957: PCIC_CARDMEM_ADDR3_LSB,
! 958: PCIC_CARDMEM_ADDR3_MSB,
! 959: PCIC_ADDRWIN_ENABLE_MEM3,
! 960: },
! 961: {
! 962: PCIC_SYSMEM_ADDR4_START_LSB,
! 963: PCIC_SYSMEM_ADDR4_START_MSB,
! 964: PCIC_SYSMEM_ADDR4_STOP_LSB,
! 965: PCIC_SYSMEM_ADDR4_STOP_MSB,
! 966: PCIC_CARDMEM_ADDR4_LSB,
! 967: PCIC_CARDMEM_ADDR4_MSB,
! 968: PCIC_ADDRWIN_ENABLE_MEM4,
! 969: },
! 970: };
! 971:
! 972: void
! 973: pcic_chip_do_mem_map(h, win)
! 974: struct pcic_handle *h;
! 975: int win;
! 976: {
! 977: int reg;
! 978: int kind = h->mem[win].kind & ~PCMCIA_WIDTH_MEM_MASK;
! 979: int mem8 =
! 980: (h->mem[win].kind & PCMCIA_WIDTH_MEM_MASK) == PCMCIA_WIDTH_MEM8
! 981: || (kind == PCMCIA_MEM_ATTR);
! 982:
! 983: pcic_write(h, mem_map_index[win].sysmem_start_lsb,
! 984: (h->mem[win].addr >> PCIC_SYSMEM_ADDRX_SHIFT) & 0xff);
! 985: pcic_write(h, mem_map_index[win].sysmem_start_msb,
! 986: ((h->mem[win].addr >> (PCIC_SYSMEM_ADDRX_SHIFT + 8)) &
! 987: PCIC_SYSMEM_ADDRX_START_MSB_ADDR_MASK) |
! 988: (mem8 ? 0 : PCIC_SYSMEM_ADDRX_START_MSB_DATASIZE_16BIT));
! 989:
! 990: pcic_write(h, mem_map_index[win].sysmem_stop_lsb,
! 991: ((h->mem[win].addr + h->mem[win].size) >>
! 992: PCIC_SYSMEM_ADDRX_SHIFT) & 0xff);
! 993: pcic_write(h, mem_map_index[win].sysmem_stop_msb,
! 994: (((h->mem[win].addr + h->mem[win].size) >>
! 995: (PCIC_SYSMEM_ADDRX_SHIFT + 8)) &
! 996: PCIC_SYSMEM_ADDRX_STOP_MSB_ADDR_MASK) |
! 997: PCIC_SYSMEM_ADDRX_STOP_MSB_WAIT2);
! 998:
! 999: pcic_write(h, mem_map_index[win].cardmem_lsb,
! 1000: (h->mem[win].offset >> PCIC_CARDMEM_ADDRX_SHIFT) & 0xff);
! 1001: pcic_write(h, mem_map_index[win].cardmem_msb,
! 1002: ((h->mem[win].offset >> (PCIC_CARDMEM_ADDRX_SHIFT + 8)) &
! 1003: PCIC_CARDMEM_ADDRX_MSB_ADDR_MASK) |
! 1004: ((kind == PCMCIA_MEM_ATTR) ?
! 1005: PCIC_CARDMEM_ADDRX_MSB_REGACTIVE_ATTR : 0));
! 1006:
! 1007: reg = pcic_read(h, PCIC_ADDRWIN_ENABLE);
! 1008: reg |= (mem_map_index[win].memenable | PCIC_ADDRWIN_ENABLE_MEMCS16);
! 1009: pcic_write(h, PCIC_ADDRWIN_ENABLE, reg);
! 1010:
! 1011: #ifdef PCICDEBUG
! 1012: {
! 1013: int r1, r2, r3, r4, r5, r6;
! 1014:
! 1015: r1 = pcic_read(h, mem_map_index[win].sysmem_start_msb);
! 1016: r2 = pcic_read(h, mem_map_index[win].sysmem_start_lsb);
! 1017: r3 = pcic_read(h, mem_map_index[win].sysmem_stop_msb);
! 1018: r4 = pcic_read(h, mem_map_index[win].sysmem_stop_lsb);
! 1019: r5 = pcic_read(h, mem_map_index[win].cardmem_msb);
! 1020: r6 = pcic_read(h, mem_map_index[win].cardmem_lsb);
! 1021:
! 1022: DPRINTF(("pcic_chip_do_mem_map window %d: %02x%02x %02x%02x "
! 1023: "%02x%02x\n", win, r1, r2, r3, r4, r5, r6));
! 1024: }
! 1025: #endif
! 1026: }
! 1027:
! 1028: int
! 1029: pcic_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
! 1030: pcmcia_chipset_handle_t pch;
! 1031: int kind;
! 1032: bus_addr_t card_addr;
! 1033: bus_size_t size;
! 1034: struct pcmcia_mem_handle *pcmhp;
! 1035: bus_size_t *offsetp;
! 1036: int *windowp;
! 1037: {
! 1038: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1039: bus_addr_t busaddr;
! 1040: long card_offset;
! 1041: int i, win;
! 1042: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 1043:
! 1044: win = -1;
! 1045: for (i = 0; i < (sizeof(mem_map_index) / sizeof(mem_map_index[0]));
! 1046: i++) {
! 1047: if ((h->memalloc & (1 << i)) == 0) {
! 1048: win = i;
! 1049: h->memalloc |= (1 << i);
! 1050: break;
! 1051: }
! 1052: }
! 1053:
! 1054: if (win == -1)
! 1055: return (1);
! 1056:
! 1057: *windowp = win;
! 1058:
! 1059: /* XXX this is pretty gross */
! 1060:
! 1061: if (sc->memt != pcmhp->memt)
! 1062: panic("pcic_chip_mem_map memt is bogus");
! 1063:
! 1064: busaddr = pcmhp->addr;
! 1065:
! 1066: /*
! 1067: * Compute the address offset to the pcmcia address space for the
! 1068: * pcic. This is intentionally signed. The masks and shifts below
! 1069: * will cause TRT to happen in the pcic registers. Deal with making
! 1070: * sure the address is aligned, and return the alignment offset.
! 1071: */
! 1072:
! 1073: *offsetp = card_addr % PCIC_MEM_ALIGN;
! 1074: card_addr -= *offsetp;
! 1075:
! 1076: DPRINTF(("pcic_chip_mem_map window %d bus %lx+%lx+%lx at card addr "
! 1077: "%lx\n", win, (u_long) busaddr, (u_long) * offsetp, (u_long) size,
! 1078: (u_long) card_addr));
! 1079:
! 1080: /*
! 1081: * include the offset in the size, and decrement size by one, since
! 1082: * the hw wants start/stop
! 1083: */
! 1084: size += *offsetp - 1;
! 1085:
! 1086: card_offset = (((long) card_addr) - ((long) busaddr));
! 1087:
! 1088: h->mem[win].addr = busaddr;
! 1089: h->mem[win].size = size;
! 1090: h->mem[win].offset = card_offset;
! 1091: h->mem[win].kind = kind;
! 1092:
! 1093: pcic_chip_do_mem_map(h, win);
! 1094:
! 1095: return (0);
! 1096: }
! 1097:
! 1098: void
! 1099: pcic_chip_mem_unmap(pch, window)
! 1100: pcmcia_chipset_handle_t pch;
! 1101: int window;
! 1102: {
! 1103: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1104: int reg;
! 1105:
! 1106: if (window >= (sizeof(mem_map_index) / sizeof(mem_map_index[0])))
! 1107: panic("pcic_chip_mem_unmap: window out of range");
! 1108:
! 1109: reg = pcic_read(h, PCIC_ADDRWIN_ENABLE);
! 1110: reg &= ~mem_map_index[window].memenable;
! 1111: pcic_write(h, PCIC_ADDRWIN_ENABLE, reg);
! 1112:
! 1113: h->memalloc &= ~(1 << window);
! 1114: }
! 1115:
! 1116: int
! 1117: pcic_chip_io_alloc(pch, start, size, align, pcihp)
! 1118: pcmcia_chipset_handle_t pch;
! 1119: bus_addr_t start;
! 1120: bus_size_t size;
! 1121: bus_size_t align;
! 1122: struct pcmcia_io_handle *pcihp;
! 1123: {
! 1124: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1125: bus_space_tag_t iot;
! 1126: bus_space_handle_t ioh;
! 1127: bus_addr_t ioaddr, beg, fin;
! 1128: int flags = 0;
! 1129: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 1130: struct pcic_ranges *range;
! 1131:
! 1132: /*
! 1133: * Allocate some arbitrary I/O space.
! 1134: */
! 1135:
! 1136: iot = sc->iot;
! 1137:
! 1138: if (start) {
! 1139: ioaddr = start;
! 1140: if (bus_space_map(iot, start, size, 0, &ioh))
! 1141: return (1);
! 1142: DPRINTF(("pcic_chip_io_alloc map port %lx+%lx\n",
! 1143: (u_long)ioaddr, (u_long)size));
! 1144: } else if (sc->ranges) {
! 1145: flags |= PCMCIA_IO_ALLOCATED;
! 1146:
! 1147: /*
! 1148: * In this case, we know the "size" and "align" that
! 1149: * we want. So we need to start walking down
! 1150: * sc->ranges, searching for a similar space that
! 1151: * is (1) large enough for the size and alignment
! 1152: * (2) then we need to try to allocate
! 1153: * (3) if it fails to allocate, we try next range.
! 1154: *
! 1155: * We must also check that the start/size of each
! 1156: * allocation we are about to do is within the bounds
! 1157: * of "sc->iobase" and "sc->iosize".
! 1158: * (Some pcmcia controllers handle a 12 bits of addressing,
! 1159: * but we want to use the same range structure)
! 1160: */
! 1161: for (range = sc->ranges; range->start; range++) {
! 1162: /* Potentially trim the range because of bounds. */
! 1163: beg = max(range->start, sc->iobase);
! 1164: fin = min(range->start + range->len,
! 1165: sc->iobase + sc->iosize);
! 1166:
! 1167: /* Short-circuit easy cases. */
! 1168: if (fin < beg || fin - beg < size)
! 1169: continue;
! 1170:
! 1171: /*
! 1172: * This call magically fulfills our alignment
! 1173: * requirements.
! 1174: */
! 1175: DPRINTF(("pcic_chip_io_alloc beg-fin %lx-%lx\n",
! 1176: (u_long)beg, (u_long)fin));
! 1177: if (bus_space_alloc(iot, beg, fin, size, align, 0, 0,
! 1178: &ioaddr, &ioh) == 0)
! 1179: break;
! 1180: }
! 1181: if (range->start == 0)
! 1182: return (1);
! 1183: DPRINTF(("pcic_chip_io_alloc alloc port %lx+%lx\n",
! 1184: (u_long)ioaddr, (u_long)size));
! 1185:
! 1186: } else {
! 1187: flags |= PCMCIA_IO_ALLOCATED;
! 1188: if (bus_space_alloc(iot, sc->iobase,
! 1189: sc->iobase + sc->iosize, size, align, 0, 0,
! 1190: &ioaddr, &ioh))
! 1191: return (1);
! 1192: DPRINTF(("pcic_chip_io_alloc alloc port %lx+%lx\n",
! 1193: (u_long)ioaddr, (u_long)size));
! 1194: }
! 1195:
! 1196: pcihp->iot = iot;
! 1197: pcihp->ioh = ioh;
! 1198: pcihp->addr = ioaddr;
! 1199: pcihp->size = size;
! 1200: pcihp->flags = flags;
! 1201:
! 1202: return (0);
! 1203: }
! 1204:
! 1205: void
! 1206: pcic_chip_io_free(pch, pcihp)
! 1207: pcmcia_chipset_handle_t pch;
! 1208: struct pcmcia_io_handle *pcihp;
! 1209: {
! 1210: bus_space_tag_t iot = pcihp->iot;
! 1211: bus_space_handle_t ioh = pcihp->ioh;
! 1212: bus_size_t size = pcihp->size;
! 1213:
! 1214: if (pcihp->flags & PCMCIA_IO_ALLOCATED)
! 1215: bus_space_free(iot, ioh, size);
! 1216: else
! 1217: bus_space_unmap(iot, ioh, size);
! 1218: }
! 1219:
! 1220:
! 1221: static struct io_map_index_st {
! 1222: int start_lsb;
! 1223: int start_msb;
! 1224: int stop_lsb;
! 1225: int stop_msb;
! 1226: int ioenable;
! 1227: int ioctlmask;
! 1228: int ioctlbits[3]; /* indexed by PCMCIA_WIDTH_* */
! 1229: } io_map_index[] = {
! 1230: {
! 1231: PCIC_IOADDR0_START_LSB,
! 1232: PCIC_IOADDR0_START_MSB,
! 1233: PCIC_IOADDR0_STOP_LSB,
! 1234: PCIC_IOADDR0_STOP_MSB,
! 1235: PCIC_ADDRWIN_ENABLE_IO0,
! 1236: PCIC_IOCTL_IO0_WAITSTATE | PCIC_IOCTL_IO0_ZEROWAIT |
! 1237: PCIC_IOCTL_IO0_IOCS16SRC_MASK | PCIC_IOCTL_IO0_DATASIZE_MASK,
! 1238: {
! 1239: PCIC_IOCTL_IO0_IOCS16SRC_CARD,
! 1240: PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE |
! 1241: PCIC_IOCTL_IO0_DATASIZE_8BIT,
! 1242: PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE |
! 1243: PCIC_IOCTL_IO0_DATASIZE_16BIT,
! 1244: },
! 1245: },
! 1246: {
! 1247: PCIC_IOADDR1_START_LSB,
! 1248: PCIC_IOADDR1_START_MSB,
! 1249: PCIC_IOADDR1_STOP_LSB,
! 1250: PCIC_IOADDR1_STOP_MSB,
! 1251: PCIC_ADDRWIN_ENABLE_IO1,
! 1252: PCIC_IOCTL_IO1_WAITSTATE | PCIC_IOCTL_IO1_ZEROWAIT |
! 1253: PCIC_IOCTL_IO1_IOCS16SRC_MASK | PCIC_IOCTL_IO1_DATASIZE_MASK,
! 1254: {
! 1255: PCIC_IOCTL_IO1_IOCS16SRC_CARD,
! 1256: PCIC_IOCTL_IO1_IOCS16SRC_DATASIZE |
! 1257: PCIC_IOCTL_IO1_DATASIZE_8BIT,
! 1258: PCIC_IOCTL_IO1_IOCS16SRC_DATASIZE |
! 1259: PCIC_IOCTL_IO1_DATASIZE_16BIT,
! 1260: },
! 1261: },
! 1262: };
! 1263:
! 1264: void
! 1265: pcic_chip_do_io_map(h, win)
! 1266: struct pcic_handle *h;
! 1267: int win;
! 1268: {
! 1269: int reg;
! 1270:
! 1271: DPRINTF(("pcic_chip_do_io_map win %d addr %lx size %lx width %d\n",
! 1272: win, (long) h->io[win].addr, (long) h->io[win].size,
! 1273: h->io[win].width * 8));
! 1274:
! 1275: pcic_write(h, io_map_index[win].start_lsb, h->io[win].addr & 0xff);
! 1276: pcic_write(h, io_map_index[win].start_msb,
! 1277: (h->io[win].addr >> 8) & 0xff);
! 1278:
! 1279: pcic_write(h, io_map_index[win].stop_lsb,
! 1280: (h->io[win].addr + h->io[win].size - 1) & 0xff);
! 1281: pcic_write(h, io_map_index[win].stop_msb,
! 1282: ((h->io[win].addr + h->io[win].size - 1) >> 8) & 0xff);
! 1283:
! 1284: reg = pcic_read(h, PCIC_IOCTL);
! 1285: reg &= ~io_map_index[win].ioctlmask;
! 1286: reg |= io_map_index[win].ioctlbits[h->io[win].width];
! 1287: pcic_write(h, PCIC_IOCTL, reg);
! 1288:
! 1289: reg = pcic_read(h, PCIC_ADDRWIN_ENABLE);
! 1290: reg |= io_map_index[win].ioenable;
! 1291: pcic_write(h, PCIC_ADDRWIN_ENABLE, reg);
! 1292: }
! 1293:
! 1294: int
! 1295: pcic_chip_io_map(pch, width, offset, size, pcihp, windowp)
! 1296: pcmcia_chipset_handle_t pch;
! 1297: int width;
! 1298: bus_addr_t offset;
! 1299: bus_size_t size;
! 1300: struct pcmcia_io_handle *pcihp;
! 1301: int *windowp;
! 1302: {
! 1303: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1304: bus_addr_t ioaddr = pcihp->addr + offset;
! 1305: int i, win;
! 1306: #ifdef PCICDEBUG
! 1307: static char *width_names[] = { "auto", "io8", "io16" };
! 1308: #endif
! 1309: struct pcic_softc *sc = (struct pcic_softc *)(h->ph_parent);
! 1310:
! 1311: /* XXX Sanity check offset/size. */
! 1312:
! 1313: win = -1;
! 1314: for (i = 0; i < (sizeof(io_map_index) / sizeof(io_map_index[0])); i++) {
! 1315: if ((h->ioalloc & (1 << i)) == 0) {
! 1316: win = i;
! 1317: h->ioalloc |= (1 << i);
! 1318: break;
! 1319: }
! 1320: }
! 1321:
! 1322: if (win == -1)
! 1323: return (1);
! 1324:
! 1325: *windowp = win;
! 1326:
! 1327: /* XXX this is pretty gross */
! 1328:
! 1329: if (sc->iot != pcihp->iot)
! 1330: panic("pcic_chip_io_map iot is bogus");
! 1331:
! 1332: DPRINTF(("pcic_chip_io_map window %d %s port %lx+%lx\n",
! 1333: win, width_names[width], (u_long) ioaddr, (u_long) size));
! 1334:
! 1335: h->io[win].addr = ioaddr;
! 1336: h->io[win].size = size;
! 1337: h->io[win].width = width;
! 1338:
! 1339: pcic_chip_do_io_map(h, win);
! 1340:
! 1341: return (0);
! 1342: }
! 1343:
! 1344: void
! 1345: pcic_chip_io_unmap(pch, window)
! 1346: pcmcia_chipset_handle_t pch;
! 1347: int window;
! 1348: {
! 1349: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1350: int reg;
! 1351:
! 1352: if (window >= (sizeof(io_map_index) / sizeof(io_map_index[0])))
! 1353: panic("pcic_chip_io_unmap: window out of range");
! 1354:
! 1355: reg = pcic_read(h, PCIC_ADDRWIN_ENABLE);
! 1356: reg &= ~io_map_index[window].ioenable;
! 1357: pcic_write(h, PCIC_ADDRWIN_ENABLE, reg);
! 1358:
! 1359: h->ioalloc &= ~(1 << window);
! 1360: }
! 1361:
! 1362: void
! 1363: pcic_wait_ready(h)
! 1364: struct pcic_handle *h;
! 1365: {
! 1366: int i;
! 1367:
! 1368: for (i = 0; i < 10000; i++) {
! 1369: if (pcic_read(h, PCIC_IF_STATUS) & PCIC_IF_STATUS_READY)
! 1370: return;
! 1371: delay(500);
! 1372: #ifdef PCICDEBUG
! 1373: if ((i>5000) && (i%100 == 99))
! 1374: printf(".");
! 1375: #endif
! 1376: }
! 1377:
! 1378: #ifdef DIAGNOSTIC
! 1379: printf("pcic_wait_ready: ready never happened, status = %02x\n",
! 1380: pcic_read(h, PCIC_IF_STATUS));
! 1381: #endif
! 1382: }
! 1383:
! 1384: void
! 1385: pcic_chip_socket_enable(pch)
! 1386: pcmcia_chipset_handle_t pch;
! 1387: {
! 1388: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1389: int cardtype, reg, win;
! 1390:
! 1391: /* this bit is mostly stolen from pcic_attach_card */
! 1392:
! 1393: /* power down the socket to reset it, clear the card reset pin */
! 1394:
! 1395: pcic_write(h, PCIC_PWRCTL, 0);
! 1396:
! 1397: /*
! 1398: * wait 300ms until power fails (Tpf). Then, wait 100ms since
! 1399: * we are changing Vcc (Toff).
! 1400: */
! 1401: delay((300 + 100) * 1000);
! 1402:
! 1403: if (h->vendor == PCIC_VENDOR_VADEM_VG469) {
! 1404: reg = pcic_read(h, PCIC_VG469_VSELECT);
! 1405: reg &= ~PCIC_VG469_VSELECT_VCC;
! 1406: pcic_write(h, PCIC_VG469_VSELECT, reg);
! 1407: }
! 1408:
! 1409: /* power up the socket */
! 1410:
! 1411: pcic_write(h, PCIC_PWRCTL, PCIC_PWRCTL_DISABLE_RESETDRV
! 1412: | PCIC_PWRCTL_PWR_ENABLE);
! 1413:
! 1414: /*
! 1415: * wait 100ms until power raise (Tpr) and 20ms to become
! 1416: * stable (Tsu(Vcc)).
! 1417: *
! 1418: * some machines require some more time to be settled
! 1419: * (another 200ms is added here).
! 1420: */
! 1421: delay((100 + 20 + 200) * 1000);
! 1422:
! 1423: pcic_write(h, PCIC_PWRCTL, PCIC_PWRCTL_DISABLE_RESETDRV |
! 1424: PCIC_PWRCTL_OE | PCIC_PWRCTL_PWR_ENABLE);
! 1425: pcic_write(h, PCIC_INTR, 0);
! 1426:
! 1427: /*
! 1428: * hold RESET at least 10us.
! 1429: */
! 1430: delay(10);
! 1431:
! 1432: /* clear the reset flag */
! 1433:
! 1434: pcic_write(h, PCIC_INTR, PCIC_INTR_RESET);
! 1435:
! 1436: /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
! 1437:
! 1438: delay(20000);
! 1439:
! 1440: /* wait for the chip to finish initializing */
! 1441:
! 1442: #ifdef DIAGNOSTIC
! 1443: reg = pcic_read(h, PCIC_IF_STATUS);
! 1444: if (!(reg & PCIC_IF_STATUS_POWERACTIVE)) {
! 1445: printf("pcic_chip_socket_enable: status %x\n", reg);
! 1446: }
! 1447: #endif
! 1448:
! 1449: pcic_wait_ready(h);
! 1450:
! 1451: /* zero out the address windows */
! 1452:
! 1453: pcic_write(h, PCIC_ADDRWIN_ENABLE, 0);
! 1454:
! 1455: /* set the card type */
! 1456:
! 1457: cardtype = pcmcia_card_gettype(h->pcmcia);
! 1458:
! 1459: reg = pcic_read(h, PCIC_INTR);
! 1460: reg &= ~PCIC_INTR_CARDTYPE_MASK;
! 1461: reg |= ((cardtype == PCMCIA_IFTYPE_IO) ?
! 1462: PCIC_INTR_CARDTYPE_IO :
! 1463: PCIC_INTR_CARDTYPE_MEM);
! 1464: reg |= h->ih_irq;
! 1465: pcic_write(h, PCIC_INTR, reg);
! 1466:
! 1467: DPRINTF(("%s: pcic_chip_socket_enable %02x cardtype %s %02x\n",
! 1468: h->ph_parent->dv_xname, h->sock,
! 1469: ((cardtype == PCMCIA_IFTYPE_IO) ? "io" : "mem"), reg));
! 1470:
! 1471: /* reinstall all the memory and io mappings */
! 1472:
! 1473: for (win = 0; win < PCIC_MEM_WINS; win++)
! 1474: if (h->memalloc & (1 << win))
! 1475: pcic_chip_do_mem_map(h, win);
! 1476:
! 1477: for (win = 0; win < PCIC_IO_WINS; win++)
! 1478: if (h->ioalloc & (1 << win))
! 1479: pcic_chip_do_io_map(h, win);
! 1480: }
! 1481:
! 1482: void
! 1483: pcic_chip_socket_disable(pch)
! 1484: pcmcia_chipset_handle_t pch;
! 1485: {
! 1486: struct pcic_handle *h = (struct pcic_handle *) pch;
! 1487:
! 1488: DPRINTF(("pcic_chip_socket_disable\n"));
! 1489:
! 1490: /* power down the socket */
! 1491:
! 1492: pcic_write(h, PCIC_PWRCTL, 0);
! 1493:
! 1494: /*
! 1495: * wait 300ms until power fails (Tpf).
! 1496: */
! 1497: delay(300 * 1000);
! 1498: }
! 1499:
! 1500: u_int8_t
! 1501: st_pcic_read(h, idx)
! 1502: struct pcic_handle *h;
! 1503: int idx;
! 1504: {
! 1505: if (idx != -1)
! 1506: bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_INDEX,
! 1507: h->sock + idx);
! 1508: return bus_space_read_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_DATA);
! 1509: }
! 1510:
! 1511: void
! 1512: st_pcic_write(h, idx, data)
! 1513: struct pcic_handle *h;
! 1514: int idx;
! 1515: int data;
! 1516: {
! 1517: if (idx != -1)
! 1518: bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_INDEX,
! 1519: h->sock + idx);
! 1520: if (data != -1)
! 1521: bus_space_write_1(h->ph_bus_t, h->ph_bus_h, PCIC_REG_DATA,
! 1522: data);
! 1523: }
CVSweb