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 <stand.h>
27 #include <sys/param.h>
28 #include <fdt_platform.h>
29 #include <openfirm.h>
30 #include <libfdt.h>
31 #include "bootstrap.h"
32
33 extern int command_fdt_internal(int argc, char *argv[]);
34
35 static int
OF_hasprop(phandle_t node,const char * prop)36 OF_hasprop(phandle_t node, const char *prop)
37 {
38 return (OF_getproplen(node, (char *)prop) > 0);
39 }
40
41 static void
add_node_to_fdt(void * buffer,phandle_t node,int fdt_offset)42 add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset)
43 {
44 int i, child_offset, error;
45 char name[255], *lastprop, *subname;
46 void *propbuf;
47 ssize_t proplen;
48
49 lastprop = NULL;
50 while (OF_nextprop(node, lastprop, name) > 0) {
51 proplen = OF_getproplen(node, name);
52
53 /* Detect and correct for errors and strangeness */
54 if (proplen < 0)
55 proplen = 0;
56 if (proplen > 1024)
57 proplen = 1024;
58
59 propbuf = malloc(proplen);
60 if (propbuf == NULL) {
61 printf("Cannot allocate memory for prop %s\n", name);
62 return;
63 }
64 OF_getprop(node, name, propbuf, proplen);
65 error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen);
66 free(propbuf);
67 lastprop = name;
68 if (error)
69 printf("Error %d adding property %s to "
70 "node %d\n", error, name, fdt_offset);
71 }
72
73 if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle")
74 && !OF_hasprop(node, "ibm,phandle"))
75 fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node));
76
77 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
78 OF_package_to_path(node, name, sizeof(name));
79 subname = strrchr(name, '/');
80 subname++;
81 child_offset = fdt_add_subnode(buffer, fdt_offset, subname);
82 if (child_offset < 0) {
83 printf("Error %d adding node %s (%s), skipping\n",
84 child_offset, name, subname);
85 continue;
86 }
87
88 add_node_to_fdt(buffer, node, child_offset);
89 }
90 }
91
92 static void
ofwfdt_fixups(void * fdtp)93 ofwfdt_fixups(void *fdtp)
94 {
95 int offset, len, i;
96 phandle_t node;
97 ihandle_t rtas;
98 const void *prop;
99
100 /*
101 * Instantiate and add reservations for RTAS state if present
102 */
103
104 offset = fdt_path_offset(fdtp, "/rtas");
105 if (offset > 0) {
106 uint32_t base;
107 void *rtasmem;
108 char path[255];
109
110 node = OF_finddevice("/rtas");
111 OF_package_to_path(node, path, sizeof(path));
112 OF_getencprop(node, "rtas-size", &len, sizeof(len));
113
114 /* Allocate memory */
115 rtasmem = OF_claim(0, len, 4096);
116
117 /* Instantiate RTAS */
118 rtas = OF_open(path);
119 base = 0;
120 OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtasmem,
121 &base);
122
123 /* Store info to FDT using Linux convention */
124 base = cpu_to_fdt32(base);
125 fdt_setprop(fdtp, offset, "linux,rtas-entry", &base,
126 sizeof(base));
127 base = cpu_to_fdt32((uint32_t)rtasmem);
128 offset = fdt_path_offset(fdtp, "/rtas");
129 fdt_setprop(fdtp, offset, "linux,rtas-base", &base,
130 sizeof(base));
131
132 /* Mark RTAS private data area reserved */
133 base = fdt32_to_cpu(base);
134 fdt_add_mem_rsv(fdtp, base, len);
135 } else {
136 /*
137 * Remove /memory/available properties, which reflect long-gone
138 * OF state. Note that this doesn't work if we need RTAS still,
139 * since that's part of the firmware.
140 */
141 offset = fdt_path_offset(fdtp, "/memory@0");
142 if (offset > 0)
143 fdt_delprop(fdtp, offset, "available");
144 }
145
146
147 /*
148 * Convert stored ihandles under /chosen to xref phandles
149 */
150 offset = fdt_path_offset(fdtp, "/chosen");
151 if (offset > 0) {
152 const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu",
153 NULL};
154 const uint32_t *ihand;
155 for (i = 0; chosenprops[i] != NULL; i++) {
156 ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len);
157 if (ihand != NULL && len == sizeof(*ihand)) {
158 node = OF_instance_to_package(*ihand);
159 if (OF_hasprop(node, "phandle"))
160 OF_getprop(node, "phandle", &node,
161 sizeof(node));
162 else if (OF_hasprop(node, "linux,phandle"))
163 OF_getprop(node, "linux,phandle", &node,
164 sizeof(node));
165 else if (OF_hasprop(node, "ibm,phandle"))
166 OF_getprop(node, "ibm,phandle", &node,
167 sizeof(node));
168 fdt_setprop(fdtp, offset, chosenprops[i], &node,
169 sizeof(node));
170 }
171
172 /* Refind node in case it moved */
173 offset = fdt_path_offset(fdtp, "/chosen");
174 }
175 }
176 }
177
178 int
fdt_platform_load_dtb(void)179 fdt_platform_load_dtb(void)
180 {
181 void *buffer;
182 size_t buflen = 409600;
183
184 buffer = malloc(buflen);
185 fdt_create_empty_tree(buffer, buflen);
186 add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/"));
187 ofwfdt_fixups(buffer);
188 fdt_pack(buffer);
189
190 fdt_load_dtb_addr(buffer);
191 free(buffer);
192
193 return (0);
194 }
195
196 void
fdt_platform_load_overlays(void)197 fdt_platform_load_overlays(void)
198 {
199
200 }
201
202 void
fdt_platform_fixups(void)203 fdt_platform_fixups(void)
204 {
205
206 }
207
208 static int
command_fdt(int argc,char * argv[])209 command_fdt(int argc, char *argv[])
210 {
211
212 return (command_fdt_internal(argc, argv));
213 }
214
215 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
216
217