Annotation of sys/arch/macppc/pci/mpcpcibus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: mpcpcibus.c,v 1.36 2006/12/14 17:36:12 kettenis Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1997 Per Fogelstrom
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
! 19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: *
! 27: */
! 28:
! 29: /*
! 30: * Generic PCI BUS Bridge driver.
! 31: * specialized hooks for different config methods.
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/malloc.h>
! 38: #include <sys/device.h>
! 39: #include <sys/proc.h>
! 40: #include <uvm/uvm_extern.h>
! 41:
! 42: #include <machine/autoconf.h>
! 43: #include <machine/pcb.h>
! 44: #include <machine/bat.h>
! 45: #include <machine/powerpc.h>
! 46:
! 47: #include <dev/pci/pcireg.h>
! 48: #include <dev/pci/pcivar.h>
! 49: #include <dev/pci/pcidevs.h>
! 50:
! 51: #include <macppc/pci/pcibrvar.h>
! 52: #include <macppc/pci/mpc106reg.h>
! 53:
! 54: #include <dev/ofw/openfirm.h>
! 55:
! 56: int mpcpcibrmatch(struct device *, void *, void *);
! 57: void mpcpcibrattach(struct device *, struct device *, void *);
! 58:
! 59: void mpc_attach_hook(struct device *, struct device *,
! 60: struct pcibus_attach_args *);
! 61: int mpc_bus_maxdevs(void *, int);
! 62: pcitag_t mpc_make_tag(void *, int, int, int);
! 63: void mpc_decompose_tag(void *, pcitag_t, int *, int *, int *);
! 64: pcireg_t mpc_conf_read(void *, pcitag_t, int);
! 65: void mpc_conf_write(void *, pcitag_t, int, pcireg_t);
! 66:
! 67: int mpc_intr_map(void *, pcitag_t, int, int, pci_intr_handle_t *);
! 68: const char *mpc_intr_string(void *, pci_intr_handle_t);
! 69: int mpc_intr_line(void *, pci_intr_handle_t);
! 70: void *mpc_intr_establish(void *, pci_intr_handle_t,
! 71: int, int (*func)(void *), void *, char *);
! 72: void mpc_intr_disestablish(void *, void *);
! 73: int mpc_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);
! 74: u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset);
! 75: int of_ether_hw_addr(struct ppc_pci_chipset *, u_int8_t *);
! 76: int find_node_intr (int parent, u_int32_t *addr, u_int32_t *intr);
! 77: u_int32_t pci_iack(void);
! 78:
! 79: void fix_node_irq(int node, struct pcibus_attach_args *pba);
! 80:
! 81: struct cfattach mpcpcibr_ca = {
! 82: sizeof(struct pcibr_softc), mpcpcibrmatch, mpcpcibrattach,
! 83: };
! 84:
! 85: struct cfdriver mpcpcibr_cd = {
! 86: NULL, "mpcpcibr", DV_DULL,
! 87: };
! 88:
! 89: static int mpcpcibrprint(void *, const char *pnp);
! 90:
! 91: struct pcibr_config mpc_config;
! 92:
! 93: /*
! 94: * config types
! 95: * bit meanings
! 96: * 0 - standard cf8/cfc type configurations,
! 97: * sometimes the base addresses for these are different
! 98: * 1 - Config Method #2 configuration - uni-north
! 99: *
! 100: * 2 - 64 bit config bus, data for accesses &4 is at daddr+4;
! 101: */
! 102: struct config_type{
! 103: char * compat;
! 104: u_int32_t addr; /* offset */
! 105: u_int32_t data; /* offset */
! 106: int config_type;
! 107: };
! 108: struct config_type config_offsets[] = {
! 109: {"grackle", 0x00c00cf8, 0x00e00cfc, 0 },
! 110: {"bandit", 0x00800000, 0x00c00000, 1 },
! 111: {"uni-north", 0x00800000, 0x00c00000, 3 },
! 112: {"u3-agp", 0x00800000, 0x00c00000, 3 },
! 113: {"u3-ht", 0x00000cf8, 0x00000cfc, 3 },
! 114: {"legacy", 0x00000cf8, 0x00000cfc, 0 },
! 115: {"IBM,27-82660", 0x00000cf8, 0x00000cfc, 0 },
! 116: {NULL, 0x00000000, 0x00000000, 0 },
! 117: };
! 118:
! 119: struct powerpc_bus_dma_tag pci_bus_dma_tag = {
! 120: NULL,
! 121: _dmamap_create,
! 122: _dmamap_destroy,
! 123: _dmamap_load,
! 124: _dmamap_load_mbuf,
! 125: _dmamap_load_uio,
! 126: _dmamap_load_raw,
! 127: _dmamap_unload,
! 128: _dmamap_sync,
! 129: _dmamem_alloc,
! 130: _dmamem_free,
! 131: _dmamem_map,
! 132: _dmamem_unmap,
! 133: _dmamem_mmap
! 134: };
! 135:
! 136: int
! 137: mpcpcibrmatch(struct device *parent, void *match, void *aux)
! 138: {
! 139: struct confargs *ca = aux;
! 140: int found = 0;
! 141:
! 142: if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0)
! 143: return (found);
! 144:
! 145: found = 1;
! 146:
! 147: return found;
! 148: }
! 149:
! 150: int pci_map_a = 0;
! 151:
! 152: struct ranges_32 {
! 153: u_int32_t flags;
! 154: u_int32_t pad1;
! 155: u_int32_t pad2;
! 156: u_int32_t base;
! 157: u_int32_t pad3;
! 158: u_int32_t size;
! 159: };
! 160: void
! 161: mpcpcibus_find_ranges_32 (struct pcibr_softc *sc, u_int32_t *range_store,
! 162: int rangesize);
! 163: void
! 164: mpcpcibus_find_ranges_64 (struct pcibr_softc *sc, u_int32_t *range_store,
! 165: int rangesize);
! 166: void
! 167: mpcpcibus_find_ranges_32 (struct pcibr_softc *sc, u_int32_t *range_store,
! 168: int rangesize)
! 169: {
! 170: int found;
! 171: unsigned int base = 0;
! 172: unsigned int size = 0;
! 173: struct ranges_32 *prange = (void *)range_store;
! 174: int rangelen;
! 175: int i;
! 176:
! 177: rangelen = rangesize / sizeof (struct ranges_32);
! 178:
! 179: /* mac configs */
! 180: sc->sc_membus_space.bus_base = 0;
! 181: sc->sc_membus_space.bus_io = 0;
! 182: sc->sc_iobus_space.bus_base = 0;
! 183: sc->sc_iobus_space.bus_io = 1;
! 184:
! 185: /* find io(config) base, flag == 0x01000000 */
! 186: found = 0;
! 187: for (i = 0; i < rangelen ; i++) {
! 188: if (prange[i].flags == 0x01000000) {
! 189: /* find last? */
! 190: found = i;
! 191: }
! 192: }
! 193: /* found the io space ranges */
! 194: if (prange[found].flags == 0x01000000) {
! 195: sc->sc_iobus_space.bus_base =
! 196: prange[found].base;
! 197: sc->sc_iobus_space.bus_size =
! 198: prange[found].size;
! 199: }
! 200:
! 201: /* the mem space ranges
! 202: * apple openfirmware always puts full
! 203: * addresses in config information,
! 204: * it is not necessary to have correct bus
! 205: * base address, but since 0 is reserved
! 206: * and all IO and device memory will be in
! 207: * upper 2G of address space, set to
! 208: * 0x80000000
! 209: * start with segment 1 not 0, 0 is config.
! 210: */
! 211: for (i = 0; i < rangelen ; i++) {
! 212: if (prange[i].flags == 0x02000000) {
! 213: #ifdef DEBUG_PCI
! 214: printf("\nfound mem %x %x",
! 215: prange[i].base,
! 216: prange[i].size);
! 217: #endif
! 218: if (base != 0) {
! 219: if ((base + size) == prange[i].base)
! 220: size += prange[i].size;
! 221: else {
! 222: size = prange[i].size;
! 223: base = prange[i].base;
! 224: }
! 225: } else {
! 226: base = prange[i].base;
! 227: size = prange[i].size;
! 228: }
! 229: }
! 230: }
! 231: sc->sc_membus_space.bus_base = base;
! 232: sc->sc_membus_space.bus_size = size;
! 233: }
! 234:
! 235: struct ranges_64 {
! 236: u_int32_t flags;
! 237: u_int32_t pad1;
! 238: u_int32_t pad2;
! 239: u_int32_t pad3;
! 240: u_int32_t base;
! 241: u_int32_t pad4;
! 242: u_int32_t size;
! 243: };
! 244: void
! 245: mpcpcibus_find_ranges_64 (struct pcibr_softc *sc, u_int32_t *range_store,
! 246: int rangesize)
! 247: {
! 248: int i, found;
! 249: unsigned int base = 0;
! 250: unsigned int size = 0;
! 251: int rangelen;
! 252: struct ranges_64 *prange = (void *)range_store;
! 253:
! 254: rangelen = rangesize / sizeof (struct ranges_64);
! 255:
! 256: /* mac configs */
! 257:
! 258: sc->sc_membus_space.bus_base = 0;
! 259: sc->sc_membus_space.bus_io = 0;
! 260: sc->sc_iobus_space.bus_base = 0;
! 261: sc->sc_iobus_space.bus_io = 1;
! 262:
! 263: if (prange[0].flags == 0xabb10113) { /* appl U3; */
! 264: prange[0].flags = 0x01000000;
! 265: prange[0].base = 0xf8070000;
! 266: prange[0].size = 0x00001000;
! 267: prange[1].flags = 0x02000000;
! 268: prange[1].base = 0xf2000000;
! 269: prange[1].size = 0x02800000;
! 270: rangelen = 2;
! 271: }
! 272:
! 273: /* find io(config) base, flag == 0x01000000 */
! 274: found = 0;
! 275: for (i = 0; i < rangelen ; i++) {
! 276: if (prange[i].flags == 0x01000000) {
! 277: /* find last? */
! 278: found = i;
! 279: }
! 280: }
! 281: /* found the io space ranges */
! 282: if (prange[found].flags == 0x01000000) {
! 283: sc->sc_iobus_space.bus_base = prange[found].base;
! 284: sc->sc_iobus_space.bus_size = prange[found].size;
! 285: }
! 286:
! 287: /* the mem space ranges
! 288: * apple openfirmware always puts full
! 289: * addresses in config information,
! 290: * it is not necessary to have correct bus
! 291: * base address, but since 0 is reserved
! 292: * and all IO and device memory will be in
! 293: * upper 2G of address space, set to
! 294: * 0x80000000
! 295: * start with segment 1 not 0, 0 is config.
! 296: */
! 297: for (i = 0; i < rangelen ; i++) {
! 298: if (prange[i].flags == 0x02000000) {
! 299: #ifdef DEBUG_PCI
! 300: printf("\nfound mem %x %x",
! 301: prange[i].base,
! 302: prange[i].size);
! 303: #endif
! 304:
! 305: if (base != 0) {
! 306: if ((base + size) == prange[i].base) {
! 307: size += prange[i].size;
! 308: } else {
! 309: base = prange[i].base;
! 310: size = prange[i].size;
! 311: }
! 312: } else {
! 313: base = prange[i].base;
! 314: size = prange[i].size;
! 315: }
! 316: }
! 317: }
! 318: sc->sc_membus_space.bus_base = base;
! 319: sc->sc_membus_space.bus_size = size;
! 320: }
! 321:
! 322: void
! 323: mpcpcibrattach(struct device *parent, struct device *self, void *aux)
! 324: {
! 325: struct pcibr_softc *sc = (struct pcibr_softc *)self;
! 326: struct confargs *ca = aux;
! 327: struct pcibr_config *lcp;
! 328: struct pcibus_attach_args pba;
! 329: int node;
! 330: int of_node = 0;
! 331: char compat[32];
! 332: u_int32_t addr_offset;
! 333: u_int32_t data_offset;
! 334: int i;
! 335: int len;
! 336: int rangesize;
! 337: u_int32_t range_store[32];
! 338:
! 339: if (ca->ca_node == 0) {
! 340: printf("invalid node on mpcpcibr config\n");
! 341: return;
! 342: }
! 343: len=OF_getprop(ca->ca_node, "name", compat, sizeof (compat));
! 344: compat[len] = '\0';
! 345: if (len > 0)
! 346: printf(" %s", compat);
! 347:
! 348: len=OF_getprop(ca->ca_node, "compatible", compat,
! 349: sizeof (compat));
! 350: if (len <= 0 ) {
! 351: len=OF_getprop(ca->ca_node, "name", compat,
! 352: sizeof (compat));
! 353: if (len <= 0) {
! 354: printf(" compatible and name not found\n");
! 355: return;
! 356: }
! 357: compat[len] = 0;
! 358: if (strcmp (compat, "bandit") != 0) {
! 359: printf(" compatible not found and name %s found\n",
! 360: compat);
! 361: return;
! 362: }
! 363: }
! 364: compat[len] = 0;
! 365: if ((rangesize = OF_getprop(ca->ca_node, "ranges",
! 366: range_store, sizeof (range_store))) <= 0) {
! 367: if (strcmp(compat, "u3-ht") == 0) {
! 368: range_store[0] = 0xabb10113; /* appl U3; */
! 369: } else
! 370: printf("range lookup failed, node %x\n", ca->ca_node);
! 371: }
! 372: /* translate byte(s) into item count*/
! 373:
! 374: lcp = sc->sc_pcibr = &sc->pcibr_config;
! 375:
! 376: if (ppc_proc_is_64b)
! 377: mpcpcibus_find_ranges_64 (sc, range_store, rangesize);
! 378: else
! 379: mpcpcibus_find_ranges_32 (sc, range_store, rangesize);
! 380:
! 381: addr_offset = 0;
! 382: for (i = 0; config_offsets[i].compat != NULL; i++) {
! 383: struct config_type *co = &config_offsets[i];
! 384: if (strcmp(co->compat, compat) == 0) {
! 385: addr_offset = co->addr;
! 386: data_offset = co->data;
! 387: lcp->config_type = co->config_type;
! 388: break;
! 389: }
! 390: }
! 391: if (addr_offset == 0) {
! 392: printf("unable to find match for"
! 393: " compatible %s\n", compat);
! 394: return;
! 395: }
! 396: #ifdef DEBUG_FIXUP
! 397: printf(" mem base %x sz %x io base %x sz %x\n"
! 398: " config addr %x config data %x\n",
! 399: sc->sc_membus_space.bus_base,
! 400: sc->sc_membus_space.bus_size,
! 401: sc->sc_iobus_space.bus_base,
! 402: sc->sc_iobus_space.bus_size,
! 403: addr_offset, data_offset);
! 404: #endif
! 405:
! 406: if ( bus_space_map(&(sc->sc_iobus_space), addr_offset,
! 407: NBPG, 0, &lcp->ioh_cf8) != 0 )
! 408: panic("mpcpcibus: unable to map self");
! 409:
! 410: if ( bus_space_map(&(sc->sc_iobus_space), data_offset,
! 411: NBPG, 0, &lcp->ioh_cfc) != 0 )
! 412: panic("mpcpcibus: unable to map self");
! 413:
! 414: of_node = ca->ca_node;
! 415:
! 416: lcp->node = ca->ca_node;
! 417: lcp->lc_pc.pc_conf_v = lcp;
! 418: lcp->lc_pc.pc_attach_hook = mpc_attach_hook;
! 419: lcp->lc_pc.pc_bus_maxdevs = mpc_bus_maxdevs;
! 420: lcp->lc_pc.pc_make_tag = mpc_make_tag;
! 421: lcp->lc_pc.pc_decompose_tag = mpc_decompose_tag;
! 422: lcp->lc_pc.pc_conf_read = mpc_conf_read;
! 423: lcp->lc_pc.pc_conf_write = mpc_conf_write;
! 424: lcp->lc_pc.pc_ether_hw_addr = of_ether_hw_addr;
! 425: lcp->lc_iot = &sc->sc_iobus_space;
! 426: lcp->lc_memt = &sc->sc_membus_space;
! 427:
! 428: lcp->lc_pc.pc_intr_v = lcp;
! 429: lcp->lc_pc.pc_intr_map = mpc_intr_map;
! 430: lcp->lc_pc.pc_intr_string = mpc_intr_string;
! 431: lcp->lc_pc.pc_intr_line = mpc_intr_line;
! 432: lcp->lc_pc.pc_intr_establish = mpc_intr_establish;
! 433: lcp->lc_pc.pc_intr_disestablish = mpc_intr_disestablish;
! 434:
! 435: printf(": %s, Revision 0x%x\n", compat,
! 436: mpc_cfg_read_1(lcp, MPC106_PCI_REVID));
! 437:
! 438: if ((strcmp(compat, "bandit")) != 0)
! 439: pci_addr_fixup(sc, &lcp->lc_pc, 32);
! 440:
! 441: pba.pba_dmat = &pci_bus_dma_tag;
! 442:
! 443: pba.pba_busname = "pci";
! 444: pba.pba_iot = &sc->sc_iobus_space;
! 445: pba.pba_memt = &sc->sc_membus_space;
! 446: pba.pba_pc = &lcp->lc_pc;
! 447: pba.pba_domain = pci_ndomains++;
! 448: pba.pba_bus = 0;
! 449: pba.pba_bridgetag = NULL;
! 450:
! 451: /* we want to check pci irq settings */
! 452: if (of_node != 0) {
! 453: int nn;
! 454:
! 455: for (node = OF_child(of_node); node; node = nn) {
! 456: char name[32];
! 457: int len;
! 458: len = OF_getprop(node, "name", name,
! 459: sizeof(name));
! 460: name[len] = 0;
! 461: fix_node_irq(node, &pba);
! 462:
! 463: /* iterate section */
! 464: if ((nn = OF_child(node)) != 0)
! 465: continue;
! 466:
! 467: while ((nn = OF_peer(node)) == 0) {
! 468: node = OF_parent(node);
! 469: if (node == of_node) {
! 470: nn = 0; /* done */
! 471: break;
! 472: }
! 473: }
! 474: }
! 475: }
! 476:
! 477: config_found(self, &pba, mpcpcibrprint);
! 478:
! 479: }
! 480:
! 481: #define OFW_PCI_PHYS_HI_BUSMASK 0x00ff0000
! 482: #define OFW_PCI_PHYS_HI_BUSSHIFT 16
! 483: #define OFW_PCI_PHYS_HI_DEVICEMASK 0x0000f800
! 484: #define OFW_PCI_PHYS_HI_DEVICESHIFT 11
! 485: #define OFW_PCI_PHYS_HI_FUNCTIONMASK 0x00000700
! 486: #define OFW_PCI_PHYS_HI_FUNCTIONSHIFT 8
! 487:
! 488: #define pcibus(x) \
! 489: (((x) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
! 490: #define pcidev(x) \
! 491: (((x) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
! 492: #define pcifunc(x) \
! 493: (((x) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
! 494:
! 495: /*
! 496: * Find PCI IRQ from OF.
! 497: */
! 498: int
! 499: find_node_intr(int parent, u_int32_t *addr, u_int32_t *intr)
! 500: {
! 501: int iparent, len, mlen, alen, ilen;
! 502: int match, i, step;
! 503: u_int32_t map[144], *mp, *mp1;
! 504: u_int32_t imask[8], maskedaddr[8];
! 505: u_int32_t address_cells, interrupt_cells, mask_cells;
! 506:
! 507: len = OF_getprop(parent, "interrupt-map", map, sizeof(map));
! 508: mlen = OF_getprop(parent, "interrupt-map-mask", imask, sizeof(imask));
! 509: alen = OF_getprop(parent, "#address-cells",
! 510: &address_cells, sizeof(address_cells));
! 511: ilen = OF_getprop(parent, "#interrupt-cells",
! 512: &interrupt_cells, sizeof(interrupt_cells));
! 513:
! 514: if (len == -1 || mlen == -1 || alen == -1 || ilen == -1)
! 515: goto nomap;
! 516:
! 517: mask_cells = address_cells + interrupt_cells;
! 518: if (mask_cells != (mlen / sizeof(u_int32_t)))
! 519: goto nomap;
! 520: for (i = 0; i < mask_cells; i++)
! 521: maskedaddr[i] = addr[i] & imask[i];
! 522:
! 523: /* interrupt-map is formatted as follows
! 524: * int * #address-cells, int * #interrupt-cells, int, int, int
! 525: * eg
! 526: * address-cells = 3
! 527: * interrupt-cells = 1
! 528: * 00001000 00000000 00000000 00000000 ff911258 00000034 00000001
! 529: * 00001800 00000000 00000000 00000000 ff911258 00000035 00000001
! 530: * 00002000 00000000 00000000 00000000 ff911258 00000036 00000001
! 531: * | address cells | | intr | |parent| | irq | |edge/level|
! 532: * | cells| | interrupt cells |
! 533: * | of parent |
! 534: * or at least something close to that.
! 535: */
! 536:
! 537: mp = map;
! 538: while (len > mlen) {
! 539: mp1 = mp + mask_cells;
! 540:
! 541: iparent = *mp1;
! 542: alen = OF_getprop(iparent, "#address-cells",
! 543: &address_cells, sizeof(address_cells));
! 544: if (alen == -1)
! 545: address_cells = 0;
! 546: ilen = OF_getprop(iparent, "#interrupt-cells",
! 547: &interrupt_cells, sizeof(interrupt_cells));
! 548: if (ilen == -1)
! 549: goto nomap;
! 550:
! 551: step = mask_cells + 1 + address_cells + interrupt_cells;
! 552:
! 553: match = bcmp(maskedaddr, mp, mlen);
! 554: if (match == 0) {
! 555: if (OF_getprop(iparent, "interrupt-controller",
! 556: NULL, 0) == 0) {
! 557: *intr = mp1[1];
! 558: return 1;
! 559: }
! 560: /* Recurse with new 'addr'. */
! 561: return find_node_intr(iparent, &mp1[1], intr);
! 562: }
! 563: len -= step * sizeof(u_int32_t);
! 564: mp += step;
! 565: }
! 566: nomap:
! 567: return -1;
! 568: }
! 569:
! 570: void
! 571: fix_node_irq(int node, struct pcibus_attach_args *pba)
! 572: {
! 573: struct {
! 574: u_int32_t phys_hi, phys_mid, phys_lo;
! 575: u_int32_t size_hi, size_lo;
! 576: } addr [8];
! 577: u_int32_t map[144];
! 578: int len;
! 579: pcitag_t tag;
! 580: u_int32_t irq;
! 581: u_int32_t intr;
! 582: int parent;
! 583:
! 584: pci_chipset_tag_t pc = pba->pba_pc;
! 585:
! 586: len = OF_getprop(node, "assigned-addresses", addr, sizeof(addr));
! 587: if (len == -1 || len < sizeof(addr[0]))
! 588: return;
! 589:
! 590: /* if this node has a AAPL,interrupts property, firmware
! 591: * has initialized the register correctly.
! 592: */
! 593: len = OF_getprop(node, "AAPL,interrupts", &intr, 4);
! 594: if (len != 4) {
! 595:
! 596: parent = OF_parent(node);
! 597:
! 598: irq = -1;
! 599:
! 600: /* we want the first interrupt, set size_hi to 1 */
! 601: addr[0].size_hi = 1;
! 602: if (find_node_intr(parent, &addr[0].phys_hi, &irq) == -1) {
! 603: len = OF_getprop(node, "interrupts", map,
! 604: sizeof(map));
! 605: if (len != -1 && len != 4) {
! 606: irq = map[0];
! 607: } else
! 608: return;
! 609: }
! 610: } else
! 611: irq = intr;
! 612: /* program the interrupt line register with the value
! 613: * found in openfirmware
! 614: */
! 615:
! 616: tag = pci_make_tag(pc, pcibus(addr[0].phys_hi),
! 617: pcidev(addr[0].phys_hi), pcifunc(addr[0].phys_hi));
! 618:
! 619: intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
! 620: intr &= ~PCI_INTERRUPT_LINE_MASK;
! 621: intr |= irq & PCI_INTERRUPT_LINE_MASK;
! 622: pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
! 623: }
! 624:
! 625: static int
! 626: mpcpcibrprint(void *aux, const char *pnp)
! 627: {
! 628: struct pcibus_attach_args *pba = aux;
! 629:
! 630: if (pnp)
! 631: printf("%s at %s", pba->pba_busname, pnp);
! 632: printf(" bus %d", pba->pba_bus);
! 633: return(UNCONF);
! 634: }
! 635:
! 636: void
! 637: mpc_attach_hook(struct device *parent, struct device *self,
! 638: struct pcibus_attach_args *pba)
! 639: {
! 640: }
! 641:
! 642: int
! 643: of_ether_hw_addr(struct ppc_pci_chipset *lcpc, u_int8_t *oaddr)
! 644: {
! 645: u_int8_t laddr[6];
! 646: struct pcibr_config *lcp = lcpc->pc_conf_v;
! 647: int of_node = lcp->node;
! 648: int node, nn;
! 649: for (node = OF_child(of_node); node; node = nn) {
! 650: char name[32];
! 651: int len;
! 652: len = OF_getprop(node, "name", name,
! 653: sizeof(name));
! 654: name[len] = 0;
! 655:
! 656: len = OF_getprop(node, "local-mac-address", laddr,
! 657: sizeof laddr);
! 658: if (sizeof (laddr) == len) {
! 659: bcopy (laddr, oaddr, sizeof laddr);
! 660: return 1;
! 661: }
! 662:
! 663: /* iterate section */
! 664: if ((nn = OF_child(node)) != 0) {
! 665: continue;
! 666: }
! 667: while ((nn = OF_peer(node)) == 0) {
! 668: node = OF_parent(node);
! 669: if (node == of_node) {
! 670: nn = 0; /* done */
! 671: break;
! 672: }
! 673: }
! 674: }
! 675: oaddr[0] = oaddr[1] = oaddr[2] = 0xff;
! 676: oaddr[3] = oaddr[4] = oaddr[5] = 0xff;
! 677: return 0;
! 678: }
! 679:
! 680: int
! 681: mpc_ether_hw_addr(struct ppc_pci_chipset *p, u_int8_t *s)
! 682: {
! 683: printf("mpc_ether_hw_addr not supported\n");
! 684: return(0);
! 685: }
! 686:
! 687: int
! 688: mpc_bus_maxdevs(void *cpv, int busno)
! 689: {
! 690: return(32);
! 691: }
! 692:
! 693: #define BUS_SHIFT 16
! 694: #define DEVICE_SHIFT 11
! 695: #define FNC_SHIFT 8
! 696:
! 697: pcitag_t
! 698: mpc_make_tag(void *cpv, int bus, int dev, int fnc)
! 699: {
! 700: return (bus << BUS_SHIFT) | (dev << DEVICE_SHIFT) | (fnc << FNC_SHIFT);
! 701: }
! 702:
! 703: void
! 704: mpc_decompose_tag(void *cpv, pcitag_t tag, int *busp, int *devp, int *fncp)
! 705: {
! 706: if (busp != NULL)
! 707: *busp = (tag >> BUS_SHIFT) & 0xff;
! 708: if (devp != NULL)
! 709: *devp = (tag >> DEVICE_SHIFT) & 0x1f;
! 710: if (fncp != NULL)
! 711: *fncp = (tag >> FNC_SHIFT) & 0x7;
! 712: }
! 713:
! 714: u_int32_t
! 715: mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset)
! 716: {
! 717: struct pcibr_config *cp = cpv;
! 718: unsigned int bus, dev, fcn;
! 719: u_int32_t reg;
! 720:
! 721: mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
! 722:
! 723: if (cp->config_type & 1) {
! 724: /* Config Mechanism #2 */
! 725: if (bus == 0) {
! 726: if (dev < 11)
! 727: return 0xffffffff;
! 728: /*
! 729: * Need to do config type 0 operation
! 730: * 1 << (11?+dev) | fcn << 8 | reg
! 731: * 11? is because pci spec states
! 732: * that 11-15 is reserved.
! 733: */
! 734: reg = 1 << (dev) | fcn << 8 | offset;
! 735:
! 736: } else {
! 737: if (dev > 15)
! 738: return 0xffffffff;
! 739: /*
! 740: * config type 1
! 741: */
! 742: reg = tag | offset | 1;
! 743: }
! 744: } else {
! 745: /* config mechanism #2, type 0
! 746: * standard cf8/cfc config
! 747: */
! 748: reg = 0x80000000 | tag | offset;
! 749: }
! 750:
! 751: return reg;
! 752: }
! 753:
! 754: /* #define DEBUG_CONFIG */
! 755: pcireg_t
! 756: mpc_conf_read(void *cpv, pcitag_t tag, int offset)
! 757: {
! 758: struct pcibr_config *cp = cpv;
! 759: pcireg_t data;
! 760: u_int32_t reg;
! 761: int s;
! 762: int daddr = 0;
! 763: faultbuf env;
! 764: void *oldh;
! 765:
! 766: if (offset & 3 || offset < 0 || offset >= 0x100) {
! 767: #ifdef DEBUG_CONFIG
! 768: printf ("pci_conf_read: bad reg %x\n", offset);
! 769: #endif /* DEBUG_CONFIG */
! 770: return(~0);
! 771: }
! 772:
! 773: reg = mpc_gen_config_reg(cpv, tag, offset);
! 774: /* if invalid tag, return -1 */
! 775: if (reg == 0xffffffff)
! 776: return(~0);
! 777:
! 778: if ((cp->config_type & 2) && (offset & 0x04))
! 779: daddr += 4;
! 780:
! 781: s = splhigh();
! 782:
! 783: oldh = curpcb->pcb_onfault;
! 784: if (setfault(&env)) {
! 785: /* we faulted during the read? */
! 786: curpcb->pcb_onfault = oldh;
! 787: splx(s);
! 788: return 0xffffffff;
! 789: }
! 790:
! 791: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
! 792: bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
! 793: data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr);
! 794: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
! 795: bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
! 796:
! 797: curpcb->pcb_onfault = oldh;
! 798:
! 799: splx(s);
! 800: #ifdef DEBUG_CONFIG
! 801: if (!((offset == 0) && (data == 0xffffffff))) {
! 802: unsigned int bus, dev, fcn;
! 803: mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
! 804: printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn,
! 805: offset);
! 806: printf(" daddr %x reg %x",daddr, reg);
! 807: printf(" data %x\n", data);
! 808: }
! 809: #endif
! 810:
! 811: return(data);
! 812: }
! 813:
! 814: void
! 815: mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data)
! 816: {
! 817: struct pcibr_config *cp = cpv;
! 818: u_int32_t reg;
! 819: int s;
! 820: int daddr = 0;
! 821:
! 822: reg = mpc_gen_config_reg(cpv, tag, offset);
! 823:
! 824: /* if invalid tag, return ??? */
! 825: if (reg == 0xffffffff)
! 826: return;
! 827:
! 828: if ((cp->config_type & 2) && (offset & 0x04))
! 829: daddr += 4;
! 830:
! 831: #ifdef DEBUG_CONFIG
! 832: {
! 833: unsigned int bus, dev, fcn;
! 834: mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn);
! 835: printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus,
! 836: dev, fcn, offset);
! 837: printf(" daddr %x reg %x",daddr, reg);
! 838: printf(" data %x\n", data);
! 839: }
! 840: #endif
! 841:
! 842: s = splhigh();
! 843:
! 844: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg);
! 845: bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
! 846: bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data);
! 847: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */
! 848: bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */
! 849:
! 850: splx(s);
! 851: }
! 852:
! 853:
! 854: /*ARGSUSED*/
! 855: int
! 856: mpc_intr_map(void *lcv, pcitag_t bustag, int buspin, int line,
! 857: pci_intr_handle_t *ihp)
! 858: {
! 859: int error = 0;
! 860:
! 861: *ihp = -1;
! 862: if (buspin == 0)
! 863: error = 1; /* No IRQ used. */
! 864: else if (buspin > 4) {
! 865: printf("mpc_intr_map: bad interrupt pin %d\n", buspin);
! 866: error = 1;
! 867: }
! 868:
! 869: if (!error)
! 870: *ihp = line;
! 871: return error;
! 872: }
! 873:
! 874: const char *
! 875: mpc_intr_string(void *lcv, pci_intr_handle_t ih)
! 876: {
! 877: static char str[16];
! 878:
! 879: snprintf(str, sizeof str, "irq %ld", ih);
! 880: return(str);
! 881: }
! 882:
! 883: int
! 884: mpc_intr_line(void *lcv, pci_intr_handle_t ih)
! 885: {
! 886: return (ih);
! 887: }
! 888:
! 889: void *
! 890: mpc_intr_establish(void *lcv, pci_intr_handle_t ih, int level,
! 891: int (*func)(void *), void *arg, char *name)
! 892: {
! 893: return (*intr_establish_func)(lcv, ih, IST_LEVEL, level, func, arg,
! 894: name);
! 895: }
! 896:
! 897: void
! 898: mpc_intr_disestablish(void *lcv, void *cookie)
! 899: {
! 900: /* XXX We should probably do something clever here.... later */
! 901: }
! 902:
! 903: u_int32_t
! 904: pci_iack()
! 905: {
! 906: /* do pci IACK cycle */
! 907: /* this should be bus allocated. */
! 908: volatile u_int8_t *iack = (u_int8_t *)0xbffffff0;
! 909: u_int8_t val;
! 910:
! 911: val = *iack;
! 912: return val;
! 913: }
! 914:
! 915: void
! 916: mpc_cfg_write_1(struct pcibr_config *cp, u_int32_t reg, u_int8_t val)
! 917: {
! 918: int s;
! 919: s = splhigh();
! 920: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 921: bus_space_write_1(cp->lc_iot, cp->ioh_cfc, 0, val);
! 922: splx(s);
! 923: }
! 924:
! 925: void
! 926: mpc_cfg_write_2(struct pcibr_config *cp, u_int32_t reg, u_int16_t val)
! 927: {
! 928: int s;
! 929: s = splhigh();
! 930: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 931: bus_space_write_2(cp->lc_iot, cp->ioh_cfc, 0, val);
! 932: splx(s);
! 933: }
! 934:
! 935: void
! 936: mpc_cfg_write_4(struct pcibr_config *cp, u_int32_t reg, u_int32_t val)
! 937: {
! 938:
! 939: int s;
! 940: s = splhigh();
! 941: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 942: bus_space_write_4(cp->lc_iot, cp->ioh_cfc, 0, val);
! 943: splx(s);
! 944: }
! 945:
! 946: u_int8_t
! 947: mpc_cfg_read_1(struct pcibr_config *cp, u_int32_t reg)
! 948: {
! 949: u_int8_t _v_;
! 950:
! 951: int s;
! 952: s = splhigh();
! 953: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 954: _v_ = bus_space_read_1(cp->lc_iot, cp->ioh_cfc, 0);
! 955: splx(s);
! 956: return(_v_);
! 957: }
! 958:
! 959: u_int16_t
! 960: mpc_cfg_read_2(struct pcibr_config *cp, u_int32_t reg)
! 961: {
! 962: u_int16_t _v_;
! 963:
! 964: int s;
! 965: s = splhigh();
! 966: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 967: _v_ = bus_space_read_2(cp->lc_iot, cp->ioh_cfc, 0);
! 968: splx(s);
! 969: return(_v_);
! 970: }
! 971:
! 972: u_int32_t
! 973: mpc_cfg_read_4(struct pcibr_config *cp, u_int32_t reg)
! 974: {
! 975: u_int32_t _v_;
! 976:
! 977: int s;
! 978: s = splhigh();
! 979: bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, MPC106_REGOFFS(reg));
! 980: _v_ = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, 0);
! 981: splx(s);
! 982: return(_v_);
! 983: }
CVSweb