1 /* $OpenBSD: sti_pci.c,v 1.8 2014/08/30 14:42:05 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 bus_space_handle_t sc_romh; 43 }; 44 45 struct cfattach sti_pci_ca = { 46 sizeof(struct sti_pci_softc), sti_pci_match, sti_pci_attach 47 }; 48 49 const struct pci_matchid sti_pci_devices[] = { 50 { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_EG }, 51 { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX2 }, 52 { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX4 }, 53 { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX6 }, 54 { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FXE }, 55 }; 56 57 int sti_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int); 58 int sti_check_rom(struct sti_pci_softc *, struct pci_attach_args *); 59 void sti_pci_enable_rom(struct sti_softc *); 60 void sti_pci_disable_rom(struct sti_softc *); 61 62 int sti_pci_is_console(struct pci_attach_args *, bus_addr_t *); 63 64 int 65 sti_pci_match(struct device *parent, void *cf, void *aux) 66 { 67 struct pci_attach_args *paa = aux; 68 69 return (pci_matchbyid(paa, sti_pci_devices, 70 sizeof(sti_pci_devices) / sizeof(sti_pci_devices[0]))); 71 } 72 73 void 74 sti_pci_attach(struct device *parent, struct device *self, void *aux) 75 { 76 struct sti_pci_softc *spc = (void *)self; 77 struct pci_attach_args *paa = aux; 78 79 spc->sc_pc = paa->pa_pc; 80 spc->sc_tag = paa->pa_tag; 81 spc->sc_base.sc_enable_rom = sti_pci_enable_rom; 82 spc->sc_base.sc_disable_rom = sti_pci_disable_rom; 83 84 printf("\n"); 85 86 if (sti_check_rom(spc, paa) != 0) 87 return; 88 89 printf("%s", self->dv_xname); 90 if (sti_pci_is_console(paa, spc->sc_base.bases) != 0) 91 spc->sc_base.sc_flags |= STI_CONSOLE; 92 if (sti_attach_common(&spc->sc_base, paa->pa_iot, paa->pa_memt, 93 spc->sc_romh, STI_CODEBASE_MAIN) == 0) 94 startuphook_establish(sti_end_attach, spc); 95 } 96 97 /* 98 * Grovel the STI ROM image. 99 */ 100 int 101 sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa) 102 { 103 struct sti_softc *sc = &spc->sc_base; 104 pcireg_t address, mask; 105 bus_space_handle_t romh; 106 bus_size_t romsize, subsize, stiromsize; 107 bus_addr_t selected, offs, suboffs; 108 u_int32_t tmp; 109 int i; 110 int rc; 111 112 /* sort of inline sti_pci_enable_rom(sc) */ 113 address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); 114 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE); 115 mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); 116 address |= PCI_ROM_ENABLE; 117 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); 118 sc->sc_flags |= STI_ROM_ENABLED; 119 120 /* 121 * Map the complete ROM for now. 122 */ 123 124 romsize = PCI_ROM_SIZE(mask); 125 rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize, 126 0, &romh); 127 sti_pci_disable_rom(sc); 128 if (rc != 0) { 129 printf("%s: can't map PCI ROM (%d)\n", 130 sc->sc_dev.dv_xname, rc); 131 goto fail2; 132 } 133 134 /* 135 * Iterate over the ROM images, pick the best candidate. 136 */ 137 138 selected = (bus_addr_t)-1; 139 for (offs = 0; offs < romsize; offs += subsize) { 140 sti_pci_enable_rom(sc); 141 /* 142 * Check for a valid ROM header. 143 */ 144 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0); 145 tmp = letoh32(tmp); 146 if (tmp != 0x55aa0000) { 147 sti_pci_disable_rom(sc); 148 if (offs == 0) { 149 printf("%s: invalid PCI ROM header signature" 150 " (%08x)\n", 151 sc->sc_dev.dv_xname, tmp); 152 rc = EINVAL; 153 } 154 break; 155 } 156 157 /* 158 * Check ROM type. 159 */ 160 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4); 161 tmp = letoh32(tmp); 162 if (tmp != 0x00000001) { /* 1 == STI ROM */ 163 sti_pci_disable_rom(sc); 164 if (offs == 0) { 165 printf("%s: invalid PCI ROM type (%08x)\n", 166 sc->sc_dev.dv_xname, tmp); 167 rc = EINVAL; 168 } 169 break; 170 } 171 172 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 173 offs + 0x0c); 174 subsize <<= 9; 175 176 #ifdef STIDEBUG 177 sti_pci_disable_rom(sc); 178 printf("ROM offset %08lx size %08lx type %08x", 179 offs, subsize, tmp); 180 sti_pci_enable_rom(sc); 181 #endif 182 183 /* 184 * Check for a valid ROM data structure. 185 * We do not need it except to know what architecture the ROM 186 * code is for. 187 */ 188 189 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh, 190 offs + 0x18); 191 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0); 192 tmp = letoh32(tmp); 193 if (tmp != 0x50434952) { /* PCIR */ 194 sti_pci_disable_rom(sc); 195 if (offs == 0) { 196 printf("%s: invalid PCI data signature" 197 " (%08x)\n", 198 sc->sc_dev.dv_xname, tmp); 199 rc = EINVAL; 200 } else { 201 #ifdef STIDEBUG 202 printf(" invalid PCI data signature %08x\n", 203 tmp); 204 #endif 205 continue; 206 } 207 } 208 209 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14); 210 sti_pci_disable_rom(sc); 211 #ifdef STIDEBUG 212 printf(" code %02x", tmp); 213 #endif 214 215 switch (tmp) { 216 #ifdef __hppa__ 217 case 0x10: 218 if (selected == (bus_addr_t)-1) 219 selected = offs; 220 break; 221 #endif 222 #ifdef __i386__ 223 case 0x00: 224 if (selected == (bus_addr_t)-1) 225 selected = offs; 226 break; 227 #endif 228 default: 229 #ifdef STIDEBUG 230 printf(" (wrong architecture)"); 231 #endif 232 break; 233 } 234 235 #ifdef STIDEBUG 236 if (selected == offs) 237 printf(" -> SELECTED"); 238 printf("\n"); 239 #endif 240 } 241 242 if (selected == (bus_addr_t)-1) { 243 if (rc == 0) { 244 printf("%s: found no ROM with correct microcode" 245 " architecture\n", sc->sc_dev.dv_xname); 246 rc = ENOEXEC; 247 } 248 goto fail; 249 } 250 251 /* 252 * Read the STI region BAR assignments. 253 */ 254 255 sti_pci_enable_rom(sc); 256 offs = selected + 257 (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e); 258 for (i = 0; i < STI_REGION_MAX; i++) { 259 rc = sti_readbar(sc, pa, i, 260 bus_space_read_1(pa->pa_memt, romh, offs + i)); 261 if (rc != 0) 262 goto fail; 263 } 264 265 /* 266 * Find out where the STI ROM itself lies, and its size. 267 */ 268 269 offs = selected + 270 (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08); 271 stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, 272 offs + 0x18); 273 stiromsize = letoh32(stiromsize); 274 sti_pci_disable_rom(sc); 275 276 /* 277 * Replace our mapping with a smaller mapping of only the area 278 * we are interested in. 279 */ 280 281 bus_space_unmap(pa->pa_memt, romh, romsize); 282 rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs, 283 stiromsize, 0, &spc->sc_romh); 284 if (rc != 0) { 285 printf("%s: can't map STI ROM (%d)\n", 286 sc->sc_dev.dv_xname, rc); 287 goto fail2; 288 } 289 290 return (0); 291 292 fail: 293 bus_space_unmap(pa->pa_memt, romh, romsize); 294 fail2: 295 sti_pci_disable_rom(sc); 296 297 return (rc); 298 } 299 300 /* 301 * Decode a BAR register. 302 */ 303 int 304 sti_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region, 305 int bar) 306 { 307 bus_addr_t addr; 308 bus_size_t size; 309 u_int32_t cf; 310 int rc; 311 312 if (bar == 0) { 313 sc->bases[region] = 0; 314 return (0); 315 } 316 317 #ifdef DIAGNOSTIC 318 if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) { 319 sti_pci_disable_rom(sc); 320 printf("%s: unexpected bar %02x for region %d\n", 321 sc->sc_dev.dv_xname, bar, region); 322 sti_pci_enable_rom(sc); 323 } 324 #endif 325 326 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 327 328 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 329 rc = pci_io_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size); 330 else 331 rc = pci_mem_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size, 332 NULL); 333 334 if (rc != 0) { 335 sti_pci_disable_rom(sc); 336 printf("%s: invalid bar %02x for region %d\n", 337 sc->sc_dev.dv_xname, bar, region); 338 sti_pci_enable_rom(sc); 339 return (rc); 340 } 341 342 sc->bases[region] = addr; 343 return (0); 344 } 345 346 /* 347 * Enable PCI ROM. 348 */ 349 void 350 sti_pci_enable_rom(struct sti_softc *sc) 351 { 352 struct sti_pci_softc *spc = (struct sti_pci_softc *)sc; 353 pcireg_t address; 354 355 if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 356 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG); 357 address |= PCI_ROM_ENABLE; 358 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address); 359 SET(sc->sc_flags, STI_ROM_ENABLED); 360 } 361 } 362 363 /* 364 * Disable PCI ROM. 365 */ 366 void 367 sti_pci_disable_rom(struct sti_softc *sc) 368 { 369 struct sti_pci_softc *spc = (struct sti_pci_softc *)sc; 370 pcireg_t address; 371 372 if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) { 373 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG); 374 address &= ~PCI_ROM_ENABLE; 375 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address); 376 377 CLR(sc->sc_flags, STI_ROM_ENABLED); 378 } 379 } 380