ofwfdt.c revision 279799
1/*- 2 * Copyright (C) 2014-2015 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/boot/powerpc/ofw/ofwfdt.c 279799 2015-03-09 02:57:34Z nwhitehorn $"); 28 29#include <stand.h> 30#include <sys/param.h> 31#include <fdt_platform.h> 32#include <openfirm.h> 33#include <libfdt.h> 34#include "bootstrap.h" 35 36static int 37OF_hasprop(phandle_t node, const char *prop) 38{ 39 return (OF_getproplen(node, prop) > 0); 40} 41 42static void 43add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset) 44{ 45 int i, child_offset, error; 46 char name[2048], *lastprop, *subname; 47 void *propbuf; 48 size_t proplen; 49 50 lastprop = NULL; 51 while (OF_nextprop(node, lastprop, name) > 0) { 52 proplen = OF_getproplen(node, name); 53 propbuf = malloc(proplen); 54 OF_getprop(node, name, propbuf, proplen); 55 error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen); 56 free(propbuf); 57 lastprop = name; 58 if (error) 59 printf("Error %d adding property %s to " 60 "node %d\n", error, name, fdt_offset); 61 } 62 63 if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle") 64 && !OF_hasprop(node, "ibm,phandle")) 65 fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node)); 66 67 for (node = OF_child(node); node > 0; node = OF_peer(node)) { 68 OF_package_to_path(node, name, sizeof(name)); 69 subname = strrchr(name, '/'); 70 subname++; 71 child_offset = fdt_add_subnode(buffer, fdt_offset, subname); 72 if (child_offset < 0) { 73 printf("Error %d adding node %s (%s), skipping\n", 74 child_offset, name, subname); 75 continue; 76 } 77 78 add_node_to_fdt(buffer, node, child_offset); 79 } 80} 81 82static void 83ofwfdt_fixups(void *fdtp) 84{ 85 int offset, len, i; 86 phandle_t node; 87 ihandle_t rtas; 88 const void *prop; 89 90 /* 91 * Instantiate and add reservations for RTAS state if present 92 */ 93 94 offset = fdt_path_offset(fdtp, "/rtas"); 95 if (offset > 0) { 96 uint32_t base; 97 void *rtasmem; 98 char path[255]; 99 100 node = OF_finddevice("/rtas"); 101 OF_package_to_path(node, path, sizeof(path)); 102 OF_getprop(node, "rtas-size", &len, sizeof(len)); 103 104 /* Allocate memory */ 105 rtasmem = OF_claim(0, len, 4096); 106 107 /* Instantiate RTAS */ 108 rtas = OF_open(path); 109 base = 0; 110 OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtas, 111 &base); 112 113 /* Store info to FDT using Linux convention */ 114 base = cpu_to_fdt32(base); 115 fdt_setprop(fdtp, offset, "linux,rtas-entry", &base, 116 sizeof(base)); 117 base = cpu_to_fdt32((uint32_t)rtasmem); 118 offset = fdt_path_offset(fdtp, "/rtas"); 119 fdt_setprop(fdtp, offset, "linux,rtas-base", &base, 120 sizeof(base)); 121 122 /* Mark RTAS private data area reserved */ 123 fdt_add_mem_rsv(fdtp, base, len); 124 } else { 125 /* 126 * Remove /memory/available properties, which reflect long-gone OF 127 * state. Note that this doesn't work if we need RTAS still, since 128 * that's part of the firmware. 129 */ 130 131 offset = fdt_path_offset(fdtp, "/memory@0"); 132 if (offset > 0) 133 fdt_delprop(fdtp, offset, "available"); 134 } 135 136 /* 137 138 /* 139 * Convert stored ihandles under /chosen to xref phandles 140 */ 141 offset = fdt_path_offset(fdtp, "/chosen"); 142 if (offset > 0) { 143 const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu", 144 NULL}; 145 const uint32_t *ihand; 146 for (i = 0; chosenprops[i] != NULL; i++) { 147 ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len); 148 if (ihand != NULL && len == sizeof(*ihand)) { 149 node = OF_instance_to_package( 150 fdt32_to_cpu(*ihand)); 151 if (OF_hasprop(node, "phandle")) 152 OF_getprop(node, "phandle", &node, 153 sizeof(node)); 154 else if (OF_hasprop(node, "linux,phandle")) 155 OF_getprop(node, "linux,phandle", &node, 156 sizeof(node)); 157 else if (OF_hasprop(node, "ibm,phandle")) 158 OF_getprop(node, "ibm,phandle", &node, 159 sizeof(node)); 160 node = cpu_to_fdt32(node); 161 fdt_setprop(fdtp, offset, chosenprops[i], &node, sizeof(node)); 162 } 163 164 /* Refind node in case it moved */ 165 offset = fdt_path_offset(fdtp, "/chosen"); 166 } 167 } 168} 169 170int 171fdt_platform_load_dtb(void) 172{ 173 void *buffer; 174 size_t buflen = 409600; 175 176 buffer = malloc(buflen); 177 fdt_create_empty_tree(buffer, buflen); 178 add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/")); 179 ofwfdt_fixups(buffer); 180 fdt_pack(buffer); 181 182 fdt_load_dtb_addr(buffer); 183 free(buffer); 184 185 return (0); 186} 187 188void 189fdt_platform_fixups(void) 190{ 191 192} 193 194static int 195command_fdt(int argc, char *argv[]) 196{ 197 198 return (command_fdt_internal(argc, argv)); 199} 200 201COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 202 203