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