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