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