blob: ec04a639f352c789ef16cb1899ecb2d7c348321d [file] [log] [blame]
Gerald Van Baren64dbbd42007-04-06 14:19:43 -04001/*
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
Gerald Van Baren35ec3982007-05-25 22:08:57 -040035#ifdef CONFIG_OF_BOARD_SETUP
36void ft_board_setup(void *blob, bd_t *bd);
37#endif
38
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040039/*
40 * Global data (for the gd->bd)
41 */
42DECLARE_GLOBAL_DATA_PTR;
43
Gerald Van Barenbb930e72007-04-25 22:23:36 -040044/*
45 * fdt points to our working device tree.
46 */
47struct fdt_header *fdt;
48
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040049/********************************************************************/
50
51int 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;
Gerald Van Baren35ec3982007-05-25 22:08:57 -040056 u32 tmp; /* used to set 32 bit integer properties */
57 char *str; /* used to set string properties */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040058
59 err = fdt_check_header(fdt);
60 if (err < 0) {
61 printf("libfdt: %s\n", fdt_strerror(err));
62 return err;
63 }
64
Gerald Van Baren35ec3982007-05-25 22:08:57 -040065#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
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040076 if (initrd_start && initrd_end) {
Gerald Van Baren7651f8b2007-04-19 23:14:39 -040077 struct fdt_reserve_entry re;
Gerald Van Barenc28abb92007-04-14 22:51:24 -040078 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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -040088 printf("WARNING fdt_chosen: "
89 "no room in the reserved map (%d of %d)\n",
Gerald Van Barenc28abb92007-04-14 22:51:24 -040090 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);
Gerald Van Baren7651f8b2007-04-19 23:14:39 -040099 if (re.address == initrd_start) {
Gerald Van Barenc28abb92007-04-14 22:51:24 -0400100 break;
101 }
102 }
103 err = fdt_replace_reservemap_entry(fdt, j,
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400104 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 */
Gerald Van Baren1a861162007-06-06 22:47:58 -0400114 nodeoffset = fdt_find_node_by_path (fdt, "/chosen");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400115
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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400132 printf("WARNING fdt_chosen: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400133 "could not create the /chosen node (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400134 fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400135 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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400144 err = fdt_setprop(fdt, nodeoffset,
145 "bootargs", str, strlen(str)+1);
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400146 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400147 printf("WARNING fdt_chosen: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400148 "could not set bootargs (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400149 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400150 }
151 if (initrd_start && initrd_end) {
152 tmp = __cpu_to_be32(initrd_start);
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400153 err = fdt_setprop(fdt, nodeoffset,
154 "linux,initrd-start", &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400155 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400156 printf("WARNING fdt_chosen: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400157 "could not set linux,initrd-start (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400158 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400159 tmp = __cpu_to_be32(initrd_end);
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400160 err = fdt_setprop(fdt, nodeoffset,
161 "linux,initrd-end", &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400162 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400163 printf("WARNING fdt_chosen: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400164 "could not set linux,initrd-end (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400165 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400166 }
167#ifdef OF_STDOUT_PATH
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400168 err = fdt_setprop(fdt, nodeoffset,
169 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400170 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400171 printf("WARNING fdt_chosen: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400172 "could not set linux,stdout-path (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400173 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400174#endif
175
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400176 return err;
177}
178
179/********************************************************************/
180
181#ifdef CONFIG_OF_HAS_UBOOT_ENV
182
183/* Function that returns a character from the environment */
184extern uchar(*env_get_char) (int);
185
186
187int 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 */
Gerald Van Baren1a861162007-06-06 22:47:58 -0400205 nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400206 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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400218 printf("WARNING fdt_env: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400219 "could not create the /u-boot-env node (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400220 fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400221 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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400248 printf("WARNING fdt_env: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400249 "could not set %s (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400250 lval, fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400251 return err;
252 }
253 }
254 return 0;
255}
Gerald Van Barenc28abb92007-04-14 22:51:24 -0400256#endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400257
258/********************************************************************/
259
260#ifdef CONFIG_OF_HAS_BD_T
261
262#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
263
264static 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
311int fdt_bd_t(void *fdt)
312{
313 bd_t *bd = gd->bd;
314 int nodeoffset;
315 int err;
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400316 u32 tmp; /* used to set 32 bit integer properties */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400317 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 */
Gerald Van Baren1a861162007-06-06 22:47:58 -0400329 nodeoffset = fdt_find_node_by_path (fdt, "/bd_t");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400330 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) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400342 printf("WARNING fdt_bd_t: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400343 "could not create the /bd_t node (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400344 fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400345 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"));
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400353 err = fdt_setprop(fdt, nodeoffset,
354 bd_map[i].name, &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400355 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400356 printf("WARNING fdt_bd_t: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400357 "could not set %s (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400358 bd_map[i].name, fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400359 }
360 /*
361 * Add a couple of oddball entries...
362 */
363 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
364 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400365 printf("WARNING fdt_bd_t: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400366 "could not set enetaddr (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400367 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400368 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
369 if (err < 0)
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400370 printf("WARNING fdt_bd_t: "
Gerald Van Baren6f35ded2007-06-25 20:55:58 -0400371 "could not set ethspeed (%s).\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400372 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400373 return 0;
374}
Gerald Van Barenc28abb92007-04-14 22:51:24 -0400375#endif /* ifdef CONFIG_OF_HAS_BD_T */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400376
377#endif /* CONFIG_OF_LIBFDT */