1fe3b4685SNathan Whitehorn /*- 2fe3b4685SNathan Whitehorn * Copyright (C) 1996 Wolfgang Solfrank. 3fe3b4685SNathan Whitehorn * Copyright (C) 1996 TooLs GmbH. 4fe3b4685SNathan Whitehorn * All rights reserved. 5fe3b4685SNathan Whitehorn * 6fe3b4685SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 7fe3b4685SNathan Whitehorn * modification, are permitted provided that the following conditions 8fe3b4685SNathan Whitehorn * are met: 9fe3b4685SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 10fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 11fe3b4685SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 12fe3b4685SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 13fe3b4685SNathan Whitehorn * documentation and/or other materials provided with the distribution. 14fe3b4685SNathan Whitehorn * 3. All advertising materials mentioning features or use of this software 15fe3b4685SNathan Whitehorn * must display the following acknowledgement: 16fe3b4685SNathan Whitehorn * This product includes software developed by TooLs GmbH. 17fe3b4685SNathan Whitehorn * 4. The name of TooLs GmbH may not be used to endorse or promote products 18fe3b4685SNathan Whitehorn * derived from this software without specific prior written permission. 19fe3b4685SNathan Whitehorn * 20fe3b4685SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 21fe3b4685SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22fe3b4685SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23fe3b4685SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24fe3b4685SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25fe3b4685SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26fe3b4685SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27fe3b4685SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28fe3b4685SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29fe3b4685SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30fe3b4685SNathan Whitehorn * 31fe3b4685SNathan Whitehorn * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $ 32fe3b4685SNathan Whitehorn */ 33fe3b4685SNathan Whitehorn 34fe3b4685SNathan Whitehorn #include <sys/cdefs.h> 35fe3b4685SNathan Whitehorn __FBSDID("$FreeBSD$"); 36fe3b4685SNathan Whitehorn 378c092157SJustin Hibbits #include "opt_platform.h" 38fe3b4685SNathan Whitehorn #include <sys/param.h> 39fe3b4685SNathan Whitehorn #include <sys/bus.h> 40fe3b4685SNathan Whitehorn #include <sys/systm.h> 41fe3b4685SNathan Whitehorn #include <sys/conf.h> 42fe3b4685SNathan Whitehorn #include <sys/disk.h> 43fe3b4685SNathan Whitehorn #include <sys/fcntl.h> 44fe3b4685SNathan Whitehorn #include <sys/malloc.h> 45fe3b4685SNathan Whitehorn #include <sys/smp.h> 46fe3b4685SNathan Whitehorn #include <sys/stat.h> 47b9d056f3SNathan Whitehorn #include <sys/endian.h> 48fe3b4685SNathan Whitehorn 49fe3b4685SNathan Whitehorn #include <net/ethernet.h> 50fe3b4685SNathan Whitehorn 518c092157SJustin Hibbits #include <dev/fdt/fdt_common.h> 52fe3b4685SNathan Whitehorn #include <dev/ofw/openfirm.h> 53fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_pci.h> 54fe3b4685SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 55fe3b4685SNathan Whitehorn 56fe3b4685SNathan Whitehorn #include <vm/vm.h> 57fe3b4685SNathan Whitehorn #include <vm/vm_param.h> 58fe3b4685SNathan Whitehorn #include <vm/vm_page.h> 59fe3b4685SNathan Whitehorn 60fe3b4685SNathan Whitehorn #include <machine/bus.h> 61fe3b4685SNathan Whitehorn #include <machine/cpu.h> 62fe3b4685SNathan Whitehorn #include <machine/md_var.h> 63fe3b4685SNathan Whitehorn #include <machine/platform.h> 64fe3b4685SNathan Whitehorn #include <machine/ofw_machdep.h> 65f367ffdeSAndreas Tobler #include <machine/trap.h> 66fe3b4685SNathan Whitehorn 676f489d43SJustin Hibbits static void *fdt; 686f489d43SJustin Hibbits int ofw_real_mode; 696f489d43SJustin Hibbits 70629aa519SNathan Whitehorn #ifdef AIM 71fe3b4685SNathan Whitehorn extern register_t ofmsr[5]; 7217879090SNathan Whitehorn extern void *openfirmware_entry; 73bb808254SNathan Whitehorn char save_trap_init[0x2f00]; /* EXC_LAST */ 74f367ffdeSAndreas Tobler char save_trap_of[0x2f00]; /* EXC_LAST */ 75fe3b4685SNathan Whitehorn 76d8c6808aSNathan Whitehorn int ofwcall(void *); 77fe3b4685SNathan Whitehorn static int openfirmware(void *args); 78fe3b4685SNathan Whitehorn 79f367ffdeSAndreas Tobler __inline void 80f367ffdeSAndreas Tobler ofw_save_trap_vec(char *save_trap_vec) 81f367ffdeSAndreas Tobler { 82c1cb22d7SNathan Whitehorn if (!ofw_real_mode) 83f367ffdeSAndreas Tobler return; 84f367ffdeSAndreas Tobler 85f367ffdeSAndreas Tobler bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST); 86f367ffdeSAndreas Tobler } 87f367ffdeSAndreas Tobler 88f367ffdeSAndreas Tobler static __inline void 89f367ffdeSAndreas Tobler ofw_restore_trap_vec(char *restore_trap_vec) 90f367ffdeSAndreas Tobler { 91c1cb22d7SNathan Whitehorn if (!ofw_real_mode) 92f367ffdeSAndreas Tobler return; 93f367ffdeSAndreas Tobler 94f367ffdeSAndreas Tobler bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST); 95f367ffdeSAndreas Tobler __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); 96f367ffdeSAndreas Tobler } 974aa3cee6SNathan Whitehorn 984aa3cee6SNathan Whitehorn /* 994aa3cee6SNathan Whitehorn * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback. 1004aa3cee6SNathan Whitehorn */ 1014aa3cee6SNathan Whitehorn register_t ofw_sprg0_save; 1024aa3cee6SNathan Whitehorn 1034aa3cee6SNathan Whitehorn static __inline void 1044aa3cee6SNathan Whitehorn ofw_sprg_prepare(void) 1054aa3cee6SNathan Whitehorn { 1064aa3cee6SNathan Whitehorn if (ofw_real_mode) 1074aa3cee6SNathan Whitehorn return; 1084aa3cee6SNathan Whitehorn 1094aa3cee6SNathan Whitehorn /* 1104aa3cee6SNathan Whitehorn * Assume that interrupt are disabled at this point, or 1114aa3cee6SNathan Whitehorn * SPRG1-3 could be trashed 1124aa3cee6SNathan Whitehorn */ 1134aa3cee6SNathan Whitehorn __asm __volatile("mfsprg0 %0\n\t" 1144aa3cee6SNathan Whitehorn "mtsprg0 %1\n\t" 1154aa3cee6SNathan Whitehorn "mtsprg1 %2\n\t" 1164aa3cee6SNathan Whitehorn "mtsprg2 %3\n\t" 1174aa3cee6SNathan Whitehorn "mtsprg3 %4\n\t" 1184aa3cee6SNathan Whitehorn : "=&r"(ofw_sprg0_save) 1194aa3cee6SNathan Whitehorn : "r"(ofmsr[1]), 1204aa3cee6SNathan Whitehorn "r"(ofmsr[2]), 1214aa3cee6SNathan Whitehorn "r"(ofmsr[3]), 1224aa3cee6SNathan Whitehorn "r"(ofmsr[4])); 1234aa3cee6SNathan Whitehorn } 1244aa3cee6SNathan Whitehorn 1254aa3cee6SNathan Whitehorn static __inline void 1264aa3cee6SNathan Whitehorn ofw_sprg_restore(void) 1274aa3cee6SNathan Whitehorn { 1284aa3cee6SNathan Whitehorn if (ofw_real_mode) 1294aa3cee6SNathan Whitehorn return; 1304aa3cee6SNathan Whitehorn 1314aa3cee6SNathan Whitehorn /* 1324aa3cee6SNathan Whitehorn * Note that SPRG1-3 contents are irrelevant. They are scratch 1334aa3cee6SNathan Whitehorn * registers used in the early portion of trap handling when 1344aa3cee6SNathan Whitehorn * interrupts are disabled. 1354aa3cee6SNathan Whitehorn * 1364aa3cee6SNathan Whitehorn * PCPU data cannot be used until this routine is called ! 1374aa3cee6SNathan Whitehorn */ 1384aa3cee6SNathan Whitehorn __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save)); 1394aa3cee6SNathan Whitehorn } 140c7291bdcSNathan Whitehorn #endif 141f367ffdeSAndreas Tobler 142fe3b4685SNathan Whitehorn static int 143fe3b4685SNathan Whitehorn parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output) 144fe3b4685SNathan Whitehorn { 145fe3b4685SNathan Whitehorn cell_t address_cells, size_cells; 146d8c6808aSNathan Whitehorn cell_t OFmem[4 * PHYS_AVAIL_SZ]; 147fe3b4685SNathan Whitehorn int sz, i, j; 148fe3b4685SNathan Whitehorn phandle_t phandle; 149fe3b4685SNathan Whitehorn 150fe3b4685SNathan Whitehorn sz = 0; 151fe3b4685SNathan Whitehorn 152fe3b4685SNathan Whitehorn /* 153fe3b4685SNathan Whitehorn * Get #address-cells from root node, defaulting to 1 if it cannot 154fe3b4685SNathan Whitehorn * be found. 155fe3b4685SNathan Whitehorn */ 156fe3b4685SNathan Whitehorn phandle = OF_finddevice("/"); 157fe3b4685SNathan Whitehorn if (OF_getprop(phandle, "#address-cells", &address_cells, 1588bab0d80SNathan Whitehorn sizeof(address_cells)) < (ssize_t)sizeof(address_cells)) 159fe3b4685SNathan Whitehorn address_cells = 1; 160fe3b4685SNathan Whitehorn if (OF_getprop(phandle, "#size-cells", &size_cells, 1618bab0d80SNathan Whitehorn sizeof(size_cells)) < (ssize_t)sizeof(size_cells)) 162fe3b4685SNathan Whitehorn size_cells = 1; 163fe3b4685SNathan Whitehorn 164fe3b4685SNathan Whitehorn /* 165fe3b4685SNathan Whitehorn * Get memory. 166fe3b4685SNathan Whitehorn */ 167d8c6808aSNathan Whitehorn if (node == -1 || (sz = OF_getprop(node, prop, 168d8c6808aSNathan Whitehorn OFmem, sizeof(OFmem))) <= 0) 169fe3b4685SNathan Whitehorn panic("Physical memory map not found"); 170fe3b4685SNathan Whitehorn 171fe3b4685SNathan Whitehorn i = 0; 172fe3b4685SNathan Whitehorn j = 0; 173fe3b4685SNathan Whitehorn while (i < sz/sizeof(cell_t)) { 174fe3b4685SNathan Whitehorn #ifndef __powerpc64__ 175fe3b4685SNathan Whitehorn /* On 32-bit PPC, ignore regions starting above 4 GB */ 176fe3b4685SNathan Whitehorn if (address_cells > 1 && OFmem[i] > 0) { 177fe3b4685SNathan Whitehorn i += address_cells + size_cells; 178fe3b4685SNathan Whitehorn continue; 179fe3b4685SNathan Whitehorn } 180fe3b4685SNathan Whitehorn #endif 181fe3b4685SNathan Whitehorn 182fe3b4685SNathan Whitehorn output[j].mr_start = OFmem[i++]; 183fe3b4685SNathan Whitehorn if (address_cells == 2) { 184fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 185fe3b4685SNathan Whitehorn output[j].mr_start <<= 32; 186fe3b4685SNathan Whitehorn #endif 187fe3b4685SNathan Whitehorn output[j].mr_start += OFmem[i++]; 188fe3b4685SNathan Whitehorn } 189fe3b4685SNathan Whitehorn 190fe3b4685SNathan Whitehorn output[j].mr_size = OFmem[i++]; 191fe3b4685SNathan Whitehorn if (size_cells == 2) { 192fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 193fe3b4685SNathan Whitehorn output[j].mr_size <<= 32; 194fe3b4685SNathan Whitehorn #endif 195fe3b4685SNathan Whitehorn output[j].mr_size += OFmem[i++]; 196fe3b4685SNathan Whitehorn } 197fe3b4685SNathan Whitehorn 198fe3b4685SNathan Whitehorn #ifndef __powerpc64__ 199fe3b4685SNathan Whitehorn /* 200fe3b4685SNathan Whitehorn * Check for memory regions extending above 32-bit 201fe3b4685SNathan Whitehorn * memory space, and restrict them to stay there. 202fe3b4685SNathan Whitehorn */ 203fe3b4685SNathan Whitehorn if (((uint64_t)output[j].mr_start + 204fe3b4685SNathan Whitehorn (uint64_t)output[j].mr_size) > 205fe3b4685SNathan Whitehorn BUS_SPACE_MAXADDR_32BIT) { 206fe3b4685SNathan Whitehorn output[j].mr_size = BUS_SPACE_MAXADDR_32BIT - 207fe3b4685SNathan Whitehorn output[j].mr_start; 208fe3b4685SNathan Whitehorn } 209fe3b4685SNathan Whitehorn #endif 210fe3b4685SNathan Whitehorn 211fe3b4685SNathan Whitehorn j++; 212fe3b4685SNathan Whitehorn } 213fe3b4685SNathan Whitehorn sz = j*sizeof(output[0]); 214fe3b4685SNathan Whitehorn 215fe3b4685SNathan Whitehorn return (sz); 216fe3b4685SNathan Whitehorn } 217fe3b4685SNathan Whitehorn 218b9d056f3SNathan Whitehorn static int 219b9d056f3SNathan Whitehorn excise_fdt_reserved(struct mem_region *avail, int asz) 220b9d056f3SNathan Whitehorn { 221b9d056f3SNathan Whitehorn struct { 222b9d056f3SNathan Whitehorn uint64_t address; 223b9d056f3SNathan Whitehorn uint64_t size; 224b9d056f3SNathan Whitehorn } fdtmap[16]; 225b9d056f3SNathan Whitehorn ssize_t fdtmapsize; 226b9d056f3SNathan Whitehorn phandle_t chosen; 227b9d056f3SNathan Whitehorn int i, j, k; 228b9d056f3SNathan Whitehorn 229b9d056f3SNathan Whitehorn chosen = OF_finddevice("/chosen"); 230b9d056f3SNathan Whitehorn fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap)); 231b9d056f3SNathan Whitehorn 232b9d056f3SNathan Whitehorn for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 233b9d056f3SNathan Whitehorn fdtmap[j].address = be64toh(fdtmap[j].address); 234b9d056f3SNathan Whitehorn fdtmap[j].size = be64toh(fdtmap[j].size); 235b9d056f3SNathan Whitehorn } 236b9d056f3SNathan Whitehorn 237b9d056f3SNathan Whitehorn for (i = 0; i < asz; i++) { 238b9d056f3SNathan Whitehorn for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) { 239b9d056f3SNathan Whitehorn /* 240b9d056f3SNathan Whitehorn * Case 1: Exclusion region encloses complete 241b9d056f3SNathan Whitehorn * available entry. Drop it and move on. 242b9d056f3SNathan Whitehorn */ 243b9d056f3SNathan Whitehorn if (fdtmap[j].address <= avail[i].mr_start && 244b9d056f3SNathan Whitehorn fdtmap[j].address + fdtmap[j].size >= 245b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 246b9d056f3SNathan Whitehorn for (k = i+1; k < asz; k++) 247b9d056f3SNathan Whitehorn avail[k-1] = avail[k]; 248b9d056f3SNathan Whitehorn asz--; 249b9d056f3SNathan Whitehorn i--; /* Repeat some entries */ 250b9d056f3SNathan Whitehorn continue; 251b9d056f3SNathan Whitehorn } 252b9d056f3SNathan Whitehorn 253b9d056f3SNathan Whitehorn /* 254b9d056f3SNathan Whitehorn * Case 2: Exclusion region starts in available entry. 255b9d056f3SNathan Whitehorn * Trim it to where the entry begins and append 256b9d056f3SNathan Whitehorn * a new available entry with the region after 257b9d056f3SNathan Whitehorn * the excluded region, if any. 258b9d056f3SNathan Whitehorn */ 259b9d056f3SNathan Whitehorn if (fdtmap[j].address >= avail[i].mr_start && 260b9d056f3SNathan Whitehorn fdtmap[j].address < avail[i].mr_start + 261b9d056f3SNathan Whitehorn avail[i].mr_size) { 262b9d056f3SNathan Whitehorn if (fdtmap[j].address + fdtmap[j].size < 263b9d056f3SNathan Whitehorn avail[i].mr_start + avail[i].mr_size) { 264b9d056f3SNathan Whitehorn avail[asz].mr_start = 265922a3152SNathan Whitehorn fdtmap[j].address + fdtmap[j].size; 266b9d056f3SNathan Whitehorn avail[asz].mr_size = avail[i].mr_start + 267b9d056f3SNathan Whitehorn avail[i].mr_size - 268b9d056f3SNathan Whitehorn avail[asz].mr_start; 269b9d056f3SNathan Whitehorn asz++; 270b9d056f3SNathan Whitehorn } 271b9d056f3SNathan Whitehorn 272922a3152SNathan Whitehorn avail[i].mr_size = fdtmap[j].address - 273b9d056f3SNathan Whitehorn avail[i].mr_start; 274b9d056f3SNathan Whitehorn } 275b9d056f3SNathan Whitehorn 276b9d056f3SNathan Whitehorn /* 277b9d056f3SNathan Whitehorn * Case 3: Exclusion region ends in available entry. 278b9d056f3SNathan Whitehorn * Move start point to where the exclusion zone ends. 279b9d056f3SNathan Whitehorn * The case of a contained exclusion zone has already 280b9d056f3SNathan Whitehorn * been caught in case 2. 281b9d056f3SNathan Whitehorn */ 282b9d056f3SNathan Whitehorn if (fdtmap[j].address + fdtmap[j].size >= 283b9d056f3SNathan Whitehorn avail[i].mr_start && fdtmap[j].address + 284b9d056f3SNathan Whitehorn fdtmap[j].size < avail[i].mr_start + 285b9d056f3SNathan Whitehorn avail[i].mr_size) { 286922a3152SNathan Whitehorn avail[i].mr_size += avail[i].mr_start; 287b9d056f3SNathan Whitehorn avail[i].mr_start = 288922a3152SNathan Whitehorn fdtmap[j].address + fdtmap[j].size; 289922a3152SNathan Whitehorn avail[i].mr_size -= avail[i].mr_start; 290b9d056f3SNathan Whitehorn } 291b9d056f3SNathan Whitehorn } 292b9d056f3SNathan Whitehorn } 293b9d056f3SNathan Whitehorn 294b9d056f3SNathan Whitehorn return (asz); 295b9d056f3SNathan Whitehorn } 296b9d056f3SNathan Whitehorn 297fe3b4685SNathan Whitehorn /* 298fe3b4685SNathan Whitehorn * This is called during powerpc_init, before the system is really initialized. 299fe3b4685SNathan Whitehorn * It shall provide the total and the available regions of RAM. 300b9d056f3SNathan Whitehorn * The available regions need not take the kernel into account. 301fe3b4685SNathan Whitehorn */ 302fe3b4685SNathan Whitehorn void 303c1cb22d7SNathan Whitehorn ofw_mem_regions(struct mem_region *memp, int *memsz, 304c1cb22d7SNathan Whitehorn struct mem_region *availp, int *availsz) 305fe3b4685SNathan Whitehorn { 306fe3b4685SNathan Whitehorn phandle_t phandle; 307c1cb22d7SNathan Whitehorn int asz, msz; 308c1cb22d7SNathan Whitehorn int res; 309d8c6808aSNathan Whitehorn char name[31]; 310fe3b4685SNathan Whitehorn 311fe3b4685SNathan Whitehorn asz = msz = 0; 312fe3b4685SNathan Whitehorn 313fe3b4685SNathan Whitehorn /* 314d8c6808aSNathan Whitehorn * Get memory from all the /memory nodes. 315fe3b4685SNathan Whitehorn */ 316d8c6808aSNathan Whitehorn for (phandle = OF_child(OF_peer(0)); phandle != 0; 317d8c6808aSNathan Whitehorn phandle = OF_peer(phandle)) { 318d8c6808aSNathan Whitehorn if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0) 319d8c6808aSNathan Whitehorn continue; 320b9d056f3SNathan Whitehorn if (strncmp(name, "memory", sizeof(name)) != 0 && 321b9d056f3SNathan Whitehorn strncmp(name, "memory@", strlen("memory@")) != 0) 322d8c6808aSNathan Whitehorn continue; 323fe3b4685SNathan Whitehorn 324c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &memp[msz]); 325d8c6808aSNathan Whitehorn msz += res/sizeof(struct mem_region); 326d8c6808aSNathan Whitehorn if (OF_getproplen(phandle, "available") >= 0) 327d8c6808aSNathan Whitehorn res = parse_ofw_memory(phandle, "available", 328c1cb22d7SNathan Whitehorn &availp[asz]); 329d8c6808aSNathan Whitehorn else 330c1cb22d7SNathan Whitehorn res = parse_ofw_memory(phandle, "reg", &availp[asz]); 331d8c6808aSNathan Whitehorn asz += res/sizeof(struct mem_region); 332d8c6808aSNathan Whitehorn } 333d8c6808aSNathan Whitehorn 334b9d056f3SNathan Whitehorn phandle = OF_finddevice("/chosen"); 335b9d056f3SNathan Whitehorn if (OF_hasprop(phandle, "fdtmemreserv")) 336b9d056f3SNathan Whitehorn asz = excise_fdt_reserved(availp, asz); 337b9d056f3SNathan Whitehorn 338d8c6808aSNathan Whitehorn *memsz = msz; 339c1cb22d7SNathan Whitehorn *availsz = asz; 340fe3b4685SNathan Whitehorn } 341fe3b4685SNathan Whitehorn 342fe3b4685SNathan Whitehorn void 343fe3b4685SNathan Whitehorn OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)) 344fe3b4685SNathan Whitehorn { 3456f489d43SJustin Hibbits #ifdef AIM 346bb808254SNathan Whitehorn ofmsr[0] = mfmsr(); 347bb808254SNathan Whitehorn #ifdef __powerpc64__ 348bb808254SNathan Whitehorn ofmsr[0] &= ~PSL_SF; 349bb808254SNathan Whitehorn #endif 350bb808254SNathan Whitehorn __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1])); 351bb808254SNathan Whitehorn __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2])); 352bb808254SNathan Whitehorn __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3])); 353bb808254SNathan Whitehorn __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4])); 3546f489d43SJustin Hibbits openfirmware_entry = openfirm; 355bb808254SNathan Whitehorn 356fe3b4685SNathan Whitehorn if (ofmsr[0] & PSL_DR) 357fe3b4685SNathan Whitehorn ofw_real_mode = 0; 358fe3b4685SNathan Whitehorn else 359fe3b4685SNathan Whitehorn ofw_real_mode = 1; 360fe3b4685SNathan Whitehorn 3616f489d43SJustin Hibbits ofw_save_trap_vec(save_trap_init); 3626f489d43SJustin Hibbits #else 3636f489d43SJustin Hibbits ofw_real_mode = 1; 3646f489d43SJustin Hibbits #endif 3656f489d43SJustin Hibbits 366fe3b4685SNathan Whitehorn fdt = fdt_ptr; 367fe3b4685SNathan Whitehorn 368fe3b4685SNathan Whitehorn #ifdef FDT_DTB_STATIC 369fe3b4685SNathan Whitehorn /* Check for a statically included blob */ 370fe3b4685SNathan Whitehorn if (fdt == NULL) 371fe3b4685SNathan Whitehorn fdt = &fdt_static_dtb; 372fe3b4685SNathan Whitehorn #endif 373fe3b4685SNathan Whitehorn } 374fe3b4685SNathan Whitehorn 375fe3b4685SNathan Whitehorn boolean_t 376fe3b4685SNathan Whitehorn OF_bootstrap() 377fe3b4685SNathan Whitehorn { 378fe3b4685SNathan Whitehorn boolean_t status = FALSE; 379fe3b4685SNathan Whitehorn 3806f489d43SJustin Hibbits #ifdef AIM 38117879090SNathan Whitehorn if (openfirmware_entry != NULL) { 382fe3b4685SNathan Whitehorn if (ofw_real_mode) { 383fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_REAL, 0); 384fe3b4685SNathan Whitehorn } else { 385fe3b4685SNathan Whitehorn #ifdef __powerpc64__ 386fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_32BIT, 0); 387fe3b4685SNathan Whitehorn #else 388fe3b4685SNathan Whitehorn status = OF_install(OFW_STD_DIRECT, 0); 389fe3b4685SNathan Whitehorn #endif 390fe3b4685SNathan Whitehorn } 391fe3b4685SNathan Whitehorn 392fe3b4685SNathan Whitehorn if (status != TRUE) 393fe3b4685SNathan Whitehorn return status; 394fe3b4685SNathan Whitehorn 395fe3b4685SNathan Whitehorn OF_init(openfirmware); 3966f489d43SJustin Hibbits } else 3976f489d43SJustin Hibbits #endif 3986f489d43SJustin Hibbits if (fdt != NULL) { 399fe3b4685SNathan Whitehorn status = OF_install(OFW_FDT, 0); 400fe3b4685SNathan Whitehorn 401fe3b4685SNathan Whitehorn if (status != TRUE) 402fe3b4685SNathan Whitehorn return status; 403fe3b4685SNathan Whitehorn 404fe3b4685SNathan Whitehorn OF_init(fdt); 4056f489d43SJustin Hibbits OF_interpret("perform-fixup", 0); 406fe3b4685SNathan Whitehorn } 407fe3b4685SNathan Whitehorn 408fe3b4685SNathan Whitehorn return (status); 409fe3b4685SNathan Whitehorn } 410fe3b4685SNathan Whitehorn 4116f489d43SJustin Hibbits #ifdef AIM 4129f706727SNathan Whitehorn void 413fe3b4685SNathan Whitehorn ofw_quiesce(void) 414fe3b4685SNathan Whitehorn { 415fe3b4685SNathan Whitehorn struct { 416fe3b4685SNathan Whitehorn cell_t name; 417fe3b4685SNathan Whitehorn cell_t nargs; 418fe3b4685SNathan Whitehorn cell_t nreturns; 419fe3b4685SNathan Whitehorn } args; 420fe3b4685SNathan Whitehorn 4219f706727SNathan Whitehorn KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up")); 422fe3b4685SNathan Whitehorn 423fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"quiesce"; 424fe3b4685SNathan Whitehorn args.nargs = 0; 425fe3b4685SNathan Whitehorn args.nreturns = 0; 426fe3b4685SNathan Whitehorn openfirmware(&args); 427fe3b4685SNathan Whitehorn } 428fe3b4685SNathan Whitehorn 429fe3b4685SNathan Whitehorn static int 430fe3b4685SNathan Whitehorn openfirmware_core(void *args) 431fe3b4685SNathan Whitehorn { 432fe3b4685SNathan Whitehorn int result; 433fe3b4685SNathan Whitehorn register_t oldmsr; 434fe3b4685SNathan Whitehorn 43544d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 43644d29d47SNathan Whitehorn return (-1); 43744d29d47SNathan Whitehorn 438fe3b4685SNathan Whitehorn /* 439fe3b4685SNathan Whitehorn * Turn off exceptions - we really don't want to end up 4404aa3cee6SNathan Whitehorn * anywhere unexpected with PCPU set to something strange 4414aa3cee6SNathan Whitehorn * or the stack pointer wrong. 442fe3b4685SNathan Whitehorn */ 443fe3b4685SNathan Whitehorn oldmsr = intr_disable(); 444fe3b4685SNathan Whitehorn 4454aa3cee6SNathan Whitehorn ofw_sprg_prepare(); 4464aa3cee6SNathan Whitehorn 447f367ffdeSAndreas Tobler /* Save trap vectors */ 448f367ffdeSAndreas Tobler ofw_save_trap_vec(save_trap_of); 449f367ffdeSAndreas Tobler 450f367ffdeSAndreas Tobler /* Restore initially saved trap vectors */ 451f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_init); 452f367ffdeSAndreas Tobler 453fe3b4685SNathan Whitehorn #if defined(AIM) && !defined(__powerpc64__) 454fe3b4685SNathan Whitehorn /* 455fe3b4685SNathan Whitehorn * Clear battable[] translations 456fe3b4685SNathan Whitehorn */ 457fe3b4685SNathan Whitehorn if (!(cpu_features & PPC_FEATURE_64)) 458fe3b4685SNathan Whitehorn __asm __volatile("mtdbatu 2, %0\n" 459fe3b4685SNathan Whitehorn "mtdbatu 3, %0" : : "r" (0)); 460fe3b4685SNathan Whitehorn isync(); 461fe3b4685SNathan Whitehorn #endif 462fe3b4685SNathan Whitehorn 463fe3b4685SNathan Whitehorn result = ofwcall(args); 464f367ffdeSAndreas Tobler 465f367ffdeSAndreas Tobler /* Restore trap vecotrs */ 466f367ffdeSAndreas Tobler ofw_restore_trap_vec(save_trap_of); 467f367ffdeSAndreas Tobler 4684aa3cee6SNathan Whitehorn ofw_sprg_restore(); 4694aa3cee6SNathan Whitehorn 470fe3b4685SNathan Whitehorn intr_restore(oldmsr); 471fe3b4685SNathan Whitehorn 472fe3b4685SNathan Whitehorn return (result); 473fe3b4685SNathan Whitehorn } 474fe3b4685SNathan Whitehorn 475fe3b4685SNathan Whitehorn #ifdef SMP 476fe3b4685SNathan Whitehorn struct ofw_rv_args { 477fe3b4685SNathan Whitehorn void *args; 478fe3b4685SNathan Whitehorn int retval; 479fe3b4685SNathan Whitehorn volatile int in_progress; 480fe3b4685SNathan Whitehorn }; 481fe3b4685SNathan Whitehorn 482fe3b4685SNathan Whitehorn static void 483fe3b4685SNathan Whitehorn ofw_rendezvous_dispatch(void *xargs) 484fe3b4685SNathan Whitehorn { 485fe3b4685SNathan Whitehorn struct ofw_rv_args *rv_args = xargs; 486fe3b4685SNathan Whitehorn 487fe3b4685SNathan Whitehorn /* NOTE: Interrupts are disabled here */ 488fe3b4685SNathan Whitehorn 489fe3b4685SNathan Whitehorn if (PCPU_GET(cpuid) == 0) { 490fe3b4685SNathan Whitehorn /* 491fe3b4685SNathan Whitehorn * Execute all OF calls on CPU 0 492fe3b4685SNathan Whitehorn */ 493fe3b4685SNathan Whitehorn rv_args->retval = openfirmware_core(rv_args->args); 494fe3b4685SNathan Whitehorn rv_args->in_progress = 0; 495fe3b4685SNathan Whitehorn } else { 496fe3b4685SNathan Whitehorn /* 497fe3b4685SNathan Whitehorn * Spin with interrupts off on other CPUs while OF has 498fe3b4685SNathan Whitehorn * control of the machine. 499fe3b4685SNathan Whitehorn */ 500fe3b4685SNathan Whitehorn while (rv_args->in_progress) 501fe3b4685SNathan Whitehorn cpu_spinwait(); 502fe3b4685SNathan Whitehorn } 503fe3b4685SNathan Whitehorn } 504fe3b4685SNathan Whitehorn #endif 505fe3b4685SNathan Whitehorn 506fe3b4685SNathan Whitehorn static int 507fe3b4685SNathan Whitehorn openfirmware(void *args) 508fe3b4685SNathan Whitehorn { 509fe3b4685SNathan Whitehorn int result; 510fe3b4685SNathan Whitehorn #ifdef SMP 511fe3b4685SNathan Whitehorn struct ofw_rv_args rv_args; 51244d29d47SNathan Whitehorn #endif 513fe3b4685SNathan Whitehorn 51444d29d47SNathan Whitehorn if (openfirmware_entry == NULL) 51544d29d47SNathan Whitehorn return (-1); 51644d29d47SNathan Whitehorn 51744d29d47SNathan Whitehorn #ifdef SMP 518fe3b4685SNathan Whitehorn rv_args.args = args; 519fe3b4685SNathan Whitehorn rv_args.in_progress = 1; 520fe3b4685SNathan Whitehorn smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch, 521fe3b4685SNathan Whitehorn smp_no_rendevous_barrier, &rv_args); 522fe3b4685SNathan Whitehorn result = rv_args.retval; 523fe3b4685SNathan Whitehorn #else 524fe3b4685SNathan Whitehorn result = openfirmware_core(args); 525fe3b4685SNathan Whitehorn #endif 526fe3b4685SNathan Whitehorn 527fe3b4685SNathan Whitehorn return (result); 528fe3b4685SNathan Whitehorn } 529fe3b4685SNathan Whitehorn 530fe3b4685SNathan Whitehorn void 531fe3b4685SNathan Whitehorn OF_reboot() 532fe3b4685SNathan Whitehorn { 533fe3b4685SNathan Whitehorn struct { 534fe3b4685SNathan Whitehorn cell_t name; 535fe3b4685SNathan Whitehorn cell_t nargs; 536fe3b4685SNathan Whitehorn cell_t nreturns; 537fe3b4685SNathan Whitehorn cell_t arg; 538fe3b4685SNathan Whitehorn } args; 539fe3b4685SNathan Whitehorn 540fe3b4685SNathan Whitehorn args.name = (cell_t)(uintptr_t)"interpret"; 541fe3b4685SNathan Whitehorn args.nargs = 1; 542fe3b4685SNathan Whitehorn args.nreturns = 0; 543fe3b4685SNathan Whitehorn args.arg = (cell_t)(uintptr_t)"reset-all"; 544fe3b4685SNathan Whitehorn openfirmware_core(&args); /* Don't do rendezvous! */ 545fe3b4685SNathan Whitehorn 546fe3b4685SNathan Whitehorn for (;;); /* just in case */ 547fe3b4685SNathan Whitehorn } 548fe3b4685SNathan Whitehorn 549629aa519SNathan Whitehorn #endif /* AIM */ 550629aa519SNathan Whitehorn 551fe3b4685SNathan Whitehorn void 552fe3b4685SNathan Whitehorn OF_getetheraddr(device_t dev, u_char *addr) 553fe3b4685SNathan Whitehorn { 554fe3b4685SNathan Whitehorn phandle_t node; 555fe3b4685SNathan Whitehorn 556fe3b4685SNathan Whitehorn node = ofw_bus_get_node(dev); 557fe3b4685SNathan Whitehorn OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN); 558fe3b4685SNathan Whitehorn } 559fe3b4685SNathan Whitehorn 560fe3b4685SNathan Whitehorn /* 561fe3b4685SNathan Whitehorn * Return a bus handle and bus tag that corresponds to the register 562fe3b4685SNathan Whitehorn * numbered regno for the device referenced by the package handle 563fe3b4685SNathan Whitehorn * dev. This function is intended to be used by console drivers in 564fe3b4685SNathan Whitehorn * early boot only. It works by mapping the address of the device's 565fe3b4685SNathan Whitehorn * register in the address space of its parent and recursively walk 566fe3b4685SNathan Whitehorn * the device tree upward this way. 567fe3b4685SNathan Whitehorn */ 568fe3b4685SNathan Whitehorn static void 569fe3b4685SNathan Whitehorn OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) 570fe3b4685SNathan Whitehorn { 57143a581e1SNathan Whitehorn char type[64]; 572fe3b4685SNathan Whitehorn uint32_t addr, size; 573fe3b4685SNathan Whitehorn int pci, res; 574fe3b4685SNathan Whitehorn 575fe3b4685SNathan Whitehorn res = OF_getprop(node, "#address-cells", &addr, sizeof(addr)); 576fe3b4685SNathan Whitehorn if (res == -1) 577fe3b4685SNathan Whitehorn addr = 2; 578fe3b4685SNathan Whitehorn res = OF_getprop(node, "#size-cells", &size, sizeof(size)); 579fe3b4685SNathan Whitehorn if (res == -1) 580fe3b4685SNathan Whitehorn size = 1; 581fe3b4685SNathan Whitehorn pci = 0; 582fe3b4685SNathan Whitehorn if (addr == 3 && size == 2) { 58343a581e1SNathan Whitehorn res = OF_getprop(node, "device_type", type, sizeof(type)); 584fe3b4685SNathan Whitehorn if (res != -1) { 58543a581e1SNathan Whitehorn type[sizeof(type) - 1] = '\0'; 58643a581e1SNathan Whitehorn pci = (strcmp(type, "pci") == 0) ? 1 : 0; 587fe3b4685SNathan Whitehorn } 588fe3b4685SNathan Whitehorn } 589fe3b4685SNathan Whitehorn if (addrp != NULL) 590fe3b4685SNathan Whitehorn *addrp = addr; 591fe3b4685SNathan Whitehorn if (sizep != NULL) 592fe3b4685SNathan Whitehorn *sizep = size; 593fe3b4685SNathan Whitehorn if (pcip != NULL) 594fe3b4685SNathan Whitehorn *pcip = pci; 595fe3b4685SNathan Whitehorn } 596fe3b4685SNathan Whitehorn 597fe3b4685SNathan Whitehorn int 598fe3b4685SNathan Whitehorn OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, 599fe3b4685SNathan Whitehorn bus_space_handle_t *handle) 600fe3b4685SNathan Whitehorn { 601fe3b4685SNathan Whitehorn uint32_t cell[32]; 602fe3b4685SNathan Whitehorn bus_addr_t addr, raddr, baddr; 603fe3b4685SNathan Whitehorn bus_size_t size, rsize; 604fe3b4685SNathan Whitehorn uint32_t c, nbridge, naddr, nsize; 605fe3b4685SNathan Whitehorn phandle_t bridge, parent; 606023864f6SNathan Whitehorn u_int spc, rspc, prefetch; 607fe3b4685SNathan Whitehorn int pci, pcib, res; 608fe3b4685SNathan Whitehorn 609fe3b4685SNathan Whitehorn /* Sanity checking. */ 610fe3b4685SNathan Whitehorn if (dev == 0) 611fe3b4685SNathan Whitehorn return (EINVAL); 612fe3b4685SNathan Whitehorn bridge = OF_parent(dev); 613fe3b4685SNathan Whitehorn if (bridge == 0) 614fe3b4685SNathan Whitehorn return (EINVAL); 615fe3b4685SNathan Whitehorn if (regno < 0) 616fe3b4685SNathan Whitehorn return (EINVAL); 617fe3b4685SNathan Whitehorn if (tag == NULL || handle == NULL) 618fe3b4685SNathan Whitehorn return (EINVAL); 619fe3b4685SNathan Whitehorn 62043a581e1SNathan Whitehorn /* Assume big-endian unless we find a PCI device */ 62143a581e1SNathan Whitehorn *tag = &bs_be_tag; 62243a581e1SNathan Whitehorn 623fe3b4685SNathan Whitehorn /* Get the requested register. */ 624fe3b4685SNathan Whitehorn OF_get_addr_props(bridge, &naddr, &nsize, &pci); 62543a581e1SNathan Whitehorn if (pci) 62643a581e1SNathan Whitehorn *tag = &bs_le_tag; 627fe3b4685SNathan Whitehorn res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg", 628fe3b4685SNathan Whitehorn cell, sizeof(cell)); 629fe3b4685SNathan Whitehorn if (res == -1) 630fe3b4685SNathan Whitehorn return (ENXIO); 631fe3b4685SNathan Whitehorn if (res % sizeof(cell[0])) 632fe3b4685SNathan Whitehorn return (ENXIO); 633fe3b4685SNathan Whitehorn res /= sizeof(cell[0]); 634fe3b4685SNathan Whitehorn regno *= naddr + nsize; 635fe3b4685SNathan Whitehorn if (regno + naddr + nsize > res) 636fe3b4685SNathan Whitehorn return (EINVAL); 637fe3b4685SNathan Whitehorn spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; 638023864f6SNathan Whitehorn prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; 639fe3b4685SNathan Whitehorn addr = 0; 640fe3b4685SNathan Whitehorn for (c = 0; c < naddr; c++) 641fe3b4685SNathan Whitehorn addr = ((uint64_t)addr << 32) | cell[regno++]; 642fe3b4685SNathan Whitehorn size = 0; 643fe3b4685SNathan Whitehorn for (c = 0; c < nsize; c++) 644fe3b4685SNathan Whitehorn size = ((uint64_t)size << 32) | cell[regno++]; 645fe3b4685SNathan Whitehorn 646fe3b4685SNathan Whitehorn /* 647fe3b4685SNathan Whitehorn * Map the address range in the bridge's decoding window as given 648fe3b4685SNathan Whitehorn * by the "ranges" property. If a node doesn't have such property 649fe3b4685SNathan Whitehorn * then no mapping is done. 650fe3b4685SNathan Whitehorn */ 651fe3b4685SNathan Whitehorn parent = OF_parent(bridge); 652fe3b4685SNathan Whitehorn while (parent != 0) { 653fe3b4685SNathan Whitehorn OF_get_addr_props(parent, &nbridge, NULL, &pcib); 65443a581e1SNathan Whitehorn if (pcib) 65543a581e1SNathan Whitehorn *tag = &bs_le_tag; 656fe3b4685SNathan Whitehorn res = OF_getprop(bridge, "ranges", cell, sizeof(cell)); 657fe3b4685SNathan Whitehorn if (res == -1) 658fe3b4685SNathan Whitehorn goto next; 659fe3b4685SNathan Whitehorn if (res % sizeof(cell[0])) 660fe3b4685SNathan Whitehorn return (ENXIO); 661fe3b4685SNathan Whitehorn res /= sizeof(cell[0]); 662fe3b4685SNathan Whitehorn regno = 0; 663fe3b4685SNathan Whitehorn while (regno < res) { 664fe3b4685SNathan Whitehorn rspc = (pci) 665fe3b4685SNathan Whitehorn ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 666fe3b4685SNathan Whitehorn : ~0; 667fe3b4685SNathan Whitehorn if (rspc != spc) { 668fe3b4685SNathan Whitehorn regno += naddr + nbridge + nsize; 669fe3b4685SNathan Whitehorn continue; 670fe3b4685SNathan Whitehorn } 671fe3b4685SNathan Whitehorn raddr = 0; 672fe3b4685SNathan Whitehorn for (c = 0; c < naddr; c++) 673fe3b4685SNathan Whitehorn raddr = ((uint64_t)raddr << 32) | cell[regno++]; 674fe3b4685SNathan Whitehorn rspc = (pcib) 675fe3b4685SNathan Whitehorn ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK 676fe3b4685SNathan Whitehorn : ~0; 677fe3b4685SNathan Whitehorn baddr = 0; 678fe3b4685SNathan Whitehorn for (c = 0; c < nbridge; c++) 679fe3b4685SNathan Whitehorn baddr = ((uint64_t)baddr << 32) | cell[regno++]; 680fe3b4685SNathan Whitehorn rsize = 0; 681fe3b4685SNathan Whitehorn for (c = 0; c < nsize; c++) 682fe3b4685SNathan Whitehorn rsize = ((uint64_t)rsize << 32) | cell[regno++]; 683fe3b4685SNathan Whitehorn if (addr < raddr || addr >= raddr + rsize) 684fe3b4685SNathan Whitehorn continue; 685fe3b4685SNathan Whitehorn addr = addr - raddr + baddr; 686fe3b4685SNathan Whitehorn if (rspc != ~0) 687fe3b4685SNathan Whitehorn spc = rspc; 688fe3b4685SNathan Whitehorn } 689fe3b4685SNathan Whitehorn 690fe3b4685SNathan Whitehorn next: 691fe3b4685SNathan Whitehorn bridge = parent; 692fe3b4685SNathan Whitehorn parent = OF_parent(bridge); 693fe3b4685SNathan Whitehorn OF_get_addr_props(bridge, &naddr, &nsize, &pci); 694fe3b4685SNathan Whitehorn } 695fe3b4685SNathan Whitehorn 696023864f6SNathan Whitehorn return (bus_space_map(*tag, addr, size, 697023864f6SNathan Whitehorn prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); 698fe3b4685SNathan Whitehorn } 699fe3b4685SNathan Whitehorn 700