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