xref: /netbsd/sys/arch/sun68k/sun68k/autoconf.c (revision c4a72b64)
1 /*	$NetBSD: autoconf.c,v 1.10 2002/10/02 16:02:31 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Adam Glass, Gordon W. Ross, and Matthew Fredette.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Setup the system to run on the current machine.
41  *
42  * Configure() is called at boot time.  Available devices are
43  * determined (from possibilities mentioned in ioconf.c), and
44  * the drivers are initialized.
45  */
46 
47 #include "opt_kgdb.h"
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/conf.h>
52 #include <sys/device.h>
53 #include <sys/reboot.h>
54 
55 #include "scsibus.h"
56 
57 #if NSCSIBUS > 0
58 #include <dev/scsipi/scsi_all.h>
59 #include <dev/scsipi/scsipi_all.h>
60 #include <dev/scsipi/scsiconf.h>
61 #endif /* NSCSIBUS > 0 */
62 
63 #include <machine/autoconf.h>
64 #include <machine/intr.h>
65 #include <machine/promlib.h>
66 
67 #ifdef	KGDB
68 #include <sys/kgdb.h>
69 #endif
70 
71 /*
72  * Do general device autoconfiguration,
73  * then choose root device (etc.)
74  * Called by machdep.c: cpu_startup()
75  */
76 void
77 cpu_configure()
78 {
79 
80 	/*
81 	 * Consider stopping for a debugger before
82 	 * autoconfiguration.
83 	 */
84 	if (boothowto & RB_KDB) {
85 #ifdef KGDB
86 		/* XXX - Ask on console for kgdb_dev? */
87 		/* Note: this will just return if kgdb_dev==NODEV */
88 		kgdb_connect(1);
89 #else	/* KGDB */
90 		/* Either DDB or no debugger (just PROM). */
91 		Debugger();
92 #endif	/* KGDB */
93 	}
94 
95 	/*
96 	 * Install handlers for our "soft" interrupts.
97 	 * There might be a better place to do this?
98 	 */
99 	softintr_init();
100 
101 	/* General device autoconfiguration. */
102 	if (config_rootfound("mainbus", NULL) == NULL)
103 		panic("configure: mainbus not found");
104 
105 	/*
106 	 * Now that device autoconfiguration is finished,
107 	 * we can safely enable interrupts.
108 	 */
109 	printf("enabling interrupts\n");
110 	(void)spl0();
111 }
112 
113 static int 	mainbus_match __P((struct device *, struct cfdata *, void *));
114 static void	mainbus_attach __P((struct device *, struct device *, void *));
115 
116 CFATTACH_DECL(mainbus, sizeof(struct device),
117     mainbus_match, mainbus_attach, NULL, NULL);
118 
119 /*
120  * Probe for the mainbus; always succeeds.
121  */
122 static int
123 mainbus_match(parent, cf, aux)
124 	struct device *parent;
125 	struct cfdata *cf;
126 	void *aux;
127 {
128 
129 	return 1;
130 }
131 
132 /*
133  * Do "direct" configuration for the bus types on mainbus.
134  * This controls the order of autoconfig for important things
135  * used early.  For example, idprom is used by Ether drivers.
136  */
137 static void
138 mainbus_attach(parent, self, args)
139 	struct device *parent;
140 	struct device *self;
141 	void *args;
142 {
143 extern struct sun68k_bus_dma_tag mainbus_dma_tag;
144 extern struct sun68k_bus_space_tag mainbus_space_tag;
145 
146 	struct mainbus_attach_args ma;
147 	const char *const *cpp;
148 	static const char *const special[] = {
149 		/* find these first */
150 		"obio",
151 		"obmem",
152 		NULL
153 	};
154 
155 	printf("\n");
156 
157 	ma.ma_bustag = &mainbus_space_tag;
158 	ma.ma_dmatag = &mainbus_dma_tag;
159 	ma.ma_paddr = LOCATOR_FORBIDDEN;
160 	ma.ma_pri = LOCATOR_FORBIDDEN;
161 
162 	/* Find all `early' mainbus buses */
163 	for (cpp = special; *cpp != NULL; cpp++) {
164 		ma.ma_name = *cpp;
165 		(void)config_found(self, &ma, NULL);
166 	}
167 
168 	/* Find the remaining buses */
169 	ma.ma_name = NULL;
170 	(void) config_found(self, &ma, NULL);
171 
172 	/* Lastly, find the PROM console */
173 	ma.ma_name = "pcons";
174 	(void) config_found(self, &ma, NULL);
175 }
176 
177 /*
178  * sun68k_bus_search:
179  * This function is passed to config_search() by the attach function
180  * for each of the "bus" drivers (obio, obmem, mbmem, vme, ...).
181  * The purpose of this function is to copy the "locators" into our
182  * _attach_args structure, so child drivers may use the _attach_args both
183  * as match parameters and as temporary storage for the defaulted
184  * locator values determined in the child_match and preserved for
185  * the child_attach function.  If the bus attach functions just
186  * used config_found, then we would not have an opportunity to
187  * setup the _attach_args for each child match and attach call.
188  */
189 int sun68k_bus_search(parent, cf, aux)
190 	struct device *parent;
191 	struct cfdata *cf;
192 	void *aux;
193 {
194 	struct mainbus_attach_args *map = aux;
195 	struct mainbus_attach_args ma;
196 
197 	/* Check whether we're looking for a specifically named device */
198 	if (map->ma_name != NULL && strcmp(map->ma_name, cf->cf_name) != 0)
199 		return (0);
200 
201 #ifdef	DIAGNOSTIC
202 	if (cf->cf_fstate == FSTATE_STAR)
203 		panic("bus_scan: FSTATE_STAR");
204 #endif
205 
206 	/*
207 	 * Prepare to copy the locators into our _attach_args.
208 	 */
209 	ma = *map;
210 	ma.ma_name = NULL;
211 
212 	/*
213 	 * Avoid entries which are missing attach information that
214 	 * they need, or that have attach information that they
215 	 * cannot have.  The individual bus attach functions tell
216 	 * us this by initializing the locator fields in the attach
217 	 * args they provide us.
218 	 *
219 	 * At the same time we copy these values into the _attach_args
220 	 * will pass to the device's match and attach functions.
221 	 */
222 #ifdef	DIAGNOSTIC
223 #define BAD_LOCATOR(ma_loc, what) panic("sun68k_bus_search: %s %s for: %s%d", \
224 				     map-> ma_loc == LOCATOR_REQUIRED ? "missing" : "unexpected", \
225 				     what, cf->cf_name, cf->cf_unit)
226 #else
227 #define BAD_LOCATOR(ma_loc, what) return (0)
228 #endif
229 #define CHECK_LOCATOR(ma_loc, cf_loc, what) \
230 	if ((map-> ma_loc == LOCATOR_FORBIDDEN && cf->cf_loc != -1) || \
231 	    (map-> ma_loc == LOCATOR_REQUIRED && cf->cf_loc == -1)) \
232 		BAD_LOCATOR( ma_loc, what); \
233 	else \
234 		ma. ma_loc = cf->cf_loc
235 	CHECK_LOCATOR(ma_paddr, cf_paddr, "address");
236 	CHECK_LOCATOR(ma_pri, cf_intpri, "ipl");
237 
238 	/*
239 	 * Note that this allows the match function to save
240 	 * defaulted locators in the _attach_args that will be
241 	 * preserved for the related attach call.
242 	 * XXX - This is a hack...
243 	 */
244 	if (config_match(parent, cf, &ma) > 0) {
245 		config_attach(parent, cf, &ma, sun68k_bus_print);
246 	}
247 	return (0);
248 }
249 
250 /*
251  * sun68k_bus_print:
252  * Just print out the final (non-default) locators.
253  * The parent name is non-NULL when there was no match
254  * found by config_found().
255  */
256 int
257 sun68k_bus_print(args, name)
258 	void *args;
259 	const char *name;
260 {
261 	struct mainbus_attach_args *ma = args;
262 
263 	if (name)
264 		printf("%s:", name);
265 
266 	if (ma->ma_paddr != -1)
267 		printf(" addr 0x%x", (unsigned int) ma->ma_paddr);
268 	if (ma->ma_pri != -1)
269 		printf(" ipl %d", ma->ma_pri);
270 
271 	return(UNCONF);
272 }
273 
274 /****************************************************************/
275 
276 /* This takes the args: name, ctlr, unit */
277 typedef struct device * (*findfunc_t) __P((char *, int, int));
278 
279 static struct device * find_dev_byname __P((char *));
280 static struct device * net_find  __P((char *, int, int));
281 #if NSCSIBUS > 0
282 static struct device * scsi_find __P((char *, int, int));
283 #endif /* NSCSIBUS > 0 */
284 static struct device * xx_find   __P((char *, int, int));
285 
286 struct prom_n2f {
287 	const char name[4];
288 	findfunc_t func;
289 };
290 static struct prom_n2f prom_dev_table[] = {
291 	{ "ie",		net_find },
292 	{ "ec",		net_find },
293 	{ "le",		net_find },
294 #if NSCSIBUS > 0
295 	{ "sd",		scsi_find },
296 #endif /* NSCSIBUS > 0 */
297 	{ "xy",		xx_find },
298 	{ "xd",		xx_find },
299 	{ "",		0 },
300 };
301 
302 /*
303  * This converts one hex number to an integer, and returns
304  * an updated string pointer.
305  */
306 static const char *str2hex __P((const char *, int *));
307 static const char *
308 str2hex(p, _val)
309 	const char *p;
310 	int *_val;
311 {
312 	int val;
313 	int c;
314 
315 	for(val = 0;; val = (val << 4) + c, p++) {
316 		c = *((unsigned char *) p);
317 		if (c >= 'a') c-= ('a' + 10);
318 		else if (c >= 'A') c -= ('A' + 10);
319 		else if (c >= '0') c -= '0';
320 		if (c < 0 || c > 15) break;
321 	}
322 	*_val = val;
323 	return (p);
324 }
325 
326 /*
327  * Choose root and swap devices.
328  */
329 void
330 cpu_rootconf()
331 {
332 	struct prom_n2f *nf;
333 	struct device *boot_device;
334 	int boot_partition;
335 	char *devname;
336 	findfunc_t find;
337 	char promname[4];
338 	char partname[4];
339 	const char *prompath;
340 	int prom_ctlr, prom_unit, prom_part;
341 
342 	/* Get the PROM boot path and take it apart. */
343 	prompath = prom_getbootpath();
344 	if (prompath == NULL) prompath = "zz(0,0,0)";
345 	promname[0] = *(prompath++);
346 	promname[1] = *(prompath++);
347 	promname[2] = '\0';
348 	prom_ctlr = prom_unit = prom_part = 0;
349 	if (*prompath == '(' &&
350 	    *(prompath = str2hex(++prompath, &prom_ctlr)) == ',' &&
351 	    *(prompath = str2hex(++prompath, &prom_unit)) == ',')
352 		(void) str2hex(++prompath, &prom_part);
353 
354 	/* Default to "unknown" */
355 	boot_device = NULL;
356 	boot_partition = 0;
357 	devname = "<unknown>";
358 	partname[0] = '\0';
359 	find = NULL;
360 
361 	/* Do we know anything about the PROM boot device? */
362 	for (nf = prom_dev_table; nf->func; nf++)
363 		if (!strcmp(nf->name, promname)) {
364 			find = nf->func;
365 			break;
366 		}
367 	if (find)
368 		boot_device = (*find)(promname, prom_ctlr, prom_unit);
369 	if (boot_device) {
370 		devname = boot_device->dv_xname;
371 		if (boot_device->dv_class == DV_DISK) {
372 			boot_partition = prom_part & 7;
373 			partname[0] = 'a' + boot_partition;
374 			partname[1] = '\0';
375 		}
376 	}
377 
378 	printf("boot device: %s%s\n", devname, partname);
379 	setroot(boot_device, boot_partition);
380 }
381 
382 /*
383  * Functions to find devices using PROM boot parameters.
384  */
385 
386 /*
387  * Network device:  Just use controller number.
388  */
389 static struct device *
390 net_find(name, ctlr, unit)
391 	char *name;
392 	int ctlr, unit;
393 {
394 	char tname[16];
395 
396 	sprintf(tname, "%s%d", name, ctlr);
397 	return (find_dev_byname(tname));
398 }
399 
400 #if NSCSIBUS > 0
401 /*
402  * SCSI device:  The controller number corresponds to the
403  * scsibus number, and the unit number is (targ*8 + LUN).
404  */
405 static struct device *
406 scsi_find(name, ctlr, unit)
407 	char *name;
408 	int ctlr, unit;
409 {
410 	struct device *scsibus;
411 	struct scsibus_softc *sbsc;
412 	struct scsipi_periph *periph;
413 	int target, lun;
414 	char tname[16];
415 
416 	sprintf(tname, "scsibus%d", ctlr);
417 	scsibus = find_dev_byname(tname);
418 	if (scsibus == NULL)
419 		return (NULL);
420 
421 	/* Compute SCSI target/LUN from PROM unit. */
422 	target = prom_sd_target((unit >> 3) & 7);
423 	lun = unit & 7;
424 
425 	/* Find the device at this target/LUN */
426 	sbsc = (struct scsibus_softc *)scsibus;
427 	periph = scsipi_lookup_periph(sbsc->sc_channel, target, lun);
428 	if (periph == NULL)
429 		return (NULL);
430 
431 	return (periph->periph_dev);
432 }
433 #endif /* NSCSIBUS > 0 */
434 
435 /*
436  * Xylogics SMD disk: (xy, xd)
437  * Assume wired-in unit numbers for now...
438  */
439 static struct device *
440 xx_find(name, ctlr, unit)
441 	char *name;
442 	int ctlr, unit;
443 {
444 	int diskunit;
445 	char tname[16];
446 
447 	diskunit = (ctlr * 2) + unit;
448 	sprintf(tname, "%s%d", name, diskunit);
449 	return (find_dev_byname(tname));
450 }
451 
452 /*
453  * Given a device name, find its struct device
454  * XXX - Move this to some common file?
455  */
456 static struct device *
457 find_dev_byname(name)
458 	char *name;
459 {
460 	struct device *dv;
461 
462 	for (dv = alldevs.tqh_first; dv != NULL;
463 	    dv = dv->dv_list.tqe_next) {
464 		if (!strcmp(dv->dv_xname, name)) {
465 			return(dv);
466 		}
467 	}
468 	return (NULL);
469 }
470