blob: 175d59eb99432ccb36078a766043c0722eb9c2ec [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
35/*
36 * Global data (for the gd->bd)
37 */
38DECLARE_GLOBAL_DATA_PTR;
39
Gerald Van Barenbb930e72007-04-25 22:23:36 -040040/*
41 * fdt points to our working device tree.
42 */
43struct fdt_header *fdt;
44
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040045/********************************************************************/
46
47int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
48{
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040049 int nodeoffset;
50 int err;
Gerald Van Baren35ec3982007-05-25 22:08:57 -040051 u32 tmp; /* used to set 32 bit integer properties */
52 char *str; /* used to set string properties */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040053
54 err = fdt_check_header(fdt);
55 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -040056 printf("fdt_chosen: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040057 return err;
58 }
59
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040060 if (initrd_start && initrd_end) {
Gerald Van Baren7651f8b2007-04-19 23:14:39 -040061 struct fdt_reserve_entry re;
Gerald Van Barenc28abb92007-04-14 22:51:24 -040062 int used;
63 int total;
64 int j;
65
66 err = fdt_num_reservemap(fdt, &used, &total);
67 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -040068 printf("fdt_chosen: %s\n", fdt_strerror(err));
Gerald Van Barenc28abb92007-04-14 22:51:24 -040069 return err;
70 }
71 if (used >= total) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -040072 printf("WARNING: "
Gerald Van Baren35ec3982007-05-25 22:08:57 -040073 "no room in the reserved map (%d of %d)\n",
Gerald Van Barenc28abb92007-04-14 22:51:24 -040074 used, total);
75 return -1;
76 }
77 /*
78 * Look for an existing entry and update it. If we don't find
79 * the entry, we will j be the next available slot.
80 */
81 for (j = 0; j < used; j++) {
82 err = fdt_get_reservemap(fdt, j, &re);
Gerald Van Baren7651f8b2007-04-19 23:14:39 -040083 if (re.address == initrd_start) {
Gerald Van Barenc28abb92007-04-14 22:51:24 -040084 break;
85 }
86 }
87 err = fdt_replace_reservemap_entry(fdt, j,
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040088 initrd_start, initrd_end - initrd_start + 1);
89 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -040090 printf("fdt_chosen: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040091 return err;
92 }
93 }
94
95 /*
96 * Find the "chosen" node.
97 */
Gerald Van Baren1a861162007-06-06 22:47:58 -040098 nodeoffset = fdt_find_node_by_path (fdt, "/chosen");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -040099
100 /*
101 * If we have a "chosen" node already the "force the writing"
102 * is not set, our job is done.
103 */
104 if ((nodeoffset >= 0) && !force)
105 return 0;
106
107 /*
108 * No "chosen" node in the blob: create it.
109 */
110 if (nodeoffset < 0) {
111 /*
112 * Create a new node "/chosen" (offset 0 is root level)
113 */
114 nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
115 if (nodeoffset < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400116 printf("WARNING: could not create /chosen %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400117 fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400118 return nodeoffset;
119 }
120 }
121
122 /*
123 * Update pre-existing properties, create them if non-existant.
124 */
125 str = getenv("bootargs");
126 if (str != NULL) {
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400127 err = fdt_setprop(fdt, nodeoffset,
128 "bootargs", str, strlen(str)+1);
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400129 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400130 printf("WARNING: could not set bootargs %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400131 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400132 }
133 if (initrd_start && initrd_end) {
134 tmp = __cpu_to_be32(initrd_start);
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400135 err = fdt_setprop(fdt, nodeoffset,
136 "linux,initrd-start", &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400137 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400138 printf("WARNING: "
139 "could not set linux,initrd-start %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400140 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400141 tmp = __cpu_to_be32(initrd_end);
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400142 err = fdt_setprop(fdt, nodeoffset,
143 "linux,initrd-end", &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400144 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400145 printf("WARNING: could not set linux,initrd-end %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400146 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400147 }
148#ifdef OF_STDOUT_PATH
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400149 err = fdt_setprop(fdt, nodeoffset,
150 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400151 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400152 printf("WARNING: could not set linux,stdout-path %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400153 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400154#endif
155
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400156 return err;
157}
158
159/********************************************************************/
160
161#ifdef CONFIG_OF_HAS_UBOOT_ENV
162
163/* Function that returns a character from the environment */
164extern uchar(*env_get_char) (int);
165
166
167int fdt_env(void *fdt)
168{
169 int nodeoffset;
170 int err;
171 int k, nxt;
172 int i;
173 static char tmpenv[256];
174
175 err = fdt_check_header(fdt);
176 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400177 printf("fdt_env: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400178 return err;
179 }
180
181 /*
182 * See if we already have a "u-boot-env" node, delete it if so.
183 * Then create a new empty node.
184 */
Gerald Van Baren1a861162007-06-06 22:47:58 -0400185 nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400186 if (nodeoffset >= 0) {
187 err = fdt_del_node(fdt, nodeoffset);
188 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400189 printf("fdt_env: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400190 return err;
191 }
192 }
193 /*
194 * Create a new node "/u-boot-env" (offset 0 is root level)
195 */
196 nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
197 if (nodeoffset < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400198 printf("WARNING: could not create /u-boot-env %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400199 fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400200 return nodeoffset;
201 }
202
203 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
204 char *s, *lval, *rval;
205
206 /*
207 * Find the end of the name=definition
208 */
209 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
210 ;
211 s = tmpenv;
212 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
213 *s++ = env_get_char(k);
214 *s++ = '\0';
215 lval = tmpenv;
216 /*
217 * Find the first '=': it separates the name from the value
218 */
219 s = strchr(tmpenv, '=');
220 if (s != NULL) {
221 *s++ = '\0';
222 rval = s;
223 } else
224 continue;
225 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
226 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400227 printf("WARNING: could not set %s %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400228 lval, fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400229 return err;
230 }
231 }
232 return 0;
233}
Gerald Van Barenc28abb92007-04-14 22:51:24 -0400234#endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400235
236/********************************************************************/
237
238#ifdef CONFIG_OF_HAS_BD_T
239
240#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
241
242static const struct {
243 const char *name;
244 int offset;
245} bd_map[] = {
246 BDM(memstart),
247 BDM(memsize),
248 BDM(flashstart),
249 BDM(flashsize),
250 BDM(flashoffset),
251 BDM(sramstart),
252 BDM(sramsize),
253#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
254 || defined(CONFIG_E500)
255 BDM(immr_base),
256#endif
257#if defined(CONFIG_MPC5xxx)
258 BDM(mbar_base),
259#endif
260#if defined(CONFIG_MPC83XX)
261 BDM(immrbar),
262#endif
263#if defined(CONFIG_MPC8220)
264 BDM(mbar_base),
265 BDM(inpfreq),
266 BDM(pcifreq),
267 BDM(pevfreq),
268 BDM(flbfreq),
269 BDM(vcofreq),
270#endif
271 BDM(bootflags),
272 BDM(ip_addr),
273 BDM(intfreq),
274 BDM(busfreq),
275#ifdef CONFIG_CPM2
276 BDM(cpmfreq),
277 BDM(brgfreq),
278 BDM(sccfreq),
279 BDM(vco),
280#endif
281#if defined(CONFIG_MPC5xxx)
282 BDM(ipbfreq),
283 BDM(pcifreq),
284#endif
285 BDM(baudrate),
286};
287
288
289int fdt_bd_t(void *fdt)
290{
291 bd_t *bd = gd->bd;
292 int nodeoffset;
293 int err;
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400294 u32 tmp; /* used to set 32 bit integer properties */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400295 int i;
296
297 err = fdt_check_header(fdt);
298 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400299 printf("fdt_bd_t: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400300 return err;
301 }
302
303 /*
304 * See if we already have a "bd_t" node, delete it if so.
305 * Then create a new empty node.
306 */
Gerald Van Baren1a861162007-06-06 22:47:58 -0400307 nodeoffset = fdt_find_node_by_path (fdt, "/bd_t");
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400308 if (nodeoffset >= 0) {
309 err = fdt_del_node(fdt, nodeoffset);
310 if (err < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400311 printf("fdt_bd_t: %s\n", fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400312 return err;
313 }
314 }
315 /*
316 * Create a new node "/bd_t" (offset 0 is root level)
317 */
318 nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
319 if (nodeoffset < 0) {
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400320 printf("WARNING: could not create /bd_t %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400321 fdt_strerror(nodeoffset));
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400322 printf("fdt_bd_t: %s\n", fdt_strerror(nodeoffset));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400323 return nodeoffset;
324 }
325 /*
326 * Use the string/pointer structure to create the entries...
327 */
328 for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
329 tmp = cpu_to_be32(getenv("bootargs"));
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400330 err = fdt_setprop(fdt, nodeoffset,
331 bd_map[i].name, &tmp, sizeof(tmp));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400332 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400333 printf("WARNING: could not set %s %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400334 bd_map[i].name, fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400335 }
336 /*
337 * Add a couple of oddball entries...
338 */
339 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
340 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400341 printf("WARNING: could not set enetaddr %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400342 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400343 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
344 if (err < 0)
Gerald Van Baren5fe6be62007-08-07 21:14:22 -0400345 printf("WARNING: could not set ethspeed %s.\n",
Gerald Van Baren35ec3982007-05-25 22:08:57 -0400346 fdt_strerror(err));
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400347 return 0;
348}
Gerald Van Barenc28abb92007-04-14 22:51:24 -0400349#endif /* ifdef CONFIG_OF_HAS_BD_T */
Gerald Van Baren64dbbd42007-04-06 14:19:43 -0400350
351#endif /* CONFIG_OF_LIBFDT */