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>
62 #include <machine/trap.h>
65 extern register_t ofmsr[5];
66 extern void *openfirmware_entry;
69 extern char save_trap_init[0x2f00]; /* EXC_LAST */
70 char save_trap_of[0x2f00]; /* EXC_LAST */
73 static int openfirmware(void *args);
76 ofw_save_trap_vec(char *save_trap_vec)
81 bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
85 ofw_restore_trap_vec(char *restore_trap_vec)
90 bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
91 __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
95 * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
97 register_t ofw_sprg0_save;
100 ofw_sprg_prepare(void)
106 * Assume that interrupt are disabled at this point, or
107 * SPRG1-3 could be trashed
109 __asm __volatile("mfsprg0 %0\n\t"
114 : "=&r"(ofw_sprg0_save)
122 ofw_sprg_restore(void)
130 * Note that SPRG1-3 contents are irrelevant. They are scratch
131 * registers used in the early portion of trap handling when
132 * interrupts are disabled.
134 * PCPU data cannot be used until this routine is called !
136 __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
141 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
143 cell_t address_cells, size_cells;
144 cell_t OFmem[4 * PHYS_AVAIL_SZ];
153 * Get #address-cells from root node, defaulting to 1 if it cannot
156 phandle = OF_finddevice("/");
157 if (OF_getprop(phandle, "#address-cells", &address_cells,
158 sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
160 if (OF_getprop(phandle, "#size-cells", &size_cells,
161 sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
167 if (node == -1 || (sz = OF_getprop(node, prop,
168 OFmem, sizeof(OFmem))) <= 0)
169 panic("Physical memory map not found");
173 while (i < sz/sizeof(cell_t)) {
174 #ifndef __powerpc64__
175 /* On 32-bit PPC, ignore regions starting above 4 GB */
176 if (address_cells > 1 && OFmem[i] > 0) {
177 i += address_cells + size_cells;
182 output[j].mr_start = OFmem[i++];
183 if (address_cells == 2) {
185 output[j].mr_start <<= 32;
187 output[j].mr_start += OFmem[i++];
190 output[j].mr_size = OFmem[i++];
191 if (size_cells == 2) {
193 output[j].mr_size <<= 32;
195 output[j].mr_size += OFmem[i++];
198 #ifndef __powerpc64__
200 * Check for memory regions extending above 32-bit
201 * memory space, and restrict them to stay there.
203 if (((uint64_t)output[j].mr_start +
204 (uint64_t)output[j].mr_size) >
205 BUS_SPACE_MAXADDR_32BIT) {
206 output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
213 sz = j*sizeof(output[0]);
219 * This is called during powerpc_init, before the system is really initialized.
220 * It shall provide the total and the available regions of RAM.
221 * Both lists must have a zero-size entry as terminator.
222 * The available regions need not take the kernel into account, but needs
223 * to provide space for two additional entry beyond the terminating one.
226 ofw_mem_regions(struct mem_region *memp, int *memsz,
227 struct mem_region *availp, int *availsz)
237 * Get memory from all the /memory nodes.
239 for (phandle = OF_child(OF_peer(0)); phandle != 0;
240 phandle = OF_peer(phandle)) {
241 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
243 if (strncmp(name, "memory", sizeof(name)) != 0)
246 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
247 msz += res/sizeof(struct mem_region);
248 if (OF_getproplen(phandle, "available") >= 0)
249 res = parse_ofw_memory(phandle, "available",
252 res = parse_ofw_memory(phandle, "reg", &availp[asz]);
253 asz += res/sizeof(struct mem_region);
262 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
264 if (ofmsr[0] & PSL_DR)
271 #ifdef FDT_DTB_STATIC
272 /* Check for a statically included blob */
274 fdt = &fdt_static_dtb;
281 boolean_t status = FALSE;
283 if (openfirmware_entry != NULL) {
285 status = OF_install(OFW_STD_REAL, 0);
288 status = OF_install(OFW_STD_32BIT, 0);
290 status = OF_install(OFW_STD_DIRECT, 0);
297 OF_init(openfirmware);
298 } else if (fdt != NULL) {
299 status = OF_install(OFW_FDT, 0);
319 KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
321 args.name = (cell_t)(uintptr_t)"quiesce";
328 openfirmware_core(void *args)
334 * Turn off exceptions - we really don't want to end up
335 * anywhere unexpected with PCPU set to something strange
336 * or the stack pointer wrong.
338 oldmsr = intr_disable();
342 /* Save trap vectors */
343 ofw_save_trap_vec(save_trap_of);
345 /* Restore initially saved trap vectors */
346 ofw_restore_trap_vec(save_trap_init);
348 #if defined(AIM) && !defined(__powerpc64__)
350 * Clear battable[] translations
352 if (!(cpu_features & PPC_FEATURE_64))
353 __asm __volatile("mtdbatu 2, %0\n"
354 "mtdbatu 3, %0" : : "r" (0));
358 result = ofwcall(args);
360 /* Restore trap vecotrs */
361 ofw_restore_trap_vec(save_trap_of);
365 intr_restore(oldmsr);
374 volatile int in_progress;
378 ofw_rendezvous_dispatch(void *xargs)
380 struct ofw_rv_args *rv_args = xargs;
382 /* NOTE: Interrupts are disabled here */
384 if (PCPU_GET(cpuid) == 0) {
386 * Execute all OF calls on CPU 0
388 rv_args->retval = openfirmware_core(rv_args->args);
389 rv_args->in_progress = 0;
392 * Spin with interrupts off on other CPUs while OF has
393 * control of the machine.
395 while (rv_args->in_progress)
402 openfirmware(void *args)
406 struct ofw_rv_args rv_args;
409 rv_args.in_progress = 1;
410 smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
411 smp_no_rendevous_barrier, &rv_args);
412 result = rv_args.retval;
414 result = openfirmware_core(args);
430 args.name = (cell_t)(uintptr_t)"interpret";
433 args.arg = (cell_t)(uintptr_t)"reset-all";
434 openfirmware_core(&args); /* Don't do rendezvous! */
436 for (;;); /* just in case */
442 OF_getetheraddr(device_t dev, u_char *addr)
446 node = ofw_bus_get_node(dev);
447 OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
451 * Return a bus handle and bus tag that corresponds to the register
452 * numbered regno for the device referenced by the package handle
453 * dev. This function is intended to be used by console drivers in
454 * early boot only. It works by mapping the address of the device's
455 * register in the address space of its parent and recursively walk
456 * the device tree upward this way.
459 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
465 res = OF_getprop(node, "#address-cells", &addr, sizeof(addr));
468 res = OF_getprop(node, "#size-cells", &size, sizeof(size));
472 if (addr == 3 && size == 2) {
473 res = OF_getprop(node, "device_type", type, sizeof(type));
475 type[sizeof(type) - 1] = '\0';
476 pci = (strcmp(type, "pci") == 0) ? 1 : 0;
488 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
489 bus_space_handle_t *handle)
492 bus_addr_t addr, raddr, baddr;
493 bus_size_t size, rsize;
494 uint32_t c, nbridge, naddr, nsize;
495 phandle_t bridge, parent;
496 u_int spc, rspc, prefetch;
499 /* Sanity checking. */
502 bridge = OF_parent(dev);
507 if (tag == NULL || handle == NULL)
510 /* Assume big-endian unless we find a PCI device */
513 /* Get the requested register. */
514 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
517 res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
521 if (res % sizeof(cell[0]))
523 res /= sizeof(cell[0]);
524 regno *= naddr + nsize;
525 if (regno + naddr + nsize > res)
527 spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0;
528 prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0;
530 for (c = 0; c < naddr; c++)
531 addr = ((uint64_t)addr << 32) | cell[regno++];
533 for (c = 0; c < nsize; c++)
534 size = ((uint64_t)size << 32) | cell[regno++];
537 * Map the address range in the bridge's decoding window as given
538 * by the "ranges" property. If a node doesn't have such property
539 * then no mapping is done.
541 parent = OF_parent(bridge);
542 while (parent != 0) {
543 OF_get_addr_props(parent, &nbridge, NULL, &pcib);
546 res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
549 if (res % sizeof(cell[0]))
551 res /= sizeof(cell[0]);
553 while (regno < res) {
555 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
558 regno += naddr + nbridge + nsize;
562 for (c = 0; c < naddr; c++)
563 raddr = ((uint64_t)raddr << 32) | cell[regno++];
565 ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
568 for (c = 0; c < nbridge; c++)
569 baddr = ((uint64_t)baddr << 32) | cell[regno++];
571 for (c = 0; c < nsize; c++)
572 rsize = ((uint64_t)rsize << 32) | cell[regno++];
573 if (addr < raddr || addr >= raddr + rsize)
575 addr = addr - raddr + baddr;
582 parent = OF_parent(bridge);
583 OF_get_addr_props(bridge, &naddr, &nsize, &pci);
586 return (bus_space_map(*tag, addr, size,
587 prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));