xref: /freebsd/sys/powerpc/ofw/ofw_machdep.c (revision 10b9d77bf1ccf2f3affafa6261692cb92cf7e992)
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/systm.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/smp.h>
45 #include <sys/stat.h>
46 
47 #include <net/ethernet.h>
48 
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_pci.h>
51 #include <dev/ofw/ofw_bus.h>
52 
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_page.h>
56 
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59 #include <machine/md_var.h>
60 #include <machine/platform.h>
61 #include <machine/ofw_machdep.h>
62 
63 #define	OFMEM_REGIONS	32
64 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
65 static struct mem_region OFfree[OFMEM_REGIONS + 3];
66 static int nOFmem;
67 
68 extern register_t ofmsr[5];
69 static int	(*ofwcall)(void *);
70 static void	*fdt;
71 int		ofw_real_mode;
72 
73 int		ofw_32bit_mode_entry(void *);
74 static void	ofw_quiesce(void);
75 static int	openfirmware(void *args);
76 
77 /*
78  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
79  */
80 register_t	ofw_sprg0_save;
81 
82 static __inline void
83 ofw_sprg_prepare(void)
84 {
85 	/*
86 	 * Assume that interrupt are disabled at this point, or
87 	 * SPRG1-3 could be trashed
88 	 */
89 	__asm __volatile("mfsprg0 %0\n\t"
90 			 "mtsprg0 %1\n\t"
91 	    		 "mtsprg1 %2\n\t"
92 	    		 "mtsprg2 %3\n\t"
93 			 "mtsprg3 %4\n\t"
94 			 : "=&r"(ofw_sprg0_save)
95 			 : "r"(ofmsr[1]),
96 			 "r"(ofmsr[2]),
97 			 "r"(ofmsr[3]),
98 			 "r"(ofmsr[4]));
99 }
100 
101 static __inline void
102 ofw_sprg_restore(void)
103 {
104 	/*
105 	 * Note that SPRG1-3 contents are irrelevant. They are scratch
106 	 * registers used in the early portion of trap handling when
107 	 * interrupts are disabled.
108 	 *
109 	 * PCPU data cannot be used until this routine is called !
110 	 */
111 	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
112 }
113 
114 /*
115  * Memory region utilities: determine if two regions overlap,
116  * and merge two overlapping regions into one
117  */
118 static int
119 memr_overlap(struct mem_region *r1, struct mem_region *r2)
120 {
121 	if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
122 	    (r2->mr_start + r2->mr_size) < r1->mr_start)
123 		return (FALSE);
124 
125 	return (TRUE);
126 }
127 
128 static void
129 memr_merge(struct mem_region *from, struct mem_region *to)
130 {
131 	vm_offset_t end;
132 	end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
133 	to->mr_start = ulmin(from->mr_start, to->mr_start);
134 	to->mr_size = end - to->mr_start;
135 }
136 
137 static int
138 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
139 {
140 	cell_t address_cells, size_cells;
141 	cell_t OFmem[4*(OFMEM_REGIONS + 1)];
142 	int sz, i, j;
143 	int apple_hack_mode;
144 	phandle_t phandle;
145 
146 	sz = 0;
147 	apple_hack_mode = 0;
148 
149 	/*
150 	 * Get #address-cells from root node, defaulting to 1 if it cannot
151 	 * be found.
152 	 */
153 	phandle = OF_finddevice("/");
154 	if (OF_getprop(phandle, "#address-cells", &address_cells,
155 	    sizeof(address_cells)) < sizeof(address_cells))
156 		address_cells = 1;
157 	if (OF_getprop(phandle, "#size-cells", &size_cells,
158 	    sizeof(size_cells)) < sizeof(size_cells))
159 		size_cells = 1;
160 
161 	/*
162 	 * On Apple hardware, address_cells is always 1 for "available",
163 	 * even when it is explicitly set to 2. Then all memory above 4 GB
164 	 * should be added by hand to the available list. Detect Apple hardware
165 	 * by seeing if ofw_real_mode is set -- only Apple seems to use
166 	 * virtual-mode OF.
167 	 */
168 	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
169 		apple_hack_mode = 1;
170 
171 	if (apple_hack_mode)
172 		address_cells = 1;
173 
174 	/*
175 	 * Get memory.
176 	 */
177 	if ((node == -1) || (sz = OF_getprop(node, prop,
178 	    OFmem, sizeof(OFmem[0]) * 4 * OFMEM_REGIONS)) <= 0)
179 		panic("Physical memory map not found");
180 
181 	i = 0;
182 	j = 0;
183 	while (i < sz/sizeof(cell_t)) {
184 	      #ifndef __powerpc64__
185 		/* On 32-bit PPC, ignore regions starting above 4 GB */
186 		if (address_cells > 1 && OFmem[i] > 0) {
187 			i += address_cells + size_cells;
188 			continue;
189 		}
190 	      #endif
191 
192 		output[j].mr_start = OFmem[i++];
193 		if (address_cells == 2) {
194 			#ifdef __powerpc64__
195 			output[j].mr_start <<= 32;
196 			#endif
197 			output[j].mr_start += OFmem[i++];
198 		}
199 
200 		output[j].mr_size = OFmem[i++];
201 		if (size_cells == 2) {
202 			#ifdef __powerpc64__
203 			output[j].mr_size <<= 32;
204 			#endif
205 			output[j].mr_size += OFmem[i++];
206 		}
207 
208 	      #ifndef __powerpc64__
209 		/*
210 		 * Check for memory regions extending above 32-bit
211 		 * memory space, and restrict them to stay there.
212 		 */
213 		if (((uint64_t)output[j].mr_start +
214 		    (uint64_t)output[j].mr_size) >
215 		    BUS_SPACE_MAXADDR_32BIT) {
216 			output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
217 			    output[j].mr_start;
218 		}
219 	      #endif
220 
221 		j++;
222 	}
223 	sz = j*sizeof(output[0]);
224 
225 	#ifdef __powerpc64__
226 	if (apple_hack_mode) {
227 		/* Add in regions above 4 GB to the available list */
228 		struct mem_region himem[OFMEM_REGIONS];
229 		int hisz;
230 
231 		hisz = parse_ofw_memory(node, "reg", himem);
232 		for (i = 0; i < hisz/sizeof(himem[0]); i++) {
233 			if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
234 				output[j].mr_start = himem[i].mr_start;
235 				output[j].mr_size = himem[i].mr_size;
236 				j++;
237 			}
238 		}
239 		sz = j*sizeof(output[0]);
240 	}
241 	#endif
242 
243 	return (sz);
244 }
245 
246 /*
247  * This is called during powerpc_init, before the system is really initialized.
248  * It shall provide the total and the available regions of RAM.
249  * Both lists must have a zero-size entry as terminator.
250  * The available regions need not take the kernel into account, but needs
251  * to provide space for two additional entry beyond the terminating one.
252  */
253 void
254 ofw_mem_regions(struct mem_region **memp, int *memsz,
255 		struct mem_region **availp, int *availsz)
256 {
257 	phandle_t phandle;
258 	int asz, msz, fsz;
259 	int i, j;
260 	int still_merging;
261 
262 	asz = msz = 0;
263 
264 	/*
265 	 * Get memory.
266 	 */
267 	phandle = OF_finddevice("/memory");
268 	if (phandle == -1)
269 		phandle = OF_finddevice("/memory@0");
270 
271 	msz = parse_ofw_memory(phandle, "reg", OFmem);
272 	nOFmem = msz / sizeof(struct mem_region);
273 	asz = parse_ofw_memory(phandle, "available", OFavail);
274 
275 	*memp = OFmem;
276 	*memsz = nOFmem;
277 
278 	/*
279 	 * OFavail may have overlapping regions - collapse these
280 	 * and copy out remaining regions to OFfree
281 	 */
282 	asz /= sizeof(struct mem_region);
283 	do {
284 		still_merging = FALSE;
285 		for (i = 0; i < asz; i++) {
286 			if (OFavail[i].mr_size == 0)
287 				continue;
288 			for (j = i+1; j < asz; j++) {
289 				if (OFavail[j].mr_size == 0)
290 					continue;
291 				if (memr_overlap(&OFavail[j], &OFavail[i])) {
292 					memr_merge(&OFavail[j], &OFavail[i]);
293 					/* mark inactive */
294 					OFavail[j].mr_size = 0;
295 					still_merging = TRUE;
296 				}
297 			}
298 		}
299 	} while (still_merging == TRUE);
300 
301 	/* evict inactive ranges */
302 	for (i = 0, fsz = 0; i < asz; i++) {
303 		if (OFavail[i].mr_size != 0) {
304 			OFfree[fsz] = OFavail[i];
305 			fsz++;
306 		}
307 	}
308 
309 	*availp = OFfree;
310 	*availsz = fsz;
311 }
312 
313 void
314 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
315 {
316 	if (ofmsr[0] & PSL_DR)
317 		ofw_real_mode = 0;
318 	else
319 		ofw_real_mode = 1;
320 
321 	ofwcall = NULL;
322 
323 	#ifdef __powerpc64__
324 		/*
325 		 * For PPC64, we need to use some hand-written
326 		 * asm trampolines to get to OF.
327 		 */
328 		if (openfirm != NULL)
329 			ofwcall = ofw_32bit_mode_entry;
330 	#else
331 		ofwcall = openfirm;
332 	#endif
333 
334 	fdt = fdt_ptr;
335 
336 	#ifdef FDT_DTB_STATIC
337 	/* Check for a statically included blob */
338 	if (fdt == NULL)
339 		fdt = &fdt_static_dtb;
340 	#endif
341 }
342 
343 boolean_t
344 OF_bootstrap()
345 {
346 	boolean_t status = FALSE;
347 
348 	if (ofwcall != NULL) {
349 		if (ofw_real_mode) {
350 			status = OF_install(OFW_STD_REAL, 0);
351 		} else {
352 			#ifdef __powerpc64__
353 			status = OF_install(OFW_STD_32BIT, 0);
354 			#else
355 			status = OF_install(OFW_STD_DIRECT, 0);
356 			#endif
357 		}
358 
359 		if (status != TRUE)
360 			return status;
361 
362 		OF_init(openfirmware);
363 
364 		/*
365 		 * On some machines, we need to quiesce OF to turn off
366 		 * background processes.
367 		 */
368 		ofw_quiesce();
369 	} else if (fdt != NULL) {
370 		status = OF_install(OFW_FDT, 0);
371 
372 		if (status != TRUE)
373 			return status;
374 
375 		OF_init(fdt);
376 	}
377 
378 	return (status);
379 }
380 
381 static void
382 ofw_quiesce(void)
383 {
384 	phandle_t rootnode;
385 	char model[32];
386 	struct {
387 		cell_t name;
388 		cell_t nargs;
389 		cell_t nreturns;
390 	} args;
391 
392 	/*
393 	 * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
394 	 * necessary there to shut down a background thread doing fan
395 	 * management, and is harmful on other machines.
396 	 *
397 	 * Note: we don't need to worry about which OF module we are
398 	 * using since this is called only from very early boot, within
399 	 * OF's boot context.
400 	 */
401 
402 	rootnode = OF_finddevice("/");
403 	if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
404 		if (strcmp(model, "PowerMac11,2") == 0 ||
405 		    strcmp(model, "PowerMac12,1") == 0) {
406 			args.name = (cell_t)(uintptr_t)"quiesce";
407 			args.nargs = 0;
408 			args.nreturns = 0;
409 			openfirmware(&args);
410 		}
411 	}
412 }
413 
414 static int
415 openfirmware_core(void *args)
416 {
417 	int		result;
418 	register_t	oldmsr;
419 
420 	/*
421 	 * Turn off exceptions - we really don't want to end up
422 	 * anywhere unexpected with PCPU set to something strange
423 	 * or the stack pointer wrong.
424 	 */
425 	oldmsr = intr_disable();
426 
427 	ofw_sprg_prepare();
428 
429 #if defined(AIM) && !defined(__powerpc64__)
430 	/*
431 	 * Clear battable[] translations
432 	 */
433 	if (!(cpu_features & PPC_FEATURE_64))
434 		__asm __volatile("mtdbatu 2, %0\n"
435 				 "mtdbatu 3, %0" : : "r" (0));
436 	isync();
437 #endif
438 
439        	result = ofwcall(args);
440 	ofw_sprg_restore();
441 
442 	intr_restore(oldmsr);
443 
444 	return (result);
445 }
446 
447 #ifdef SMP
448 struct ofw_rv_args {
449 	void *args;
450 	int retval;
451 	volatile int in_progress;
452 };
453 
454 static void
455 ofw_rendezvous_dispatch(void *xargs)
456 {
457 	struct ofw_rv_args *rv_args = xargs;
458 
459 	/* NOTE: Interrupts are disabled here */
460 
461 	if (PCPU_GET(cpuid) == 0) {
462 		/*
463 		 * Execute all OF calls on CPU 0
464 		 */
465 		rv_args->retval = openfirmware_core(rv_args->args);
466 		rv_args->in_progress = 0;
467 	} else {
468 		/*
469 		 * Spin with interrupts off on other CPUs while OF has
470 		 * control of the machine.
471 		 */
472 		while (rv_args->in_progress)
473 			cpu_spinwait();
474 	}
475 }
476 #endif
477 
478 static int
479 openfirmware(void *args)
480 {
481 	int result;
482 	#ifdef SMP
483 	struct ofw_rv_args rv_args;
484 	#endif
485 
486 	if (pmap_bootstrapped && ofw_real_mode)
487 		args = (void *)pmap_kextract((vm_offset_t)args);
488 
489 	#ifdef SMP
490 	rv_args.args = args;
491 	rv_args.in_progress = 1;
492 	smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
493 	    smp_no_rendevous_barrier, &rv_args);
494 	result = rv_args.retval;
495 	#else
496 	result = openfirmware_core(args);
497 	#endif
498 
499 	return (result);
500 }
501 
502 void
503 OF_reboot()
504 {
505 	struct {
506 		cell_t name;
507 		cell_t nargs;
508 		cell_t nreturns;
509 		cell_t arg;
510 	} args;
511 
512 	args.name = (cell_t)(uintptr_t)"interpret";
513 	args.nargs = 1;
514 	args.nreturns = 0;
515 	args.arg = (cell_t)(uintptr_t)"reset-all";
516 	openfirmware_core(&args); /* Don't do rendezvous! */
517 
518 	for (;;);	/* just in case */
519 }
520 
521 void
522 OF_getetheraddr(device_t dev, u_char *addr)
523 {
524 	phandle_t	node;
525 
526 	node = ofw_bus_get_node(dev);
527 	OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
528 }
529 
530 /*
531  * Return a bus handle and bus tag that corresponds to the register
532  * numbered regno for the device referenced by the package handle
533  * dev. This function is intended to be used by console drivers in
534  * early boot only. It works by mapping the address of the device's
535  * register in the address space of its parent and recursively walk
536  * the device tree upward this way.
537  */
538 static void
539 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
540 {
541 	char name[16];
542 	uint32_t addr, size;
543 	int pci, res;
544 
545 	res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
546 	if (res == -1)
547 		addr = 2;
548 	res = OF_getprop(node, "#size-cells", &size, sizeof(size));
549 	if (res == -1)
550 		size = 1;
551 	pci = 0;
552 	if (addr == 3 && size == 2) {
553 		res = OF_getprop(node, "name", name, sizeof(name));
554 		if (res != -1) {
555 			name[sizeof(name) - 1] = '\0';
556 			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
557 		}
558 	}
559 	if (addrp != NULL)
560 		*addrp = addr;
561 	if (sizep != NULL)
562 		*sizep = size;
563 	if (pcip != NULL)
564 		*pcip = pci;
565 }
566 
567 int
568 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
569     bus_space_handle_t *handle)
570 {
571 	uint32_t cell[32];
572 	bus_addr_t addr, raddr, baddr;
573 	bus_size_t size, rsize;
574 	uint32_t c, nbridge, naddr, nsize;
575 	phandle_t bridge, parent;
576 	u_int spc, rspc;
577 	int pci, pcib, res;
578 
579 	/* Sanity checking. */
580 	if (dev == 0)
581 		return (EINVAL);
582 	bridge = OF_parent(dev);
583 	if (bridge == 0)
584 		return (EINVAL);
585 	if (regno < 0)
586 		return (EINVAL);
587 	if (tag == NULL || handle == NULL)
588 		return (EINVAL);
589 
590 	/* Get the requested register. */
591 	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
592 	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
593 	    cell, sizeof(cell));
594 	if (res == -1)
595 		return (ENXIO);
596 	if (res % sizeof(cell[0]))
597 		return (ENXIO);
598 	res /= sizeof(cell[0]);
599 	regno *= naddr + nsize;
600 	if (regno + naddr + nsize > res)
601 		return (EINVAL);
602 	spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
603 	addr = 0;
604 	for (c = 0; c < naddr; c++)
605 		addr = ((uint64_t)addr << 32) | cell[regno++];
606 	size = 0;
607 	for (c = 0; c < nsize; c++)
608 		size = ((uint64_t)size << 32) | cell[regno++];
609 
610 	/*
611 	 * Map the address range in the bridge's decoding window as given
612 	 * by the "ranges" property. If a node doesn't have such property
613 	 * then no mapping is done.
614 	 */
615 	parent = OF_parent(bridge);
616 	while (parent != 0) {
617 		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
618 		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
619 		if (res == -1)
620 			goto next;
621 		if (res % sizeof(cell[0]))
622 			return (ENXIO);
623 		res /= sizeof(cell[0]);
624 		regno = 0;
625 		while (regno < res) {
626 			rspc = (pci)
627 			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
628 			    : ~0;
629 			if (rspc != spc) {
630 				regno += naddr + nbridge + nsize;
631 				continue;
632 			}
633 			raddr = 0;
634 			for (c = 0; c < naddr; c++)
635 				raddr = ((uint64_t)raddr << 32) | cell[regno++];
636 			rspc = (pcib)
637 			    ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
638 			    : ~0;
639 			baddr = 0;
640 			for (c = 0; c < nbridge; c++)
641 				baddr = ((uint64_t)baddr << 32) | cell[regno++];
642 			rsize = 0;
643 			for (c = 0; c < nsize; c++)
644 				rsize = ((uint64_t)rsize << 32) | cell[regno++];
645 			if (addr < raddr || addr >= raddr + rsize)
646 				continue;
647 			addr = addr - raddr + baddr;
648 			if (rspc != ~0)
649 				spc = rspc;
650 		}
651 
652 	next:
653 		bridge = parent;
654 		parent = OF_parent(bridge);
655 		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
656 	}
657 
658 	*tag = &bs_le_tag;
659 	return (bus_space_map(*tag, addr, size, 0, handle));
660 }
661 
662