]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/fdt_support.c
Removed some nonused fdt functions and moved fdt_find_and_setprop out of libfdt
[karo-tx-uboot.git] / common / fdt_support.c
1 /*
2  * (C) Copyright 2007
3  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <linux/ctype.h>
26 #include <linux/types.h>
27
28 #ifdef CONFIG_OF_LIBFDT
29
30 #include <asm/global_data.h>
31 #include <fdt.h>
32 #include <libfdt.h>
33 #include <fdt_support.h>
34
35 /*
36  * Global data (for the gd->bd)
37  */
38 DECLARE_GLOBAL_DATA_PTR;
39
40 /*
41  * fdt points to our working device tree.
42  */
43 struct fdt_header *fdt;
44
45 /********************************************************************/
46
47 /**
48  * fdt_find_and_setprop: Find a node and set it's property
49  *
50  * @fdt: ptr to device tree
51  * @node: path of node
52  * @prop: property name
53  * @val: ptr to new value
54  * @len: length of new property value
55  * @create: flag to create the property if it doesn't exist
56  *
57  * Convenience function to directly set a property given the path to the node.
58  */
59 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
60                          const void *val, int len, int create)
61 {
62         int nodeoff = fdt_find_node_by_path(fdt, node);
63
64         if (nodeoff < 0)
65                 return nodeoff;
66
67         if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
68                 return 0; /* create flag not set; so exit quietly */
69
70         return fdt_setprop(fdt, nodeoff, prop, val, len);
71 }
72
73 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
74 {
75         int   nodeoffset;
76         int   err;
77         u32   tmp;              /* used to set 32 bit integer properties */
78         char  *str;             /* used to set string properties */
79
80         err = fdt_check_header(fdt);
81         if (err < 0) {
82                 printf("fdt_chosen: %s\n", fdt_strerror(err));
83                 return err;
84         }
85
86         if (initrd_start && initrd_end) {
87                 struct fdt_reserve_entry re;
88                 int  used;
89                 int  total;
90                 int  j;
91
92                 err = fdt_num_reservemap(fdt, &used, &total);
93                 if (err < 0) {
94                         printf("fdt_chosen: %s\n", fdt_strerror(err));
95                         return err;
96                 }
97                 if (used >= total) {
98                         printf("WARNING: "
99                                 "no room in the reserved map (%d of %d)\n",
100                                 used, total);
101                         return -1;
102                 }
103                 /*
104                  * Look for an existing entry and update it.  If we don't find
105                  * the entry, we will j be the next available slot.
106                  */
107                 for (j = 0; j < used; j++) {
108                         err = fdt_get_reservemap(fdt, j, &re);
109                         if (re.address == initrd_start) {
110                                 break;
111                         }
112                 }
113                 err = fdt_replace_reservemap_entry(fdt, j,
114                         initrd_start, initrd_end - initrd_start + 1);
115                 if (err < 0) {
116                         printf("fdt_chosen: %s\n", fdt_strerror(err));
117                         return err;
118                 }
119         }
120
121         /*
122          * Find the "chosen" node.
123          */
124         nodeoffset = fdt_find_node_by_path (fdt, "/chosen");
125
126         /*
127          * If we have a "chosen" node already the "force the writing"
128          * is not set, our job is done.
129          */
130         if ((nodeoffset >= 0) && !force)
131                 return 0;
132
133         /*
134          * No "chosen" node in the blob: create it.
135          */
136         if (nodeoffset < 0) {
137                 /*
138                  * Create a new node "/chosen" (offset 0 is root level)
139                  */
140                 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
141                 if (nodeoffset < 0) {
142                         printf("WARNING: could not create /chosen %s.\n",
143                                 fdt_strerror(nodeoffset));
144                         return nodeoffset;
145                 }
146         }
147
148         /*
149          * Update pre-existing properties, create them if non-existant.
150          */
151         str = getenv("bootargs");
152         if (str != NULL) {
153                 err = fdt_setprop(fdt, nodeoffset,
154                         "bootargs", str, strlen(str)+1);
155                 if (err < 0)
156                         printf("WARNING: could not set bootargs %s.\n",
157                                 fdt_strerror(err));
158         }
159         if (initrd_start && initrd_end) {
160                 tmp = __cpu_to_be32(initrd_start);
161                 err = fdt_setprop(fdt, nodeoffset,
162                          "linux,initrd-start", &tmp, sizeof(tmp));
163                 if (err < 0)
164                         printf("WARNING: "
165                                 "could not set linux,initrd-start %s.\n",
166                                 fdt_strerror(err));
167                 tmp = __cpu_to_be32(initrd_end);
168                 err = fdt_setprop(fdt, nodeoffset,
169                         "linux,initrd-end", &tmp, sizeof(tmp));
170                 if (err < 0)
171                         printf("WARNING: could not set linux,initrd-end %s.\n",
172                                 fdt_strerror(err));
173         }
174 #ifdef OF_STDOUT_PATH
175         err = fdt_setprop(fdt, nodeoffset,
176                 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
177         if (err < 0)
178                 printf("WARNING: could not set linux,stdout-path %s.\n",
179                         fdt_strerror(err));
180 #endif
181
182         return err;
183 }
184
185 /********************************************************************/
186
187 #ifdef CONFIG_OF_HAS_UBOOT_ENV
188
189 /* Function that returns a character from the environment */
190 extern uchar(*env_get_char) (int);
191
192
193 int fdt_env(void *fdt)
194 {
195         int   nodeoffset;
196         int   err;
197         int   k, nxt;
198         int i;
199         static char tmpenv[256];
200
201         err = fdt_check_header(fdt);
202         if (err < 0) {
203                 printf("fdt_env: %s\n", fdt_strerror(err));
204                 return err;
205         }
206
207         /*
208          * See if we already have a "u-boot-env" node, delete it if so.
209          * Then create a new empty node.
210          */
211         nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env");
212         if (nodeoffset >= 0) {
213                 err = fdt_del_node(fdt, nodeoffset);
214                 if (err < 0) {
215                         printf("fdt_env: %s\n", fdt_strerror(err));
216                         return err;
217                 }
218         }
219         /*
220          * Create a new node "/u-boot-env" (offset 0 is root level)
221          */
222         nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
223         if (nodeoffset < 0) {
224                 printf("WARNING: could not create /u-boot-env %s.\n",
225                         fdt_strerror(nodeoffset));
226                 return nodeoffset;
227         }
228
229         for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
230                 char *s, *lval, *rval;
231
232                 /*
233                  * Find the end of the name=definition
234                  */
235                 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
236                         ;
237                 s = tmpenv;
238                 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
239                         *s++ = env_get_char(k);
240                 *s++ = '\0';
241                 lval = tmpenv;
242                 /*
243                  * Find the first '=': it separates the name from the value
244                  */
245                 s = strchr(tmpenv, '=');
246                 if (s != NULL) {
247                         *s++ = '\0';
248                         rval = s;
249                 } else
250                         continue;
251                 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
252                 if (err < 0) {
253                         printf("WARNING: could not set %s %s.\n",
254                                 lval, fdt_strerror(err));
255                         return err;
256                 }
257         }
258         return 0;
259 }
260 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */
261
262 /********************************************************************/
263
264 #ifdef CONFIG_OF_HAS_BD_T
265
266 #define BDM(x)  {       .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
267
268 static const struct {
269         const char *name;
270         int offset;
271 } bd_map[] = {
272         BDM(memstart),
273         BDM(memsize),
274         BDM(flashstart),
275         BDM(flashsize),
276         BDM(flashoffset),
277         BDM(sramstart),
278         BDM(sramsize),
279 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
280         || defined(CONFIG_E500)
281         BDM(immr_base),
282 #endif
283 #if defined(CONFIG_MPC5xxx)
284         BDM(mbar_base),
285 #endif
286 #if defined(CONFIG_MPC83XX)
287         BDM(immrbar),
288 #endif
289 #if defined(CONFIG_MPC8220)
290         BDM(mbar_base),
291         BDM(inpfreq),
292         BDM(pcifreq),
293         BDM(pevfreq),
294         BDM(flbfreq),
295         BDM(vcofreq),
296 #endif
297         BDM(bootflags),
298         BDM(ip_addr),
299         BDM(intfreq),
300         BDM(busfreq),
301 #ifdef CONFIG_CPM2
302         BDM(cpmfreq),
303         BDM(brgfreq),
304         BDM(sccfreq),
305         BDM(vco),
306 #endif
307 #if defined(CONFIG_MPC5xxx)
308         BDM(ipbfreq),
309         BDM(pcifreq),
310 #endif
311         BDM(baudrate),
312 };
313
314
315 int fdt_bd_t(void *fdt)
316 {
317         bd_t *bd = gd->bd;
318         int   nodeoffset;
319         int   err;
320         u32   tmp;              /* used to set 32 bit integer properties */
321         int i;
322
323         err = fdt_check_header(fdt);
324         if (err < 0) {
325                 printf("fdt_bd_t: %s\n", fdt_strerror(err));
326                 return err;
327         }
328
329         /*
330          * See if we already have a "bd_t" node, delete it if so.
331          * Then create a new empty node.
332          */
333         nodeoffset = fdt_find_node_by_path (fdt, "/bd_t");
334         if (nodeoffset >= 0) {
335                 err = fdt_del_node(fdt, nodeoffset);
336                 if (err < 0) {
337                         printf("fdt_bd_t: %s\n", fdt_strerror(err));
338                         return err;
339                 }
340         }
341         /*
342          * Create a new node "/bd_t" (offset 0 is root level)
343          */
344         nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
345         if (nodeoffset < 0) {
346                 printf("WARNING: could not create /bd_t %s.\n",
347                         fdt_strerror(nodeoffset));
348                 printf("fdt_bd_t: %s\n", fdt_strerror(nodeoffset));
349                 return nodeoffset;
350         }
351         /*
352          * Use the string/pointer structure to create the entries...
353          */
354         for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
355                 tmp = cpu_to_be32(getenv("bootargs"));
356                 err = fdt_setprop(fdt, nodeoffset,
357                         bd_map[i].name, &tmp, sizeof(tmp));
358                 if (err < 0)
359                         printf("WARNING: could not set %s %s.\n",
360                                 bd_map[i].name, fdt_strerror(err));
361         }
362         /*
363          * Add a couple of oddball entries...
364          */
365         err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
366         if (err < 0)
367                 printf("WARNING: could not set enetaddr %s.\n",
368                         fdt_strerror(err));
369         err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
370         if (err < 0)
371                 printf("WARNING: could not set ethspeed %s.\n",
372                         fdt_strerror(err));
373         return 0;
374 }
375 #endif /* ifdef CONFIG_OF_HAS_BD_T */
376
377 #endif /* CONFIG_OF_LIBFDT */