autoconf.c revision 1.108
1/* $NetBSD: autoconf.c,v 1.108 2011/08/04 17:48:50 rkujawa Exp $ */ 2 3/* 4 * Copyright (c) 1994 Christian E. Hopps 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 Christian E. Hopps. 18 * 4. The name of the author 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 THE AUTHOR ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.108 2011/08/04 17:48:50 rkujawa Exp $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/reboot.h> 39#include <sys/conf.h> 40#include <sys/buf.h> 41#include <sys/device.h> 42#include <sys/disklabel.h> 43#include <sys/disk.h> 44#include <sys/proc.h> 45#include <machine/cpu.h> 46#include <amiga/amiga/cfdev.h> 47#include <amiga/amiga/device.h> 48#include <amiga/amiga/custom.h> 49#ifdef DRACO 50#include <amiga/amiga/drcustom.h> 51#endif 52#include <dev/pci/pcireg.h> 53#include <dev/pci/pcivar.h> 54#include <dev/pci/pcidevs.h> 55 56static void findroot(void); 57void mbattach(device_t, device_t, void *); 58int mbprint(void *, const char *); 59int mbmatch(device_t, cfdata_t, void *); 60 61#include <sys/kernel.h> 62 63u_long boot_partition; 64 65int amiga_realconfig; 66 67/* 68 * called at boot time, configure all devices on system 69 */ 70void 71cpu_configure(void) 72{ 73 int s; 74#ifdef DEBUG_KERNEL_START 75 int i; 76#endif 77 78 /* 79 * this is the real thing baby (i.e. not console init) 80 */ 81 amiga_realconfig = 1; 82#ifdef DRACO 83 if (is_draco()) { 84 *draco_intena &= ~DRIRQ_GLOBAL; 85 } else 86#endif 87 custom.intena = INTF_INTEN; 88 s = splhigh(); 89 90 if (config_rootfound("mainbus", NULL) == NULL) 91 panic("no mainbus found"); 92 93#ifdef DEBUG_KERNEL_START 94 printf("survived autoconf, going to enable interrupts\n"); 95#endif 96 97#ifdef DRACO 98 if (is_draco()) { 99 *draco_intena |= DRIRQ_GLOBAL; 100 /* softints always enabled */ 101 } else 102#endif 103 { 104 custom.intena = INTF_SETCLR | INTF_INTEN; 105 106 /* also enable hardware aided software interrupts */ 107 custom.intena = INTF_SETCLR | INTF_SOFTINT; 108 } 109#ifdef DEBUG_KERNEL_START 110 for (i=splhigh(); i>=s ;i-=0x100) { 111 splx(i); 112 printf("%d...", (i>>8) & 7); 113 } 114 printf("survived interrupt enable\n"); 115#else 116 splx(s); 117#endif 118#ifdef DEBUG_KERNEL_START 119 printf("survived configure...\n"); 120#endif 121} 122 123void 124cpu_rootconf(void) 125{ 126 findroot(); 127#ifdef DEBUG_KERNEL_START 128 printf("survived findroot()\n"); 129#endif 130 setroot(booted_device, booted_partition); 131#ifdef DEBUG_KERNEL_START 132 printf("survived setroot()\n"); 133#endif 134} 135 136/*ARGSUSED*/ 137int 138simple_devprint(void *auxp, const char *pnp) 139{ 140 return(QUIET); 141} 142 143int 144matchname(const char *fp, const char *sp) 145{ 146 int len; 147 148 len = strlen(fp); 149 if (strlen(sp) != len) 150 return(0); 151 if (memcmp(fp, sp, len) == 0) 152 return(1); 153 return(0); 154} 155 156/* 157 * use config_search_ia to find appropriate device, then call that device 158 * directly with NULL device variable storage. A device can then 159 * always tell the difference betwean the real and console init 160 * by checking for NULL. 161 */ 162int 163amiga_config_found(cfdata_t pcfp, device_t pdp, void *auxp, cfprint_t pfn) 164{ 165 struct device temp; 166 cfdata_t cf; 167 const struct cfattach *ca; 168 169 if (amiga_realconfig) 170 return(config_found(pdp, auxp, pfn) != NULL); 171 172 if (pdp == NULL) { 173 memset(&temp, 0, sizeof temp); 174 pdp = &temp; 175 } 176 177 pdp->dv_cfdata = pcfp; 178 pdp->dv_cfdriver = config_cfdriver_lookup(pcfp->cf_name); 179 pdp->dv_unit = pcfp->cf_unit; 180 181 if ((cf = config_search_ia(NULL, pdp, NULL, auxp)) != NULL) { 182 ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); 183 if (ca != NULL) { 184 (*ca->ca_attach)(pdp, NULL, auxp); 185 pdp->dv_cfdata = NULL; 186 return(1); 187 } 188 } 189 pdp->dv_cfdata = NULL; 190 return(0); 191} 192 193/* 194 * this function needs to get enough configured to do a console 195 * basically this means start attaching the grfxx's that support 196 * the console. Kinda hacky but it works. 197 */ 198void 199config_console(void) 200{ 201 cfdata_t cf; 202 203 config_init(); 204 205 /* 206 * we need mainbus' cfdata. 207 */ 208 cf = config_rootsearch(NULL, "mainbus", NULL); 209 if (cf == NULL) { 210 panic("no mainbus"); 211 } 212 /* 213 * delay clock calibration. 214 */ 215 amiga_config_found(cf, NULL, __UNCONST("clock"), NULL); 216 217 /* 218 * internal grf. 219 */ 220#ifdef DRACO 221 if (!(is_draco())) 222#endif 223 amiga_config_found(cf, NULL, __UNCONST("grfcc"), NULL); 224 225 /* 226 * zbus knows when its not for real and will 227 * only configure the appropriate hardware 228 */ 229 amiga_config_found(cf, NULL, __UNCONST("zbus"), NULL); 230} 231 232/* 233 * mainbus driver 234 */ 235CFATTACH_DECL_NEW(mainbus, 0, 236 mbmatch, mbattach, NULL, NULL); 237 238int 239mbmatch(device_t pdp, cfdata_t cfp, void *auxp) 240{ 241#if 0 /* 242 * XXX is this right? but we need to be found twice 243 * (early console init hack) 244 */ 245 static int mainbus_matched = 0; 246 247 /* Allow only one instance. */ 248 if (mainbus_matched) 249 return (0); 250 251 mainbus_matched = 1; 252#endif 253 return (1); 254} 255 256/* 257 * "find" all the things that should be there. 258 */ 259void 260mbattach(device_t pdp, device_t dp, void *auxp) 261{ 262 printf("\n"); 263 config_found(dp, __UNCONST("clock"), simple_devprint); 264 if (is_a3000() || is_a4000()) { 265 config_found(dp, __UNCONST("a34kbbc"), simple_devprint); 266 } else 267#ifdef DRACO 268 if (!is_draco()) 269#endif 270 { 271 config_found(dp, __UNCONST("a2kbbc"), simple_devprint); 272 } 273#ifdef DRACO 274 if (is_draco()) { 275 config_found(dp, __UNCONST("drbbc"), simple_devprint); 276 config_found(dp, __UNCONST("kbd"), simple_devprint); 277 config_found(dp, __UNCONST("drsc"), simple_devprint); 278 config_found(dp, __UNCONST("drsupio"), simple_devprint); 279 } else 280#endif 281 { 282 config_found(dp, __UNCONST("ser"), simple_devprint); 283 config_found(dp, __UNCONST("par"), simple_devprint); 284 config_found(dp, __UNCONST("kbd"), simple_devprint); 285 config_found(dp, __UNCONST("ms"), simple_devprint); 286 config_found(dp, __UNCONST("grfcc"), simple_devprint); 287 config_found(dp, __UNCONST("amidisplaycc"), simple_devprint); 288 config_found(dp, __UNCONST("fdc"), simple_devprint); 289 } 290 if (is_a4000() || is_a1200() || is_a600()) 291 config_found(dp, __UNCONST("wdc"), simple_devprint); 292 if (is_a4000()) /* Try to configure A4000T SCSI */ 293 config_found(dp, __UNCONST("afsc"), simple_devprint); 294 if (is_a3000()) 295 config_found(dp, __UNCONST("ahsc"), simple_devprint); 296 if (is_a600() || is_a1200()) 297 config_found(dp, __UNCONST("pccard"), simple_devprint); 298#ifdef DRACO 299 if (!is_draco()) 300#endif 301 config_found(dp, __UNCONST("aucc"), simple_devprint); 302 303 config_found(dp, __UNCONST("zbus"), simple_devprint); 304} 305 306int 307mbprint(void *auxp, const char *pnp) 308{ 309 if (pnp) 310 aprint_normal("%s at %s", (char *)auxp, pnp); 311 return(UNCONF); 312} 313 314/* 315 * The system will assign the "booted device" indicator (and thus 316 * rootdev if rootspec is wildcarded) to the first partition 'a' 317 * in preference of boot. However, it does walk unit backwards 318 * to remain compatible with the old Amiga method of picking the 319 * last root found. 320 */ 321#include <sys/fcntl.h> /* XXXX and all that uses it */ 322#include <sys/proc.h> /* XXXX and all that uses it */ 323 324#include "fd.h" 325#include "sd.h" 326#include "cd.h" 327#include "wd.h" 328 329#if NFD > 0 330extern struct cfdriver fd_cd; 331extern const struct bdevsw fd_bdevsw; 332#endif 333#if NSD > 0 334extern struct cfdriver sd_cd; 335extern const struct bdevsw sd_bdevsw; 336#endif 337#if NCD > 0 338extern struct cfdriver cd_cd; 339extern const struct bdevsw cd_bdevsw; 340#endif 341#if NWD > 0 342extern struct cfdriver wd_cd; 343extern const struct bdevsw wd_bdevsw; 344#endif 345 346struct cfdriver *genericconf[] = { 347#if NFD > 0 348 &fd_cd, 349#endif 350#if NSD > 0 351 &sd_cd, 352#endif 353#if NWD > 0 354 &wd_cd, 355#endif 356#if NCD > 0 357 &cd_cd, 358#endif 359 NULL, 360}; 361 362void 363findroot(void) 364{ 365 struct disk *dkp; 366 struct partition *pp; 367 device_t *devs; 368 int i, maj, unit; 369 const struct bdevsw *bdp; 370 371#if NSD > 0 372 /* 373 * If we have the boot partition offset (boot_partition), try 374 * to locate the device corresponding to that partition. 375 */ 376#ifdef DEBUG_KERNEL_START 377 printf("Boot partition offset is %ld\n", boot_partition); 378#endif 379 if (boot_partition != 0) { 380 381 for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) { 382#ifdef DEBUG_KERNEL_START 383 printf("probing for sd%d\n", unit); 384#endif 385 if (device_lookup(&sd_cd,unit) == NULL) 386 continue; 387 388 /* 389 * Find the disk corresponding to the current 390 * device. 391 */ 392 devs = (device_t *)sd_cd.cd_devs; 393 if ((dkp = disk_find(device_xname(device_lookup(&sd_cd, unit)))) == NULL) 394 continue; 395 396 if (dkp->dk_driver == NULL || 397 dkp->dk_driver->d_strategy == NULL) 398 continue; 399 bdp = &sd_bdevsw; 400 maj = bdevsw_lookup_major(bdp); 401 if ((*bdp->d_open)(MAKEDISKDEV(maj, unit, RAW_PART), 402 FREAD | FNONBLOCK, 0, curlwp)) 403 continue; 404 (*bdp->d_close)(MAKEDISKDEV(maj, unit, RAW_PART), 405 FREAD | FNONBLOCK, 0, curlwp); 406 pp = &dkp->dk_label->d_partitions[0]; 407 for (i = 0; i < dkp->dk_label->d_npartitions; 408 i++, pp++) { 409#ifdef DEBUG_KERNEL_START 410 printf("sd%d%c type %d offset %d size %d\n", 411 unit, i+'a', pp->p_fstype, 412 pp->p_offset, pp->p_size); 413#endif 414 if (pp->p_size == 0 || 415 (pp->p_fstype != FS_BSDFFS && 416 pp->p_fstype != FS_SWAP)) 417 continue; 418 if (pp->p_offset == boot_partition) { 419 if (booted_device == NULL) { 420 booted_device = devs[unit]; 421 booted_partition = i; 422 } else 423 printf("Ambiguous boot device\n"); 424 } 425 } 426 } 427 } 428 if (booted_device != NULL) 429 return; /* we found the boot device */ 430#endif 431 432 for (i = 0; genericconf[i] != NULL; i++) { 433 for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) { 434 if (genericconf[i]->cd_devs[unit] == NULL) 435 continue; 436 437 /* 438 * Find the disk structure corresponding to the 439 * current device. 440 */ 441 devs = (device_t *)genericconf[i]->cd_devs; 442 if ((dkp = disk_find(device_xname(devs[unit]))) == NULL) 443 continue; 444 445 if (dkp->dk_driver == NULL || 446 dkp->dk_driver->d_strategy == NULL) 447 continue; 448 449 bdp = NULL; 450#if NFD > 0 451 if (fd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 452 bdp = &fd_bdevsw; 453#endif 454#if NSD > 0 455 if (sd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 456 bdp = &sd_bdevsw; 457#endif 458#if NWD > 0 459 if (wd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 460 bdp = &wd_bdevsw; 461#endif 462#if NCD > 0 463 if (cd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 464 bdp = &cd_bdevsw; 465#endif 466#ifdef DIAGNOSTIC 467 if (bdp == NULL) 468 panic("findroot: impossible"); 469#endif 470 maj = bdevsw_lookup_major(bdp); 471 472 /* Open disk; forces read of disklabel. */ 473 if ((*bdp->d_open)(MAKEDISKDEV(maj, 474 unit, 0), FREAD|FNONBLOCK, 0, &lwp0)) 475 continue; 476 (void)(*bdp->d_close)(MAKEDISKDEV(maj, 477 unit, 0), FREAD|FNONBLOCK, 0, &lwp0); 478 479 pp = &dkp->dk_label->d_partitions[0]; 480 if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) { 481 booted_device = devs[unit]; 482 booted_partition = 0; 483 return; 484 } 485 } 486 } 487} 488 489/* 490 * Try to determine, of this machine is an A3000, which has a builtin 491 * realtime clock and scsi controller, so that this hardware is only 492 * included as "configured" if this IS an A3000 493 */ 494 495int a3000_flag = 1; /* patchable */ 496#ifdef A4000 497int a4000_flag = 1; /* patchable - default to A4000 */ 498#else 499int a4000_flag = 0; /* patchable */ 500#endif 501 502int 503is_a3000() 504{ 505 /* this is a dirty kludge.. but how do you do this RIGHT ? :-) */ 506 extern long boot_fphystart; 507 short sc; 508 509 if ((machineid >> 16) == 3000) 510 return (1); /* It's an A3000 */ 511 if (machineid >> 16) 512 return (0); /* It's not an A3000 */ 513 /* Machine type is unknown, so try to guess it */ 514 /* where is fastram on the A4000 ?? */ 515 /* if fastram is below 0x07000000, assume it's not an A3000 */ 516 if (boot_fphystart < 0x07000000) 517 return(0); 518 /* 519 * OK, fastram starts at or above 0x07000000, check specific 520 * machines 521 */ 522 for (sc = 0; sc < ncfdev; sc++) { 523 switch (cfdev[sc].rom.manid) { 524 case 2026: /* Progressive Peripherals, Inc */ 525 switch (cfdev[sc].rom.prodid) { 526 case 0: /* PPI Mercury - A3000 */ 527 case 1: /* PP&S A3000 '040 */ 528 return(1); 529 case 150: /* PPI Zeus - it's an A2000 */ 530 case 105: /* PP&S A2000 '040 */ 531 case 187: /* PP&S A500 '040 */ 532 return(0); 533 } 534 break; 535 536 case 2112: /* IVS */ 537 switch (cfdev[sc].rom.prodid) { 538 case 242: 539 return(0); /* A2000 accelerator? */ 540 } 541 break; 542 } 543 } 544 return (a3000_flag); /* XXX let flag tell now */ 545} 546 547int 548is_a4000() 549{ 550 if ((machineid >> 16) == 4000) 551 return (1); /* It's an A4000 */ 552 if ((machineid >> 16) == 1200) 553 return (0); /* It's an A1200, so not A4000 */ 554#ifdef DRACO 555 if (is_draco()) 556 return (0); 557#endif 558 /* Do I need this any more? */ 559 if ((custom.deniseid & 0xff) == 0xf8) 560 return (1); 561#ifdef DEBUG 562 if (a4000_flag) 563 printf("Denise ID = %04x\n", (unsigned short)custom.deniseid); 564#endif 565 if (machineid >> 16) 566 return (0); /* It's not an A4000 */ 567 return (a4000_flag); /* Machine type not set */ 568} 569 570int 571is_a1200() 572{ 573 if ((machineid >> 16) == 1200) 574 return (1); /* It's an A1200 */ 575 return (0); /* Machine type not set */ 576} 577 578int 579is_a600() 580{ 581 if ((machineid >> 16) == 600) 582 return (1); /* It's an A600 */ 583 return (0); /* Machine type not set */ 584} 585 586 587void 588device_register(device_t dev, void *aux) 589{ 590 prop_dictionary_t dict, parent_dict; 591 struct pci_attach_args *pa = aux; 592 593 if (device_parent(dev) && device_is_a(device_parent(dev), "pci")) { 594 595 dict = device_properties(dev); 596 597 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) { 598 599 /* Handle CVPPC/BVPPC card. */ 600 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI) 601 && (PCI_PRODUCT(pa->pa_id) == 602 PCI_PRODUCT_TI_TVP4020) ) { 603 604 /* 605 * PCI bridge knows the properties, 606 * PCI device doesn't - let's copy 607 * them. 608 */ 609 parent_dict = device_properties( 610 device_parent(device_parent(dev))); 611 612 prop_dictionary_set(dict, "width", 613 prop_dictionary_get(parent_dict, "width")); 614 615 prop_dictionary_set(dict, "height", 616 prop_dictionary_get(parent_dict, "height")); 617 618 prop_dictionary_set(dict, "depth", 619 prop_dictionary_get(parent_dict, "depth")); 620 621 prop_dictionary_set(dict, "linebytes", 622 prop_dictionary_get(parent_dict, 623 "linebytes")); 624 625 prop_dictionary_set(dict, "address", 626 prop_dictionary_get(parent_dict, 627 "address")); 628#if (NGENFB > 0) 629 prop_dictionary_set(dict, "virtual_address", 630 prop_dictionary_get(parent_dict, 631 "virtual_address")); 632#endif 633 } 634 } 635 } 636} 637 638