blob: c129993a912e5281e4298550056e6cfe16e8cdea [file] [log] [blame]
Gerald Van Barenade8ef42007-03-31 12:22:10 -04001/*
2 * (C) Copyright 2007
3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
4 * Based on code written by:
5 * Pantelis Antoniou <pantelis.antoniou@gmail.com> and
6 * Matthew McClintock <msm@freescale.com>
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27#include <common.h>
28#include <command.h>
29#include <linux/ctype.h>
30#include <linux/types.h>
Gerald Van Barenade8ef42007-03-31 12:22:10 -040031#include <asm/global_data.h>
32#include <fdt.h>
33#include <libfdt.h>
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -040034#include <fdt_support.h>
Gerald Van Barenade8ef42007-03-31 12:22:10 -040035
36#define MAX_LEVEL 32 /* how deeply nested we will go */
Gerald Van Baren5606a362007-06-25 23:25:28 -040037#define SCRATCHPAD 1024 /* bytes of scratchpad memory */
Gerald Van Barenade8ef42007-03-31 12:22:10 -040038
39/*
40 * Global data (for the gd->bd)
41 */
42DECLARE_GLOBAL_DATA_PTR;
43
Gerald Van Barenade8ef42007-03-31 12:22:10 -040044static int fdt_valid(void);
Andy Fleming46891472008-03-31 20:45:56 -050045static int fdt_parse_prop(char **newval, int count, char *data, int *len);
Kumar Gala1e386af2007-11-21 14:07:46 -060046static int fdt_print(const char *pathp, char *prop, int depth);
Gerald Van Barenade8ef42007-03-31 12:22:10 -040047
Gerald Van Barenade8ef42007-03-31 12:22:10 -040048/*
Gerald Van Barene81ce612008-06-10 22:15:58 -040049 * The working_fdt points to our working flattened device tree.
50 */
51struct fdt_header *working_fdt;
52
53/*
Gerald Van Barenade8ef42007-03-31 12:22:10 -040054 * Flattened Device Tree command, see the help for parameter definitions.
55 */
56int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
57{
Gerald Van Barenade8ef42007-03-31 12:22:10 -040058 if (argc < 2) {
59 printf ("Usage:\n%s\n", cmdtp->usage);
60 return 1;
61 }
62
Gerald Van Barenade8ef42007-03-31 12:22:10 -040063 /********************************************************************
64 * Set the address of the fdt
65 ********************************************************************/
Gerald Van Baren0ea55d22007-05-12 09:47:25 -040066 if (argv[1][0] == 'a') {
Gerald Van Barenade8ef42007-03-31 12:22:10 -040067 /*
68 * Set the address [and length] of the fdt.
69 */
Kumar Gala708a18b2008-08-15 08:24:35 -050070 if (argc == 2) {
71 if (!fdt_valid()) {
72 return 1;
73 }
74 printf("The address of the fdt is %p\n", working_fdt);
75 return 0;
76 }
77
Kim Phillipsf3a42e22008-06-10 11:06:17 -050078 working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
Gerald Van Barenade8ef42007-03-31 12:22:10 -040079
80 if (!fdt_valid()) {
81 return 1;
82 }
83
84 if (argc >= 4) {
85 int len;
86 int err;
87 /*
88 * Optional new length
89 */
Gerald Van Bareneb999ee2007-11-22 17:23:23 -050090 len = simple_strtoul(argv[3], NULL, 16);
Kim Phillipsf3a42e22008-06-10 11:06:17 -050091 if (len < fdt_totalsize(working_fdt)) {
Gerald Van Barene596a162007-05-16 22:39:59 -040092 printf ("New length %d < existing length %d, "
93 "ignoring.\n",
Kim Phillipsf3a42e22008-06-10 11:06:17 -050094 len, fdt_totalsize(working_fdt));
Gerald Van Barenade8ef42007-03-31 12:22:10 -040095 } else {
96 /*
97 * Open in place with a new length.
98 */
Kim Phillipsf3a42e22008-06-10 11:06:17 -050099 err = fdt_open_into(working_fdt, working_fdt, len);
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400100 if (err != 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400101 printf ("libfdt fdt_open_into(): %s\n",
102 fdt_strerror(err));
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400103 }
104 }
105 }
106
107 /********************************************************************
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500108 * Move the working_fdt
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400109 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400110 } else if (strncmp(argv[1], "mo", 2) == 0) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400111 struct fdt_header *newaddr;
112 int len;
113 int err;
114
Gerald Van Baren4d223922007-04-25 22:47:15 -0400115 if (argc < 4) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400116 printf ("Usage:\n%s\n", cmdtp->usage);
117 return 1;
118 }
119
120 /*
121 * Set the address and length of the fdt.
122 */
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500123 working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16);
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400124 if (!fdt_valid()) {
125 return 1;
126 }
127
Gerald Van Barene596a162007-05-16 22:39:59 -0400128 newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16);
Gerald Van Baren4d223922007-04-25 22:47:15 -0400129
130 /*
131 * If the user specifies a length, use that. Otherwise use the
132 * current length.
133 */
134 if (argc <= 4) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500135 len = fdt_totalsize(working_fdt);
Gerald Van Baren4d223922007-04-25 22:47:15 -0400136 } else {
137 len = simple_strtoul(argv[4], NULL, 16);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500138 if (len < fdt_totalsize(working_fdt)) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400139 printf ("New length 0x%X < existing length "
140 "0x%X, aborting.\n",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500141 len, fdt_totalsize(working_fdt));
Gerald Van Baren4d223922007-04-25 22:47:15 -0400142 return 1;
143 }
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400144 }
145
146 /*
147 * Copy to the new location.
148 */
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500149 err = fdt_open_into(working_fdt, newaddr, len);
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400150 if (err != 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400151 printf ("libfdt fdt_open_into(): %s\n",
152 fdt_strerror(err));
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400153 return 1;
154 }
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500155 working_fdt = newaddr;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400156
157 /********************************************************************
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400158 * Make a new node
159 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400160 } else if (strncmp(argv[1], "mk", 2) == 0) {
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400161 char *pathp; /* path */
162 char *nodep; /* new node to add */
163 int nodeoffset; /* node offset from libfdt */
164 int err;
165
166 /*
167 * Parameters: Node path, new node to be appended to the path.
168 */
169 if (argc < 4) {
170 printf ("Usage:\n%s\n", cmdtp->usage);
171 return 1;
172 }
173
174 pathp = argv[2];
175 nodep = argv[3];
176
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500177 nodeoffset = fdt_path_offset (working_fdt, pathp);
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400178 if (nodeoffset < 0) {
179 /*
180 * Not found or something else bad happened.
181 */
Kumar Galac8ab7052007-10-24 11:04:22 -0500182 printf ("libfdt fdt_path_offset() returned %s\n",
Gerald Van Baren1178d6a2007-05-21 23:27:16 -0400183 fdt_strerror(nodeoffset));
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400184 return 1;
185 }
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500186 err = fdt_add_subnode(working_fdt, nodeoffset, nodep);
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400187 if (err < 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400188 printf ("libfdt fdt_add_subnode(): %s\n",
189 fdt_strerror(err));
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400190 return 1;
191 }
192
193 /********************************************************************
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500194 * Set the value of a property in the working_fdt.
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400195 ********************************************************************/
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400196 } else if (argv[1][0] == 's') {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400197 char *pathp; /* path */
Gerald Van Barene596a162007-05-16 22:39:59 -0400198 char *prop; /* property */
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400199 int nodeoffset; /* node offset from libfdt */
Gerald Van Barene596a162007-05-16 22:39:59 -0400200 static char data[SCRATCHPAD]; /* storage for the property */
201 int len; /* new length of the property */
202 int ret; /* return value */
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400203
204 /*
Gerald Van Barend91383a2008-01-05 14:52:04 -0500205 * Parameters: Node path, property, optional value.
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400206 */
Gerald Van Barend91383a2008-01-05 14:52:04 -0500207 if (argc < 4) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400208 printf ("Usage:\n%s\n", cmdtp->usage);
209 return 1;
210 }
211
212 pathp = argv[2];
213 prop = argv[3];
Gerald Van Barend91383a2008-01-05 14:52:04 -0500214 if (argc == 4) {
215 len = 0;
216 } else {
Andy Fleming46891472008-03-31 20:45:56 -0500217 ret = fdt_parse_prop(&argv[4], argc - 4, data, &len);
Gerald Van Barend91383a2008-01-05 14:52:04 -0500218 if (ret != 0)
219 return ret;
220 }
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400221
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500222 nodeoffset = fdt_path_offset (working_fdt, pathp);
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400223 if (nodeoffset < 0) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400224 /*
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400225 * Not found or something else bad happened.
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400226 */
Kumar Galac8ab7052007-10-24 11:04:22 -0500227 printf ("libfdt fdt_path_offset() returned %s\n",
Gerald Van Baren1178d6a2007-05-21 23:27:16 -0400228 fdt_strerror(nodeoffset));
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400229 return 1;
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400230 }
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400231
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500232 ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len);
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400233 if (ret < 0) {
234 printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret));
235 return 1;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400236 }
237
238 /********************************************************************
239 * Print (recursive) / List (single level)
240 ********************************************************************/
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400241 } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400242 int depth = MAX_LEVEL; /* how deep to print */
243 char *pathp; /* path */
Gerald Van Barene596a162007-05-16 22:39:59 -0400244 char *prop; /* property */
245 int ret; /* return value */
Kumar Gala51ab7f92007-10-25 16:15:07 -0500246 static char root[2] = "/";
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400247
248 /*
249 * list is an alias for print, but limited to 1 level
250 */
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400251 if (argv[1][0] == 'l') {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400252 depth = 1;
253 }
254
255 /*
256 * Get the starting path. The root node is an oddball,
257 * the offset is zero and has no name.
258 */
Kumar Gala51ab7f92007-10-25 16:15:07 -0500259 if (argc == 2)
260 pathp = root;
261 else
262 pathp = argv[2];
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400263 if (argc > 3)
264 prop = argv[3];
265 else
266 prop = NULL;
267
Gerald Van Barene596a162007-05-16 22:39:59 -0400268 ret = fdt_print(pathp, prop, depth);
269 if (ret != 0)
270 return ret;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400271
272 /********************************************************************
273 * Remove a property/node
274 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400275 } else if (strncmp(argv[1], "rm", 2) == 0) {
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400276 int nodeoffset; /* node offset from libfdt */
277 int err;
278
279 /*
280 * Get the path. The root node is an oddball, the offset
281 * is zero and has no name.
282 */
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500283 nodeoffset = fdt_path_offset (working_fdt, argv[2]);
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400284 if (nodeoffset < 0) {
285 /*
286 * Not found or something else bad happened.
287 */
Kumar Galac8ab7052007-10-24 11:04:22 -0500288 printf ("libfdt fdt_path_offset() returned %s\n",
Gerald Van Baren1178d6a2007-05-21 23:27:16 -0400289 fdt_strerror(nodeoffset));
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400290 return 1;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400291 }
292 /*
293 * Do the delete. A fourth parameter means delete a property,
294 * otherwise delete the node.
295 */
296 if (argc > 3) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500297 err = fdt_delprop(working_fdt, nodeoffset, argv[3]);
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400298 if (err < 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400299 printf("libfdt fdt_delprop(): %s\n",
300 fdt_strerror(err));
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400301 return err;
302 }
303 } else {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500304 err = fdt_del_node(working_fdt, nodeoffset);
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400305 if (err < 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400306 printf("libfdt fdt_del_node(): %s\n",
307 fdt_strerror(err));
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400308 return err;
309 }
310 }
Kumar Galab79da7b2008-02-15 03:34:36 -0600311
312 /********************************************************************
313 * Display header info
314 ********************************************************************/
315 } else if (argv[1][0] == 'h') {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500316 u32 version = fdt_version(working_fdt);
317 printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt));
318 printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt),
319 fdt_totalsize(working_fdt));
320 printf("off_dt_struct:\t\t0x%x\n",
321 fdt_off_dt_struct(working_fdt));
322 printf("off_dt_strings:\t\t0x%x\n",
323 fdt_off_dt_strings(working_fdt));
324 printf("off_mem_rsvmap:\t\t0x%x\n",
325 fdt_off_mem_rsvmap(working_fdt));
Kumar Galab79da7b2008-02-15 03:34:36 -0600326 printf("version:\t\t%d\n", version);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500327 printf("last_comp_version:\t%d\n",
328 fdt_last_comp_version(working_fdt));
Kumar Galab79da7b2008-02-15 03:34:36 -0600329 if (version >= 2)
330 printf("boot_cpuid_phys:\t0x%x\n",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500331 fdt_boot_cpuid_phys(working_fdt));
Kumar Galab79da7b2008-02-15 03:34:36 -0600332 if (version >= 3)
333 printf("size_dt_strings:\t0x%x\n",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500334 fdt_size_dt_strings(working_fdt));
Kumar Galab79da7b2008-02-15 03:34:36 -0600335 if (version >= 17)
336 printf("size_dt_struct:\t\t0x%x\n",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500337 fdt_size_dt_struct(working_fdt));
338 printf("number mem_rsv:\t\t0x%x\n",
339 fdt_num_mem_rsv(working_fdt));
Kumar Galab79da7b2008-02-15 03:34:36 -0600340 printf("\n");
341
342 /********************************************************************
343 * Set boot cpu id
344 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400345 } else if (strncmp(argv[1], "boo", 3) == 0) {
Kumar Galab79da7b2008-02-15 03:34:36 -0600346 unsigned long tmp = simple_strtoul(argv[2], NULL, 16);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500347 fdt_set_boot_cpuid_phys(working_fdt, tmp);
Kumar Galab79da7b2008-02-15 03:34:36 -0600348
349 /********************************************************************
350 * memory command
351 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400352 } else if (strncmp(argv[1], "me", 2) == 0) {
Kumar Galab79da7b2008-02-15 03:34:36 -0600353 uint64_t addr, size;
354 int err;
355#ifdef CFG_64BIT_STRTOUL
356 addr = simple_strtoull(argv[2], NULL, 16);
357 size = simple_strtoull(argv[3], NULL, 16);
358#else
359 addr = simple_strtoul(argv[2], NULL, 16);
360 size = simple_strtoul(argv[3], NULL, 16);
361#endif
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500362 err = fdt_fixup_memory(working_fdt, addr, size);
Kumar Galab79da7b2008-02-15 03:34:36 -0600363 if (err < 0)
364 return err;
365
366 /********************************************************************
367 * mem reserve commands
368 ********************************************************************/
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400369 } else if (strncmp(argv[1], "rs", 2) == 0) {
Kumar Galab79da7b2008-02-15 03:34:36 -0600370 if (argv[2][0] == 'p') {
371 uint64_t addr, size;
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500372 int total = fdt_num_mem_rsv(working_fdt);
Kumar Galab79da7b2008-02-15 03:34:36 -0600373 int j, err;
374 printf("index\t\t start\t\t size\n");
375 printf("-------------------------------"
376 "-----------------\n");
377 for (j = 0; j < total; j++) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500378 err = fdt_get_mem_rsv(working_fdt, j, &addr, &size);
Kumar Galab79da7b2008-02-15 03:34:36 -0600379 if (err < 0) {
380 printf("libfdt fdt_get_mem_rsv(): %s\n",
381 fdt_strerror(err));
382 return err;
383 }
384 printf(" %x\t%08x%08x\t%08x%08x\n", j,
385 (u32)(addr >> 32),
386 (u32)(addr & 0xffffffff),
387 (u32)(size >> 32),
388 (u32)(size & 0xffffffff));
389 }
390 } else if (argv[2][0] == 'a') {
391 uint64_t addr, size;
392 int err;
393#ifdef CFG_64BIT_STRTOUL
394 addr = simple_strtoull(argv[3], NULL, 16);
395 size = simple_strtoull(argv[4], NULL, 16);
396#else
397 addr = simple_strtoul(argv[3], NULL, 16);
398 size = simple_strtoul(argv[4], NULL, 16);
399#endif
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500400 err = fdt_add_mem_rsv(working_fdt, addr, size);
Kumar Galab79da7b2008-02-15 03:34:36 -0600401
402 if (err < 0) {
403 printf("libfdt fdt_add_mem_rsv(): %s\n",
404 fdt_strerror(err));
405 return err;
406 }
407 } else if (argv[2][0] == 'd') {
408 unsigned long idx = simple_strtoul(argv[3], NULL, 16);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500409 int err = fdt_del_mem_rsv(working_fdt, idx);
Kumar Galab79da7b2008-02-15 03:34:36 -0600410
411 if (err < 0) {
412 printf("libfdt fdt_del_mem_rsv(): %s\n",
413 fdt_strerror(err));
414 return err;
415 }
416 } else {
417 /* Unrecognized command */
418 printf ("Usage:\n%s\n", cmdtp->usage);
419 return 1;
420 }
Kim Phillipsbd9d1152007-07-17 13:57:04 -0500421 }
Gerald Van Baren5606a362007-06-25 23:25:28 -0400422#ifdef CONFIG_OF_BOARD_SETUP
Kim Phillipsbd9d1152007-07-17 13:57:04 -0500423 /* Call the board-specific fixup routine */
Gerald Van Baren3b9d6292008-06-09 21:02:17 -0400424 else if (strncmp(argv[1], "boa", 3) == 0)
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500425 ft_board_setup(working_fdt, gd->bd);
Gerald Van Baren5606a362007-06-25 23:25:28 -0400426#endif
Kim Phillipsbd9d1152007-07-17 13:57:04 -0500427 /* Create a chosen node */
Kumar Galafb5dcd52008-08-15 08:24:34 -0500428 else if (argv[1][0] == 'c') {
429 unsigned long initrd_start = 0, initrd_end = 0;
430
431 if ((argc != 2) && (argc != 4)) {
432 printf ("Usage:\n%s\n", cmdtp->usage);
433 return 1;
434 }
435
436 if (argc == 4) {
437 initrd_start = simple_strtoul(argv[2], NULL, 16);
438 initrd_end = simple_strtoul(argv[3], NULL, 16);
439 }
440
441 fdt_chosen(working_fdt, initrd_start, initrd_end, 1);
442 } else {
Kim Phillipsbd9d1152007-07-17 13:57:04 -0500443 /* Unrecognized command */
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400444 printf ("Usage:\n%s\n", cmdtp->usage);
445 return 1;
446 }
447
448 return 0;
449}
450
Gerald Van Barene596a162007-05-16 22:39:59 -0400451/****************************************************************************/
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400452
453static int fdt_valid(void)
454{
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400455 int err;
456
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500457 if (working_fdt == NULL) {
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400458 printf ("The address of the fdt is invalid (NULL).\n");
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400459 return 0;
460 }
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400461
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500462 err = fdt_check_header(working_fdt);
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400463 if (err == 0)
464 return 1; /* valid */
465
466 if (err < 0) {
Gerald Van Baren0ea55d22007-05-12 09:47:25 -0400467 printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400468 /*
469 * Be more informative on bad version.
470 */
471 if (err == -FDT_ERR_BADVERSION) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500472 if (fdt_version(working_fdt) <
473 FDT_FIRST_SUPPORTED_VERSION) {
Andrew Klossnere4ad4542008-07-07 06:41:14 -0700474 printf (" - too old, fdt %d < %d",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500475 fdt_version(working_fdt),
Gerald Van Barene596a162007-05-16 22:39:59 -0400476 FDT_FIRST_SUPPORTED_VERSION);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500477 working_fdt = NULL;
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400478 }
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500479 if (fdt_last_comp_version(working_fdt) >
480 FDT_LAST_SUPPORTED_VERSION) {
Andrew Klossnere4ad4542008-07-07 06:41:14 -0700481 printf (" - too new, fdt %d > %d",
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500482 fdt_version(working_fdt),
Gerald Van Barene596a162007-05-16 22:39:59 -0400483 FDT_LAST_SUPPORTED_VERSION);
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500484 working_fdt = NULL;
Gerald Van Barenc4a57ea2007-04-06 14:19:43 -0400485 }
486 return 0;
487 }
488 printf("\n");
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400489 return 0;
490 }
491 return 1;
492}
493
Gerald Van Barene596a162007-05-16 22:39:59 -0400494/****************************************************************************/
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400495
496/*
Gerald Van Barene596a162007-05-16 22:39:59 -0400497 * Parse the user's input, partially heuristic. Valid formats:
Andy Fleming46891472008-03-31 20:45:56 -0500498 * <0x00112233 4 05> - an array of cells. Numbers follow standard
Wolfgang Denka1be4762008-05-20 16:00:29 +0200499 * C conventions.
Gerald Van Barene596a162007-05-16 22:39:59 -0400500 * [00 11 22 .. nn] - byte stream
501 * "string" - If the the value doesn't start with "<" or "[", it is
502 * treated as a string. Note that the quotes are
503 * stripped by the parser before we get the string.
Andy Fleming46891472008-03-31 20:45:56 -0500504 * newval: An array of strings containing the new property as specified
Wolfgang Denka1be4762008-05-20 16:00:29 +0200505 * on the command line
Andy Fleming46891472008-03-31 20:45:56 -0500506 * count: The number of strings in the array
507 * data: A bytestream to be placed in the property
508 * len: The length of the resulting bytestream
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400509 */
Andy Fleming46891472008-03-31 20:45:56 -0500510static int fdt_parse_prop(char **newval, int count, char *data, int *len)
Gerald Van Barene596a162007-05-16 22:39:59 -0400511{
512 char *cp; /* temporary char pointer */
Andy Fleming46891472008-03-31 20:45:56 -0500513 char *newp; /* temporary newval char pointer */
Gerald Van Barene596a162007-05-16 22:39:59 -0400514 unsigned long tmp; /* holds converted values */
Andy Fleming46891472008-03-31 20:45:56 -0500515 int stridx = 0;
Gerald Van Barene596a162007-05-16 22:39:59 -0400516
Andy Fleming46891472008-03-31 20:45:56 -0500517 *len = 0;
518 newp = newval[0];
519
520 /* An array of cells */
521 if (*newp == '<') {
522 newp++;
523 while ((*newp != '>') && (stridx < count)) {
524 /*
525 * Keep searching until we find that last ">"
526 * That way users don't have to escape the spaces
527 */
528 if (*newp == '\0') {
529 newp = newval[++stridx];
530 continue;
531 }
532
533 cp = newp;
534 tmp = simple_strtoul(cp, &newp, 0);
535 *(uint32_t *)data = __cpu_to_be32(tmp);
536 data += 4;
537 *len += 4;
538
539 /* If the ptr didn't advance, something went wrong */
540 if ((newp - cp) <= 0) {
Gerald Van Barene596a162007-05-16 22:39:59 -0400541 printf("Sorry, I could not convert \"%s\"\n",
542 cp);
543 return 1;
544 }
Andy Fleming46891472008-03-31 20:45:56 -0500545
546 while (*newp == ' ')
547 newp++;
Gerald Van Barene596a162007-05-16 22:39:59 -0400548 }
Andy Fleming46891472008-03-31 20:45:56 -0500549
550 if (*newp != '>') {
551 printf("Unexpected character '%c'\n", *newp);
Gerald Van Barene596a162007-05-16 22:39:59 -0400552 return 1;
553 }
Andy Fleming46891472008-03-31 20:45:56 -0500554 } else if (*newp == '[') {
Gerald Van Barene596a162007-05-16 22:39:59 -0400555 /*
556 * Byte stream. Convert the values.
557 */
Andy Fleming46891472008-03-31 20:45:56 -0500558 newp++;
559 while ((*newp != ']') && (stridx < count)) {
560 tmp = simple_strtoul(newp, &newp, 16);
Gerald Van Barene596a162007-05-16 22:39:59 -0400561 *data++ = tmp & 0xFF;
Gerald Van Baren5606a362007-06-25 23:25:28 -0400562 *len = *len + 1;
Andy Fleming46891472008-03-31 20:45:56 -0500563 while (*newp == ' ')
564 newp++;
565 if (*newp != '\0')
566 newp = newval[++stridx];
Gerald Van Barene596a162007-05-16 22:39:59 -0400567 }
Andy Fleming46891472008-03-31 20:45:56 -0500568 if (*newp != ']') {
Andrew Klossnere4ad4542008-07-07 06:41:14 -0700569 printf("Unexpected character '%c'\n", *newp);
Gerald Van Barene596a162007-05-16 22:39:59 -0400570 return 1;
571 }
572 } else {
573 /*
574 * Assume it is a string. Copy it into our data area for
575 * convenience (including the terminating '\0').
576 */
Andy Fleming46891472008-03-31 20:45:56 -0500577 while (stridx < count) {
578 *len = strlen(newp) + 1;
579 strcpy(data, newp);
580 newp = newval[++stridx];
581 }
Gerald Van Barene596a162007-05-16 22:39:59 -0400582 }
583 return 0;
584}
585
586/****************************************************************************/
587
588/*
589 * Heuristic to guess if this is a string or concatenated strings.
590 */
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400591
592static int is_printable_string(const void *data, int len)
593{
594 const char *s = data;
595
596 /* zero length is not */
597 if (len == 0)
598 return 0;
599
600 /* must terminate with zero */
601 if (s[len - 1] != '\0')
602 return 0;
603
604 /* printable or a null byte (concatenated strings) */
605 while (((*s == '\0') || isprint(*s)) && (len > 0)) {
606 /*
607 * If we see a null, there are three possibilities:
608 * 1) If len == 1, it is the end of the string, printable
609 * 2) Next character also a null, not printable.
610 * 3) Next character not a null, continue to check.
611 */
612 if (s[0] == '\0') {
613 if (len == 1)
614 return 1;
615 if (s[1] == '\0')
616 return 0;
617 }
618 s++;
619 len--;
620 }
621
622 /* Not the null termination, or not done yet: not printable */
623 if (*s != '\0' || (len != 0))
624 return 0;
625
626 return 1;
627}
628
Gerald Van Barene596a162007-05-16 22:39:59 -0400629
630/*
631 * Print the property in the best format, a heuristic guess. Print as
632 * a string, concatenated strings, a byte, word, double word, or (if all
633 * else fails) it is printed as a stream of bytes.
634 */
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400635static void print_data(const void *data, int len)
636{
637 int j;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400638
639 /* no data, don't print */
640 if (len == 0)
641 return;
642
643 /*
644 * It is a string, but it may have multiple strings (embedded '\0's).
645 */
646 if (is_printable_string(data, len)) {
647 puts("\"");
648 j = 0;
649 while (j < len) {
650 if (j > 0)
651 puts("\", \"");
652 puts(data);
653 j += strlen(data) + 1;
654 data += strlen(data) + 1;
655 }
656 puts("\"");
657 return;
658 }
659
Andy Fleming46891472008-03-31 20:45:56 -0500660 if ((len %4) == 0) {
661 const u32 *p;
662
663 printf("<");
664 for (j = 0, p = data; j < len/4; j ++)
665 printf("0x%x%s", p[j], j < (len/4 - 1) ? " " : "");
666 printf(">");
667 } else { /* anything else... hexdump */
668 const u8 *s;
669
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400670 printf("[");
671 for (j = 0, s = data; j < len; j++)
672 printf("%02x%s", s[j], j < len - 1 ? " " : "");
673 printf("]");
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400674 }
Gerald Van Barene596a162007-05-16 22:39:59 -0400675}
676
677/****************************************************************************/
678
679/*
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500680 * Recursively print (a portion of) the working_fdt. The depth parameter
Gerald Van Barene596a162007-05-16 22:39:59 -0400681 * determines how deeply nested the fdt is printed.
682 */
Kumar Gala1e386af2007-11-21 14:07:46 -0600683static int fdt_print(const char *pathp, char *prop, int depth)
Gerald Van Barene596a162007-05-16 22:39:59 -0400684{
Gerald Van Barene596a162007-05-16 22:39:59 -0400685 static char tabs[MAX_LEVEL+1] =
686 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
687 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
Kumar Gala1e386af2007-11-21 14:07:46 -0600688 const void *nodep; /* property node pointer */
Gerald Van Barene596a162007-05-16 22:39:59 -0400689 int nodeoffset; /* node offset from libfdt */
690 int nextoffset; /* next node offset from libfdt */
691 uint32_t tag; /* tag */
692 int len; /* length of the property */
693 int level = 0; /* keep track of nesting level */
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500694 const struct fdt_property *fdt_prop;
Gerald Van Barene596a162007-05-16 22:39:59 -0400695
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500696 nodeoffset = fdt_path_offset (working_fdt, pathp);
Gerald Van Barene596a162007-05-16 22:39:59 -0400697 if (nodeoffset < 0) {
698 /*
699 * Not found or something else bad happened.
700 */
Kumar Galac8ab7052007-10-24 11:04:22 -0500701 printf ("libfdt fdt_path_offset() returned %s\n",
Gerald Van Baren1178d6a2007-05-21 23:27:16 -0400702 fdt_strerror(nodeoffset));
Gerald Van Barene596a162007-05-16 22:39:59 -0400703 return 1;
704 }
705 /*
706 * The user passed in a property as well as node path.
707 * Print only the given property and then return.
708 */
709 if (prop) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500710 nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len);
Gerald Van Barene596a162007-05-16 22:39:59 -0400711 if (len == 0) {
712 /* no property value */
713 printf("%s %s\n", pathp, prop);
714 return 0;
715 } else if (len > 0) {
Gerald Van Barenfc1a1092007-11-23 19:43:20 -0500716 printf("%s = ", prop);
Gerald Van Barene596a162007-05-16 22:39:59 -0400717 print_data (nodep, len);
718 printf("\n");
719 return 0;
720 } else {
721 printf ("libfdt fdt_getprop(): %s\n",
722 fdt_strerror(len));
723 return 1;
724 }
725 }
726
727 /*
728 * The user passed in a node path and no property,
729 * print the node and all subnodes.
730 */
Gerald Van Barene596a162007-05-16 22:39:59 -0400731 while(level >= 0) {
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500732 tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset);
Gerald Van Barene596a162007-05-16 22:39:59 -0400733 switch(tag) {
734 case FDT_BEGIN_NODE:
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500735 pathp = fdt_get_name(working_fdt, nodeoffset, NULL);
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500736 if (level <= depth) {
737 if (pathp == NULL)
738 pathp = "/* NULL pointer error */";
739 if (*pathp == '\0')
740 pathp = "/"; /* root is nameless */
Gerald Van Barene596a162007-05-16 22:39:59 -0400741 printf("%s%s {\n",
742 &tabs[MAX_LEVEL - level], pathp);
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500743 }
Gerald Van Barene596a162007-05-16 22:39:59 -0400744 level++;
Gerald Van Barene596a162007-05-16 22:39:59 -0400745 if (level >= MAX_LEVEL) {
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500746 printf("Nested too deep, aborting.\n");
Gerald Van Barene596a162007-05-16 22:39:59 -0400747 return 1;
748 }
749 break;
750 case FDT_END_NODE:
751 level--;
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500752 if (level <= depth)
Gerald Van Barene596a162007-05-16 22:39:59 -0400753 printf("%s};\n", &tabs[MAX_LEVEL - level]);
754 if (level == 0) {
755 level = -1; /* exit the loop */
756 }
757 break;
758 case FDT_PROP:
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500759 fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset,
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500760 sizeof(*fdt_prop));
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500761 pathp = fdt_string(working_fdt,
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500762 fdt32_to_cpu(fdt_prop->nameoff));
763 len = fdt32_to_cpu(fdt_prop->len);
764 nodep = fdt_prop->data;
Gerald Van Barene596a162007-05-16 22:39:59 -0400765 if (len < 0) {
766 printf ("libfdt fdt_getprop(): %s\n",
767 fdt_strerror(len));
768 return 1;
769 } else if (len == 0) {
770 /* the property has no value */
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500771 if (level <= depth)
Gerald Van Barene596a162007-05-16 22:39:59 -0400772 printf("%s%s;\n",
773 &tabs[MAX_LEVEL - level],
774 pathp);
775 } else {
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500776 if (level <= depth) {
Gerald Van Barenfc1a1092007-11-23 19:43:20 -0500777 printf("%s%s = ",
Gerald Van Barene596a162007-05-16 22:39:59 -0400778 &tabs[MAX_LEVEL - level],
779 pathp);
780 print_data (nodep, len);
781 printf(";\n");
782 }
783 }
784 break;
785 case FDT_NOP:
Andrew Klossnere4ad4542008-07-07 06:41:14 -0700786 printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]);
Gerald Van Barene596a162007-05-16 22:39:59 -0400787 break;
788 case FDT_END:
789 return 1;
790 default:
Gerald Van Bareneb999ee2007-11-22 17:23:23 -0500791 if (level <= depth)
Gerald Van Barene596a162007-05-16 22:39:59 -0400792 printf("Unknown tag 0x%08X\n", tag);
793 return 1;
794 }
795 nodeoffset = nextoffset;
796 }
797 return 0;
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400798}
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400799
800/********************************************************************/
801
802U_BOOT_CMD(
Andy Fleming46891472008-03-31 20:45:56 -0500803 fdt, 255, 0, do_fdt,
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400804 "fdt - flattened device tree utility commands\n",
805 "addr <addr> [<length>] - Set the fdt location to <addr>\n"
Gerald Van Baren5606a362007-06-25 23:25:28 -0400806#ifdef CONFIG_OF_BOARD_SETUP
807 "fdt boardsetup - Do board-specific set up\n"
808#endif
Gerald Van Baren7655c092008-01-05 15:33:29 -0500809 "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n"
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400810 "fdt print <path> [<prop>] - Recursive print starting at <path>\n"
811 "fdt list <path> [<prop>] - Print one level starting at <path>\n"
812 "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n"
813 "fdt mknode <path> <node> - Create a new node after <path>\n"
814 "fdt rm <path> [<prop>] - Delete the node or <property>\n"
Kumar Galab79da7b2008-02-15 03:34:36 -0600815 "fdt header - Display header info\n"
816 "fdt bootcpu <id> - Set boot cpuid\n"
817 "fdt memory <addr> <size> - Add/Update memory node\n"
818 "fdt rsvmem print - Show current mem reserves\n"
819 "fdt rsvmem add <addr> <size> - Add a mem reserve\n"
820 "fdt rsvmem delete <index> - Delete a mem reserves\n"
Kumar Galafb5dcd52008-08-15 08:24:34 -0500821 "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n"
822 " <start>/<end> - initrd start/end addr\n"
Gerald Van Baren7655c092008-01-05 15:33:29 -0500823 "NOTE: If the path or property you are setting/printing has a '#' character\n"
824 " or spaces, you MUST escape it with a \\ character or quote it with \".\n"
Gerald Van Barenade8ef42007-03-31 12:22:10 -0400825);