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