]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/fdt_support.c
Tighten up the error messages.
[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 #ifdef CONFIG_OF_BOARD_SETUP
36 void ft_board_setup(void *blob, bd_t *bd);
37 #endif
38
39 /*
40  * Global data (for the gd->bd)
41  */
42 DECLARE_GLOBAL_DATA_PTR;
43
44 /*
45  * fdt points to our working device tree.
46  */
47 struct fdt_header *fdt;
48
49 /********************************************************************/
50
51 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
52 {
53         bd_t *bd = gd->bd;
54         int   nodeoffset;
55         int   err;
56         u32   tmp;              /* used to set 32 bit integer properties */
57         char  *str;             /* used to set string properties */
58
59         err = fdt_check_header(fdt);
60         if (err < 0) {
61                 printf("libfdt: %s\n", fdt_strerror(err));
62                 return err;
63         }
64
65 #ifdef CONFIG_OF_BOARD_SETUP
66         /*
67          * ft_board_setup() sets various board-specific properties to
68          * the proper values.
69          *
70          * STRICTLY SPEAKING, this is out of place, but it isn't clear
71          * where a better place would be.
72          */
73         ft_board_setup(fdt, bd);
74 #endif
75
76         if (initrd_start && initrd_end) {
77                 struct fdt_reserve_entry re;
78                 int  used;
79                 int  total;
80                 int  j;
81
82                 err = fdt_num_reservemap(fdt, &used, &total);
83                 if (err < 0) {
84                         printf("libfdt: %s\n", fdt_strerror(err));
85                         return err;
86                 }
87                 if (used >= total) {
88                         printf("WARNING fdt_chosen: "
89                                 "no room in the reserved map (%d of %d)\n",
90                                 used, total);
91                         return -1;
92                 }
93                 /*
94                  * Look for an existing entry and update it.  If we don't find
95                  * the entry, we will j be the next available slot.
96                  */
97                 for (j = 0; j < used; j++) {
98                         err = fdt_get_reservemap(fdt, j, &re);
99                         if (re.address == initrd_start) {
100                                 break;
101                         }
102                 }
103                 err = fdt_replace_reservemap_entry(fdt, j,
104                         initrd_start, initrd_end - initrd_start + 1);
105                 if (err < 0) {
106                         printf("libfdt: %s\n", fdt_strerror(err));
107                         return err;
108                 }
109         }
110
111         /*
112          * Find the "chosen" node.
113          */
114         nodeoffset = fdt_find_node_by_path (fdt, "/chosen");
115
116         /*
117          * If we have a "chosen" node already the "force the writing"
118          * is not set, our job is done.
119          */
120         if ((nodeoffset >= 0) && !force)
121                 return 0;
122
123         /*
124          * No "chosen" node in the blob: create it.
125          */
126         if (nodeoffset < 0) {
127                 /*
128                  * Create a new node "/chosen" (offset 0 is root level)
129                  */
130                 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
131                 if (nodeoffset < 0) {
132                         printf("WARNING fdt_chosen: "
133                                 "could not create the /chosen node (%s).\n",
134                                 fdt_strerror(nodeoffset));
135                         return nodeoffset;
136                 }
137         }
138
139         /*
140          * Update pre-existing properties, create them if non-existant.
141          */
142         str = getenv("bootargs");
143         if (str != NULL) {
144                 err = fdt_setprop(fdt, nodeoffset,
145                         "bootargs", str, strlen(str)+1);
146                 if (err < 0)
147                         printf("WARNING fdt_chosen: "
148                                 "could not set bootargs (%s).\n",
149                                 fdt_strerror(err));
150         }
151         if (initrd_start && initrd_end) {
152                 tmp = __cpu_to_be32(initrd_start);
153                 err = fdt_setprop(fdt, nodeoffset,
154                          "linux,initrd-start", &tmp, sizeof(tmp));
155                 if (err < 0)
156                         printf("WARNING fdt_chosen: "
157                                 "could not set linux,initrd-start (%s).\n",
158                                 fdt_strerror(err));
159                 tmp = __cpu_to_be32(initrd_end);
160                 err = fdt_setprop(fdt, nodeoffset,
161                         "linux,initrd-end", &tmp, sizeof(tmp));
162                 if (err < 0)
163                         printf("WARNING fdt_chosen: "
164                                 "could not set linux,initrd-end (%s).\n",
165                                 fdt_strerror(err));
166         }
167 #ifdef OF_STDOUT_PATH
168         err = fdt_setprop(fdt, nodeoffset,
169                 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
170         if (err < 0)
171                 printf("WARNING fdt_chosen: "
172                         "could not set linux,stdout-path (%s).\n",
173                         fdt_strerror(err));
174 #endif
175
176         return err;
177 }
178
179 /********************************************************************/
180
181 #ifdef CONFIG_OF_HAS_UBOOT_ENV
182
183 /* Function that returns a character from the environment */
184 extern uchar(*env_get_char) (int);
185
186
187 int fdt_env(void *fdt)
188 {
189         int   nodeoffset;
190         int   err;
191         int   k, nxt;
192         int i;
193         static char tmpenv[256];
194
195         err = fdt_check_header(fdt);
196         if (err < 0) {
197                 printf("libfdt: %s\n", fdt_strerror(err));
198                 return err;
199         }
200
201         /*
202          * See if we already have a "u-boot-env" node, delete it if so.
203          * Then create a new empty node.
204          */
205         nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env");
206         if (nodeoffset >= 0) {
207                 err = fdt_del_node(fdt, nodeoffset);
208                 if (err < 0) {
209                         printf("libfdt: %s\n", fdt_strerror(err));
210                         return err;
211                 }
212         }
213         /*
214          * Create a new node "/u-boot-env" (offset 0 is root level)
215          */
216         nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
217         if (nodeoffset < 0) {
218                 printf("WARNING fdt_env: "
219                         "could not create the /u-boot-env node (%s).\n",
220                         fdt_strerror(nodeoffset));
221                 return nodeoffset;
222         }
223
224         for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
225                 char *s, *lval, *rval;
226
227                 /*
228                  * Find the end of the name=definition
229                  */
230                 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
231                         ;
232                 s = tmpenv;
233                 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
234                         *s++ = env_get_char(k);
235                 *s++ = '\0';
236                 lval = tmpenv;
237                 /*
238                  * Find the first '=': it separates the name from the value
239                  */
240                 s = strchr(tmpenv, '=');
241                 if (s != NULL) {
242                         *s++ = '\0';
243                         rval = s;
244                 } else
245                         continue;
246                 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
247                 if (err < 0) {
248                         printf("WARNING fdt_env: "
249                                 "could not set %s (%s).\n",
250                                 lval, fdt_strerror(err));
251                         return err;
252                 }
253         }
254         return 0;
255 }
256 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */
257
258 /********************************************************************/
259
260 #ifdef CONFIG_OF_HAS_BD_T
261
262 #define BDM(x)  {       .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
263
264 static const struct {
265         const char *name;
266         int offset;
267 } bd_map[] = {
268         BDM(memstart),
269         BDM(memsize),
270         BDM(flashstart),
271         BDM(flashsize),
272         BDM(flashoffset),
273         BDM(sramstart),
274         BDM(sramsize),
275 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
276         || defined(CONFIG_E500)
277         BDM(immr_base),
278 #endif
279 #if defined(CONFIG_MPC5xxx)
280         BDM(mbar_base),
281 #endif
282 #if defined(CONFIG_MPC83XX)
283         BDM(immrbar),
284 #endif
285 #if defined(CONFIG_MPC8220)
286         BDM(mbar_base),
287         BDM(inpfreq),
288         BDM(pcifreq),
289         BDM(pevfreq),
290         BDM(flbfreq),
291         BDM(vcofreq),
292 #endif
293         BDM(bootflags),
294         BDM(ip_addr),
295         BDM(intfreq),
296         BDM(busfreq),
297 #ifdef CONFIG_CPM2
298         BDM(cpmfreq),
299         BDM(brgfreq),
300         BDM(sccfreq),
301         BDM(vco),
302 #endif
303 #if defined(CONFIG_MPC5xxx)
304         BDM(ipbfreq),
305         BDM(pcifreq),
306 #endif
307         BDM(baudrate),
308 };
309
310
311 int fdt_bd_t(void *fdt)
312 {
313         bd_t *bd = gd->bd;
314         int   nodeoffset;
315         int   err;
316         u32   tmp;              /* used to set 32 bit integer properties */
317         int i;
318
319         err = fdt_check_header(fdt);
320         if (err < 0) {
321                 printf("libfdt: %s\n", fdt_strerror(err));
322                 return err;
323         }
324
325         /*
326          * See if we already have a "bd_t" node, delete it if so.
327          * Then create a new empty node.
328          */
329         nodeoffset = fdt_find_node_by_path (fdt, "/bd_t");
330         if (nodeoffset >= 0) {
331                 err = fdt_del_node(fdt, nodeoffset);
332                 if (err < 0) {
333                         printf("libfdt: %s\n", fdt_strerror(err));
334                         return err;
335                 }
336         }
337         /*
338          * Create a new node "/bd_t" (offset 0 is root level)
339          */
340         nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
341         if (nodeoffset < 0) {
342                 printf("WARNING fdt_bd_t: "
343                         "could not create the /bd_t node (%s).\n",
344                         fdt_strerror(nodeoffset));
345                 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
346                 return nodeoffset;
347         }
348         /*
349          * Use the string/pointer structure to create the entries...
350          */
351         for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
352                 tmp = cpu_to_be32(getenv("bootargs"));
353                 err = fdt_setprop(fdt, nodeoffset,
354                         bd_map[i].name, &tmp, sizeof(tmp));
355                 if (err < 0)
356                         printf("WARNING fdt_bd_t: "
357                                 "could not set %s (%s).\n",
358                                 bd_map[i].name, fdt_strerror(err));
359         }
360         /*
361          * Add a couple of oddball entries...
362          */
363         err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
364         if (err < 0)
365                 printf("WARNING fdt_bd_t: "
366                         "could not set enetaddr (%s).\n",
367                         fdt_strerror(err));
368         err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
369         if (err < 0)
370                 printf("WARNING fdt_bd_t: "
371                         "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 */