Annotation of sys/dev/pci/sti_pci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sti_pci.c,v 1.6 2007/06/17 12:07:10 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006, 2007 Miodrag Vallat.
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice, this permission notice, and the disclaimer below
! 9: * appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: #include <sys/param.h>
! 21: #include <sys/systm.h>
! 22: #include <sys/device.h>
! 23:
! 24: #include <dev/pci/pcireg.h>
! 25: #include <dev/pci/pcivar.h>
! 26: #include <dev/pci/pcidevs.h>
! 27:
! 28: #include <dev/wscons/wsdisplayvar.h>
! 29:
! 30: #include <dev/ic/stireg.h>
! 31: #include <dev/ic/stivar.h>
! 32:
! 33: int sti_pci_match(struct device *, void *, void *);
! 34: void sti_pci_attach(struct device *, struct device *, void *);
! 35:
! 36: struct sti_pci_softc {
! 37: struct sti_softc sc_base;
! 38:
! 39: pci_chipset_tag_t sc_pc;
! 40: pcitag_t sc_tag;
! 41: };
! 42:
! 43: struct cfattach sti_pci_ca = {
! 44: sizeof(struct sti_pci_softc), sti_pci_match, sti_pci_attach
! 45: };
! 46:
! 47: const struct pci_matchid sti_pci_devices[] = {
! 48: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_EG },
! 49: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX2 },
! 50: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX4 },
! 51: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX6 },
! 52: { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FXE },
! 53: };
! 54:
! 55: int sti_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
! 56: int sti_check_rom(struct sti_pci_softc *, struct pci_attach_args *);
! 57: void sti_pci_enable_rom(struct sti_softc *);
! 58: void sti_pci_disable_rom(struct sti_softc *);
! 59:
! 60: int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
! 61:
! 62: int
! 63: sti_pci_match(struct device *parent, void *cf, void *aux)
! 64: {
! 65: struct pci_attach_args *paa = aux;
! 66:
! 67: return (pci_matchbyid(paa, sti_pci_devices,
! 68: sizeof(sti_pci_devices) / sizeof(sti_pci_devices[0])));
! 69: }
! 70:
! 71: void
! 72: sti_pci_attach(struct device *parent, struct device *self, void *aux)
! 73: {
! 74: struct sti_pci_softc *spc = (void *)self;
! 75: struct pci_attach_args *paa = aux;
! 76:
! 77: spc->sc_pc = paa->pa_pc;
! 78: spc->sc_tag = paa->pa_tag;
! 79: spc->sc_base.sc_enable_rom = sti_pci_enable_rom;
! 80: spc->sc_base.sc_disable_rom = sti_pci_disable_rom;
! 81:
! 82: printf("\n");
! 83:
! 84: if (sti_check_rom(spc, paa) != 0)
! 85: return;
! 86:
! 87: printf("%s", self->dv_xname);
! 88: if (sti_attach_common(&spc->sc_base, STI_CODEBASE_MAIN) == 0) {
! 89: if (sti_pci_is_console(paa, spc->sc_base.bases) != 0)
! 90: spc->sc_base.sc_flags |= STI_CONSOLE;
! 91: startuphook_establish(sti_end_attach, spc);
! 92: }
! 93: }
! 94:
! 95: /*
! 96: * Grovel the STI ROM image.
! 97: */
! 98: int
! 99: sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa)
! 100: {
! 101: struct sti_softc *sc = &spc->sc_base;
! 102: pcireg_t address, mask;
! 103: bus_space_handle_t romh;
! 104: bus_size_t romsize, subsize, stiromsize;
! 105: bus_addr_t selected, offs, suboffs;
! 106: u_int32_t tmp;
! 107: int i;
! 108: int rc;
! 109:
! 110: /* sort of inline sti_pci_enable_rom(sc) */
! 111: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
! 112: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
! 113: mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
! 114: address |= PCI_ROM_ENABLE;
! 115: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
! 116: sc->sc_flags |= STI_ROM_ENABLED;
! 117:
! 118: /*
! 119: * Map the complete ROM for now.
! 120: */
! 121:
! 122: romsize = PCI_ROM_SIZE(mask);
! 123: rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize,
! 124: 0, &romh);
! 125: sti_pci_disable_rom(sc);
! 126: if (rc != 0) {
! 127: printf("%s: can't map PCI ROM (%d)\n",
! 128: sc->sc_dev.dv_xname, rc);
! 129: goto fail2;
! 130: }
! 131:
! 132: /*
! 133: * Iterate over the ROM images, pick the best candidate.
! 134: */
! 135:
! 136: selected = (bus_addr_t)-1;
! 137: for (offs = 0; offs < romsize; offs += subsize) {
! 138: sti_pci_enable_rom(sc);
! 139: /*
! 140: * Check for a valid ROM header.
! 141: */
! 142: tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
! 143: tmp = letoh32(tmp);
! 144: if (tmp != 0x55aa0000) {
! 145: sti_pci_disable_rom(sc);
! 146: if (offs == 0) {
! 147: printf("%s: invalid PCI ROM header signature"
! 148: " (%08x)\n",
! 149: sc->sc_dev.dv_xname, tmp);
! 150: rc = EINVAL;
! 151: }
! 152: break;
! 153: }
! 154:
! 155: /*
! 156: * Check ROM type.
! 157: */
! 158: tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
! 159: tmp = letoh32(tmp);
! 160: if (tmp != 0x00000001) { /* 1 == STI ROM */
! 161: sti_pci_disable_rom(sc);
! 162: if (offs == 0) {
! 163: printf("%s: invalid PCI ROM type (%08x)\n",
! 164: sc->sc_dev.dv_xname, tmp);
! 165: rc = EINVAL;
! 166: }
! 167: break;
! 168: }
! 169:
! 170: subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
! 171: offs + 0x0c);
! 172: subsize <<= 9;
! 173:
! 174: #ifdef STIDEBUG
! 175: sti_pci_disable_rom(sc);
! 176: printf("ROM offset %08x size %08x type %08x",
! 177: offs, subsize, tmp);
! 178: sti_pci_enable_rom(sc);
! 179: #endif
! 180:
! 181: /*
! 182: * Check for a valid ROM data structure.
! 183: * We do not need it except to know what architecture the ROM
! 184: * code is for.
! 185: */
! 186:
! 187: suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
! 188: offs + 0x18);
! 189: tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
! 190: tmp = letoh32(tmp);
! 191: if (tmp != 0x50434952) { /* PCIR */
! 192: sti_pci_disable_rom(sc);
! 193: if (offs == 0) {
! 194: printf("%s: invalid PCI data signature"
! 195: " (%08x)\n",
! 196: sc->sc_dev.dv_xname, tmp);
! 197: rc = EINVAL;
! 198: } else {
! 199: #ifdef STIDEBUG
! 200: printf(" invalid PCI data signature %08x\n",
! 201: tmp);
! 202: #endif
! 203: continue;
! 204: }
! 205: }
! 206:
! 207: tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
! 208: sti_pci_disable_rom(sc);
! 209: #ifdef STIDEBUG
! 210: printf(" code %02x", tmp);
! 211: #endif
! 212:
! 213: switch (tmp) {
! 214: #ifdef __hppa__
! 215: case 0x10:
! 216: if (selected == (bus_addr_t)-1)
! 217: selected = offs;
! 218: break;
! 219: #endif
! 220: #ifdef __i386__
! 221: case 0x00:
! 222: if (selected == (bus_addr_t)-1)
! 223: selected = offs;
! 224: break;
! 225: #endif
! 226: default:
! 227: #ifdef STIDEBUG
! 228: printf(" (wrong architecture)");
! 229: #endif
! 230: break;
! 231: }
! 232:
! 233: #ifdef STIDEBUG
! 234: if (selected == offs)
! 235: printf(" -> SELECTED");
! 236: printf("\n");
! 237: #endif
! 238: }
! 239:
! 240: if (selected == (bus_addr_t)-1) {
! 241: if (rc == 0) {
! 242: printf("%s: found no ROM with correct microcode"
! 243: " architecture\n", sc->sc_dev.dv_xname);
! 244: rc = ENOEXEC;
! 245: }
! 246: goto fail;
! 247: }
! 248:
! 249: /*
! 250: * Read the STI region BAR assignments.
! 251: */
! 252:
! 253: sti_pci_enable_rom(sc);
! 254: offs = selected +
! 255: (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
! 256: for (i = 0; i < STI_REGION_MAX; i++) {
! 257: rc = sti_readbar(sc, pa, i,
! 258: bus_space_read_1(pa->pa_memt, romh, offs + i));
! 259: if (rc != 0)
! 260: goto fail;
! 261: }
! 262:
! 263: /*
! 264: * Find out where the STI ROM itself lies, and its size.
! 265: */
! 266:
! 267: offs = selected +
! 268: (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
! 269: stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
! 270: offs + 0x18);
! 271: stiromsize = letoh32(stiromsize);
! 272: sti_pci_disable_rom(sc);
! 273:
! 274: /*
! 275: * Replace our mapping with a smaller mapping of only the area
! 276: * we are interested in.
! 277: */
! 278:
! 279: bus_space_unmap(pa->pa_memt, romh, romsize);
! 280: rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs,
! 281: stiromsize, 0, &sc->romh);
! 282: if (rc != 0) {
! 283: printf("%s: can't map STI ROM (%d)\n",
! 284: sc->sc_dev.dv_xname, rc);
! 285: goto fail2;
! 286: }
! 287: sc->memt = pa->pa_memt;
! 288:
! 289: return (0);
! 290:
! 291: fail:
! 292: bus_space_unmap(pa->pa_memt, romh, romsize);
! 293: fail2:
! 294: sti_pci_disable_rom(sc);
! 295:
! 296: return (rc);
! 297: }
! 298:
! 299: /*
! 300: * Decode a BAR register.
! 301: */
! 302: int
! 303: sti_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
! 304: int bar)
! 305: {
! 306: bus_addr_t addr;
! 307: bus_size_t size;
! 308: u_int32_t cf;
! 309: int rc;
! 310:
! 311: if (bar == 0) {
! 312: sc->bases[region] = 0;
! 313: return (0);
! 314: }
! 315:
! 316: #ifdef DIAGNOSTIC
! 317: if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
! 318: sti_pci_disable_rom(sc);
! 319: printf("%s: unexpected bar %02x for region %d\n",
! 320: sc->sc_dev.dv_xname, bar, region);
! 321: sti_pci_enable_rom(sc);
! 322: }
! 323: #endif
! 324:
! 325: cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
! 326:
! 327: if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
! 328: rc = pci_io_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size);
! 329: else
! 330: rc = pci_mem_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size,
! 331: NULL);
! 332:
! 333: if (rc != 0) {
! 334: sti_pci_disable_rom(sc);
! 335: printf("%s: invalid bar %02x for region %d\n",
! 336: sc->sc_dev.dv_xname, bar, region);
! 337: sti_pci_enable_rom(sc);
! 338: return (rc);
! 339: }
! 340:
! 341: sc->bases[region] = addr;
! 342: return (0);
! 343: }
! 344:
! 345: /*
! 346: * Enable PCI ROM.
! 347: */
! 348: void
! 349: sti_pci_enable_rom(struct sti_softc *sc)
! 350: {
! 351: struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
! 352: pcireg_t address;
! 353:
! 354: if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
! 355: address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
! 356: address |= PCI_ROM_ENABLE;
! 357: pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
! 358: SET(sc->sc_flags, STI_ROM_ENABLED);
! 359: }
! 360: }
! 361:
! 362: /*
! 363: * Disable PCI ROM.
! 364: */
! 365: void
! 366: sti_pci_disable_rom(struct sti_softc *sc)
! 367: {
! 368: struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
! 369: pcireg_t address;
! 370:
! 371: if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
! 372: address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
! 373: address &= ~PCI_ROM_ENABLE;
! 374: pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
! 375:
! 376: CLR(sc->sc_flags, STI_ROM_ENABLED);
! 377: }
! 378: }
CVSweb