2 * Copyright (C) 1996 Wolfgang Solfrank.
3 * Copyright (C) 1996 TooLs GmbH.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
31 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
39 #include <sys/systm.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
47 #include <net/ethernet.h>
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_pci.h>
51 #include <dev/ofw/ofw_bus.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_page.h>
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>
63 static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
64 static struct mem_region OFfree[PHYS_AVAIL_SZ];
66 extern register_t ofmsr[5];
67 extern void *openfirmware_entry;
72 static void ofw_quiesce(void);
73 static int openfirmware(void *args);
76 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
78 register_t ofw_sprg0_save;
81 ofw_sprg_prepare(void)
84 * Assume that interrupt are disabled at this point, or
85 * SPRG1-3 could be trashed
87 __asm __volatile("mfsprg0 %0\n\t"
92 : "=&r"(ofw_sprg0_save)
100 ofw_sprg_restore(void)
103 * Note that SPRG1-3 contents are irrelevant. They are scratch
104 * registers used in the early portion of trap handling when
105 * interrupts are disabled.
107 * PCPU data cannot be used until this routine is called !
109 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
113 * Memory region utilities: determine if two regions overlap,
114 * and merge two overlapping regions into one
117 memr_overlap(struct mem_region *r1, struct mem_region *r2)
119 if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
120 (r2->mr_start + r2->mr_size) < r1->mr_start)
127 memr_merge(struct mem_region *from, struct mem_region *to)
130 end = ulmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
131 to->mr_start = ulmin(from->mr_start, to->mr_start);
132 to->mr_size = end - to->mr_start;
136 * Quick sort callout for comparing memory regions.
138 static int mr_cmp(const void *a, const void *b);
141 mr_cmp(const void *a, const void *b)
143 const struct mem_region *regiona;
144 const struct mem_region *regionb;
148 if (regiona->mr_start < regionb->mr_start)
150 else if (regiona->mr_start > regionb->mr_start)
157 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
159 cell_t address_cells, size_cells;
160 cell_t OFmem[4 * PHYS_AVAIL_SZ];
169 * Get #address-cells from root node, defaulting to 1 if it cannot
172 phandle = OF_finddevice("/");
173 if (OF_getprop(phandle, "#address-cells", &address_cells,
174 sizeof(address_cells)) < sizeof(address_cells))
176 if (OF_getprop(phandle, "#size-cells", &size_cells,
177 sizeof(size_cells)) < sizeof(size_cells))
181 * On Apple hardware, address_cells is always 1 for "available",
182 * even when it is explicitly set to 2. Then all memory above 4 GB
183 * should be added by hand to the available list. Detect Apple hardware
184 * by seeing if ofw_real_mode is set -- only Apple seems to use
187 if (strcmp(prop, "available") == 0 && !ofw_real_mode)
196 if (node == -1 || (sz = OF_getprop(node, prop,
197 OFmem, sizeof(OFmem))) <= 0)
198 panic("Physical memory map not found");
202 while (i < sz/sizeof(cell_t)) {
203 #ifndef __powerpc64__
204 /* On 32-bit PPC, ignore regions starting above 4 GB */
205 if (address_cells > 1 && OFmem[i] > 0) {
206 i += address_cells + size_cells;
211 output[j].mr_start = OFmem[i++];
212 if (address_cells == 2) {
214 output[j].mr_start <<= 32;
216 output[j].mr_start += OFmem[i++];
219 output[j].mr_size = OFmem[i++];
220 if (size_cells == 2) {
222 output[j].mr_size <<= 32;
224 output[j].mr_size += OFmem[i++];
227 #ifndef __powerpc64__
229 * Check for memory regions extending above 32-bit
230 * memory space, and restrict them to stay there.
232 if (((uint64_t)output[j].mr_start +
233 (uint64_t)output[j].mr_size) >
234 BUS_SPACE_MAXADDR_32BIT) {
235 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
242 sz = j*sizeof(output[0]);
245 if (apple_hack_mode) {
246 /* Add in regions above 4 GB to the available list */
247 struct mem_region himem[16];
250 hisz = parse_ofw_memory(node, "reg", himem);
251 for (i = 0; i < hisz/sizeof(himem[0]); i++) {
252 if (himem[i].mr_start > BUS_SPACE_MAXADDR_32BIT) {
253 output[j].mr_start = himem[i].mr_start;
254 output[j].mr_size = himem[i].mr_size;
258 sz = j*sizeof(output[0]);
266 parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
267 struct mem_region *ofavail)
271 int i, idx, len, lasz, lmsz, res;
272 uint32_t lmb_size[2];
273 unsigned long *dmem, flags;
278 phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
280 /* No drconf node, return. */
283 res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
287 /* Parse the /ibm,dynamic-memory.
288 The first position gives the # of entries. The next two words
289 reflect the address of the memory block. The next four words are
290 the DRC index, reserved, list index and flags.
291 (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
293 #el Addr DRC-idx res list-idx flags
294 -------------------------------------------------
295 | 4 | 8 | 4 | 4 | 4 | 4 |....
296 -------------------------------------------------
299 len = OF_getproplen(phandle, "ibm,dynamic-memory");
302 /* We have to use a variable length array on the stack
303 since we have very limited stack space.
305 cell_t arr[len/sizeof(cell_t)];
307 res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
312 /* Number of elements */
316 dmem = (void*)&arr[1];
318 for (i = 0; i < idx; i++) {
322 /* Use region only if available and not reserved. */
323 if ((flags & 0x8) && !(flags & 0x80)) {
324 ofmem[lmsz].mr_start = base;
325 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
326 ofavail[lasz].mr_start = base;
327 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
341 * This is called during powerpc_init, before the system is really initialized.
342 * It shall provide the total and the available regions of RAM.
343 * Both lists must have a zero-size entry as terminator.
344 * The available regions need not take the kernel into account, but needs
345 * to provide space for two additional entry beyond the terminating one.
348 ofw_mem_regions(struct mem_region **memp, int *memsz,
349 struct mem_region **availp, int *availsz)
352 vm_offset_t maxphysaddr;
361 * Get memory from all the /memory nodes.
363 for (phandle = OF_child(OF_peer(0)); phandle != 0;
364 phandle = OF_peer(phandle)) {
365 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
367 if (strncmp(name, "memory", sizeof(name)) != 0)
370 res = parse_ofw_memory(phandle, "reg", &OFmem[msz]);
371 msz += res/sizeof(struct mem_region);
372 if (OF_getproplen(phandle, "available") >= 0)
373 res = parse_ofw_memory(phandle, "available",
376 res = parse_ofw_memory(phandle, "reg", &OFavail[asz]);
377 asz += res/sizeof(struct mem_region);
380 /* Check for memory in ibm,dynamic-reconfiguration-memory */
381 parse_drconf_memory(&msz, &asz, OFmem, OFavail);
383 qsort(OFmem, msz, sizeof(*OFmem), mr_cmp);
384 qsort(OFavail, asz, sizeof(*OFavail), mr_cmp);
390 * On some firmwares (SLOF), some memory may be marked available that
391 * doesn't actually exist. This manifests as an extension of the last
392 * available segment past the end of physical memory, so truncate that
396 for (i = 0; i < msz; i++)
397 if (OFmem[i].mr_start + OFmem[i].mr_size > maxphysaddr)
398 maxphysaddr = OFmem[i].mr_start + OFmem[i].mr_size;
400 if (OFavail[asz - 1].mr_start + OFavail[asz - 1].mr_size > maxphysaddr)
401 OFavail[asz - 1].mr_size = maxphysaddr -
402 OFavail[asz - 1].mr_start;
405 * OFavail may have overlapping regions - collapse these
406 * and copy out remaining regions to OFfree
409 still_merging = FALSE;
410 for (i = 0; i < asz; i++) {
411 if (OFavail[i].mr_size == 0)
413 for (j = i+1; j < asz; j++) {
414 if (OFavail[j].mr_size == 0)
416 if (memr_overlap(&OFavail[j], &OFavail[i])) {
417 memr_merge(&OFavail[j], &OFavail[i]);
419 OFavail[j].mr_size = 0;
420 still_merging = TRUE;
424 } while (still_merging == TRUE);
426 /* evict inactive ranges */
427 for (i = 0, fsz = 0; i < asz; i++) {
428 if (OFavail[i].mr_size != 0) {
429 OFfree[fsz] = OFavail[i];
439 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
441 if (ofmsr[0] & PSL_DR)
448 #ifdef FDT_DTB_STATIC
449 /* Check for a statically included blob */
451 fdt = &fdt_static_dtb;
458 boolean_t status = FALSE;
460 if (openfirmware_entry != NULL) {
462 status = OF_install(OFW_STD_REAL, 0);
465 status = OF_install(OFW_STD_32BIT, 0);
467 status = OF_install(OFW_STD_DIRECT, 0);
474 OF_init(openfirmware);
477 * On some machines, we need to quiesce OF to turn off
478 * background processes.
481 } else if (fdt != NULL) {
482 status = OF_install(OFW_FDT, 0);
505 * Only quiesce Open Firmware on PowerMac11,2 and 12,1. It is
506 * necessary there to shut down a background thread doing fan
507 * management, and is harmful on other machines.
509 * Note: we don't need to worry about which OF module we are
510 * using since this is called only from very early boot, within
514 rootnode = OF_finddevice("/");
515 if (OF_getprop(rootnode, "model", model, sizeof(model)) > 0) {
516 if (strcmp(model, "PowerMac11,2") == 0 ||
517 strcmp(model, "PowerMac12,1") == 0) {
518 args.name = (cell_t)(uintptr_t)"quiesce";
527 openfirmware_core(void *args)
533 * Turn off exceptions - we really don't want to end up
534 * anywhere unexpected with PCPU set to something strange
535 * or the stack pointer wrong.
537 oldmsr = intr_disable();
541 #if defined(AIM) && !defined(__powerpc64__)
543 * Clear battable[] translations
545 if (!(cpu_features & PPC_FEATURE_64))
546 __asm __volatile("mtdbatu 2, %0\n"
547 "mtdbatu 3, %0" : : "r" (0));
551 result = ofwcall(args);
554 intr_restore(oldmsr);
563 volatile int in_progress;
567 ofw_rendezvous_dispatch(void *xargs)
569 struct ofw_rv_args *rv_args = xargs;
571 /* NOTE: Interrupts are disabled here */
573 if (PCPU_GET(cpuid) == 0) {
575 * Execute all OF calls on CPU 0
577 rv_args->retval = openfirmware_core(rv_args->args);
578 rv_args->in_progress = 0;
581 * Spin with interrupts off on other CPUs while OF has
582 * control of the machine.
584 while (rv_args->in_progress)
591 openfirmware(void *args)
595 struct ofw_rv_args rv_args;
598 rv_args.in_progress = 1;
599 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
600 smp_no_rendevous_barrier, &rv_args);
601 result = rv_args.retval;
603 result = openfirmware_core(args);
619 args.name = (cell_t)(uintptr_t)"interpret";
622 args.arg = (cell_t)(uintptr_t)"reset-all";
623 openfirmware_core(&args); /* Don't do rendezvous! */
625 for (;;); /* just in case */
629 OF_getetheraddr(device_t dev, u_char *addr)
633 node = ofw_bus_get_node(dev);
634 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
638 * Return a bus handle and bus tag that corresponds to the register
639 * numbered regno for the device referenced by the package handle
640 * dev. This function is intended to be used by console drivers in
641 * early boot only. It works by mapping the address of the device's
642 * register in the address space of its parent and recursively walk
643 * the device tree upward this way.
646 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
652 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
655 res = OF_getprop(node, "#size-cells", &size, sizeof(size));
659 if (addr == 3 && size == 2) {
660 res = OF_getprop(node, "name", name, sizeof(name));
662 name[sizeof(name) - 1] = '\0';
663 pci = (strcmp(name, "pci") == 0) ? 1 : 0;
675 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
676 bus_space_handle_t *handle)
679 bus_addr_t addr, raddr, baddr;
680 bus_size_t size, rsize;
681 uint32_t c, nbridge, naddr, nsize;
682 phandle_t bridge, parent;
686 /* Sanity checking. */
689 bridge = OF_parent(dev);
694 if (tag == NULL || handle == NULL)
697 /* Get the requested register. */
698 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
699 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
703 if (res % sizeof(cell[0]))
705 res /= sizeof(cell[0]);
706 regno *= naddr + nsize;
707 if (regno + naddr + nsize > res)
709 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
711 for (c = 0; c < naddr; c++)
712 addr = ((uint64_t)addr << 32) | cell[regno++];
714 for (c = 0; c < nsize; c++)
715 size = ((uint64_t)size << 32) | cell[regno++];
718 * Map the address range in the bridge's decoding window as given
719 * by the "ranges" property. If a node doesn't have such property
720 * then no mapping is done.
722 parent = OF_parent(bridge);
723 while (parent != 0) {
724 OF_get_addr_props(parent, &nbridge, NULL, &pcib);
725 res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
728 if (res % sizeof(cell[0]))
730 res /= sizeof(cell[0]);
732 while (regno < res) {
734 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
737 regno += naddr + nbridge + nsize;
741 for (c = 0; c < naddr; c++)
742 raddr = ((uint64_t)raddr << 32) | cell[regno++];
744 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
747 for (c = 0; c < nbridge; c++)
748 baddr = ((uint64_t)baddr << 32) | cell[regno++];
750 for (c = 0; c < nsize; c++)
751 rsize = ((uint64_t)rsize << 32) | cell[regno++];
752 if (addr < raddr || addr >= raddr + rsize)
754 addr = addr - raddr + baddr;
761 parent = OF_parent(bridge);
762 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
766 return (bus_space_map(*tag, addr, size, 0, handle));