]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/powerpc/ofw/ofwfdt.c
MFV r346563:
[FreeBSD/FreeBSD.git] / stand / powerpc / ofw / ofwfdt.c
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