1 /* $NetBSD: ofw_autoconf.c,v 1.29 2025/11/10 02:20:47 macallan Exp $ */ 2 /* 3 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 4 * Copyright (C) 1995, 1996 TooLs GmbH. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by TooLs GmbH. 18 * 4. The name of TooLs GmbH may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: ofw_autoconf.c,v 1.29 2025/11/10 02:20:47 macallan Exp $"); 35 36 #ifdef ofppc 37 #include "gtpci.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 #include <sys/reboot.h> 44 #include <sys/systm.h> 45 46 #include <uvm/uvm_extern.h> 47 48 #include <machine/autoconf.h> 49 #include <sys/bus.h> 50 51 #include <dev/ofw/openfirm.h> 52 #include <dev/marvell/marvellvar.h> 53 #include <dev/pci/pcireg.h> 54 #include <dev/pci/pcivar.h> 55 #if NGTPCI > 0 56 #include <dev/marvell/gtpcivar.h> 57 #endif 58 #include <dev/scsipi/scsi_all.h> 59 #include <dev/scsipi/scsipi_all.h> 60 #include <dev/scsipi/scsiconf.h> 61 #include <dev/ata/atavar.h> 62 #include <dev/ic/wdcvar.h> 63 64 #include <dev/wscons/wsconsio.h> 65 #include <dev/wscons/wsdisplayvar.h> 66 #include <dev/rasops/rasops.h> 67 #include <powerpc/oea/ofw_rasconsvar.h> 68 #include <powerpc/ofw_machdep.h> 69 70 #include <machine/pci_machdep.h> 71 72 #include <prop/proplib.h> 73 74 #include "wsdisplay.h" 75 76 extern char bootpath[256]; 77 char cbootpath[256]; 78 static int boot_node = 0; /* points at boot device if we netboot */ 79 80 static void canonicalize_bootpath(void); 81 82 /* 83 * Determine device configuration for a machine. 84 */ 85 void 86 cpu_configure(void) 87 { 88 #if NWSDISPLAY > 0 89 rascons_add_rom_font(); 90 #endif 91 init_interrupt(); 92 canonicalize_bootpath(); 93 94 if (config_rootfound("mainbus", NULL) == NULL) 95 panic("configure: mainbus not configured"); 96 97 genppc_cpu_configure(); 98 } 99 100 static void 101 canonicalize_bootpath(void) 102 { 103 int node, len; 104 char *p, *lastp; 105 char last[32], type[32]; 106 107 /* 108 * If the bootpath doesn't start with a / then it isn't 109 * an OFW path and probably is an alias, so look up the alias 110 * and regenerate the full bootpath so device_register will work. 111 */ 112 if (bootpath[0] != '/' && bootpath[0] != '\0') { 113 int aliases = OF_finddevice("/aliases"); 114 char tmpbuf[100]; 115 char aliasbuf[256]; 116 if (aliases != 0) { 117 char *cp1, *cp2, *cp; 118 char saved_ch = '\0'; 119 cp1 = strchr(bootpath, ':'); 120 cp2 = strchr(bootpath, ','); 121 cp = cp1; 122 if (cp1 == NULL || (cp2 != NULL && cp2 < cp1)) 123 cp = cp2; 124 tmpbuf[0] = '\0'; 125 if (cp != NULL) { 126 strcpy(tmpbuf, cp); 127 saved_ch = *cp; 128 *cp = '\0'; 129 } 130 len = OF_getprop(aliases, bootpath, aliasbuf, 131 sizeof(aliasbuf)); 132 if (len > 0) { 133 if (aliasbuf[len-1] == '\0') 134 len--; 135 memcpy(bootpath, aliasbuf, len); 136 strcpy(&bootpath[len], tmpbuf); 137 } else { 138 *cp = saved_ch; 139 } 140 } 141 } 142 143 /* 144 * Strip kernel name. bootpath contains "OF-path"/"kernel". 145 * 146 * for example: 147 * /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd (OF-1.x) 148 * /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new (OF-3.x) 149 */ 150 strcpy(cbootpath, bootpath); 151 152 if ((node = OF_finddevice("/options")) == -1 || 153 OF_getprop(node, "qemu_boot_hack", type, sizeof(type) - 1) == -1 || 154 type[0] != 'y') { 155 while ((node = OF_finddevice(cbootpath)) == -1) { 156 if ((p = strrchr(cbootpath, '/')) == NULL) 157 break; 158 *p = '\0'; 159 } 160 } else { 161 node = -1; 162 } 163 164 printf("bootpath: %s\n", bootpath); 165 if (node == -1) { 166 /* Cannot canonicalize... use bootpath anyway. */ 167 strcpy(cbootpath, bootpath); 168 169 return; 170 } 171 172 /* see if we netbooted */ 173 len = OF_getprop(node, "device_type", type, sizeof(type) - 1); 174 if (len > -1) { 175 type[len] = 0; 176 if (strcmp(type, "network") == 0) { 177 boot_node = node; 178 } 179 } 180 181 /* 182 * cbootpath is a valid OF path. Use package-to-path to 183 * canonicalize pathname. 184 */ 185 186 /* Back up the last component for later use. */ 187 if ((p = strrchr(cbootpath, '/')) != NULL) 188 strcpy(last, p + 1); 189 else 190 last[0] = '\0'; 191 192 memset(cbootpath, 0, sizeof(cbootpath)); 193 OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1); 194 195 /* 196 * OF_1.x (at least) always returns addr == 0 for 197 * SCSI disks (i.e. "/bandit (at) .../.../sd@0,0"). 198 * also check for .../disk@ which some Adaptec firmware uses 199 */ 200 lastp = strrchr(cbootpath, '/'); 201 if (lastp != NULL) { 202 lastp++; 203 if ((strncmp(lastp, "sd@", 3) == 0 204 && strncmp(last, "sd@", 3) == 0) || 205 (strncmp(lastp, "disk@", 5) == 0 206 && strncmp(last, "disk@", 5) == 0)) 207 strcpy(lastp, last); 208 } else { 209 lastp = cbootpath; 210 } 211 212 /* 213 * At this point, cbootpath contains like: 214 * "/pci@80000000/mac-io@10/ata-3@20000/disk" 215 * 216 * The last component may have no address... so append it. 217 */ 218 if (strchr(lastp, '@') == NULL) { 219 /* Append it. */ 220 if ((p = strrchr(last, '@')) != NULL) 221 strcat(cbootpath, p); 222 } 223 224 if ((p = strrchr(lastp, ':')) != NULL) { 225 *p++ = '\0'; 226 /* booted_partition = *p - '0'; XXX correct? */ 227 } 228 } 229 230 /* 231 * device_register is called from config_attach as each device is 232 * attached. We use it to find the NetBSD device corresponding to the 233 * known OF boot device. 234 */ 235 void 236 ofw_device_register(device_t dev, void *aux) 237 { 238 static device_t parent; 239 static char *bp = bootpath + 1, *cp = cbootpath; 240 unsigned long addr, addr2; 241 char *p; 242 #if NGTPCI > 0 243 struct powerpc_bus_space *gtpci_mem_bs_tag = NULL; 244 #endif 245 246 /* Skip over devices not represented in the OF tree. */ 247 if (device_is_a(dev, "mainbus")) { 248 parent = dev; 249 return; 250 } 251 252 /* skip over CPUs */ 253 if (device_is_a(dev, "cpu")) { 254 return; 255 } 256 257 if (device_is_a(dev, "valkyriefb")) { 258 struct confargs *ca = aux; 259 prop_dictionary_t dict; 260 261 dict = device_properties(dev); 262 copy_disp_props(dev, ca->ca_node, dict); 263 } 264 265 /* cannot read useful display properties for platinum */ 266 if (device_is_a(dev, "platinumfb")) { 267 return; 268 } 269 270 #if NGTPCI > 0 271 if (device_is_a(dev, "gtpci")) { 272 extern struct gtpci_prot gtpci0_prot, gtpci1_prot; 273 extern struct powerpc_bus_space 274 gtpci0_io_bs_tag, gtpci0_mem_bs_tag, 275 gtpci1_io_bs_tag, gtpci1_mem_bs_tag; 276 extern struct genppc_pci_chipset 277 genppc_gtpci0_chipset, genppc_gtpci1_chipset; 278 279 struct marvell_attach_args *mva = aux; 280 struct gtpci_prot *gtpci_prot; 281 struct powerpc_bus_space *gtpci_io_bs_tag; 282 struct genppc_pci_chipset *genppc_gtpci_chipset; 283 prop_dictionary_t dict = device_properties(dev); 284 prop_data_t prot, io_bs_tag, mem_bs_tag, pc; 285 int iostart, ioend; 286 287 if (mva->mva_unit == 0) { 288 gtpci_prot = >pci0_prot; 289 gtpci_io_bs_tag = >pci0_io_bs_tag; 290 gtpci_mem_bs_tag = >pci0_mem_bs_tag; 291 genppc_gtpci_chipset = &genppc_gtpci0_chipset; 292 iostart = 0; 293 ioend = 0; 294 } else { 295 gtpci_prot = >pci1_prot; 296 gtpci_io_bs_tag = >pci1_io_bs_tag; 297 gtpci_mem_bs_tag = >pci1_mem_bs_tag; 298 genppc_gtpci_chipset = &genppc_gtpci1_chipset; 299 iostart = 0x1400; 300 ioend = 0xffff; 301 } 302 303 prot = prop_data_create_data_nocopy( 304 gtpci_prot, sizeof(struct gtpci_prot)); 305 KASSERT(prot != NULL); 306 prop_dictionary_set(dict, "prot", prot); 307 prop_object_release(prot); 308 309 io_bs_tag = prop_data_create_data_nocopy( 310 gtpci_io_bs_tag, sizeof(struct powerpc_bus_space)); 311 KASSERT(io_bs_tag != NULL); 312 prop_dictionary_set(dict, "io-bus-tag", io_bs_tag); 313 prop_object_release(io_bs_tag); 314 mem_bs_tag = prop_data_create_data_nocopy( 315 gtpci_mem_bs_tag, sizeof(struct powerpc_bus_space)); 316 KASSERT(mem_bs_tag != NULL); 317 prop_dictionary_set(dict, "mem-bus-tag", mem_bs_tag); 318 prop_object_release(mem_bs_tag); 319 320 genppc_gtpci_chipset->pc_conf_v = device_private(dev); 321 pc = prop_data_create_data_nocopy(genppc_gtpci_chipset, 322 sizeof(struct genppc_pci_chipset)); 323 KASSERT(pc != NULL); 324 prop_dictionary_set(dict, "pci-chipset", pc); 325 prop_object_release(pc); 326 327 prop_dictionary_set_uint64(dict, "iostart", iostart); 328 prop_dictionary_set_uint64(dict, "ioend", ioend); 329 prop_dictionary_set_uint64(dict, "memstart", 330 gtpci_mem_bs_tag->pbs_base); 331 prop_dictionary_set_uint64(dict, "memend", 332 gtpci_mem_bs_tag->pbs_limit - 1); 333 prop_dictionary_set_uint32(dict, "cache-line-size", 334 CACHELINESIZE); 335 } 336 #endif 337 if (device_is_a(dev, "atapibus") || 338 #ifndef PMAC_G5 339 device_is_a(dev, "pci") || 340 #endif 341 device_is_a(dev, "scsibus") || device_is_a(dev, "atabus")) 342 return; 343 344 if (device_is_a(device_parent(dev), "pci")) { 345 struct pci_attach_args *pa = aux; 346 prop_dictionary_t dict; 347 prop_bool_t b; 348 int node; 349 char name[32]; 350 351 dict = device_properties(dev); 352 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 353 354 /* enable configuration of irq 14/15 for VIA native IDE */ 355 if (device_is_a(dev, "viaide") && 356 strncmp(model_name, "Pegasos", 7) == 0) { 357 b = prop_bool_create(true); 358 KASSERT(b != NULL); 359 (void)prop_dictionary_set(dict, 360 "use-compat-native-irq", b); 361 prop_object_release(b); 362 } 363 364 if (node != 0) { 365 int pci_class = 0; 366 367 prop_dictionary_set_uint32(dict, "device_node", node); 368 369 if (node == boot_node) { 370 /* we netbooted from whatever this is */ 371 booted_device = dev; 372 } 373 /* see if this is going to be console */ 374 memset(name, 0, sizeof(name)); 375 OF_getprop(node, "device_type", name, sizeof(name)); 376 377 OF_getprop(node, "class-code", &pci_class, 378 sizeof pci_class); 379 pci_class = (pci_class >> 16) & 0xff; 380 381 if (strcmp(name, "display") == 0 || 382 strcmp(name, "ATY,DDParent") == 0 || 383 pci_class == PCI_CLASS_DISPLAY) { 384 /* setup display properties for fb driver */ 385 prop_dictionary_set_bool(dict, "is_console", 0); 386 copy_disp_props(dev, node, dict); 387 } 388 } 389 #ifdef macppc 390 /* 391 * XXX 392 * some macppc boxes have onboard devices where parts or all of 393 * the PCI_INTERRUPT register are hardwired to 0 394 */ 395 if (pa->pa_intrpin == 0) 396 pa->pa_intrpin = 1; 397 #endif 398 } 399 400 if (booted_device) 401 return; 402 403 /* 404 * Skip over devices that are really just layers of NetBSD 405 * autoconf(9) we should just skip as they do not have any 406 * OFW devices. 407 * XXX except on G5, where we have /ht/pci* instead of /pci* 408 */ 409 if (device_is_a(device_parent(dev), "atapibus") || 410 device_is_a(device_parent(dev), "atabus") || 411 #ifndef PMAC_G5 412 device_is_a(device_parent(dev), "pci") || 413 #endif 414 device_is_a(device_parent(dev), "scsibus")) { 415 if (device_parent(device_parent(dev)) != parent) { 416 return; 417 } 418 } else { 419 if (device_parent(dev) != parent) 420 return; 421 } 422 423 /* 424 * Get the address part of the current path component. The 425 * last component of the canonical bootpath may have no 426 * address (eg, "disk"), in which case we need to get the 427 * address from the original bootpath instead. 428 */ 429 p = strchr(cp, '@'); 430 if (!p) { 431 if (bp) 432 p = strchr(bp, '@'); 433 if (!p) 434 addr = 0; 435 else 436 addr = strtoul(p + 1, &p, 16); 437 } else 438 addr = strtoul(p + 1, &p, 16); 439 440 /* if the current path has more address, grab that too */ 441 if (p && *p == ',') 442 addr2 = strtoul(p + 1, &p, 16); 443 else 444 addr2 = 0; 445 446 if (device_is_a(device_parent(dev), "mainbus")) { 447 struct confargs *ca = aux; 448 if (strcmp(ca->ca_name, "ofw") == 0) /* XXX */ 449 return; 450 if (strcmp(ca->ca_name, "gt") == 0) 451 parent = dev; 452 if (addr != ca->ca_reg[0]) 453 return; 454 if (addr2 != 0 && addr2 != ca->ca_reg[1]) 455 return; 456 } else if (device_is_a(device_parent(dev), "gt")) { 457 /* 458 * Special handle for MV64361 on PegasosII(ofppc). 459 */ 460 if (device_is_a(dev, "mvgbec")) { 461 /* 462 * Fix cp to /port@N from /ethernet/portN. (N is 0...2) 463 */ 464 static char fix_cp[8] = "/port@N"; 465 466 if (strlen(cp) != 15 || 467 strncmp(cp, "/ethernet/port", 14) != 0) 468 return; 469 fix_cp[7] = *(cp + 15); 470 p = fix_cp; 471 #if NGTPCI > 0 472 } else if (device_is_a(dev, "gtpci")) { 473 if (gtpci_mem_bs_tag != NULL && 474 addr != gtpci_mem_bs_tag->pbs_base) 475 return; 476 #endif 477 } else 478 return; 479 } else if (device_is_a(device_parent(dev), "pci")) { 480 struct pci_attach_args *pa = aux; 481 482 if (addr != pa->pa_device || 483 addr2 != pa->pa_function) 484 return; 485 } else if (device_is_a(device_parent(dev), "obio")) { 486 struct confargs *ca = aux; 487 488 if (addr != ca->ca_reg[0]) 489 return; 490 } else if (device_is_a(device_parent(dev), "scsibus") || 491 device_is_a(device_parent(dev), "atapibus")) { 492 struct scsipibus_attach_args *sa = aux; 493 494 /* periph_target is target for scsi, drive # for atapi */ 495 if (addr != sa->sa_periph->periph_target) 496 return; 497 } else if (device_is_a(device_parent(device_parent(dev)), "pciide") || 498 device_is_a(device_parent(device_parent(dev)), "viaide") || 499 device_is_a(device_parent(device_parent(dev)), "slide")) { 500 struct ata_device *adev = aux; 501 502 if (addr != adev->adev_channel || 503 addr2 != adev->adev_drv_data->drive) 504 return; 505 } else if (device_is_a(device_parent(device_parent(dev)), "wdc")) { 506 struct ata_device *adev = aux; 507 508 if (addr != adev->adev_drv_data->drive) 509 return; 510 } else if (device_is_a(dev, "pci")) { 511 if (addr != device_unit(dev)) 512 return; 513 } else if (device_is_a(device_parent(dev), "atabus")) { 514 /* 515 * XXX 516 * on svwsata this is the channel number and we ignore the 517 * drive number which is always 0 anyway 518 * needs to be revisited for other (S)ATA cards 519 */ 520 struct ata_device *adev = aux; 521 if (addr != adev->adev_channel) 522 return; 523 /* we have our match, cut off the rest */ 524 if (p) *p = 0; 525 } else 526 return; 527 528 /* If we reach this point, then dev is a match for the current 529 * path component. 530 */ 531 if (p && *p) { 532 parent = dev; 533 cp = p; 534 bp = strchr(bp, '/'); 535 if (bp) 536 bp++; 537 return; 538 } else { 539 booted_device = dev; 540 booted_partition = 0; /* XXX -- should be extracted from bootpath */ 541 return; 542 } 543 } 544 545 /* 546 * Setup root device. 547 * Configure swap area. 548 */ 549 void 550 cpu_rootconf(void) 551 { 552 printf("boot device: %s\n", 553 booted_device ? device_xname(booted_device) : "<unknown>"); 554 555 rootconf(); 556 } 557 558 /* 559 * Find OF-device corresponding to the PCI device. 560 */ 561 int 562 pcidev_to_ofdev(pci_chipset_tag_t pc, pcitag_t tag) 563 { 564 int bus, dev, func; 565 u_int reg[5]; 566 int p, q; 567 int l, b, d, f; 568 569 pci_decompose_tag(pc, tag, &bus, &dev, &func); 570 571 for (q = OF_peer(0); q; q = p) { 572 l = OF_getprop(q, "assigned-addresses", reg, sizeof(reg)); 573 if (l > 4) { 574 b = (reg[0] >> 16) & 0xff; 575 d = (reg[0] >> 11) & 0x1f; 576 f = (reg[0] >> 8) & 0x07; 577 578 if (b == bus && d == dev && f == func) 579 return q; 580 } 581 if ((p = OF_child(q))) 582 continue; 583 while (q) { 584 if ((p = OF_peer(q))) 585 break; 586 q = OF_parent(q); 587 } 588 } 589 return 0; 590 } 591