xref: /freebsd/stand/powerpc/ofw/ofwfdt.c (revision 3e15b01d)
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