1fe3b4685SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 371e3c308SPedro F. Giffuni * 4fe3b4685SNathan Whitehorn * Copyright (C) 1996 Wolfgang Solfrank. 5fe3b4685SNathan Whitehorn * Copyright (C) 1996 TooLs GmbH. 6fe3b4685SNathan Whitehorn * All rights reserved. 7fe3b4685SNathan Whitehorn * 8fe3b4685SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 9fe3b4685SNathan Whitehorn * modification, are permitted provided that the following conditions 10fe3b4685SNathan Whitehorn * are met: 11fe3b4685SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 12fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 13fe3b4685SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 14fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 15fe3b4685SNathan Whitehorn * documentation and/or other materials provided with the distribution. 16fe3b4685SNathan Whitehorn * 3. All advertising materials mentioning features or use of this software 17fe3b4685SNathan Whitehorn * must display the following acknowledgement: 18fe3b4685SNathan Whitehorn * This product includes software developed by TooLs GmbH. 19fe3b4685SNathan Whitehorn * 4. The name of TooLs GmbH may not be used to endorse or promote products 20fe3b4685SNathan Whitehorn * derived from this software without specific prior written permission. 21fe3b4685SNathan Whitehorn * 22fe3b4685SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23fe3b4685SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24fe3b4685SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25fe3b4685SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26fe3b4685SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27fe3b4685SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28fe3b4685SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29fe3b4685SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30fe3b4685SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31fe3b4685SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32fe3b4685SNathan Whitehorn * 33fe3b4685SNathan Whitehorn * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 34fe3b4685SNathan Whitehorn */ 35fe3b4685SNathan Whitehorn 36fe3b4685SNathan Whitehorn #include <sys/cdefs.h> 37fe3b4685SNathan Whitehorn __FBSDID("$FreeBSD$"); 38fe3b4685SNathan Whitehorn 398c092157SJustin Hibbits #include "opt_platform.h" 40fe3b4685SNathan Whitehorn #include <sys/param.h> 41fe3b4685SNathan Whitehorn #include <sys/bus.h> 42fe3b4685SNathan Whitehorn #include <sys/systm.h> 43fe3b4685SNathan Whitehorn #include <sys/conf.h> 44fe3b4685SNathan Whitehorn #include <sys/disk.h> 45fe3b4685SNathan Whitehorn #include <sys/fcntl.h> 46fe3b4685SNathan Whitehorn #include <sys/malloc.h> 47fe3b4685SNathan Whitehorn #include <sys/smp.h> 48fe3b4685SNathan Whitehorn #include <sys/stat.h> 49b9d056f3SNathan Whitehorn #include <sys/endian.h> 50fe3b4685SNathan Whitehorn 51fe3b4685SNathan Whitehorn #include <net/ethernet.h> 52fe3b4685SNathan Whitehorn 538c092157SJustin Hibbits #include <dev/fdt/fdt_common.h> 54fe3b4685SNathan Whitehorn #include <dev/ofw/openfirm.h> 55fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_pci.h> 56fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 57bc7b9300SIan Lepore #include <dev/ofw/ofw_subr.h> 58fe3b4685SNathan Whitehorn 59fe3b4685SNathan Whitehorn #include <vm/vm.h> 60fe3b4685SNathan Whitehorn #include <vm/vm_param.h> 61fe3b4685SNathan Whitehorn #include <vm/vm_page.h> 62fe3b4685SNathan Whitehorn 63fe3b4685SNathan Whitehorn #include <machine/bus.h> 64fe3b4685SNathan Whitehorn #include <machine/cpu.h> 65fe3b4685SNathan Whitehorn #include <machine/md_var.h> 66fe3b4685SNathan Whitehorn #include <machine/platform.h> 67fe3b4685SNathan Whitehorn #include <machine/ofw_machdep.h> 68f367ffdeSAndreas Tobler #include <machine/trap.h> 69fe3b4685SNathan Whitehorn 70c0650b2fSNathan Whitehorn #include <contrib/libfdt/libfdt.h> 71c0650b2fSNathan Whitehorn 726f489d43SJustin Hibbits static void *fdt; 736f489d43SJustin Hibbits int ofw_real_mode; 746f489d43SJustin Hibbits 75629aa519SNathan Whitehorn #ifdef AIM 76fe3b4685SNathan Whitehorn extern register_t ofmsr[5]; 7717879090SNathan Whitehorn extern void *openfirmware_entry; 78bb808254SNathan Whitehorn char save_trap_init[0x2f00]; /* EXC_LAST */ 79f367ffdeSAndreas Tobler char save_trap_of[0x2f00]; /* EXC_LAST */ 80fe3b4685SNathan Whitehorn 81d8c6808aSNathan Whitehorn int ofwcall(void *); 82fe3b4685SNathan Whitehorn static int openfirmware(void *args); 83fe3b4685SNathan Whitehorn 84f367ffdeSAndreas Tobler __inline void 85f367ffdeSAndreas Tobler ofw_save_trap_vec(char *save_trap_vec) 86f367ffdeSAndreas Tobler { 87f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 88f367ffdeSAndreas Tobler return; 89f367ffdeSAndreas Tobler 90f9edb09dSNathan Whitehorn bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST); 91f367ffdeSAndreas Tobler } 92f367ffdeSAndreas Tobler 93f367ffdeSAndreas Tobler static __inline void 94f367ffdeSAndreas Tobler ofw_restore_trap_vec(char *restore_trap_vec) 95f367ffdeSAndreas Tobler { 96f9edb09dSNathan Whitehorn if (!ofw_real_mode || !hw_direct_map) 97f367ffdeSAndreas Tobler return; 98f367ffdeSAndreas Tobler 99f9edb09dSNathan Whitehorn bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST), 100f9edb09dSNathan Whitehorn EXC_LAST - EXC_RST); 101f9edb09dSNathan Whitehorn __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD); 102f367ffdeSAndreas Tobler } 1034aa3cee6SNathan Whitehorn 1044aa3cee6SNathan Whitehorn /* 1054aa3cee6SNathan Whitehorn * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 1064aa3cee6SNathan Whitehorn */ 1074aa3cee6SNathan Whitehorn register_t ofw_sprg0_save; 1084aa3cee6SNathan Whitehorn 1094aa3cee6SNathan Whitehorn static __inline void 1104aa3cee6SNathan Whitehorn ofw_sprg_prepare(void) 1114aa3cee6SNathan Whitehorn { 1124aa3cee6SNathan Whitehorn if (ofw_real_mode) 1134aa3cee6SNathan Whitehorn return; 1144aa3cee6SNathan Whitehorn 1154aa3cee6SNathan Whitehorn /* 1164aa3cee6SNathan Whitehorn * Assume that interrupt are disabled at this point, or 1174aa3cee6SNathan Whitehorn * SPRG1-3 could be trashed 1184aa3cee6SNathan Whitehorn */ 11962c6b30eSJustin Hibbits #ifdef __powerpc64__ 12062c6b30eSJustin Hibbits __asm __volatile("mtsprg1 %0\n\t" 12162c6b30eSJustin Hibbits "mtsprg2 %1\n\t" 12262c6b30eSJustin Hibbits "mtsprg3 %2\n\t" 12362c6b30eSJustin Hibbits : 12462c6b30eSJustin Hibbits : "r"(ofmsr[2]), 12562c6b30eSJustin Hibbits "r"(ofmsr[3]), 12662c6b30eSJustin Hibbits "r"(ofmsr[4])); 12762c6b30eSJustin Hibbits #else 1284aa3cee6SNathan Whitehorn __asm __volatile("mfsprg0 %0\n\t" 1294aa3cee6SNathan Whitehorn "mtsprg0 %1\n\t" 1304aa3cee6SNathan Whitehorn "mtsprg1 %2\n\t" 1314aa3cee6SNathan Whitehorn "mtsprg2 %3\n\t" 1324aa3cee6SNathan Whitehorn "mtsprg3 %4\n\t" 1334aa3cee6SNathan Whitehorn : "=&r"(ofw_sprg0_save) 1344aa3cee6SNathan Whitehorn : "r"(ofmsr[1]), 1354aa3cee6SNathan Whitehorn "r"(ofmsr[2]), 1364aa3cee6SNathan Whitehorn "r"(ofmsr[3]), 1374aa3cee6SNathan Whitehorn "r"(ofmsr[4])); 13862c6b30eSJustin Hibbits #endif 1394aa3cee6SNathan Whitehorn } 1404aa3cee6SNathan Whitehorn 1414aa3cee6SNathan Whitehorn static __inline void 1424aa3cee6SNathan Whitehorn ofw_sprg_restore(void) 1434aa3cee6SNathan Whitehorn { 1444aa3cee6SNathan Whitehorn if (ofw_real_mode) 1454aa3cee6SNathan Whitehorn return; 1464aa3cee6SNathan Whitehorn 1474aa3cee6SNathan Whitehorn /* 1484aa3cee6SNathan Whitehorn * Note that SPRG1-3 contents are irrelevant. They are scratch 1494aa3cee6SNathan Whitehorn * registers used in the early portion of trap handling when 1504aa3cee6SNathan Whitehorn * interrupts are disabled. 1514aa3cee6SNathan Whitehorn * 1524aa3cee6SNathan Whitehorn * PCPU data cannot be used until this routine is called ! 1534aa3cee6SNathan Whitehorn */ 15462c6b30eSJustin Hibbits #ifndef __powerpc64__ 1554aa3cee6SNathan Whitehorn __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 15662c6b30eSJustin Hibbits #endif 1574aa3cee6SNathan Whitehorn } 158c7291bdcSNathan Whitehorn #endif 159f367ffdeSAndreas Tobler 160fe3b4685SNathan Whitehorn static int 161fe3b4685SNathan Whitehorn parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 162fe3b4685SNathan Whitehorn { 163fe3b4685SNathan Whitehorn cell_t address_cells, size_cells; 164d8c6808aSNathan Whitehorn cell_t OFmem[4 * PHYS_AVAIL_SZ]; 165fe3b4685SNathan Whitehorn int sz, i, j; 166fe3b4685SNathan Whitehorn phandle_t phandle; 167fe3b4685SNathan Whitehorn 168fe3b4685SNathan Whitehorn sz = 0; 169fe3b4685SNathan Whitehorn 170fe3b4685SNathan Whitehorn /* 171fe3b4685SNathan Whitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 172fe3b4685SNathan Whitehorn * be found. 173fe3b4685SNathan Whitehorn */ 174fe3b4685SNathan Whitehorn phandle = OF_finddevice("/"); 175509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#address-cells", &address_cells, 1768bab0d80SNathan Whitehorn sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 177fe3b4685SNathan Whitehorn address_cells = 1; 178509142e1SNathan Whitehorn if (OF_getencprop(phandle, "#size-cells", &size_cells, 1798bab0d80SNathan Whitehorn sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 180fe3b4685SNathan Whitehorn size_cells = 1; 181fe3b4685SNathan Whitehorn 182fe3b4685SNathan Whitehorn /* 183fe3b4685SNathan Whitehorn * Get memory. 184fe3b4685SNathan Whitehorn */ 185509142e1SNathan Whitehorn if (node == -1 || (sz = OF_getencprop(node, prop, 186d8c6808aSNathan Whitehorn OFmem, sizeof(OFmem))) <= 0) 187fe3b4685SNathan Whitehorn panic("Physical memory map not found"); 188fe3b4685SNathan Whitehorn 189fe3b4685SNathan Whitehorn i = 0; 190fe3b4685SNathan Whitehorn j = 0; 191fe3b4685SNathan Whitehorn while (i < sz/sizeof(cell_t)) { 192fe3b4685SNathan Whitehorn output[j].mr_start = OFmem[i++]; 193fe3b4685SNathan Whitehorn if (address_cells == 2) { 194fe3b4685SNathan Whitehorn output[j].mr_start <<= 32; 195fe3b4685SNathan Whitehorn output[j].mr_start += OFmem[i++]; 196fe3b4685SNathan Whitehorn } 197fe3b4685SNathan Whitehorn 198fe3b4685SNathan Whitehorn output[j].mr_size = OFmem[i++]; 199fe3b4685SNathan Whitehorn if (size_cells == 2) { 200fe3b4685SNathan Whitehorn output[j].mr_size <<= 32; 201fe3b4685SNathan Whitehorn output[j].mr_size += OFmem[i++]; 202fe3b4685SNathan Whitehorn } 203fe3b4685SNathan Whitehorn 204bb7137e1SJustin Hibbits if (output[j].mr_start > BUS_SPACE_MAXADDR) 205bb7137e1SJustin Hibbits continue; 206bb7137e1SJustin Hibbits 207fe3b4685SNathan Whitehorn /* 208bb7137e1SJustin Hibbits * Constrain memory to that which we can access. 209bb7137e1SJustin Hibbits * 32-bit AIM can only reference 32 bits of address currently, 210bb7137e1SJustin Hibbits * but Book-E can access 36 bits. 211fe3b4685SNathan Whitehorn */ 212fe3b4685SNathan Whitehorn if (((uint64_t)output[j].mr_start + 213bb7137e1SJustin Hibbits (uint64_t)output[j].mr_size - 1) > 214bb7137e1SJustin Hibbits BUS_SPACE_MAXADDR) { 215bb7137e1SJustin Hibbits output[j].mr_size = BUS_SPACE_MAXADDR - 216bb7137e1SJustin Hibbits output[j].mr_start + 1; 217fe3b4685SNathan Whitehorn } 218fe3b4685SNathan Whitehorn 219fe3b4685SNathan Whitehorn j++; 220fe3b4685SNathan Whitehorn } 221fe3b4685SNathan Whitehorn sz = j*sizeof(output[0]); 222fe3b4685SNathan Whitehorn 223fe3b4685SNathan Whitehorn return (sz); 224fe3b4685SNathan Whitehorn } 225fe3b4685SNathan Whitehorn 22635feca37SNathan Whitehorn #ifdef FDT 227b9d056f3SNathan Whitehorn static int 228b9d056f3SNathan Whitehorn excise_fdt_reserved(struct mem_region *avail, int asz) 229b9d056f3SNathan Whitehorn { 230b9d056f3SNathan Whitehorn struct { 231b9d056f3SNathan Whitehorn uint64_t address; 232b9d056f3SNathan Whitehorn uint64_t size; 23342ca1d5cSJustin Hibbits } fdtmap[32]; 234b9d056f3SNathan Whitehorn ssize_t fdtmapsize; 235b9d056f3SNathan Whitehorn phandle_t chosen; 236b9d056f3SNathan Whitehorn int i, j, k; 237b9d056f3SNathan Whitehorn 238b9d056f3SNathan Whitehorn chosen = OF_finddevice("/chosen"); 239b9d056f3SNathan Whitehorn fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 240b9d056f3SNathan Whitehorn 241b9d056f3SNathan Whitehorn for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 242c0650b2fSNathan Whitehorn fdtmap[j].address = be64toh(fdtmap[j].address) & ~PAGE_MASK; 243c0650b2fSNathan Whitehorn fdtmap[j].size = round_page(be64toh(fdtmap[j].size)); 244c0650b2fSNathan Whitehorn } 245c0650b2fSNathan Whitehorn 246c0650b2fSNathan Whitehorn KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap), 247c0650b2fSNathan Whitehorn ("Exceeded number of FDT reservations")); 248c0650b2fSNathan Whitehorn /* Add a virtual entry for the FDT itself */ 249c0650b2fSNathan Whitehorn if (fdt != NULL) { 250c0650b2fSNathan Whitehorn fdtmap[j].address = (vm_offset_t)fdt & ~PAGE_MASK; 251c0650b2fSNathan Whitehorn fdtmap[j].size = round_page(fdt_totalsize(fdt)); 252c0650b2fSNathan Whitehorn fdtmapsize += sizeof(fdtmap[0]); 253b9d056f3SNathan Whitehorn } 254b9d056f3SNathan Whitehorn 255b9d056f3SNathan Whitehorn for (i = 0; i < asz; i++) { 256b9d056f3SNathan Whitehorn for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 257b9d056f3SNathan Whitehorn /* 258b9d056f3SNathan Whitehorn * Case 1: Exclusion region encloses complete 259b9d056f3SNathan Whitehorn * available entry. Drop it and move on. 260b9d056f3SNathan Whitehorn */ 261b9d056f3SNathan Whitehorn if (fdtmap[j].address <= avail[i].mr_start && 262b9d056f3SNathan Whitehorn fdtmap[j].address + fdtmap[j].size >= 263b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 264b9d056f3SNathan Whitehorn for (k = i+1; k < asz; k++) 265b9d056f3SNathan Whitehorn avail[k-1] = avail[k]; 266b9d056f3SNathan Whitehorn asz--; 267b9d056f3SNathan Whitehorn i--; /* Repeat some entries */ 268b9d056f3SNathan Whitehorn continue; 269b9d056f3SNathan Whitehorn } 270b9d056f3SNathan Whitehorn 271b9d056f3SNathan Whitehorn /* 272b9d056f3SNathan Whitehorn * Case 2: Exclusion region starts in available entry. 273b9d056f3SNathan Whitehorn * Trim it to where the entry begins and append 274b9d056f3SNathan Whitehorn * a new available entry with the region after 275b9d056f3SNathan Whitehorn * the excluded region, if any. 276b9d056f3SNathan Whitehorn */ 277b9d056f3SNathan Whitehorn if (fdtmap[j].address >= avail[i].mr_start && 278b9d056f3SNathan Whitehorn fdtmap[j].address < avail[i].mr_start + 279b9d056f3SNathan Whitehorn avail[i].mr_size) { 280b9d056f3SNathan Whitehorn if (fdtmap[j].address + fdtmap[j].size < 281b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 282b9d056f3SNathan Whitehorn avail[asz].mr_start = 283922a3152SNathan Whitehorn fdtmap[j].address + fdtmap[j].size; 284b9d056f3SNathan Whitehorn avail[asz].mr_size = avail[i].mr_start + 285b9d056f3SNathan Whitehorn avail[i].mr_size - 286b9d056f3SNathan Whitehorn avail[asz].mr_start; 287b9d056f3SNathan Whitehorn asz++; 288b9d056f3SNathan Whitehorn } 289b9d056f3SNathan Whitehorn 290922a3152SNathan Whitehorn avail[i].mr_size = fdtmap[j].address - 291b9d056f3SNathan Whitehorn avail[i].mr_start; 292b9d056f3SNathan Whitehorn } 293b9d056f3SNathan Whitehorn 294b9d056f3SNathan Whitehorn /* 295b9d056f3SNathan Whitehorn * Case 3: Exclusion region ends in available entry. 296b9d056f3SNathan Whitehorn * Move start point to where the exclusion zone ends. 297b9d056f3SNathan Whitehorn * The case of a contained exclusion zone has already 298b9d056f3SNathan Whitehorn * been caught in case 2. 299b9d056f3SNathan Whitehorn */ 300b9d056f3SNathan Whitehorn if (fdtmap[j].address + fdtmap[j].size >= 301b9d056f3SNathan Whitehorn avail[i].mr_start && fdtmap[j].address + 302b9d056f3SNathan Whitehorn fdtmap[j].size < avail[i].mr_start + 303b9d056f3SNathan Whitehorn avail[i].mr_size) { 304922a3152SNathan Whitehorn avail[i].mr_size += avail[i].mr_start; 305b9d056f3SNathan Whitehorn avail[i].mr_start = 306922a3152SNathan Whitehorn fdtmap[j].address + fdtmap[j].size; 307922a3152SNathan Whitehorn avail[i].mr_size -= avail[i].mr_start; 308b9d056f3SNathan Whitehorn } 309b9d056f3SNathan Whitehorn } 310b9d056f3SNathan Whitehorn } 311b9d056f3SNathan Whitehorn 312b9d056f3SNathan Whitehorn return (asz); 313b9d056f3SNathan Whitehorn } 31435feca37SNathan Whitehorn #endif 315b9d056f3SNathan Whitehorn 316fe3b4685SNathan Whitehorn /* 317fe3b4685SNathan Whitehorn * This is called during powerpc_init, before the system is really initialized. 318fe3b4685SNathan Whitehorn * It shall provide the total and the available regions of RAM. 319b9d056f3SNathan Whitehorn * The available regions need not take the kernel into account. 320fe3b4685SNathan Whitehorn */ 321fe3b4685SNathan Whitehorn void 322c1cb22d7SNathan Whitehorn ofw_mem_regions(struct mem_region *memp, int *memsz, 323c1cb22d7SNathan Whitehorn struct mem_region *availp, int *availsz) 324fe3b4685SNathan Whitehorn { 325fe3b4685SNathan Whitehorn phandle_t phandle; 326c1cb22d7SNathan Whitehorn int asz, msz; 327c1cb22d7SNathan Whitehorn int res; 328d8c6808aSNathan Whitehorn char name[31]; 329fe3b4685SNathan Whitehorn 330fe3b4685SNathan Whitehorn asz = msz = 0; 331fe3b4685SNathan Whitehorn 332fe3b4685SNathan Whitehorn /* 333d8c6808aSNathan Whitehorn * Get memory from all the /memory nodes. 334fe3b4685SNathan Whitehorn */ 335d8c6808aSNathan Whitehorn for (phandle = OF_child(OF_peer(0)); phandle != 0; 336d8c6808aSNathan Whitehorn phandle = OF_peer(phandle)) { 337d8c6808aSNathan Whitehorn if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 338d8c6808aSNathan Whitehorn continue; 339b9d056f3SNathan Whitehorn if (strncmp(name, "memory", sizeof(name)) != 0 && 340b9d056f3SNathan Whitehorn strncmp(name, "memory@", strlen("memory@")) != 0) 341d8c6808aSNathan Whitehorn continue; 342fe3b4685SNathan Whitehorn 343c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &memp[msz]); 344d8c6808aSNathan Whitehorn msz += res/sizeof(struct mem_region); 345876f3b92SJustin Hibbits 346876f3b92SJustin Hibbits /* 347876f3b92SJustin Hibbits * On POWER9 Systems we might have both linux,usable-memory and 348876f3b92SJustin Hibbits * reg properties. 'reg' denotes all available memory, but we 349876f3b92SJustin Hibbits * must use 'linux,usable-memory', a subset, as some memory 350876f3b92SJustin Hibbits * regions are reserved for NVLink. 351876f3b92SJustin Hibbits */ 352876f3b92SJustin Hibbits if (OF_getproplen(phandle, "linux,usable-memory") >= 0) 353876f3b92SJustin Hibbits res = parse_ofw_memory(phandle, "linux,usable-memory", 354876f3b92SJustin Hibbits &availp[asz]); 355d8c6808aSNathan Whitehorn if (OF_getproplen(phandle, "available") >= 0) 356d8c6808aSNathan Whitehorn res = parse_ofw_memory(phandle, "available", 357c1cb22d7SNathan Whitehorn &availp[asz]); 358d8c6808aSNathan Whitehorn else 359c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &availp[asz]); 360d8c6808aSNathan Whitehorn asz += res/sizeof(struct mem_region); 361d8c6808aSNathan Whitehorn } 362d8c6808aSNathan Whitehorn 36335feca37SNathan Whitehorn #ifdef FDT 364b9d056f3SNathan Whitehorn phandle = OF_finddevice("/chosen"); 365b9d056f3SNathan Whitehorn if (OF_hasprop(phandle, "fdtmemreserv")) 366b9d056f3SNathan Whitehorn asz = excise_fdt_reserved(availp, asz); 36735feca37SNathan Whitehorn #endif 368b9d056f3SNathan Whitehorn 369d8c6808aSNathan Whitehorn *memsz = msz; 370c1cb22d7SNathan Whitehorn *availsz = asz; 371fe3b4685SNathan Whitehorn } 372fe3b4685SNathan Whitehorn 373fe3b4685SNathan Whitehorn void 374fe3b4685SNathan Whitehorn OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 375fe3b4685SNathan Whitehorn { 3766f489d43SJustin Hibbits #ifdef AIM 377bb808254SNathan Whitehorn ofmsr[0] = mfmsr(); 378bb808254SNathan Whitehorn #ifdef __powerpc64__ 379bb808254SNathan Whitehorn ofmsr[0] &= ~PSL_SF; 38062c6b30eSJustin Hibbits #else 381bb808254SNathan Whitehorn __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 38262c6b30eSJustin Hibbits #endif 383bb808254SNathan Whitehorn __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 384bb808254SNathan Whitehorn __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 385bb808254SNathan Whitehorn __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 3866f489d43SJustin Hibbits openfirmware_entry = openfirm; 387bb808254SNathan Whitehorn 388fe3b4685SNathan Whitehorn if (ofmsr[0] & PSL_DR) 389fe3b4685SNathan Whitehorn ofw_real_mode = 0; 390fe3b4685SNathan Whitehorn else 391fe3b4685SNathan Whitehorn ofw_real_mode = 1; 392fe3b4685SNathan Whitehorn 3936f489d43SJustin Hibbits ofw_save_trap_vec(save_trap_init); 3946f489d43SJustin Hibbits #else 3956f489d43SJustin Hibbits ofw_real_mode = 1; 3966f489d43SJustin Hibbits #endif 3976f489d43SJustin Hibbits 398fe3b4685SNathan Whitehorn fdt = fdt_ptr; 399fe3b4685SNathan Whitehorn } 400fe3b4685SNathan Whitehorn 401fe3b4685SNathan Whitehorn boolean_t 402fe3b4685SNathan Whitehorn OF_bootstrap() 403fe3b4685SNathan Whitehorn { 404fe3b4685SNathan Whitehorn boolean_t status = FALSE; 4052bfca577SNathan Whitehorn int err = 0; 406fe3b4685SNathan Whitehorn 4076f489d43SJustin Hibbits #ifdef AIM 40817879090SNathan Whitehorn if (openfirmware_entry != NULL) { 409fe3b4685SNathan Whitehorn if (ofw_real_mode) { 410fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_REAL, 0); 411fe3b4685SNathan Whitehorn } else { 412fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 413fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_32BIT, 0); 414fe3b4685SNathan Whitehorn #else 415fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_DIRECT, 0); 416fe3b4685SNathan Whitehorn #endif 417fe3b4685SNathan Whitehorn } 418fe3b4685SNathan Whitehorn 419fe3b4685SNathan Whitehorn if (status != TRUE) 420fe3b4685SNathan Whitehorn return status; 421fe3b4685SNathan Whitehorn 4222bfca577SNathan Whitehorn err = OF_init(openfirmware); 4236f489d43SJustin Hibbits } else 4246f489d43SJustin Hibbits #endif 4256f489d43SJustin Hibbits if (fdt != NULL) { 42635feca37SNathan Whitehorn #ifdef FDT 427f9edb09dSNathan Whitehorn #ifdef AIM 428f9edb09dSNathan Whitehorn bus_space_tag_t fdt_bt; 429f9edb09dSNathan Whitehorn vm_offset_t tmp_fdt_ptr; 430f9edb09dSNathan Whitehorn vm_size_t fdt_size; 431f9edb09dSNathan Whitehorn uintptr_t fdt_va; 432f9edb09dSNathan Whitehorn #endif 433fe3b4685SNathan Whitehorn 434f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 435fe3b4685SNathan Whitehorn if (status != TRUE) 436fe3b4685SNathan Whitehorn return status; 437fe3b4685SNathan Whitehorn 438f9edb09dSNathan Whitehorn #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */ 439f9edb09dSNathan Whitehorn /* Get the FDT size for mapping if we can */ 440f9edb09dSNathan Whitehorn tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE); 441f9edb09dSNathan Whitehorn if (fdt_check_header((void *)tmp_fdt_ptr) != 0) { 442f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 443f9edb09dSNathan Whitehorn return FALSE; 444fe3b4685SNathan Whitehorn } 445f9edb09dSNathan Whitehorn fdt_size = fdt_totalsize((void *)tmp_fdt_ptr); 446f9edb09dSNathan Whitehorn pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE); 447f9edb09dSNathan Whitehorn 448f9edb09dSNathan Whitehorn /* 449f9edb09dSNathan Whitehorn * Map this for real. Use bus_space_map() to take advantage 450f9edb09dSNathan Whitehorn * of its auto-remapping function once the kernel is loaded. 451f9edb09dSNathan Whitehorn * This is a dirty hack, but what we have. 452f9edb09dSNathan Whitehorn */ 453f9edb09dSNathan Whitehorn #ifdef _LITTLE_ENDIAN 454f9edb09dSNathan Whitehorn fdt_bt = &bs_le_tag; 455f9edb09dSNathan Whitehorn #else 456f9edb09dSNathan Whitehorn fdt_bt = &bs_be_tag; 457f9edb09dSNathan Whitehorn #endif 458f9edb09dSNathan Whitehorn bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va); 459f9edb09dSNathan Whitehorn 460f9edb09dSNathan Whitehorn err = OF_init((void *)fdt_va); 461f9edb09dSNathan Whitehorn #else 462f9edb09dSNathan Whitehorn err = OF_init(fdt); 463f9edb09dSNathan Whitehorn #endif 46435feca37SNathan Whitehorn #endif 465f9edb09dSNathan Whitehorn } 466f9edb09dSNathan Whitehorn 467f9edb09dSNathan Whitehorn #ifdef FDT_DTB_STATIC 468f9edb09dSNathan Whitehorn /* 469f9edb09dSNathan Whitehorn * Check for a statically included blob already in the kernel and 470f9edb09dSNathan Whitehorn * needing no mapping. 471f9edb09dSNathan Whitehorn */ 472f9edb09dSNathan Whitehorn else { 473f9edb09dSNathan Whitehorn status = OF_install(OFW_FDT, 0); 474f9edb09dSNathan Whitehorn if (status != TRUE) 475f9edb09dSNathan Whitehorn return status; 476f9edb09dSNathan Whitehorn err = OF_init(&fdt_static_dtb); 477f9edb09dSNathan Whitehorn } 478f9edb09dSNathan Whitehorn #endif 479fe3b4685SNathan Whitehorn 4802bfca577SNathan Whitehorn if (err != 0) { 4812bfca577SNathan Whitehorn OF_install(NULL, 0); 4822bfca577SNathan Whitehorn status = FALSE; 4832bfca577SNathan Whitehorn } 4842bfca577SNathan Whitehorn 485fe3b4685SNathan Whitehorn return (status); 486fe3b4685SNathan Whitehorn } 487fe3b4685SNathan Whitehorn 4886f489d43SJustin Hibbits #ifdef AIM 4899f706727SNathan Whitehorn void 490fe3b4685SNathan Whitehorn ofw_quiesce(void) 491fe3b4685SNathan Whitehorn { 492fe3b4685SNathan Whitehorn struct { 493fe3b4685SNathan Whitehorn cell_t name; 494fe3b4685SNathan Whitehorn cell_t nargs; 495fe3b4685SNathan Whitehorn cell_t nreturns; 496fe3b4685SNathan Whitehorn } args; 497fe3b4685SNathan Whitehorn 4989f706727SNathan Whitehorn KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 499fe3b4685SNathan Whitehorn 500fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 501fe3b4685SNathan Whitehorn args.nargs = 0; 502fe3b4685SNathan Whitehorn args.nreturns = 0; 503fe3b4685SNathan Whitehorn openfirmware(&args); 504fe3b4685SNathan Whitehorn } 505fe3b4685SNathan Whitehorn 506fe3b4685SNathan Whitehorn static int 507fe3b4685SNathan Whitehorn openfirmware_core(void *args) 508fe3b4685SNathan Whitehorn { 509fe3b4685SNathan Whitehorn int result; 510fe3b4685SNathan Whitehorn register_t oldmsr; 511fe3b4685SNathan Whitehorn 51244d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 51344d29d47SNathan Whitehorn return (-1); 51444d29d47SNathan Whitehorn 515fe3b4685SNathan Whitehorn /* 516fe3b4685SNathan Whitehorn * Turn off exceptions - we really don't want to end up 5174aa3cee6SNathan Whitehorn * anywhere unexpected with PCPU set to something strange 5184aa3cee6SNathan Whitehorn * or the stack pointer wrong. 519fe3b4685SNathan Whitehorn */ 520fe3b4685SNathan Whitehorn oldmsr = intr_disable(); 521fe3b4685SNathan Whitehorn 5224aa3cee6SNathan Whitehorn ofw_sprg_prepare(); 5234aa3cee6SNathan Whitehorn 524f367ffdeSAndreas Tobler /* Save trap vectors */ 525f367ffdeSAndreas Tobler ofw_save_trap_vec(save_trap_of); 526f367ffdeSAndreas Tobler 527f367ffdeSAndreas Tobler /* Restore initially saved trap vectors */ 528f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_init); 529f367ffdeSAndreas Tobler 53095ce4c00SJustin Hibbits #ifndef __powerpc64__ 531fe3b4685SNathan Whitehorn /* 532fe3b4685SNathan Whitehorn * Clear battable[] translations 533fe3b4685SNathan Whitehorn */ 534fe3b4685SNathan Whitehorn if (!(cpu_features & PPC_FEATURE_64)) 535fe3b4685SNathan Whitehorn __asm __volatile("mtdbatu 2, %0\n" 536fe3b4685SNathan Whitehorn "mtdbatu 3, %0" : : "r" (0)); 537fe3b4685SNathan Whitehorn isync(); 538fe3b4685SNathan Whitehorn #endif 539fe3b4685SNathan Whitehorn 540fe3b4685SNathan Whitehorn result = ofwcall(args); 541f367ffdeSAndreas Tobler 542f367ffdeSAndreas Tobler /* Restore trap vecotrs */ 543f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_of); 544f367ffdeSAndreas Tobler 5454aa3cee6SNathan Whitehorn ofw_sprg_restore(); 5464aa3cee6SNathan Whitehorn 547fe3b4685SNathan Whitehorn intr_restore(oldmsr); 548fe3b4685SNathan Whitehorn 549fe3b4685SNathan Whitehorn return (result); 550fe3b4685SNathan Whitehorn } 551fe3b4685SNathan Whitehorn 552fe3b4685SNathan Whitehorn #ifdef SMP 553fe3b4685SNathan Whitehorn struct ofw_rv_args { 554fe3b4685SNathan Whitehorn void *args; 555fe3b4685SNathan Whitehorn int retval; 556fe3b4685SNathan Whitehorn volatile int in_progress; 557fe3b4685SNathan Whitehorn }; 558fe3b4685SNathan Whitehorn 559fe3b4685SNathan Whitehorn static void 560fe3b4685SNathan Whitehorn ofw_rendezvous_dispatch(void *xargs) 561fe3b4685SNathan Whitehorn { 562fe3b4685SNathan Whitehorn struct ofw_rv_args *rv_args = xargs; 563fe3b4685SNathan Whitehorn 564fe3b4685SNathan Whitehorn /* NOTE: Interrupts are disabled here */ 565fe3b4685SNathan Whitehorn 566fe3b4685SNathan Whitehorn if (PCPU_GET(cpuid) == 0) { 567fe3b4685SNathan Whitehorn /* 568fe3b4685SNathan Whitehorn * Execute all OF calls on CPU 0 569fe3b4685SNathan Whitehorn */ 570fe3b4685SNathan Whitehorn rv_args->retval = openfirmware_core(rv_args->args); 571fe3b4685SNathan Whitehorn rv_args->in_progress = 0; 572fe3b4685SNathan Whitehorn } else { 573fe3b4685SNathan Whitehorn /* 574fe3b4685SNathan Whitehorn * Spin with interrupts off on other CPUs while OF has 575fe3b4685SNathan Whitehorn * control of the machine. 576fe3b4685SNathan Whitehorn */ 577fe3b4685SNathan Whitehorn while (rv_args->in_progress) 578fe3b4685SNathan Whitehorn cpu_spinwait(); 579fe3b4685SNathan Whitehorn } 580fe3b4685SNathan Whitehorn } 581fe3b4685SNathan Whitehorn #endif 582fe3b4685SNathan Whitehorn 583fe3b4685SNathan Whitehorn static int 584fe3b4685SNathan Whitehorn openfirmware(void *args) 585fe3b4685SNathan Whitehorn { 586fe3b4685SNathan Whitehorn int result; 587fe3b4685SNathan Whitehorn #ifdef SMP 588fe3b4685SNathan Whitehorn struct ofw_rv_args rv_args; 58944d29d47SNathan Whitehorn #endif 590fe3b4685SNathan Whitehorn 59144d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 59244d29d47SNathan Whitehorn return (-1); 59344d29d47SNathan Whitehorn 59444d29d47SNathan Whitehorn #ifdef SMP 59591419bdaSNathan Whitehorn if (cold) { 59691419bdaSNathan Whitehorn result = openfirmware_core(args); 59791419bdaSNathan Whitehorn } else { 598fe3b4685SNathan Whitehorn rv_args.args = args; 599fe3b4685SNathan Whitehorn rv_args.in_progress = 1; 60091419bdaSNathan Whitehorn smp_rendezvous(smp_no_rendezvous_barrier, 60191419bdaSNathan Whitehorn ofw_rendezvous_dispatch, smp_no_rendezvous_barrier, 60291419bdaSNathan Whitehorn &rv_args); 603fe3b4685SNathan Whitehorn result = rv_args.retval; 60491419bdaSNathan Whitehorn } 605fe3b4685SNathan Whitehorn #else 606fe3b4685SNathan Whitehorn result = openfirmware_core(args); 607fe3b4685SNathan Whitehorn #endif 608fe3b4685SNathan Whitehorn 609fe3b4685SNathan Whitehorn return (result); 610fe3b4685SNathan Whitehorn } 611fe3b4685SNathan Whitehorn 612fe3b4685SNathan Whitehorn void 613fe3b4685SNathan Whitehorn OF_reboot() 614fe3b4685SNathan Whitehorn { 615fe3b4685SNathan Whitehorn struct { 616fe3b4685SNathan Whitehorn cell_t name; 617fe3b4685SNathan Whitehorn cell_t nargs; 618fe3b4685SNathan Whitehorn cell_t nreturns; 619fe3b4685SNathan Whitehorn cell_t arg; 620fe3b4685SNathan Whitehorn } args; 621fe3b4685SNathan Whitehorn 622fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"interpret"; 623fe3b4685SNathan Whitehorn args.nargs = 1; 624fe3b4685SNathan Whitehorn args.nreturns = 0; 625fe3b4685SNathan Whitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 626fe3b4685SNathan Whitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 627fe3b4685SNathan Whitehorn 628fe3b4685SNathan Whitehorn for (;;); /* just in case */ 629fe3b4685SNathan Whitehorn } 630fe3b4685SNathan Whitehorn 631629aa519SNathan Whitehorn #endif /* AIM */ 632629aa519SNathan Whitehorn 633fe3b4685SNathan Whitehorn void 634fe3b4685SNathan Whitehorn OF_getetheraddr(device_t dev, u_char *addr) 635fe3b4685SNathan Whitehorn { 636fe3b4685SNathan Whitehorn phandle_t node; 637fe3b4685SNathan Whitehorn 638fe3b4685SNathan Whitehorn node = ofw_bus_get_node(dev); 639fe3b4685SNathan Whitehorn OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 640fe3b4685SNathan Whitehorn } 641fe3b4685SNathan Whitehorn 642fe3b4685SNathan Whitehorn /* 643fe3b4685SNathan Whitehorn * Return a bus handle and bus tag that corresponds to the register 644fe3b4685SNathan Whitehorn * numbered regno for the device referenced by the package handle 645fe3b4685SNathan Whitehorn * dev. This function is intended to be used by console drivers in 646fe3b4685SNathan Whitehorn * early boot only. It works by mapping the address of the device's 647fe3b4685SNathan Whitehorn * register in the address space of its parent and recursively walk 648fe3b4685SNathan Whitehorn * the device tree upward this way. 649fe3b4685SNathan Whitehorn */ 650fe3b4685SNathan Whitehorn int 651fe3b4685SNathan Whitehorn OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 65245fd1862SAndrew Turner bus_space_handle_t *handle, bus_size_t *sz) 653fe3b4685SNathan Whitehorn { 654bc7b9300SIan Lepore bus_addr_t addr; 655bc7b9300SIan Lepore bus_size_t size; 656bc7b9300SIan Lepore pcell_t pci_hi; 657bc7b9300SIan Lepore int flags, res; 658fe3b4685SNathan Whitehorn 659bc7b9300SIan Lepore res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); 660bc7b9300SIan Lepore if (res < 0) 661bc7b9300SIan Lepore return (res); 662fe3b4685SNathan Whitehorn 663bc7b9300SIan Lepore if (pci_hi == OFW_PADDR_NOT_PCI) { 66443a581e1SNathan Whitehorn *tag = &bs_be_tag; 665bc7b9300SIan Lepore flags = 0; 666bc7b9300SIan Lepore } else { 66743a581e1SNathan Whitehorn *tag = &bs_le_tag; 668bc7b9300SIan Lepore flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 669bc7b9300SIan Lepore BUS_SPACE_MAP_PREFETCHABLE: 0; 670fe3b4685SNathan Whitehorn } 671fe3b4685SNathan Whitehorn 67245fd1862SAndrew Turner if (sz != NULL) 67345fd1862SAndrew Turner *sz = size; 67445fd1862SAndrew Turner 675bc7b9300SIan Lepore return (bus_space_map(*tag, addr, size, flags, handle)); 676fe3b4685SNathan Whitehorn } 677fe3b4685SNathan Whitehorn 678