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