1 /* $NetBSD: p5pb.c,v 1.21 2023/12/20 00:40:42 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2011, 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/time.h> 35 #include <sys/systm.h> 36 #include <sys/errno.h> 37 #include <sys/device.h> 38 #include <sys/kmem.h> 39 40 #include <uvm/uvm_extern.h> 41 42 #define _M68K_BUS_DMA_PRIVATE 43 #include <machine/bus.h> 44 #include <machine/cpu.h> 45 46 #include <m68k/bus_dma.h> 47 #include <amiga/dev/zbusvar.h> 48 #include <amiga/dev/p5busvar.h> 49 #include <amiga/pci/p5pbreg.h> 50 #include <amiga/pci/p5pbvar.h> 51 #include <amiga/pci/p5membarvar.h> 52 53 #include <dev/pci/pcivar.h> 54 #include <dev/pci/pcireg.h> 55 #include <dev/pci/pcidevs.h> 56 #ifdef PCI_NETBSD_CONFIGURE 57 #include <dev/pci/pciconf.h> 58 #endif /* PCI_NETBSD_CONFIGURE */ 59 60 #include "opt_p5pb.h" 61 #include "opt_pci.h" 62 #include "genfb.h" 63 64 /* Initial CVPPC/BVPPC resolution as configured by the firmware */ 65 #define P5GFX_WIDTH 640 66 #define P5GFX_HEIGHT 480 67 #define P5GFX_DEPTH 8 68 #define P5GFX_LINEBYTES 640 69 70 struct m68k_bus_dma_tag p5pb_bus_dma_tag = { 71 0, 72 0, 73 _bus_dmamap_create, 74 _bus_dmamap_destroy, 75 _bus_dmamap_load_direct, 76 _bus_dmamap_load_mbuf_direct, 77 _bus_dmamap_load_uio_direct, 78 _bus_dmamap_load_raw_direct, 79 _bus_dmamap_unload, 80 _bus_dmamap_sync, 81 _bus_dmamem_alloc, 82 _bus_dmamem_free, 83 _bus_dmamem_map, 84 _bus_dmamem_unmap, 85 _bus_dmamem_mmap 86 }; 87 88 static int p5pb_match(device_t, cfdata_t, void *); 89 static void p5pb_attach(device_t, device_t, void *); 90 void p5pb_set_props(struct p5pb_softc *); 91 pcireg_t p5pb_pci_conf_read(pci_chipset_tag_t, pcitag_t, int); 92 void p5pb_pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 93 int p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t, int); 94 int p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t, int); 95 int p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t, int); 96 int p5pb_pci_conf_hook(pci_chipset_tag_t, int, int, int, pcireg_t); 97 void p5pb_pci_attach_hook (device_t, device_t, 98 struct pcibus_attach_args *); 99 pcitag_t p5pb_pci_make_tag(pci_chipset_tag_t, int, int, int); 100 void p5pb_pci_decompose_tag(pci_chipset_tag_t, pcitag_t, 101 int *, int *, int *); 102 int p5pb_pci_intr_map(const struct pci_attach_args *, 103 pci_intr_handle_t *); 104 bool p5pb_bus_map_memio(struct p5pb_softc *); 105 bool p5pb_bus_map_conf(struct p5pb_softc *); 106 uint8_t p5pb_find_resources(struct p5pb_softc *); 107 static bool p5pb_identify_bridge(struct p5pb_softc *); 108 void p5pb_membar_grex(struct p5pb_softc *); 109 static bool p5pb_cvppc_probe(struct p5pb_softc *); 110 #ifdef PCI_NETBSD_CONFIGURE 111 bool p5pb_bus_reconfigure(struct p5pb_softc *); 112 #endif /* PCI_NETBSD_CONFIGURE */ 113 #ifdef P5PB_DEBUG 114 void p5pb_usable_ranges(struct p5pb_softc *); 115 void p5pb_badaddr_range(struct p5pb_softc *, bus_space_tag_t, 116 bus_addr_t, size_t); 117 void p5pb_conf_search(struct p5pb_softc *, uint16_t); 118 #endif /* P5PB_DEBUG */ 119 120 CFATTACH_DECL_NEW(p5pb, sizeof(struct p5pb_softc), 121 p5pb_match, p5pb_attach, NULL, NULL); 122 123 static int 124 p5pb_match(device_t parent, cfdata_t cf, void *aux) 125 { 126 struct p5bus_attach_args *p5baa; 127 128 p5baa = (struct p5bus_attach_args *) aux; 129 130 if (strcmp(p5baa->p5baa_name, "p5pb") == 0) 131 return 1; 132 133 return 0; 134 } 135 136 static void 137 p5pb_attach(device_t parent, device_t self, void *aux) 138 { 139 struct p5pb_softc *sc; 140 struct pcibus_attach_args pba; 141 142 sc = device_private(self); 143 sc->sc_dev = self; 144 sc->p5baa = (struct p5bus_attach_args *) aux; 145 146 pci_chipset_tag_t pc = &sc->apc; 147 148 if (!p5pb_bus_map_conf(sc)) { 149 aprint_error_dev(self, 150 "couldn't map PCI configuration space\n"); 151 return; 152 } 153 154 if (!p5pb_identify_bridge(sc)) { 155 return; 156 } 157 158 if (sc->bridge_type == P5PB_BRIDGE_CVPPC) { 159 sc->pci_mem_lowest = P5BUS_PCI_MEM_BASE; 160 sc->pci_mem_highest = P5BUS_PCI_MEM_BASE + P5BUS_PCI_MEM_SIZE; 161 } else { 162 p5pb_membar_grex(sc); 163 } 164 165 if (!p5pb_bus_map_memio(sc)) { 166 aprint_error_dev(self, 167 "couldn't map PCI I/O and memory space\n"); 168 return; 169 } 170 171 #ifdef P5PB_DEBUG 172 aprint_normal("p5pb: map conf %x -> %x, io %x -> %x, mem %x -> %x\n", 173 kvtop((void*) sc->pci_conf_area.base), sc->pci_conf_area.base, 174 kvtop((void*) sc->pci_io_area.base), sc->pci_io_area.base, 175 kvtop((void*) sc->pci_mem_area.base), sc->pci_mem_area.base ); 176 #endif 177 178 /* Initialize the PCI chipset tag. */ 179 180 if (sc->bridge_type == P5PB_BRIDGE_GREX1200) 181 sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex1200; 182 else if (sc->bridge_type == P5PB_BRIDGE_GREX4000) 183 sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_grex4000; 184 else 185 sc->apc.pc_bus_maxdevs = p5pb_pci_bus_maxdevs_cvppc; 186 187 sc->apc.pc_conf_v = (void*) pc; 188 sc->apc.pc_make_tag = amiga_pci_make_tag; 189 sc->apc.pc_decompose_tag = amiga_pci_decompose_tag; 190 sc->apc.pc_conf_read = p5pb_pci_conf_read; 191 sc->apc.pc_conf_write = p5pb_pci_conf_write; 192 sc->apc.pc_conf_hook = p5pb_pci_conf_hook; 193 sc->apc.pc_conf_interrupt = amiga_pci_conf_interrupt; 194 sc->apc.pc_attach_hook = p5pb_pci_attach_hook; 195 196 sc->apc.pc_intr_map = p5pb_pci_intr_map; 197 sc->apc.pc_intr_string = amiga_pci_intr_string; 198 sc->apc.pc_intr_establish = amiga_pci_intr_establish; 199 sc->apc.pc_intr_disestablish = amiga_pci_intr_disestablish; 200 201 #ifdef PCI_NETBSD_CONFIGURE 202 /* Never reconfigure the bus on CVPPC/BVPPC, avoid the fb breakage. */ 203 if (sc->bridge_type != P5PB_BRIDGE_CVPPC) { 204 p5pb_bus_reconfigure(sc); 205 } 206 #endif /* PCI_NETBSD_CONFIGURE */ 207 208 /* Initialize the bus attachment structure. */ 209 210 pba.pba_iot = &(sc->pci_io_area); 211 pba.pba_memt = &(sc->pci_mem_area); 212 pba.pba_dmat = &p5pb_bus_dma_tag; 213 pba.pba_dmat64 = NULL; 214 pba.pba_pc = pc; 215 pba.pba_flags = PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY; 216 pba.pba_bus = 0; 217 pba.pba_bridgetag = NULL; 218 219 p5pb_set_props(sc); 220 221 config_found(self, &pba, pcibusprint, CFARGS_NONE); 222 } 223 224 /* 225 * Try to detect what kind of bridge are we dealing with. 226 */ 227 static bool 228 p5pb_identify_bridge(struct p5pb_softc *sc) 229 { 230 int pcires_count; /* Number of AutoConfig(TM) PCI resources */ 231 232 pcires_count = p5pb_find_resources(sc); 233 234 switch (pcires_count) { 235 case 0: 236 /* 237 * Zero AutoConfig(TM) PCI resources, means that there's nothing 238 * OR there's a CVPPC/BVPPC with a pre-44.69 firmware. 239 */ 240 if (p5pb_cvppc_probe(sc)) { 241 sc->bridge_type = P5PB_BRIDGE_CVPPC; 242 aprint_normal(": Phase5 CVPPC/BVPPC PCI bridge\n"); 243 } else { 244 aprint_normal(": no PCI bridges detected\n"); 245 return false; 246 } 247 break; 248 case 6: 249 /* 250 * We have a slight possibility, that there's a CVPPC/BVPPC with 251 * the new firmware. So check for it first. 252 */ 253 if (p5pb_cvppc_probe(sc)) { 254 /* New firmware, treat as one-slot GREX. */ 255 sc->bridge_type = P5PB_BRIDGE_CVPPC; 256 aprint_normal( 257 ": Phase5 CVPPC/BVPPC PCI bridge (44.69/44.71)\n"); 258 break; 259 } 260 default: 261 /* We have a G-REX surely. */ 262 263 if (sc->p5baa->p5baa_cardtype == P5_CARDTYPE_CS) { 264 sc->bridge_type = P5PB_BRIDGE_GREX4000; 265 aprint_normal(": DCE G-REX 4000 PCI bridge\n"); 266 } else { 267 sc->bridge_type = P5PB_BRIDGE_GREX1200; 268 aprint_normal(": DCE G-REX 1200 PCI bridge\n"); 269 } 270 break; 271 } 272 return true; 273 } 274 275 /* 276 * Find AutoConfig(TM) resuorces (for boards running G-REX firmware). Return the 277 * total number of found resources. 278 */ 279 uint8_t 280 p5pb_find_resources(struct p5pb_softc *sc) 281 { 282 uint8_t i, rv; 283 struct p5pb_autoconf_entry *auto_entry; 284 struct p5membar_softc *membar_sc; 285 device_t p5membar_dev; 286 287 rv = 0; 288 289 TAILQ_INIT(&sc->auto_bars); 290 291 /* 255 should be enough for everybody */ 292 for(i = 0; i < 255; i++) { 293 294 if ((p5membar_dev = 295 device_find_by_driver_unit("p5membar", i)) != NULL) { 296 297 rv++; 298 299 membar_sc = device_private(p5membar_dev); 300 if (membar_sc->sc_type == P5MEMBAR_TYPE_INTERNAL) 301 continue; 302 303 auto_entry = 304 kmem_alloc(sizeof(struct p5pb_autoconf_entry), 305 KM_SLEEP); 306 307 auto_entry->base = membar_sc->sc_base; 308 auto_entry->size = membar_sc->sc_size; 309 310 TAILQ_INSERT_TAIL(&sc->auto_bars, auto_entry, entries); 311 } 312 } 313 return rv; 314 } 315 316 /* 317 * Set properties needed to support fb driver. These are read later during 318 * autoconfg in device_register(). Needed for CVPPC/BVPPC. 319 */ 320 void 321 p5pb_set_props(struct p5pb_softc *sc) 322 { 323 #if NGENFB > 0 324 prop_dictionary_t dict; 325 device_t dev; 326 327 dev = sc->sc_dev; 328 dict = device_properties(dev); 329 330 /* genfb needs additional properties, like virtual, physical address */ 331 /* XXX: currently genfb is supported only on CVPPC/BVPPC */ 332 prop_dictionary_set_uint64(dict, "virtual_address", 333 sc->pci_mem_area.base); 334 prop_dictionary_set_uint64(dict, "address", 335 kvtop((void*) sc->pci_mem_area.base)); 336 #endif 337 } 338 339 pcireg_t 340 p5pb_pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 341 { 342 uint32_t data; 343 uint32_t bus, dev, func; 344 uint32_t offset; 345 346 if ((unsigned int)reg >= PCI_CONF_SIZE) 347 return 0xFFFFFFFF; 348 349 pci_decompose_tag(pc, tag, &bus, &dev, &func); 350 351 offset = (OFF_PCI_DEVICE << dev) + reg; 352 353 if(func == 0) /* ugly, ugly hack */ 354 offset += 0; 355 else if(func == 1) 356 offset += OFF_PCI_FUNCTION; 357 else 358 return 0xFFFFFFFF; 359 360 if(badaddr((void *)__UNVOLATILE(((uint32_t) 361 bus_space_vaddr(pc->pci_conf_datat, pc->pci_conf_datah) 362 + offset)))) 363 return 0xFFFFFFFF; 364 365 data = bus_space_read_4(pc->pci_conf_datat, pc->pci_conf_datah, 366 offset); 367 #ifdef P5PB_DEBUG_CONF 368 aprint_normal("p5pb conf read va: %lx, bus: %d, dev: %d, " 369 "func: %d, reg: %d -r-> data %x\n", 370 pc->pci_conf_datah, bus, dev, func, reg, data); 371 #endif 372 return data; 373 } 374 375 void 376 p5pb_pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t val) 377 { 378 uint32_t bus, dev, func; 379 uint32_t offset; 380 381 if ((unsigned int)reg >= PCI_CONF_SIZE) 382 return; 383 384 pci_decompose_tag(pc, tag, &bus, &dev, &func); 385 386 offset = (OFF_PCI_DEVICE << dev) + reg; 387 388 if(func == 0) /* ugly, ugly hack */ 389 offset += 0; 390 else if(func == 1) 391 offset += OFF_PCI_FUNCTION; 392 else 393 return; 394 395 if(badaddr((void *)__UNVOLATILE(((uint32_t) 396 bus_space_vaddr(pc->pci_conf_datat, pc->pci_conf_datah) 397 + offset)))) 398 return; 399 400 bus_space_write_4(pc->pci_conf_datat, pc->pci_conf_datah, 401 offset, val); 402 #ifdef P5PB_DEBUG_CONF 403 aprint_normal("p5pb conf write va: %lx, bus: %d, dev: %d, " 404 "func: %d, reg: %d -w-> data %x\n", 405 pc->pci_conf_datah, bus, dev, func, reg, val); 406 #endif 407 408 } 409 410 int 411 p5pb_pci_bus_maxdevs_cvppc(pci_chipset_tag_t pc, int busno) 412 { 413 /* CVPPC/BVPPC has only 1 "slot". */ 414 return 1; 415 } 416 417 int 418 p5pb_pci_bus_maxdevs_grex4000(pci_chipset_tag_t pc, int busno) 419 { 420 /* G-REX 4000 has 4, G-REX 4000T has 3 slots? */ 421 return 4; 422 } 423 424 int 425 p5pb_pci_bus_maxdevs_grex1200(pci_chipset_tag_t pc, int busno) 426 { 427 /* G-REX 1200 has 5 slots. */ 428 return 4; /* XXX: 5 not yet! */ 429 } 430 431 void 432 p5pb_pci_attach_hook(device_t parent, device_t self, 433 struct pcibus_attach_args *pba) 434 { 435 } 436 437 int 438 p5pb_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 439 { 440 /* TODO: add sanity checking */ 441 442 *ihp = 2; 443 return 0; 444 } 445 446 /* Probe for CVPPC/BVPPC. */ 447 static bool 448 p5pb_cvppc_probe(struct p5pb_softc *sc) 449 { 450 bus_space_handle_t probe_h; 451 uint16_t prodid, manid; 452 void* data; 453 bool rv; 454 455 manid = 0; prodid = 0; 456 rv = false; 457 458 if (bus_space_map(sc->apc.pci_conf_datat, 0, 4, 0, &probe_h)) 459 return rv; 460 461 data = bus_space_vaddr(sc->apc.pci_conf_datat, probe_h); 462 463 if (badaddr((void *)__UNVOLATILE((uint32_t) data))) { 464 #ifdef P5PB_DEBUG_PROBE 465 aprint_normal("p5pb: CVPPC configuration space not usable!\n"); 466 #endif /* P5PB_DEBUG_PROBE */ 467 } else { 468 prodid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 0); 469 manid = bus_space_read_2(sc->apc.pci_conf_datat, probe_h, 2); 470 471 if ((prodid == P5PB_PM2_PRODUCT_ID) && 472 (manid == P5PB_PM2_VENDOR_ID)) 473 rv = true; 474 } 475 476 #ifdef P5PB_DEBUG_PROBE 477 aprint_normal("p5pb: CVPPC probe for PCI ID: %x, %x returns %d\n", 478 manid, prodid, (int) rv); 479 #endif /* P5PB_DEBUG_PROBE */ 480 481 bus_space_unmap(sc->apc.pci_conf_datat, probe_h, 4); 482 return rv; 483 } 484 485 #ifdef PCI_NETBSD_CONFIGURE 486 /* Reconfigure the bus. */ 487 bool 488 p5pb_bus_reconfigure(struct p5pb_softc *sc) 489 { 490 pci_chipset_tag_t pc; 491 492 pc = &sc->apc; 493 494 struct pciconf_resources *pcires = pciconf_resource_init(); 495 496 pciconf_resource_add(pcires, PCICONF_RESOURCE_IO, 497 0, P5BUS_PCI_IO_SIZE); 498 pciconf_resource_add(pcires, PCICONF_RESOURCE_MEM, 499 sc->pci_mem_lowest, sc->pci_mem_highest - sc->pci_mem_lowest); 500 501 #ifdef P5PB_DEBUG 502 aprint_normal("p5pb: reconfiguring the bus!\n"); 503 #endif /* P5PB_DEBUG */ 504 pci_configure_bus(pc, pcires, 0, CACHELINE_SIZE); 505 506 pciconf_resource_fini(pcires); 507 508 return true; /* TODO: better error handling */ 509 } 510 #endif /* PCI_NETBSD_CONFIGURE */ 511 512 /* Determine the PCI memory space (done G-REX-style). */ 513 void 514 p5pb_membar_grex(struct p5pb_softc *sc) 515 { 516 struct p5pb_autoconf_entry *membar_entry; 517 uint32_t bar_address; 518 519 sc->pci_mem_lowest = 0xFFFFFFFF; 520 sc->pci_mem_highest = 0; 521 522 /* Iterate over membar entries to find lowest and highest address. */ 523 TAILQ_FOREACH(membar_entry, &sc->auto_bars, entries) { 524 525 bar_address = (uint32_t) membar_entry->base; 526 if ((bar_address + membar_entry->size) > sc->pci_mem_highest) 527 sc->pci_mem_highest = bar_address + membar_entry->size; 528 if (bar_address < sc->pci_mem_lowest) 529 sc->pci_mem_lowest = bar_address; 530 531 #ifdef P5PB_DEBUG_BAR 532 aprint_normal("p5pb: %d kB mem BAR at %p, hi = %x, lo = %x\n", 533 membar_entry->size / 1024, membar_entry->base, 534 sc->pci_mem_highest, sc->pci_mem_lowest); 535 #endif /* P5PB_DEBUG_BAR */ 536 } 537 538 aprint_normal("p5pb: %d kB PCI memory space (%8p to %8p)\n", 539 (sc->pci_mem_highest - sc->pci_mem_lowest) / 1024, 540 (void*) sc->pci_mem_lowest, (void*) sc->pci_mem_highest); 541 542 } 543 544 bool 545 p5pb_bus_map_conf(struct p5pb_softc *sc) 546 { 547 sc->pci_conf_area.base = (bus_addr_t) zbusmap( 548 (void *) P5BUS_PCI_CONF_BASE, P5BUS_PCI_CONF_SIZE); 549 sc->pci_conf_area.absm = &amiga_bus_stride_1; 550 551 sc->apc.pci_conf_datat = &(sc->pci_conf_area); 552 553 if (bus_space_map(sc->apc.pci_conf_datat, OFF_PCI_CONF_DATA, 554 P5BUS_PCI_CONF_SIZE, 0, &sc->apc.pci_conf_datah)) 555 return false; 556 557 return true; 558 } 559 560 /* Map I/O and memory space. */ 561 bool 562 p5pb_bus_map_memio(struct p5pb_softc *sc) 563 { 564 sc->pci_io_area.base = (bus_addr_t) zbusmap( 565 (void *) P5BUS_PCI_IO_BASE, P5BUS_PCI_IO_SIZE); 566 sc->pci_io_area.absm = &amiga_bus_stride_1swap; 567 568 sc->pci_mem_area.base = (bus_addr_t) zbusmap( 569 (void *) sc->pci_mem_lowest, 570 sc->pci_mem_highest - sc->pci_mem_lowest); 571 sc->pci_mem_area.absm = &amiga_bus_stride_1swap_abs; 572 573 return true; 574 } 575 576 int 577 p5pb_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, 578 int func, pcireg_t id) 579 { 580 /* XXX: What should we do on CVPPC/BVPPC? It breaks genfb. */ 581 582 return PCI_CONF_DEFAULT; 583 } 584 585 #ifdef P5PB_DEBUG 586 /* Check which config and I/O ranges are usable. */ 587 void 588 p5pb_usable_ranges(struct p5pb_softc *sc) 589 { 590 p5pb_badaddr_range(sc, &(sc->pci_conf_area), 0, P5BUS_PCI_CONF_SIZE); 591 p5pb_badaddr_range(sc, &(sc->pci_io_area), 0, P5BUS_PCI_IO_SIZE); 592 } 593 594 void 595 p5pb_badaddr_range(struct p5pb_softc *sc, bus_space_tag_t bust, bus_addr_t base, 596 size_t len) 597 { 598 int i, state, prev_state; 599 bus_space_handle_t bush; 600 volatile void *data; 601 602 state = -1; 603 prev_state = -1; 604 605 bus_space_map(bust, base, len, 0, &bush); 606 607 aprint_normal("p5pb: badaddr range check from %x (%x) to %x (%x)\n", 608 (bus_addr_t) bush, /* start VA */ 609 (bus_addr_t) kvtop((void*) bush), /* start PA */ 610 (bus_addr_t) bush + len, /* end VA */ 611 (bus_addr_t) kvtop((void*) (bush + len)));/* end PA */ 612 613 data = bus_space_vaddr(bust, bush); 614 615 for(i = 0; i < len; i++) { 616 state = badaddr((void *)__UNVOLATILE(((uint32_t) data + i))); 617 if(state != prev_state) { 618 aprint_normal("p5pb: badaddr %p (%x) : %d\n", 619 (void*) ((uint32_t) data + i), 620 (bus_addr_t) kvtop((void*) ((uint32_t) data + i)), 621 state); 622 prev_state = state; 623 } 624 625 } 626 627 bus_space_unmap(bust, bush, len); 628 } 629 630 /* Search for 16-bit value in the configuration space. */ 631 void 632 p5pb_conf_search(struct p5pb_softc *sc, uint16_t val) 633 { 634 int i, state; 635 uint16_t readv; 636 void *va; 637 638 va = bus_space_vaddr(sc->apc.pci_conf_datat, sc->apc.pci_conf_datah); 639 640 for (i = 0; i < P5BUS_PCI_CONF_SIZE; i++) { 641 state = badaddr((void *)__UNVOLATILE(((uint32_t) va + i))); 642 if(state == 0) { 643 readv = bus_space_read_2(sc->apc.pci_conf_datat, 644 sc->apc.pci_conf_datah, i); 645 if(readv == val) 646 aprint_normal("p5pb: found val %x @ %x (%x)\n", 647 readv, (uint32_t) sc->apc.pci_conf_datah 648 + i, (bus_addr_t) kvtop((void*) 649 ((uint32_t) sc->apc.pci_conf_datah + i))); 650 } 651 } 652 } 653 654 #endif /* P5PB_DEBUG */ 655 656 #ifdef P5PB_CONSOLE 657 void 658 p5pb_device_register(device_t dev, void *aux) 659 { 660 prop_dictionary_t dict; 661 struct pci_attach_args *pa = aux; 662 663 if (device_parent(dev) && device_is_a(device_parent(dev), "pci")) { 664 665 dict = device_properties(dev); 666 667 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) { 668 669 /* Handle the CVPPC/BVPPC card... */ 670 if ( ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI) 671 && (PCI_PRODUCT(pa->pa_id) == 672 PCI_PRODUCT_TI_TVP4020) ) || 673 /* ...and 3Dfx Voodoo 3 in G-REX. */ 674 ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DFX) 675 && (PCI_PRODUCT(pa->pa_id) == 676 PCI_PRODUCT_3DFX_VOODOO3) )) { 677 678 prop_dictionary_set_uint32(dict, "width", 679 P5GFX_WIDTH); 680 681 prop_dictionary_set_uint32(dict, "height", 682 P5GFX_HEIGHT); 683 684 prop_dictionary_set_uint32(dict, "depth", 685 P5GFX_DEPTH); 686 687 #if NGENFB > 0 688 prop_dictionary_t parent_dict; 689 690 parent_dict = device_properties( 691 device_parent(device_parent(dev))); 692 693 prop_dictionary_set_uint32(dict, "linebytes", 694 P5GFX_LINEBYTES); 695 696 prop_dictionary_set(dict, "address", 697 prop_dictionary_get(parent_dict, 698 "address")); 699 prop_dictionary_set(dict, "virtual_address", 700 prop_dictionary_get(parent_dict, 701 "virtual_address")); 702 #endif 703 prop_dictionary_set_bool(dict, "is_console", 704 true); 705 } 706 } 707 } 708 } 709 #endif /* P5PB_CONSOLE */ 710