09038cc93fdfeed8bee8bffde1e7899cc318067f
[platform/kernel/u-boot.git] / lib_arm / armlinux.c
1 /*
2  * (C) Copyright 2002
3  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4  * Marius Groeger <mgroeger@sysgo.de>
5  *
6  * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (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, MA  02111-1307  USA
21  *
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <image.h>
27 #include <zlib.h>
28 #include <asm/byteorder.h>
29 #ifdef CONFIG_HAS_DATAFLASH
30 #include <dataflash.h>
31 #endif
32
33 DECLARE_GLOBAL_DATA_PTR;
34
35 /*cmd_boot.c*/
36 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
37
38 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
39     defined (CONFIG_CMDLINE_TAG) || \
40     defined (CONFIG_INITRD_TAG) || \
41     defined (CONFIG_SERIAL_TAG) || \
42     defined (CONFIG_REVISION_TAG) || \
43     defined (CONFIG_VFD) || \
44     defined (CONFIG_LCD)
45 static void setup_start_tag (bd_t *bd);
46
47 # ifdef CONFIG_SETUP_MEMORY_TAGS
48 static void setup_memory_tags (bd_t *bd);
49 # endif
50 static void setup_commandline_tag (bd_t *bd, char *commandline);
51
52 #if 0
53 static void setup_ramdisk_tag (bd_t *bd);
54 #endif
55 # ifdef CONFIG_INITRD_TAG
56 static void setup_initrd_tag (bd_t *bd, ulong initrd_start,
57                               ulong initrd_end);
58 # endif
59 static void setup_end_tag (bd_t *bd);
60
61 # if defined (CONFIG_VFD) || defined (CONFIG_LCD)
62 static void setup_videolfb_tag (gd_t *gd);
63 # endif
64
65
66 static struct tag *params;
67 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
68
69 extern image_header_t header;   /* from cmd_bootm.c */
70
71
72 void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
73                      ulong addr, ulong *len_ptr, int verify)
74 {
75         ulong len = 0;
76         ulong initrd_start, initrd_end;
77         ulong data;
78         void (*theKernel)(int zero, int arch, uint params);
79         image_header_t *hdr = &header;
80         bd_t *bd = gd->bd;
81
82 #ifdef CONFIG_CMDLINE_TAG
83         char *commandline = getenv ("bootargs");
84 #endif
85
86         theKernel = (void (*)(int, int, uint))image_get_ep (hdr);
87
88         /*
89          * Check if there is an initrd image
90          */
91         if (argc >= 3) {
92                 show_boot_progress (9);
93
94                 addr = simple_strtoul (argv[2], NULL, 16);
95
96                 printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
97
98                 /* Copy header so we can blank CRC field for re-calculation */
99 #ifdef CONFIG_HAS_DATAFLASH
100                 if (addr_dataflash (addr)) {
101                         read_dataflash (addr, image_get_header_size (),
102                                         (char *) &header);
103                 } else
104 #endif
105                         memcpy (&header, (char *) addr,
106                                 image_get_header_size ());
107
108                 if (!image_check_magic (hdr)) {
109                         printf ("Bad Magic Number\n");
110                         show_boot_progress (-10);
111                         do_reset (cmdtp, flag, argc, argv);
112                 }
113
114                 if (!image_check_hcrc (hdr)) {
115                         printf ("Bad Header Checksum\n");
116                         show_boot_progress (-11);
117                         do_reset (cmdtp, flag, argc, argv);
118                 }
119
120                 show_boot_progress (10);
121
122                 print_image_hdr (hdr);
123
124                 data = image_get_data (hdr);
125                 len = image_get_data_size (hdr);
126
127 #ifdef CONFIG_HAS_DATAFLASH
128                 if (addr_dataflash (addr)) {
129                         read_dataflash (data, len, (char *) CFG_LOAD_ADDR);
130                         data = CFG_LOAD_ADDR;
131                 }
132 #endif
133
134                 if (verify) {
135                         printf ("   Verifying Checksum ... ");
136                         if (!image_get_dcrc (hdr)) {
137                                 printf ("Bad Data CRC\n");
138                                 show_boot_progress (-12);
139                                 do_reset (cmdtp, flag, argc, argv);
140                         }
141                         printf ("OK\n");
142                 }
143
144                 show_boot_progress (11);
145
146                 if (!image_check_os (hdr, IH_OS_LINUX) ||
147                     !image_check_arch (hdr, IH_ARCH_ARM) ||
148                     !image_check_type (hdr, IH_TYPE_RAMDISK)) {
149                         printf ("No Linux ARM Ramdisk Image\n");
150                         show_boot_progress (-13);
151                         do_reset (cmdtp, flag, argc, argv);
152                 }
153
154 #if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
155                 /*
156                  *we need to copy the ramdisk to SRAM to let Linux boot
157                  */
158                 memmove ((void *)image_get_load (hdr), (uchar *)data, len);
159                 data = image_get_load (hdr);
160 #endif /* CONFIG_B2 || CONFIG_EVB4510 */
161
162                 /*
163                  * Now check if we have a multifile image
164                  */
165         } else if (image_check_type (hdr, IH_TYPE_MULTI) && (len_ptr[1])) {
166                 ulong tail = image_to_cpu (len_ptr[0]) % 4;
167                 int i;
168
169                 show_boot_progress (13);
170
171                 /* skip kernel length and terminator */
172                 data = (ulong) (&len_ptr[2]);
173                 /* skip any additional image length fields */
174                 for (i = 1; len_ptr[i]; ++i)
175                         data += 4;
176                 /* add kernel length, and align */
177                 data += image_to_cpu (len_ptr[0]);
178                 if (tail) {
179                         data += 4 - tail;
180                 }
181
182                 len = image_to_cpu (len_ptr[1]);
183
184         } else {
185                 /*
186                  * no initrd image
187                  */
188                 show_boot_progress (14);
189
190                 len = data = 0;
191         }
192
193 #ifdef  DEBUG
194         if (!data) {
195                 printf ("No initrd\n");
196         }
197 #endif
198
199         if (data) {
200                 initrd_start = data;
201                 initrd_end = initrd_start + len;
202         } else {
203                 initrd_start = 0;
204                 initrd_end = 0;
205         }
206
207         show_boot_progress (15);
208
209         debug ("## Transferring control to Linux (at address %08lx) ...\n",
210                (ulong) theKernel);
211
212 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
213     defined (CONFIG_CMDLINE_TAG) || \
214     defined (CONFIG_INITRD_TAG) || \
215     defined (CONFIG_SERIAL_TAG) || \
216     defined (CONFIG_REVISION_TAG) || \
217     defined (CONFIG_LCD) || \
218     defined (CONFIG_VFD)
219         setup_start_tag (bd);
220 #ifdef CONFIG_SERIAL_TAG
221         setup_serial_tag (&params);
222 #endif
223 #ifdef CONFIG_REVISION_TAG
224         setup_revision_tag (&params);
225 #endif
226 #ifdef CONFIG_SETUP_MEMORY_TAGS
227         setup_memory_tags (bd);
228 #endif
229 #ifdef CONFIG_CMDLINE_TAG
230         setup_commandline_tag (bd, commandline);
231 #endif
232 #ifdef CONFIG_INITRD_TAG
233         if (initrd_start && initrd_end)
234                 setup_initrd_tag (bd, initrd_start, initrd_end);
235 #endif
236 #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
237         setup_videolfb_tag ((gd_t *) gd);
238 #endif
239         setup_end_tag (bd);
240 #endif
241
242         /* we assume that the kernel is in place */
243         printf ("\nStarting kernel ...\n\n");
244
245 #ifdef CONFIG_USB_DEVICE
246         {
247                 extern void udc_disconnect (void);
248                 udc_disconnect ();
249         }
250 #endif
251
252         cleanup_before_linux ();
253
254         theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
255 }
256
257
258 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
259     defined (CONFIG_CMDLINE_TAG) || \
260     defined (CONFIG_INITRD_TAG) || \
261     defined (CONFIG_SERIAL_TAG) || \
262     defined (CONFIG_REVISION_TAG) || \
263     defined (CONFIG_LCD) || \
264     defined (CONFIG_VFD)
265 static void setup_start_tag (bd_t *bd)
266 {
267         params = (struct tag *) bd->bi_boot_params;
268
269         params->hdr.tag = ATAG_CORE;
270         params->hdr.size = tag_size (tag_core);
271
272         params->u.core.flags = 0;
273         params->u.core.pagesize = 0;
274         params->u.core.rootdev = 0;
275
276         params = tag_next (params);
277 }
278
279
280 #ifdef CONFIG_SETUP_MEMORY_TAGS
281 static void setup_memory_tags (bd_t *bd)
282 {
283         int i;
284
285         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
286                 params->hdr.tag = ATAG_MEM;
287                 params->hdr.size = tag_size (tag_mem32);
288
289                 params->u.mem.start = bd->bi_dram[i].start;
290                 params->u.mem.size = bd->bi_dram[i].size;
291
292                 params = tag_next (params);
293         }
294 }
295 #endif /* CONFIG_SETUP_MEMORY_TAGS */
296
297
298 static void setup_commandline_tag (bd_t *bd, char *commandline)
299 {
300         char *p;
301
302         if (!commandline)
303                 return;
304
305         /* eat leading white space */
306         for (p = commandline; *p == ' '; p++);
307
308         /* skip non-existent command lines so the kernel will still
309          * use its default command line.
310          */
311         if (*p == '\0')
312                 return;
313
314         params->hdr.tag = ATAG_CMDLINE;
315         params->hdr.size =
316                 (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
317
318         strcpy (params->u.cmdline.cmdline, p);
319
320         params = tag_next (params);
321 }
322
323
324 #ifdef CONFIG_INITRD_TAG
325 static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
326 {
327         /* an ATAG_INITRD node tells the kernel where the compressed
328          * ramdisk can be found. ATAG_RDIMG is a better name, actually.
329          */
330         params->hdr.tag = ATAG_INITRD2;
331         params->hdr.size = tag_size (tag_initrd);
332
333         params->u.initrd.start = initrd_start;
334         params->u.initrd.size = initrd_end - initrd_start;
335
336         params = tag_next (params);
337 }
338 #endif /* CONFIG_INITRD_TAG */
339
340
341 #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
342 extern ulong calc_fbsize (void);
343 static void setup_videolfb_tag (gd_t *gd)
344 {
345         /* An ATAG_VIDEOLFB node tells the kernel where and how large
346          * the framebuffer for video was allocated (among other things).
347          * Note that a _physical_ address is passed !
348          *
349          * We only use it to pass the address and size, the other entries
350          * in the tag_videolfb are not of interest.
351          */
352         params->hdr.tag = ATAG_VIDEOLFB;
353         params->hdr.size = tag_size (tag_videolfb);
354
355         params->u.videolfb.lfb_base = (u32) gd->fb_base;
356         /* Fb size is calculated according to parameters for our panel
357          */
358         params->u.videolfb.lfb_size = calc_fbsize();
359
360         params = tag_next (params);
361 }
362 #endif /* CONFIG_VFD || CONFIG_LCD */
363
364 #ifdef CONFIG_SERIAL_TAG
365 void setup_serial_tag (struct tag **tmp)
366 {
367         struct tag *params = *tmp;
368         struct tag_serialnr serialnr;
369         void get_board_serial(struct tag_serialnr *serialnr);
370
371         get_board_serial(&serialnr);
372         params->hdr.tag = ATAG_SERIAL;
373         params->hdr.size = tag_size (tag_serialnr);
374         params->u.serialnr.low = serialnr.low;
375         params->u.serialnr.high= serialnr.high;
376         params = tag_next (params);
377         *tmp = params;
378 }
379 #endif
380
381 #ifdef CONFIG_REVISION_TAG
382 void setup_revision_tag(struct tag **in_params)
383 {
384         u32 rev = 0;
385         u32 get_board_rev(void);
386
387         rev = get_board_rev();
388         params->hdr.tag = ATAG_REVISION;
389         params->hdr.size = tag_size (tag_revision);
390         params->u.revision.rev = rev;
391         params = tag_next (params);
392 }
393 #endif  /* CONFIG_REVISION_TAG */
394
395
396 static void setup_end_tag (bd_t *bd)
397 {
398         params->hdr.tag = ATAG_NONE;
399         params->hdr.size = 0;
400 }
401
402 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */