]> git.sur5r.net Git - u-boot/blob - common/fdt_support.c
d12c7516f018bb07d174954dd43c083a60489e95
[u-boot] / 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\" "
134                                 "(libfdt error %s).\n",
135                                 fdt_strerror(nodeoffset));
136                         return nodeoffset;
137                 }
138         }
139
140         /*
141          * Update pre-existing properties, create them if non-existant.
142          */
143         str = getenv("bootargs");
144         if (str != NULL) {
145                 err = fdt_setprop(fdt, nodeoffset,
146                         "bootargs", str, strlen(str)+1);
147                 if (err < 0)
148                         printf("WARNING fdt_chosen: "
149                                 "could not set \"bootargs\" "
150                                 "(libfdt error %s).\n",
151                                 fdt_strerror(err));
152         }
153         if (initrd_start && initrd_end) {
154                 tmp = __cpu_to_be32(initrd_start);
155                 err = fdt_setprop(fdt, nodeoffset,
156                          "linux,initrd-start", &tmp, sizeof(tmp));
157                 if (err < 0)
158                         printf("WARNING fdt_chosen: "
159                                 "could not set \"linux,initrd-start\" "
160                                 "(libfdt error %s).\n",
161                                 fdt_strerror(err));
162                 tmp = __cpu_to_be32(initrd_end);
163                 err = fdt_setprop(fdt, nodeoffset,
164                         "linux,initrd-end", &tmp, sizeof(tmp));
165                 if (err < 0)
166                         printf("WARNING fdt_chosen: "
167                                 "could not set \"linux,initrd-end\" "
168                                 "(libfdt error %s).\n",
169                                 fdt_strerror(err));
170         }
171 #ifdef OF_STDOUT_PATH
172         err = fdt_setprop(fdt, nodeoffset,
173                 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
174         if (err < 0)
175                 printf("WARNING fdt_chosen: "
176                         "could not set \"linux,stdout-path\" "
177                         "(libfdt error %s).\n",
178                         fdt_strerror(err));
179 #endif
180
181         return err;
182 }
183
184 /********************************************************************/
185
186 #ifdef CONFIG_OF_HAS_UBOOT_ENV
187
188 /* Function that returns a character from the environment */
189 extern uchar(*env_get_char) (int);
190
191
192 int fdt_env(void *fdt)
193 {
194         int   nodeoffset;
195         int   err;
196         int   k, nxt;
197         int i;
198         static char tmpenv[256];
199
200         err = fdt_check_header(fdt);
201         if (err < 0) {
202                 printf("libfdt: %s\n", fdt_strerror(err));
203                 return err;
204         }
205
206         /*
207          * See if we already have a "u-boot-env" node, delete it if so.
208          * Then create a new empty node.
209          */
210         nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env");
211         if (nodeoffset >= 0) {
212                 err = fdt_del_node(fdt, nodeoffset);
213                 if (err < 0) {
214                         printf("libfdt: %s\n", fdt_strerror(err));
215                         return err;
216                 }
217         }
218         /*
219          * Create a new node "/u-boot-env" (offset 0 is root level)
220          */
221         nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
222         if (nodeoffset < 0) {
223                 printf("WARNING fdt_env: "
224                         "could not create the \"/u-boot-env node\" "
225                         "(libfdt error %s).\n",
226                         fdt_strerror(nodeoffset));
227                 return nodeoffset;
228         }
229
230         for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
231                 char *s, *lval, *rval;
232
233                 /*
234                  * Find the end of the name=definition
235                  */
236                 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
237                         ;
238                 s = tmpenv;
239                 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
240                         *s++ = env_get_char(k);
241                 *s++ = '\0';
242                 lval = tmpenv;
243                 /*
244                  * Find the first '=': it separates the name from the value
245                  */
246                 s = strchr(tmpenv, '=');
247                 if (s != NULL) {
248                         *s++ = '\0';
249                         rval = s;
250                 } else
251                         continue;
252                 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
253                 if (err < 0) {
254                         printf("WARNING fdt_env: "
255                                 "could not set \"%s\" "
256                                 "(libfdt error %s).\n",
257                                 lval, fdt_strerror(err));
258                         return err;
259                 }
260         }
261         return 0;
262 }
263 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */
264
265 /********************************************************************/
266
267 #ifdef CONFIG_OF_HAS_BD_T
268
269 #define BDM(x)  {       .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
270
271 static const struct {
272         const char *name;
273         int offset;
274 } bd_map[] = {
275         BDM(memstart),
276         BDM(memsize),
277         BDM(flashstart),
278         BDM(flashsize),
279         BDM(flashoffset),
280         BDM(sramstart),
281         BDM(sramsize),
282 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
283         || defined(CONFIG_E500)
284         BDM(immr_base),
285 #endif
286 #if defined(CONFIG_MPC5xxx)
287         BDM(mbar_base),
288 #endif
289 #if defined(CONFIG_MPC83XX)
290         BDM(immrbar),
291 #endif
292 #if defined(CONFIG_MPC8220)
293         BDM(mbar_base),
294         BDM(inpfreq),
295         BDM(pcifreq),
296         BDM(pevfreq),
297         BDM(flbfreq),
298         BDM(vcofreq),
299 #endif
300         BDM(bootflags),
301         BDM(ip_addr),
302         BDM(intfreq),
303         BDM(busfreq),
304 #ifdef CONFIG_CPM2
305         BDM(cpmfreq),
306         BDM(brgfreq),
307         BDM(sccfreq),
308         BDM(vco),
309 #endif
310 #if defined(CONFIG_MPC5xxx)
311         BDM(ipbfreq),
312         BDM(pcifreq),
313 #endif
314         BDM(baudrate),
315 };
316
317
318 int fdt_bd_t(void *fdt)
319 {
320         bd_t *bd = gd->bd;
321         int   nodeoffset;
322         int   err;
323         u32   tmp;              /* used to set 32 bit integer properties */
324         int i;
325
326         err = fdt_check_header(fdt);
327         if (err < 0) {
328                 printf("libfdt: %s\n", fdt_strerror(err));
329                 return err;
330         }
331
332         /*
333          * See if we already have a "bd_t" node, delete it if so.
334          * Then create a new empty node.
335          */
336         nodeoffset = fdt_find_node_by_path (fdt, "/bd_t");
337         if (nodeoffset >= 0) {
338                 err = fdt_del_node(fdt, nodeoffset);
339                 if (err < 0) {
340                         printf("libfdt: %s\n", fdt_strerror(err));
341                         return err;
342                 }
343         }
344         /*
345          * Create a new node "/bd_t" (offset 0 is root level)
346          */
347         nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
348         if (nodeoffset < 0) {
349                 printf("WARNING fdt_bd_t: "
350                         "could not create the \"/bd_t node\" "
351                         "(libfdt error %s).\n",
352                         fdt_strerror(nodeoffset));
353                 printf("libfdt: %s\n", fdt_strerror(nodeoffset));
354                 return nodeoffset;
355         }
356         /*
357          * Use the string/pointer structure to create the entries...
358          */
359         for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
360                 tmp = cpu_to_be32(getenv("bootargs"));
361                 err = fdt_setprop(fdt, nodeoffset,
362                         bd_map[i].name, &tmp, sizeof(tmp));
363                 if (err < 0)
364                         printf("WARNING fdt_bd_t: "
365                                 "could not set \"%s\" "
366                                 "(libfdt error %s).\n",
367                                 bd_map[i].name, fdt_strerror(err));
368         }
369         /*
370          * Add a couple of oddball entries...
371          */
372         err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
373         if (err < 0)
374                 printf("WARNING fdt_bd_t: "
375                         "could not set \"enetaddr\" "
376                         "(libfdt error %s).\n",
377                         fdt_strerror(err));
378         err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
379         if (err < 0)
380                 printf("WARNING fdt_bd_t: "
381                         "could not set \"ethspeed\" "
382                         "(libfdt error %s).\n",
383                         fdt_strerror(err));
384         return 0;
385 }
386 #endif /* ifdef CONFIG_OF_HAS_BD_T */
387
388 #endif /* CONFIG_OF_LIBFDT */