blob: 10a0b12141e24fea1ddb9162a0872c558107d115 [file] [log] [blame]
Marian Balakowicz2437cf22008-01-08 18:11:43 +01001/*
2 * (C) Copyright 2008 Semihalf
3 *
4 * (C) Copyright 2000-2006
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6 *
7 * See file CREDITS for list of people who contributed to this
8 * project.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 */
25
Marian Balakowiczf92332b2008-01-31 13:20:06 +010026
Marian Balakowicz2437cf22008-01-08 18:11:43 +010027#include <common.h>
28#include <watchdog.h>
29#include <command.h>
30#include <image.h>
31#include <malloc.h>
32#include <zlib.h>
33#include <bzlib.h>
34#include <environment.h>
35#include <asm/byteorder.h>
36
37#if defined(CONFIG_OF_LIBFDT)
38#include <fdt.h>
39#include <libfdt.h>
40#include <fdt_support.h>
Marian Balakowicz28fb6152008-01-31 13:20:08 +010041
42static void fdt_error (const char *msg);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +010043static int boot_get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
Marian Balakowicz6881dae2008-02-04 08:28:17 +010044 bootm_headers_t *images, char **of_flat_tree, ulong *of_size);
Marian Balakowiczd7c88a42008-02-29 14:58:34 +010045static int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
Marian Balakowicz6881dae2008-02-04 08:28:17 +010046 cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
47 char **of_flat_tree, ulong *of_size);
Marian Balakowicz2437cf22008-01-08 18:11:43 +010048#endif
49
Marian Balakowicz2437cf22008-01-08 18:11:43 +010050#ifdef CFG_INIT_RAM_LOCK
51#include <asm/cache.h>
52#endif
53
Marian Balakowicz2437cf22008-01-08 18:11:43 +010054DECLARE_GLOBAL_DATA_PTR;
Marian Balakowicz2437cf22008-01-08 18:11:43 +010055
Marian Balakowicz2437cf22008-01-08 18:11:43 +010056extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
Kumar Galab937bb72008-02-27 21:51:49 -060057extern ulong get_effective_memsize(void);
Marian Balakowicz9c701e82008-01-31 13:57:17 +010058static ulong get_sp (void);
Marian Balakowicz2efc2642008-01-31 13:58:13 +010059static void set_clocks_in_mhz (bd_t *kbd);
Marian Balakowicz2437cf22008-01-08 18:11:43 +010060
Kumar Galac5bacfd2008-02-27 21:51:50 -060061#ifndef CFG_LINUX_LOWMEM_MAX_SIZE
62#define CFG_LINUX_LOWMEM_MAX_SIZE (768*1024*1024)
63#endif
64
Marian Balakowicz2437cf22008-01-08 18:11:43 +010065void __attribute__((noinline))
Marian Balakowicz61fde552008-02-27 11:01:04 +010066do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
67 bootm_headers_t *images)
Marian Balakowicz2437cf22008-01-08 18:11:43 +010068{
Kumar Galab937bb72008-02-27 21:51:49 -060069 ulong sp;
Marian Balakowicz2efc2642008-01-31 13:58:13 +010070
Marian Balakowiczb4a12a92008-01-08 18:12:17 +010071 ulong initrd_start, initrd_end;
Marian Balakowicz95418502008-01-31 13:55:39 +010072 ulong rd_data_start, rd_data_end, rd_len;
Kumar Galac5bacfd2008-02-27 21:51:50 -060073 ulong size;
Becky Bruced26d67c2008-06-09 20:37:18 -050074 phys_size_t bootm_size;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +010075
Kumar Galab937bb72008-02-27 21:51:49 -060076 ulong cmd_start, cmd_end, bootmap_base;
Marian Balakowicz2437cf22008-01-08 18:11:43 +010077 bd_t *kbd;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +010078 ulong ep = 0;
Marian Balakowicz2437cf22008-01-08 18:11:43 +010079 void (*kernel)(bd_t *, ulong, ulong, ulong, ulong);
Kumar Gala56bdf1d2008-02-27 21:51:45 -060080 int ret;
Kumar Galaa56d7d52008-02-27 21:51:44 -060081 ulong of_size = 0;
Kumar Galab937bb72008-02-27 21:51:49 -060082 struct lmb *lmb = images->lmb;
Marian Balakowiczb4a12a92008-01-08 18:12:17 +010083
Marian Balakowiczd2160852008-01-31 13:20:07 +010084#if defined(CONFIG_OF_LIBFDT)
Marian Balakowicz6881dae2008-02-04 08:28:17 +010085 char *of_flat_tree = NULL;
Marian Balakowicz2437cf22008-01-08 18:11:43 +010086#endif
87
Kumar Galac5bacfd2008-02-27 21:51:50 -060088 bootmap_base = getenv_bootm_low();
Becky Bruced26d67c2008-06-09 20:37:18 -050089 bootm_size = getenv_bootm_size();
Kumar Galac5bacfd2008-02-27 21:51:50 -060090
91#ifdef DEBUG
Becky Bruced26d67c2008-06-09 20:37:18 -050092 if (((u64)bootmap_base + bootm_size) >
93 (CFG_SDRAM_BASE + (u64)gd->ram_size))
Kumar Galac5bacfd2008-02-27 21:51:50 -060094 puts("WARNING: bootm_low + bootm_size exceed total memory\n");
Becky Bruced26d67c2008-06-09 20:37:18 -050095 if ((bootmap_base + bootm_size) > get_effective_memsize())
Kumar Galac5bacfd2008-02-27 21:51:50 -060096 puts("WARNING: bootm_low + bootm_size exceed eff. memory\n");
97#endif
98
Becky Bruced26d67c2008-06-09 20:37:18 -050099 size = min(bootm_size, get_effective_memsize());
Kumar Galac5bacfd2008-02-27 21:51:50 -0600100 size = min(size, CFG_LINUX_LOWMEM_MAX_SIZE);
101
Becky Bruced26d67c2008-06-09 20:37:18 -0500102 if (size < bootm_size) {
Kumar Galac5bacfd2008-02-27 21:51:50 -0600103 ulong base = bootmap_base + size;
104 printf("WARNING: adjusting available memory to %x\n", size);
Becky Bruced26d67c2008-06-09 20:37:18 -0500105 lmb_reserve(lmb, base, bootm_size - size);
Kumar Galac5bacfd2008-02-27 21:51:50 -0600106 }
Kumar Galab937bb72008-02-27 21:51:49 -0600107
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100108 /*
109 * Booting a (Linux) kernel image
110 *
111 * Allocate space for command line and board info - the
112 * address should be as high as possible within the reach of
113 * the kernel (see CFG_BOOTMAPSZ settings), but in unused
114 * memory, which means far enough below the current stack
115 * pointer.
116 */
Marian Balakowicz2efc2642008-01-31 13:58:13 +0100117 sp = get_sp();
Kumar Galac5bacfd2008-02-27 21:51:50 -0600118 debug ("## Current stack ends at 0x%08lx\n", sp);
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100119
Kumar Galab937bb72008-02-27 21:51:49 -0600120 /* adjust sp by 1K to be safe */
121 sp -= 1024;
122 lmb_reserve(lmb, sp, (CFG_SDRAM_BASE + get_effective_memsize() - sp));
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100123
Kumar Galaa56d7d52008-02-27 21:51:44 -0600124#if defined(CONFIG_OF_LIBFDT)
125 /* find flattened device tree */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100126 ret = boot_get_fdt (cmdtp, flag, argc, argv, images, &of_flat_tree, &of_size);
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600127
128 if (ret)
129 goto error;
Kumar Galaa56d7d52008-02-27 21:51:44 -0600130#endif
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100131
Kumar Galaa56d7d52008-02-27 21:51:44 -0600132 if (!of_size) {
133 /* allocate space and init command line */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100134 ret = boot_get_cmdline (lmb, &cmd_start, &cmd_end, bootmap_base);
Kumar Galab937bb72008-02-27 21:51:49 -0600135 if (ret) {
136 puts("ERROR with allocation of cmdline\n");
137 goto error;
138 }
Kumar Galaa56d7d52008-02-27 21:51:44 -0600139
140 /* allocate space for kernel copy of board info */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100141 ret = boot_get_kbd (lmb, &kbd, bootmap_base);
Kumar Galab937bb72008-02-27 21:51:49 -0600142 if (ret) {
143 puts("ERROR with allocation of kernel bd\n");
144 goto error;
145 }
Kumar Galaa56d7d52008-02-27 21:51:44 -0600146 set_clocks_in_mhz(kbd);
147 }
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100148
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100149 /* find kernel entry point */
150 if (images->legacy_hdr_valid) {
Marian Balakowiczab00e022008-04-11 11:07:49 +0200151 ep = image_get_ep (&images->legacy_hdr_os_copy);
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100152#if defined(CONFIG_FIT)
153 } else if (images->fit_uname_os) {
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100154 ret = fit_image_get_entry (images->fit_hdr_os,
155 images->fit_noffset_os, &ep);
156 if (ret) {
157 puts ("Can't get entry point property!\n");
158 goto error;
159 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100160#endif
161 } else {
162 puts ("Could not find kernel entry point!\n");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600163 goto error;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100164 }
165 kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))ep;
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100166
Marian Balakowicz9c701e82008-01-31 13:57:17 +0100167 /* find ramdisk */
Marian Balakowicza0ffb422008-03-12 10:14:38 +0100168 ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_PPC,
169 &rd_data_start, &rd_data_end);
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600170 if (ret)
171 goto error;
172
Marian Balakowicz95418502008-01-31 13:55:39 +0100173 rd_len = rd_data_end - rd_data_start;
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100174
Marian Balakowiczd2160852008-01-31 13:20:07 +0100175#if defined(CONFIG_OF_LIBFDT)
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100176 ret = boot_relocate_fdt (lmb, bootmap_base,
Kumar Galab937bb72008-02-27 21:51:49 -0600177 cmdtp, flag, argc, argv, &of_flat_tree, &of_size);
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100178
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100179 /*
180 * Add the chosen node if it doesn't exist, add the env and bd_t
181 * if the user wants it (the logic is in the subroutines).
182 */
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100183 if (of_size) {
Kumar Gala56bdf1d2008-02-27 21:51:45 -0600184 /* pass in dummy initrd info, we'll fix up later */
185 if (fdt_chosen(of_flat_tree, rd_data_start, rd_data_end, 0) < 0) {
Marian Balakowicz28fb6152008-01-31 13:20:08 +0100186 fdt_error ("/chosen node create failed");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600187 goto error;
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100188 }
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100189#ifdef CONFIG_OF_BOARD_SETUP
190 /* Call the board-specific fixup routine */
191 ft_board_setup(of_flat_tree, gd->bd);
192#endif
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100193 }
Marian Balakowiczd2160852008-01-31 13:20:07 +0100194#endif /* CONFIG_OF_LIBFDT */
Marian Balakowicz751b2b82008-01-08 18:11:43 +0100195
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100196 ret = boot_ramdisk_high (lmb, rd_data_start, rd_len, &initrd_start, &initrd_end);
Kumar Galab937bb72008-02-27 21:51:49 -0600197 if (ret)
198 goto error;
Kumar Gala56bdf1d2008-02-27 21:51:45 -0600199
200#if defined(CONFIG_OF_LIBFDT)
201 /* fixup the initrd now that we know where it should be */
202 if ((of_flat_tree) && (initrd_start && initrd_end)) {
203 uint64_t addr, size;
204 int total = fdt_num_mem_rsv(of_flat_tree);
205 int j;
206
207 /* Look for the dummy entry and delete it */
208 for (j = 0; j < total; j++) {
209 fdt_get_mem_rsv(of_flat_tree, j, &addr, &size);
210 if (addr == rd_data_start) {
211 fdt_del_mem_rsv(of_flat_tree, j);
212 break;
213 }
214 }
215
216 ret = fdt_add_mem_rsv(of_flat_tree, initrd_start,
217 initrd_end - initrd_start + 1);
218 if (ret < 0) {
219 printf("fdt_chosen: %s\n", fdt_strerror(ret));
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600220 goto error;
Kumar Gala56bdf1d2008-02-27 21:51:45 -0600221 }
222
223 do_fixup_by_path_u32(of_flat_tree, "/chosen",
224 "linux,initrd-start", initrd_start, 0);
225 do_fixup_by_path_u32(of_flat_tree, "/chosen",
226 "linux,initrd-end", initrd_end, 0);
227 }
228#endif
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100229 debug ("## Transferring control to Linux (at address %08lx) ...\n",
230 (ulong)kernel);
231
232 show_boot_progress (15);
233
234#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500)
235 unlock_ram_in_cache();
236#endif
Kumar Galaaa0826b2008-02-27 21:51:51 -0600237 if (!images->autostart)
238 return ;
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100239
Marian Balakowiczd2160852008-01-31 13:20:07 +0100240#if defined(CONFIG_OF_LIBFDT)
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100241 if (of_flat_tree) { /* device tree; boot new style */
242 /*
243 * Linux Kernel Parameters (passing device tree):
244 * r3: pointer to the fdt, followed by the board info data
245 * r4: physical pointer to the kernel itself
246 * r5: NULL
247 * r6: NULL
248 * r7: NULL
249 */
Marian Balakowicz0d871362008-03-12 10:32:53 +0100250 debug (" Booting using OF flat tree...\n");
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100251 (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0);
252 /* does not return */
Marian Balakowicz0d871362008-03-12 10:32:53 +0100253 } else
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100254#endif
Marian Balakowicz0d871362008-03-12 10:32:53 +0100255 {
256 /*
257 * Linux Kernel Parameters (passing board info data):
258 * r3: ptr to board info data
259 * r4: initrd_start or 0 if no initrd
260 * r5: initrd_end - unused if r4 is 0
261 * r6: Start of command line string
262 * r7: End of command line string
263 */
264 debug (" Booting using board info...\n");
265 (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
266 /* does not return */
267 }
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600268 return ;
269
270error:
Kumar Galaaa0826b2008-02-27 21:51:51 -0600271 if (images->autostart)
272 do_reset (cmdtp, flag, argc, argv);
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600273 return ;
Marian Balakowicz2437cf22008-01-08 18:11:43 +0100274}
Marian Balakowicz28fb6152008-01-31 13:20:08 +0100275
Marian Balakowicz9c701e82008-01-31 13:57:17 +0100276static ulong get_sp (void)
277{
278 ulong sp;
279
280 asm( "mr %0,1": "=r"(sp) : );
281 return sp;
282}
283
Marian Balakowicz2efc2642008-01-31 13:58:13 +0100284static void set_clocks_in_mhz (bd_t *kbd)
285{
286 char *s;
287
288 if ((s = getenv ("clocks_in_mhz")) != NULL) {
289 /* convert all clock information to MHz */
290 kbd->bi_intfreq /= 1000000L;
291 kbd->bi_busfreq /= 1000000L;
292#if defined(CONFIG_MPC8220)
293 kbd->bi_inpfreq /= 1000000L;
294 kbd->bi_pcifreq /= 1000000L;
295 kbd->bi_pevfreq /= 1000000L;
296 kbd->bi_flbfreq /= 1000000L;
297 kbd->bi_vcofreq /= 1000000L;
298#endif
299#if defined(CONFIG_CPM2)
300 kbd->bi_cpmfreq /= 1000000L;
301 kbd->bi_brgfreq /= 1000000L;
302 kbd->bi_sccfreq /= 1000000L;
Wolfgang Denk8f702ad2008-03-26 11:48:46 +0100303 kbd->bi_vco /= 1000000L;
Marian Balakowicz2efc2642008-01-31 13:58:13 +0100304#endif
305#if defined(CONFIG_MPC5xxx)
306 kbd->bi_ipbfreq /= 1000000L;
307 kbd->bi_pcifreq /= 1000000L;
308#endif /* CONFIG_MPC5xxx */
309 }
310}
311
Marian Balakowicz28fb6152008-01-31 13:20:08 +0100312#if defined(CONFIG_OF_LIBFDT)
313static void fdt_error (const char *msg)
314{
315 puts ("ERROR: ");
316 puts (msg);
317 puts (" - must RESET the board to recover.\n");
318}
Marian Balakowicz25154b62008-01-31 13:58:20 +0100319
Marian Balakowicz351d3e32008-02-27 11:02:26 +0100320static image_header_t *image_get_fdt (ulong fdt_addr)
321{
322 image_header_t *fdt_hdr = (image_header_t *)fdt_addr;
323
324 image_print_contents (fdt_hdr);
325
326 puts (" Verifying Checksum ... ");
327 if (!image_check_hcrc (fdt_hdr)) {
328 fdt_error ("fdt header checksum invalid");
329 return NULL;
330 }
331
332 if (!image_check_dcrc (fdt_hdr)) {
333 fdt_error ("fdt checksum invalid");
334 return NULL;
335 }
336 puts ("OK\n");
337
338 if (!image_check_type (fdt_hdr, IH_TYPE_FLATDT)) {
339 fdt_error ("uImage is not a fdt");
340 return NULL;
341 }
342 if (image_get_comp (fdt_hdr) != IH_COMP_NONE) {
343 fdt_error ("uImage is compressed");
344 return NULL;
345 }
346 if (fdt_check_header ((char *)image_get_data (fdt_hdr)) != 0) {
347 fdt_error ("uImage data is not a fdt");
348 return NULL;
349 }
350 return fdt_hdr;
351}
352
Marian Balakowicz0d871362008-03-12 10:32:53 +0100353/**
354 * fit_check_fdt - verify FIT format FDT subimage
355 * @fit_hdr: pointer to the FIT header
356 * fdt_noffset: FDT subimage node offset within FIT image
357 * @verify: data CRC verification flag
358 *
359 * fit_check_fdt() verifies integrity of the FDT subimage and from
360 * specified FIT image.
361 *
362 * returns:
363 * 1, on success
364 * 0, on failure
365 */
366#if defined(CONFIG_FIT)
367static int fit_check_fdt (const void *fit, int fdt_noffset, int verify)
368{
369 fit_image_print (fit, fdt_noffset, " ");
370
371 if (verify) {
372 puts (" Verifying Hash Integrity ... ");
373 if (!fit_image_check_hashes (fit, fdt_noffset)) {
374 fdt_error ("Bad Data Hash");
375 return 0;
376 }
377 puts ("OK\n");
378 }
379
380 if (!fit_image_check_type (fit, fdt_noffset, IH_TYPE_FLATDT)) {
381 fdt_error ("Not a FDT image");
382 return 0;
383 }
384
385 if (!fit_image_check_comp (fit, fdt_noffset, IH_COMP_NONE)) {
386 fdt_error ("FDT image is compressed");
387 return 0;
388 }
389
390 return 1;
391}
392#endif /* CONFIG_FIT */
393
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100394static int boot_get_fdt (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100395 bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
Marian Balakowicz25154b62008-01-31 13:58:20 +0100396{
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100397 ulong fdt_addr;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100398 image_header_t *fdt_hdr;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100399 char *fdt_blob = NULL;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100400 ulong image_start, image_end;
401 ulong load_start, load_end;
402#if defined(CONFIG_FIT)
Wolfgang Denk8f702ad2008-03-26 11:48:46 +0100403 void *fit_hdr;
404 const char *fit_uname_config = NULL;
405 const char *fit_uname_fdt = NULL;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100406 ulong default_addr;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100407 int cfg_noffset;
Marian Balakowicz0d871362008-03-12 10:32:53 +0100408 int fdt_noffset;
409 const void *data;
410 size_t size;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100411#endif
Marian Balakowicz25154b62008-01-31 13:58:20 +0100412
Marian Balakowicz0d871362008-03-12 10:32:53 +0100413 *of_flat_tree = NULL;
414 *of_size = 0;
415
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100416 if (argc > 3 || genimg_has_config (images)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100417#if defined(CONFIG_FIT)
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100418 if (argc > 3) {
419 /*
420 * If the FDT blob comes from the FIT image and the
421 * FIT image address is omitted in the command line
422 * argument, try to use ramdisk or os FIT image
423 * address or default load address.
424 */
425 if (images->fit_uname_rd)
426 default_addr = (ulong)images->fit_hdr_rd;
427 else if (images->fit_uname_os)
428 default_addr = (ulong)images->fit_hdr_os;
429 else
430 default_addr = load_addr;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100431
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100432 if (fit_parse_conf (argv[3], default_addr,
433 &fdt_addr, &fit_uname_config)) {
434 debug ("* fdt: config '%s' from image at 0x%08lx\n",
435 fit_uname_config, fdt_addr);
436 } else if (fit_parse_subimage (argv[3], default_addr,
437 &fdt_addr, &fit_uname_fdt)) {
438 debug ("* fdt: subimage '%s' from image at 0x%08lx\n",
439 fit_uname_fdt, fdt_addr);
440 } else
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100441#endif
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100442 {
443 fdt_addr = simple_strtoul(argv[3], NULL, 16);
444 debug ("* fdt: cmdline image address = 0x%08lx\n",
445 fdt_addr);
446 }
447#if defined(CONFIG_FIT)
448 } else {
449 /* use FIT configuration provided in first bootm
450 * command argument
451 */
452 fdt_addr = (ulong)images->fit_hdr_os;
453 fit_uname_config = images->fit_uname_cfg;
454 debug ("* fdt: using config '%s' from image at 0x%08lx\n",
455 fit_uname_config, fdt_addr);
456
457 /*
458 * Check whether configuration has FDT blob defined,
459 * if not quit silently.
460 */
461 fit_hdr = (void *)fdt_addr;
462 cfg_noffset = fit_conf_get_node (fit_hdr,
463 fit_uname_config);
464 if (cfg_noffset < 0) {
465 debug ("* fdt: no such config\n");
466 return 0;
467 }
468
469 fdt_noffset = fit_conf_get_fdt_node (fit_hdr,
470 cfg_noffset);
471 if (fdt_noffset < 0) {
472 debug ("* fdt: no fdt in config\n");
473 return 0;
474 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100475 }
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100476#endif
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100477
Marian Balakowicz0d871362008-03-12 10:32:53 +0100478 debug ("## Checking for 'FDT'/'FDT Image' at %08lx\n",
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100479 fdt_addr);
Marian Balakowiczc536d6f2008-02-21 17:20:19 +0100480
481 /* copy from dataflash if needed */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100482 fdt_addr = genimg_get_image (fdt_addr);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100483
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100484 /*
485 * Check if there is an FDT image at the
486 * address provided in the second bootm argument
487 * check image type, for FIT images get a FIT node.
488 */
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100489 switch (genimg_get_format ((void *)fdt_addr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100490 case IMAGE_FORMAT_LEGACY:
Marian Balakowicz351d3e32008-02-27 11:02:26 +0100491 /* verify fdt_addr points to a valid image header */
Marian Balakowicz0d871362008-03-12 10:32:53 +0100492 printf ("## Flattened Device Tree from Legacy Image at %08lx\n",
Marian Balakowicz351d3e32008-02-27 11:02:26 +0100493 fdt_addr);
494 fdt_hdr = image_get_fdt (fdt_addr);
495 if (!fdt_hdr)
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600496 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100497
Marian Balakowicz351d3e32008-02-27 11:02:26 +0100498 /*
499 * move image data to the load address,
500 * make sure we don't overwrite initial image
501 */
Marian Balakowicz25154b62008-01-31 13:58:20 +0100502 image_start = (ulong)fdt_hdr;
503 image_end = image_get_image_end (fdt_hdr);
504
505 load_start = image_get_load (fdt_hdr);
506 load_end = load_start + image_get_data_size (fdt_hdr);
507
508 if ((load_start < image_end) && (load_end > image_start)) {
509 fdt_error ("fdt overwritten");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600510 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100511 }
Marian Balakowicz0d871362008-03-12 10:32:53 +0100512
513 debug (" Loading FDT from 0x%08lx to 0x%08lx\n",
514 image_get_data (fdt_hdr), load_start);
515
516 memmove ((void *)load_start,
Marian Balakowicz351d3e32008-02-27 11:02:26 +0100517 (void *)image_get_data (fdt_hdr),
518 image_get_data_size (fdt_hdr));
Marian Balakowicz25154b62008-01-31 13:58:20 +0100519
Marian Balakowicz0d871362008-03-12 10:32:53 +0100520 fdt_blob = (char *)load_start;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100521 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100522 case IMAGE_FORMAT_FIT:
Marian Balakowicz12560682008-02-27 11:02:26 +0100523 /*
524 * This case will catch both: new uImage format
525 * (libfdt based) and raw FDT blob (also libfdt
526 * based).
527 */
528#if defined(CONFIG_FIT)
529 /* check FDT blob vs FIT blob */
Marian Balakowicz0d871362008-03-12 10:32:53 +0100530 if (fit_check_format ((const void *)fdt_addr)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100531 /*
532 * FIT image
533 */
534 fit_hdr = (void *)fdt_addr;
Marian Balakowicz0d871362008-03-12 10:32:53 +0100535 printf ("## Flattened Device Tree from FIT Image at %08lx\n",
536 fdt_addr);
537
538 if (!fit_uname_fdt) {
539 /*
540 * no FDT blob image node unit name,
541 * try to get config node first. If
542 * config unit node name is NULL
543 * fit_conf_get_node() will try to
544 * find default config node
545 */
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100546 cfg_noffset = fit_conf_get_node (fit_hdr,
Marian Balakowicz0d871362008-03-12 10:32:53 +0100547 fit_uname_config);
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100548
549 if (cfg_noffset < 0) {
550 fdt_error ("Could not find configuration node\n");
Marian Balakowicz0d871362008-03-12 10:32:53 +0100551 goto error;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100552 }
553
554 fit_uname_config = fdt_get_name (fit_hdr,
555 cfg_noffset, NULL);
556 printf (" Using '%s' configuration\n",
557 fit_uname_config);
Marian Balakowicz0d871362008-03-12 10:32:53 +0100558
559 fdt_noffset = fit_conf_get_fdt_node (fit_hdr,
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100560 cfg_noffset);
Marian Balakowicz0d871362008-03-12 10:32:53 +0100561 fit_uname_fdt = fit_get_name (fit_hdr,
562 fdt_noffset, NULL);
563 } else {
564 /* get FDT component image node offset */
565 fdt_noffset = fit_image_get_node (fit_hdr,
566 fit_uname_fdt);
567 }
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100568 if (fdt_noffset < 0) {
569 fdt_error ("Could not find subimage node\n");
Marian Balakowicz0d871362008-03-12 10:32:53 +0100570 goto error;
Marian Balakowicz0cd4f3d2008-03-12 10:35:46 +0100571 }
Marian Balakowicz0d871362008-03-12 10:32:53 +0100572
573 printf (" Trying '%s' FDT blob subimage\n",
574 fit_uname_fdt);
575
576 if (!fit_check_fdt (fit_hdr, fdt_noffset,
577 images->verify))
578 goto error;
579
580 /* get ramdisk image data address and length */
581 if (fit_image_get_data (fit_hdr, fdt_noffset,
582 &data, &size)) {
583 fdt_error ("Could not find FDT subimage data");
584 goto error;
585 }
586
587 /* verift that image data is a proper FDT blob */
588 if (fdt_check_header ((char *)data) != 0) {
589 fdt_error ("Subimage data is not a FTD");
590 goto error;
591 }
592
593 /*
594 * move image data to the load address,
595 * make sure we don't overwrite initial image
596 */
597 image_start = (ulong)fit_hdr;
598 image_end = fit_get_end (fit_hdr);
599
600 if (fit_image_get_load (fit_hdr, fdt_noffset,
601 &load_start) == 0) {
602 load_end = load_start + size;
603
604 if ((load_start < image_end) &&
605 (load_end > image_start)) {
606 fdt_error ("FDT overwritten");
607 goto error;
608 }
609
610 printf (" Loading FDT from 0x%08lx to 0x%08lx\n",
611 (ulong)data, load_start);
612
613 memmove ((void *)load_start,
614 (void *)data, size);
615
616 fdt_blob = (char *)load_start;
617 } else {
618 fdt_blob = (char *)data;
619 }
620
621 images->fit_hdr_fdt = fit_hdr;
622 images->fit_uname_fdt = fit_uname_fdt;
Marian Balakowicz61c1ad52008-03-12 10:32:59 +0100623 images->fit_noffset_fdt = fdt_noffset;
Marian Balakowicz0d871362008-03-12 10:32:53 +0100624 break;
Marian Balakowicz12560682008-02-27 11:02:26 +0100625 } else
626#endif
627 {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100628 /*
629 * FDT blob
630 */
Marian Balakowicze5d63b72008-04-11 11:07:43 +0200631 fdt_blob = (char *)fdt_addr;
Marian Balakowicz12560682008-02-27 11:02:26 +0100632 debug ("* fdt: raw FDT blob\n");
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100633 printf ("## Flattened Device Tree blob at %08lx\n", fdt_blob);
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100634 }
635 break;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100636 default:
637 fdt_error ("Did not find a cmdline Flattened Device Tree");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600638 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100639 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100640
641 printf (" Booting using the fdt blob at 0x%x\n", fdt_blob);
642
643 } else if (images->legacy_hdr_valid &&
Marian Balakowiczab00e022008-04-11 11:07:49 +0200644 image_check_type (&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100645
Marian Balakowicz25154b62008-01-31 13:58:20 +0100646 ulong fdt_data, fdt_len;
647
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100648 /*
649 * Now check if we have a legacy multi-component image,
650 * get second entry data start address and len.
651 */
Marian Balakowicz25154b62008-01-31 13:58:20 +0100652 printf ("## Flattened Device Tree from multi "
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100653 "component Image at %08lX\n",
654 (ulong)images->legacy_hdr_os);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100655
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100656 image_multi_getimg (images->legacy_hdr_os, 2, &fdt_data, &fdt_len);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100657 if (fdt_len) {
658
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100659 fdt_blob = (char *)fdt_data;
660 printf (" Booting using the fdt at 0x%x\n", fdt_blob);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100661
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100662 if (fdt_check_header (fdt_blob) != 0) {
Marian Balakowicz25154b62008-01-31 13:58:20 +0100663 fdt_error ("image is not a fdt");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600664 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100665 }
666
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100667 if (be32_to_cpu (fdt_totalsize (fdt_blob)) != fdt_len) {
Marian Balakowicz25154b62008-01-31 13:58:20 +0100668 fdt_error ("fdt size != image size");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600669 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100670 }
671 } else {
Nick Spence5bcd4102008-05-08 22:32:22 -0700672 debug ("## No Flattened Device Tree\n");
673 return 0;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100674 }
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100675 } else {
676 debug ("## No Flattened Device Tree\n");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600677 return 0;
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100678 }
679
680 *of_flat_tree = fdt_blob;
681 *of_size = be32_to_cpu (fdt_totalsize (fdt_blob));
682 debug (" of_flat_tree at 0x%08lx size 0x%08lx\n",
683 *of_flat_tree, *of_size);
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600684
685 return 0;
686
687error:
688 do_reset (cmdtp, flag, argc, argv);
689 return 1;
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100690}
691
Marian Balakowiczd7c88a42008-02-29 14:58:34 +0100692static int boot_relocate_fdt (struct lmb *lmb, ulong bootmap_base,
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100693 cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
694 char **of_flat_tree, ulong *of_size)
695{
696 char *fdt_blob = *of_flat_tree;
697 ulong relocate = 0;
Kumar Galab937bb72008-02-27 21:51:49 -0600698 ulong of_len = 0;
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100699
700 /* nothing to do */
701 if (*of_size == 0)
Kumar Galab937bb72008-02-27 21:51:49 -0600702 return 0;
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100703
704 if (fdt_check_header (fdt_blob) != 0) {
705 fdt_error ("image is not a fdt");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600706 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100707 }
708
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100709#ifndef CFG_NO_FLASH
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100710 /* move the blob if it is in flash (set relocate) */
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100711 if (addr2info ((ulong)fdt_blob) != NULL)
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100712 relocate = 1;
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100713#endif
714
Marian Balakowicz25154b62008-01-31 13:58:20 +0100715 /*
716 * The blob must be within CFG_BOOTMAPSZ,
717 * so we flag it to be copied if it is not.
718 */
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100719 if (fdt_blob >= (char *)CFG_BOOTMAPSZ)
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100720 relocate = 1;
Kumar Galab937bb72008-02-27 21:51:49 -0600721
Marian Balakowiczb5ec1b92008-02-29 22:22:46 +0100722 of_len = be32_to_cpu (fdt_totalsize (fdt_blob));
Marian Balakowicz25154b62008-01-31 13:58:20 +0100723
724 /* move flattend device tree if needed */
Marian Balakowicz6881dae2008-02-04 08:28:17 +0100725 if (relocate) {
Marian Balakowicz25154b62008-01-31 13:58:20 +0100726 int err;
Kumar Galab937bb72008-02-27 21:51:49 -0600727 ulong of_start;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100728
729 /* position on a 4K boundary before the alloc_current */
Becky Bruced26d67c2008-06-09 20:37:18 -0500730 of_start = (unsigned long)lmb_alloc_base(lmb, of_len, 0x1000,
Kumar Galab937bb72008-02-27 21:51:49 -0600731 (CFG_BOOTMAPSZ + bootmap_base));
732
733 if (of_start == 0) {
734 puts("device tree - allocation error\n");
735 goto error;
736 }
Marian Balakowicz25154b62008-01-31 13:58:20 +0100737
738 debug ("## device tree at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100739 (ulong)fdt_blob, (ulong)fdt_blob + of_len - 1,
Marian Balakowicz25154b62008-01-31 13:58:20 +0100740 of_len, of_len);
741
742 printf (" Loading Device Tree to %08lx, end %08lx ... ",
743 of_start, of_start + of_len - 1);
744
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100745 err = fdt_open_into (fdt_blob, (void *)of_start, of_len);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100746 if (err != 0) {
747 fdt_error ("fdt move failed");
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600748 goto error;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100749 }
750 puts ("OK\n");
751
752 *of_flat_tree = (char *)of_start;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100753 } else {
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100754 *of_flat_tree = fdt_blob;
Kim Phillipsf3a42e22008-06-10 11:06:17 -0500755 lmb_reserve(lmb, (ulong)working_fdt, of_len);
Marian Balakowicz25154b62008-01-31 13:58:20 +0100756 }
757
Kumar Galab937bb72008-02-27 21:51:49 -0600758 return 0;
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600759
760error:
Kumar Gala18f4c0f2008-02-27 21:51:46 -0600761 return 1;
Marian Balakowicz25154b62008-01-31 13:58:20 +0100762}
Marian Balakowicz28fb6152008-01-31 13:20:08 +0100763#endif