1 /* $NetBSD: ofw_autoconf.c,v 1.12 2010/06/09 04:41:43 kiyohara 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.12 2010/06/09 04:41:43 kiyohara 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 <machine/bus.h> 50 #include <machine/stdarg.h> 51 52 #include <dev/ofw/openfirm.h> 53 #include <dev/marvell/marvellvar.h> 54 #include <dev/pci/pcireg.h> 55 #include <dev/pci/pcivar.h> 56 #if NGTPCI > 0 57 #include <dev/marvell/gtpcivar.h> 58 #endif 59 #include <dev/scsipi/scsi_all.h> 60 #include <dev/scsipi/scsipi_all.h> 61 #include <dev/scsipi/scsiconf.h> 62 #include <dev/ata/atavar.h> 63 #include <dev/ic/wdcvar.h> 64 65 #include <machine/pci_machdep.h> 66 67 #include <prop/proplib.h> 68 69 extern char bootpath[256]; 70 char cbootpath[256]; 71 int console_node = 0, console_instance = 0; 72 73 static void canonicalize_bootpath(void); 74 75 /* 76 * Determine device configuration for a machine. 77 */ 78 void 79 cpu_configure(void) 80 { 81 init_interrupt(); 82 canonicalize_bootpath(); 83 84 if (config_rootfound("mainbus", NULL) == NULL) 85 panic("configure: mainbus not configured"); 86 87 genppc_cpu_configure(); 88 } 89 90 static void 91 canonicalize_bootpath(void) 92 { 93 int node; 94 char *p, *lastp; 95 char last[32]; 96 97 /* 98 * If the bootpath doesn't start with a / then it isn't 99 * an OFW path and probably is an alias, so look up the alias 100 * and regenerate the full bootpath so device_register will work. 101 */ 102 if (bootpath[0] != '/' && bootpath[0] != '\0') { 103 int aliases = OF_finddevice("/aliases"); 104 char tmpbuf[100]; 105 char aliasbuf[256]; 106 if (aliases != 0) { 107 char *cp1, *cp2, *cp; 108 char saved_ch = '\0'; 109 int len; 110 cp1 = strchr(bootpath, ':'); 111 cp2 = strchr(bootpath, ','); 112 cp = cp1; 113 if (cp1 == NULL || (cp2 != NULL && cp2 < cp1)) 114 cp = cp2; 115 tmpbuf[0] = '\0'; 116 if (cp != NULL) { 117 strcpy(tmpbuf, cp); 118 saved_ch = *cp; 119 *cp = '\0'; 120 } 121 len = OF_getprop(aliases, bootpath, aliasbuf, 122 sizeof(aliasbuf)); 123 if (len > 0) { 124 if (aliasbuf[len-1] == '\0') 125 len--; 126 memcpy(bootpath, aliasbuf, len); 127 strcpy(&bootpath[len], tmpbuf); 128 } else { 129 *cp = saved_ch; 130 } 131 } 132 } 133 134 /* 135 * Strip kernel name. bootpath contains "OF-path"/"kernel". 136 * 137 * for example: 138 * /bandit@F2000000/gc@10/53c94@10000/sd@0,0/netbsd (OF-1.x) 139 * /pci/mac-io/ata-3@2000/disk@0:0/netbsd.new (OF-3.x) 140 */ 141 strcpy(cbootpath, bootpath); 142 while ((node = OF_finddevice(cbootpath)) == -1) { 143 if ((p = strrchr(cbootpath, '/')) == NULL) 144 break; 145 *p = '\0'; 146 } 147 148 printf("bootpath: %s\n", bootpath); 149 if (node == -1) { 150 /* Cannot canonicalize... use bootpath anyway. */ 151 strcpy(cbootpath, bootpath); 152 153 return; 154 } 155 156 /* 157 * cbootpath is a valid OF path. Use package-to-path to 158 * canonicalize pathname. 159 */ 160 161 /* Back up the last component for later use. */ 162 if ((p = strrchr(cbootpath, '/')) != NULL) 163 strcpy(last, p + 1); 164 else 165 last[0] = '\0'; 166 167 memset(cbootpath, 0, sizeof(cbootpath)); 168 OF_package_to_path(node, cbootpath, sizeof(cbootpath) - 1); 169 170 /* 171 * OF_1.x (at least) always returns addr == 0 for 172 * SCSI disks (i.e. "/bandit@.../.../sd@0,0"). 173 */ 174 lastp = strrchr(cbootpath, '/'); 175 if (lastp != NULL) { 176 lastp++; 177 if (strncmp(lastp, "sd@", 3) == 0 178 && strncmp(last, "sd@", 3) == 0) 179 strcpy(lastp, last); 180 } else { 181 lastp = cbootpath; 182 } 183 184 /* 185 * At this point, cbootpath contains like: 186 * "/pci@80000000/mac-io@10/ata-3@20000/disk" 187 * 188 * The last component may have no address... so append it. 189 */ 190 if (strchr(lastp, '@') == NULL) { 191 /* Append it. */ 192 if ((p = strrchr(last, '@')) != NULL) 193 strcat(cbootpath, p); 194 } 195 196 if ((p = strrchr(lastp, ':')) != NULL) { 197 *p++ = '\0'; 198 /* booted_partition = *p - '0'; XXX correct? */ 199 } 200 } 201 202 /* 203 * device_register is called from config_attach as each device is 204 * attached. We use it to find the NetBSD device corresponding to the 205 * known OF boot device. 206 */ 207 void 208 device_register(struct device *dev, void *aux) 209 { 210 static struct device *parent; 211 static char *bp = bootpath + 1, *cp = cbootpath; 212 unsigned long addr, addr2; 213 char *p; 214 #if NGTPCI > 0 215 struct powerpc_bus_space *gtpci_mem_bs_tag = NULL; 216 #endif 217 218 /* Skip over devices not represented in the OF tree. */ 219 if (device_is_a(dev, "mainbus")) { 220 parent = dev; 221 return; 222 } 223 #if NGTPCI > 0 224 if (device_is_a(dev, "gtpci")) { 225 extern struct gtpci_prot gtpci0_prot, gtpci1_prot; 226 extern struct powerpc_bus_space 227 gtpci0_io_bs_tag, gtpci0_mem_bs_tag, 228 gtpci1_io_bs_tag, gtpci1_mem_bs_tag; 229 extern struct genppc_pci_chipset 230 genppc_gtpci0_chipset, genppc_gtpci1_chipset; 231 232 struct marvell_attach_args *mva = aux; 233 struct gtpci_prot *gtpci_prot; 234 struct powerpc_bus_space *gtpci_io_bs_tag; 235 struct genppc_pci_chipset *genppc_gtpci_chipset; 236 prop_dictionary_t dict = device_properties(dev); 237 prop_data_t prot, io_bs_tag, mem_bs_tag, pc; 238 int iostart, ioend; 239 240 if (mva->mva_unit == 0) { 241 gtpci_prot = >pci0_prot; 242 gtpci_io_bs_tag = >pci0_io_bs_tag; 243 gtpci_mem_bs_tag = >pci0_mem_bs_tag; 244 genppc_gtpci_chipset = &genppc_gtpci0_chipset; 245 iostart = 0; 246 ioend = 0; 247 } else { 248 gtpci_prot = >pci1_prot; 249 gtpci_io_bs_tag = >pci1_io_bs_tag; 250 gtpci_mem_bs_tag = >pci1_mem_bs_tag; 251 genppc_gtpci_chipset = &genppc_gtpci1_chipset; 252 iostart = 0x1400; 253 ioend = 0xffff; 254 } 255 256 prot = prop_data_create_data_nocopy( 257 gtpci_prot, sizeof(struct gtpci_prot)); 258 KASSERT(prot != NULL); 259 prop_dictionary_set(dict, "prot", prot); 260 prop_object_release(prot); 261 262 io_bs_tag = prop_data_create_data_nocopy( 263 gtpci_io_bs_tag, sizeof(struct powerpc_bus_space)); 264 KASSERT(io_bs_tag != NULL); 265 prop_dictionary_set(dict, "io-bus-tag", io_bs_tag); 266 prop_object_release(io_bs_tag); 267 mem_bs_tag = prop_data_create_data_nocopy( 268 gtpci_mem_bs_tag, sizeof(struct powerpc_bus_space)); 269 KASSERT(mem_bs_tag != NULL); 270 prop_dictionary_set(dict, "mem-bus-tag", mem_bs_tag); 271 prop_object_release(mem_bs_tag); 272 273 genppc_gtpci_chipset->pc_conf_v = device_private(dev); 274 pc = prop_data_create_data_nocopy(genppc_gtpci_chipset, 275 sizeof(struct genppc_pci_chipset)); 276 KASSERT(pc != NULL); 277 prop_dictionary_set(dict, "pci-chipset", pc); 278 prop_object_release(pc); 279 280 prop_dictionary_set_uint64(dict, "iostart", iostart); 281 prop_dictionary_set_uint64(dict, "ioend", ioend); 282 prop_dictionary_set_uint64(dict, "memstart", 283 gtpci_mem_bs_tag->pbs_base); 284 prop_dictionary_set_uint64(dict, "memend", 285 gtpci_mem_bs_tag->pbs_limit - 1); 286 prop_dictionary_set_uint32(dict, "cache-line-size", 287 CACHELINESIZE); 288 } 289 #endif 290 if (device_is_a(dev, "atapibus") || device_is_a(dev, "pci") || 291 device_is_a(dev, "scsibus") || device_is_a(dev, "atabus")) 292 return; 293 294 if (device_is_a(device_parent(dev), "pci")) { 295 struct pci_attach_args *pa = aux; 296 prop_dictionary_t dict; 297 prop_bool_t b; 298 int node; 299 char name[32]; 300 301 dict = device_properties(dev); 302 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 303 304 /* enable configuration of irq 14/15 for VIA native IDE */ 305 if (device_is_a(dev, "viaide") && 306 strncmp(model_name, "Pegasos", 7) == 0) { 307 b = prop_bool_create(true); 308 KASSERT(b != NULL); 309 (void)prop_dictionary_set(dict, 310 "use-compat-native-irq", b); 311 prop_object_release(b); 312 } 313 314 if (node != 0) { 315 int pci_class = 0; 316 317 prop_dictionary_set_uint32(dict, "device_node", node); 318 319 /* see if this is going to be console */ 320 memset(name, 0, sizeof(name)); 321 OF_getprop(node, "device_type", name, sizeof(name)); 322 323 OF_getprop(node, "class-code", &pci_class, 324 sizeof pci_class); 325 pci_class = (pci_class >> 16) & 0xff; 326 327 if (strcmp(name, "display") == 0 || 328 strcmp(name, "ATY,DDParent") == 0 || 329 pci_class == PCI_CLASS_DISPLAY) { 330 /* setup display properties for fb driver */ 331 prop_dictionary_set_bool(dict, "is_console", 0); 332 copy_disp_props(dev, node, dict); 333 } 334 if (pci_class == PCI_CLASS_NETWORK) { 335 of_to_dataprop(dict, node, "local-mac-address", 336 "mac-address"); 337 of_to_dataprop(dict, node, "shared-pins", 338 "shared-pins"); 339 } 340 } 341 } 342 343 if (booted_device) 344 return; 345 346 /* 347 * Skip over devices that are really just layers of NetBSD 348 * autoconf(9) we should just skip as they do not have any 349 * OFW devices. 350 */ 351 if (device_is_a(device_parent(dev), "atapibus") || 352 device_is_a(device_parent(dev), "atabus") || 353 device_is_a(device_parent(dev), "pci") || 354 device_is_a(device_parent(dev), "scsibus")) { 355 if (device_parent(device_parent(dev)) != parent) 356 return; 357 } else { 358 if (device_parent(dev) != parent) 359 return; 360 } 361 362 /* 363 * Get the address part of the current path component. The 364 * last component of the canonical bootpath may have no 365 * address (eg, "disk"), in which case we need to get the 366 * address from the original bootpath instead. 367 */ 368 p = strchr(cp, '@'); 369 if (!p) { 370 if (bp) 371 p = strchr(bp, '@'); 372 if (!p) 373 addr = 0; 374 else 375 addr = strtoul(p + 1, &p, 16); 376 } else 377 addr = strtoul(p + 1, &p, 16); 378 379 /* if the current path has more address, grab that too */ 380 if (p && *p == ',') 381 addr2 = strtoul(p + 1, &p, 16); 382 else 383 addr2 = 0; 384 385 if (device_is_a(device_parent(dev), "mainbus")) { 386 struct confargs *ca = aux; 387 388 if (strcmp(ca->ca_name, "ofw") == 0) /* XXX */ 389 return; 390 if (strcmp(ca->ca_name, "gt") == 0) 391 parent = dev; 392 if (addr != ca->ca_reg[0]) 393 return; 394 } else if (device_is_a(device_parent(dev), "gt")) { 395 /* 396 * Special handle for MV64361 on PegasosII(ofppc). 397 */ 398 if (device_is_a(dev, "mvgbec")) { 399 /* 400 * Fix cp to /port@N from /ethernet/portN. (N is 0...2) 401 */ 402 static char fix_cp[8] = "/port@N"; 403 404 if (strlen(cp) != 15 || 405 strncmp(cp, "/ethernet/port", 14) != 0) 406 return; 407 fix_cp[7] = *(cp + 15); 408 p = fix_cp; 409 #if NGTPCI > 0 410 } else if (device_is_a(dev, "gtpci")) { 411 if (gtpci_mem_bs_tag != NULL && 412 addr != gtpci_mem_bs_tag->pbs_base) 413 return; 414 #endif 415 } else 416 return; 417 } else if (device_is_a(device_parent(dev), "pci")) { 418 struct pci_attach_args *pa = aux; 419 420 if (addr != pa->pa_device || 421 addr2 != pa->pa_function) 422 return; 423 } else if (device_is_a(device_parent(dev), "obio")) { 424 struct confargs *ca = aux; 425 426 if (addr != ca->ca_reg[0]) 427 return; 428 } else if (device_is_a(device_parent(dev), "scsibus") || 429 device_is_a(device_parent(dev), "atapibus")) { 430 struct scsipibus_attach_args *sa = aux; 431 432 /* periph_target is target for scsi, drive # for atapi */ 433 if (addr != sa->sa_periph->periph_target) 434 return; 435 } else if (device_is_a(device_parent(device_parent(dev)), "pciide") || 436 device_is_a(device_parent(device_parent(dev)), "viaide") || 437 device_is_a(device_parent(device_parent(dev)), "slide")) { 438 struct ata_device *adev = aux; 439 440 if (addr != adev->adev_channel || 441 addr2 != adev->adev_drv_data->drive) 442 return; 443 } else if (device_is_a(device_parent(device_parent(dev)), "wdc")) { 444 struct ata_device *adev = aux; 445 446 if (addr != adev->adev_drv_data->drive) 447 return; 448 } else 449 return; 450 451 /* If we reach this point, then dev is a match for the current 452 * path component. 453 */ 454 455 if (p && *p) { 456 parent = dev; 457 cp = p; 458 bp = strchr(bp, '/'); 459 if (bp) 460 bp++; 461 return; 462 } else { 463 booted_device = dev; 464 booted_partition = 0; /* XXX -- should be extracted from bootpath */ 465 return; 466 } 467 } 468 469 /* 470 * Setup root device. 471 * Configure swap area. 472 */ 473 void 474 cpu_rootconf(void) 475 { 476 printf("boot device: %s\n", 477 booted_device ? booted_device->dv_xname : "<unknown>"); 478 479 setroot(booted_device, booted_partition); 480 } 481 482 /* 483 * Find OF-device corresponding to the PCI device. 484 */ 485 int 486 pcidev_to_ofdev(pci_chipset_tag_t pc, pcitag_t tag) 487 { 488 int bus, dev, func; 489 u_int reg[5]; 490 int p, q; 491 int l, b, d, f; 492 493 pci_decompose_tag(pc, tag, &bus, &dev, &func); 494 495 for (q = OF_peer(0); q; q = p) { 496 l = OF_getprop(q, "assigned-addresses", reg, sizeof(reg)); 497 if (l > 4) { 498 b = (reg[0] >> 16) & 0xff; 499 d = (reg[0] >> 11) & 0x1f; 500 f = (reg[0] >> 8) & 0x07; 501 502 if (b == bus && d == dev && f == func) 503 return q; 504 } 505 if ((p = OF_child(q))) 506 continue; 507 while (q) { 508 if ((p = OF_peer(q))) 509 break; 510 q = OF_parent(q); 511 } 512 } 513 return 0; 514 } 515