2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (C) 1996 Wolfgang Solfrank.
5 * Copyright (C) 1996 TooLs GmbH.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include "opt_platform.h"
40 #include <sys/param.h>
42 #include <sys/systm.h>
45 #include <sys/fcntl.h>
46 #include <sys/malloc.h>
49 #include <sys/endian.h>
51 #include <net/ethernet.h>
53 #include <dev/fdt/fdt_common.h>
54 #include <dev/ofw/openfirm.h>
55 #include <dev/ofw/ofw_pci.h>
56 #include <dev/ofw/ofw_bus.h>
57 #include <dev/ofw/ofw_subr.h>
60 #include <vm/vm_param.h>
61 #include <vm/vm_page.h>
63 #include <machine/bus.h>
64 #include <machine/cpu.h>
65 #include <machine/md_var.h>
66 #include <machine/platform.h>
67 #include <machine/ofw_machdep.h>
68 #include <machine/trap.h>
70 #include <contrib/libfdt/libfdt.h>
76 extern register_t ofmsr[5];
77 extern void *openfirmware_entry;
78 char save_trap_init[0x2f00]; /* EXC_LAST */
79 char save_trap_of[0x2f00]; /* EXC_LAST */
82 static int openfirmware(void *args);
85 ofw_save_trap_vec(char *save_trap_vec)
90 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
94 ofw_restore_trap_vec(char *restore_trap_vec)
99 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
100 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
104 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
106 register_t ofw_sprg0_save;
109 ofw_sprg_prepare(void)
115 * Assume that interrupt are disabled at this point, or
116 * SPRG1-3 could be trashed
119 __asm __volatile("mtsprg1 %0\n\t"
127 __asm __volatile("mfsprg0 %0\n\t"
132 : "=&r"(ofw_sprg0_save)
141 ofw_sprg_restore(void)
147 * Note that SPRG1-3 contents are irrelevant. They are scratch
148 * registers used in the early portion of trap handling when
149 * interrupts are disabled.
151 * PCPU data cannot be used until this routine is called !
153 #ifndef __powerpc64__
154 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
160 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
162 cell_t address_cells, size_cells;
163 cell_t OFmem[4 * PHYS_AVAIL_SZ];
170 * Get #address-cells from root node, defaulting to 1 if it cannot
173 phandle = OF_finddevice("/");
174 if (OF_getencprop(phandle, "#address-cells", &address_cells,
175 sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
177 if (OF_getencprop(phandle, "#size-cells", &size_cells,
178 sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
184 if (node == -1 || (sz = OF_getencprop(node, prop,
185 OFmem, sizeof(OFmem))) <= 0)
186 panic("Physical memory map not found");
190 while (i < sz/sizeof(cell_t)) {
191 output[j].mr_start = OFmem[i++];
192 if (address_cells == 2) {
193 output[j].mr_start <<= 32;
194 output[j].mr_start += OFmem[i++];
197 output[j].mr_size = OFmem[i++];
198 if (size_cells == 2) {
199 output[j].mr_size <<= 32;
200 output[j].mr_size += OFmem[i++];
203 if (output[j].mr_start > BUS_SPACE_MAXADDR)
207 * Constrain memory to that which we can access.
208 * 32-bit AIM can only reference 32 bits of address currently,
209 * but Book-E can access 36 bits.
211 if (((uint64_t)output[j].mr_start +
212 (uint64_t)output[j].mr_size - 1) >
214 output[j].mr_size = BUS_SPACE_MAXADDR -
215 output[j].mr_start + 1;
220 sz = j*sizeof(output[0]);
226 excise_fdt_reserved(struct mem_region *avail, int asz)
236 chosen = OF_finddevice("/chosen");
237 fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
239 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
240 fdtmap[j].address = be64toh(fdtmap[j].address) & ~PAGE_MASK;
241 fdtmap[j].size = round_page(be64toh(fdtmap[j].size));
244 KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap),
245 ("Exceeded number of FDT reservations"));
246 /* Add a virtual entry for the FDT itself */
248 fdtmap[j].address = (vm_offset_t)fdt & ~PAGE_MASK;
249 fdtmap[j].size = round_page(fdt_totalsize(fdt));
250 fdtmapsize += sizeof(fdtmap[0]);
253 for (i = 0; i < asz; i++) {
254 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
256 * Case 1: Exclusion region encloses complete
257 * available entry. Drop it and move on.
259 if (fdtmap[j].address <= avail[i].mr_start &&
260 fdtmap[j].address + fdtmap[j].size >=
261 avail[i].mr_start + avail[i].mr_size) {
262 for (k = i+1; k < asz; k++)
263 avail[k-1] = avail[k];
265 i--; /* Repeat some entries */
270 * Case 2: Exclusion region starts in available entry.
271 * Trim it to where the entry begins and append
272 * a new available entry with the region after
273 * the excluded region, if any.
275 if (fdtmap[j].address >= avail[i].mr_start &&
276 fdtmap[j].address < avail[i].mr_start +
278 if (fdtmap[j].address + fdtmap[j].size <
279 avail[i].mr_start + avail[i].mr_size) {
280 avail[asz].mr_start =
281 fdtmap[j].address + fdtmap[j].size;
282 avail[asz].mr_size = avail[i].mr_start +
288 avail[i].mr_size = fdtmap[j].address -
293 * Case 3: Exclusion region ends in available entry.
294 * Move start point to where the exclusion zone ends.
295 * The case of a contained exclusion zone has already
296 * been caught in case 2.
298 if (fdtmap[j].address + fdtmap[j].size >=
299 avail[i].mr_start && fdtmap[j].address +
300 fdtmap[j].size < avail[i].mr_start +
302 avail[i].mr_size += avail[i].mr_start;
304 fdtmap[j].address + fdtmap[j].size;
305 avail[i].mr_size -= avail[i].mr_start;
314 * This is called during powerpc_init, before the system is really initialized.
315 * It shall provide the total and the available regions of RAM.
316 * The available regions need not take the kernel into account.
319 ofw_mem_regions(struct mem_region *memp, int *memsz,
320 struct mem_region *availp, int *availsz)
330 * Get memory from all the /memory nodes.
332 for (phandle = OF_child(OF_peer(0)); phandle != 0;
333 phandle = OF_peer(phandle)) {
334 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
336 if (strncmp(name, "memory", sizeof(name)) != 0 &&
337 strncmp(name, "memory@", strlen("memory@")) != 0)
340 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
341 msz += res/sizeof(struct mem_region);
342 if (OF_getproplen(phandle, "available") >= 0)
343 res = parse_ofw_memory(phandle, "available",
346 res = parse_ofw_memory(phandle, "reg", &availp[asz]);
347 asz += res/sizeof(struct mem_region);
350 phandle = OF_finddevice("/chosen");
351 if (OF_hasprop(phandle, "fdtmemreserv"))
352 asz = excise_fdt_reserved(availp, asz);
359 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
366 __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
368 __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
369 __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
370 __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
371 openfirmware_entry = openfirm;
373 if (ofmsr[0] & PSL_DR)
378 ofw_save_trap_vec(save_trap_init);
385 #ifdef FDT_DTB_STATIC
386 /* Check for a statically included blob */
388 fdt = &fdt_static_dtb;
395 boolean_t status = FALSE;
399 if (openfirmware_entry != NULL) {
401 status = OF_install(OFW_STD_REAL, 0);
404 status = OF_install(OFW_STD_32BIT, 0);
406 status = OF_install(OFW_STD_DIRECT, 0);
413 err = OF_init(openfirmware);
417 status = OF_install(OFW_FDT, 0);
424 OF_interpret("perform-fixup", 0);
445 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
447 args.name = (cell_t)(uintptr_t)"quiesce";
454 openfirmware_core(void *args)
459 if (openfirmware_entry == NULL)
463 * Turn off exceptions - we really don't want to end up
464 * anywhere unexpected with PCPU set to something strange
465 * or the stack pointer wrong.
467 oldmsr = intr_disable();
471 /* Save trap vectors */
472 ofw_save_trap_vec(save_trap_of);
474 /* Restore initially saved trap vectors */
475 ofw_restore_trap_vec(save_trap_init);
477 #ifndef __powerpc64__
479 * Clear battable[] translations
481 if (!(cpu_features & PPC_FEATURE_64))
482 __asm __volatile("mtdbatu 2, %0\n"
483 "mtdbatu 3, %0" : : "r" (0));
487 result = ofwcall(args);
489 /* Restore trap vecotrs */
490 ofw_restore_trap_vec(save_trap_of);
494 intr_restore(oldmsr);
503 volatile int in_progress;
507 ofw_rendezvous_dispatch(void *xargs)
509 struct ofw_rv_args *rv_args = xargs;
511 /* NOTE: Interrupts are disabled here */
513 if (PCPU_GET(cpuid) == 0) {
515 * Execute all OF calls on CPU 0
517 rv_args->retval = openfirmware_core(rv_args->args);
518 rv_args->in_progress = 0;
521 * Spin with interrupts off on other CPUs while OF has
522 * control of the machine.
524 while (rv_args->in_progress)
531 openfirmware(void *args)
535 struct ofw_rv_args rv_args;
538 if (openfirmware_entry == NULL)
543 result = openfirmware_core(args);
546 rv_args.in_progress = 1;
547 smp_rendezvous(smp_no_rendezvous_barrier,
548 ofw_rendezvous_dispatch, smp_no_rendezvous_barrier,
550 result = rv_args.retval;
553 result = openfirmware_core(args);
569 args.name = (cell_t)(uintptr_t)"interpret";
572 args.arg = (cell_t)(uintptr_t)"reset-all";
573 openfirmware_core(&args); /* Don't do rendezvous! */
575 for (;;); /* just in case */
581 OF_getetheraddr(device_t dev, u_char *addr)
585 node = ofw_bus_get_node(dev);
586 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
590 * Return a bus handle and bus tag that corresponds to the register
591 * numbered regno for the device referenced by the package handle
592 * dev. This function is intended to be used by console drivers in
593 * early boot only. It works by mapping the address of the device's
594 * register in the address space of its parent and recursively walk
595 * the device tree upward this way.
598 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
599 bus_space_handle_t *handle, bus_size_t *sz)
606 res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi);
610 if (pci_hi == OFW_PADDR_NOT_PCI) {
615 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ?
616 BUS_SPACE_MAP_PREFETCHABLE: 0;
622 return (bus_space_map(*tag, addr, size, flags, handle));