]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - lib_arm/armlinux.c
* Fix mdelay() on TRAB - this was still the debugging version with
[karo-tx-uboot.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 <cmd_boot.h>
27 #include <image.h>
28 #include <zlib.h>
29 #include <asm/byteorder.h>
30
31 #include <asm/setup.h>
32 #define tag_size(type)  ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
33 #define tag_next(t)     ((struct tag *)((u32 *)(t) + (t)->hdr.size))
34
35 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
36     defined (CONFIG_CMDLINE_TAG) || \
37     defined (CONFIG_INITRD_TAG) || \
38     defined (CONFIG_VFD)
39 static void setup_start_tag(bd_t *bd);
40 # ifdef CONFIG_SETUP_MEMORY_TAGS
41 static void setup_memory_tags(bd_t *bd);
42 # endif
43 static void setup_commandline_tag(bd_t *bd, char *commandline);
44 #if 0
45 static void setup_ramdisk_tag(bd_t *bd);
46 #endif
47 # ifdef CONFIG_INITRD_TAG
48 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
49 # endif
50 static void setup_end_tag(bd_t *bd);
51 # if defined (CONFIG_VFD)
52 static void setup_videolfb_tag(gd_t *gd);
53 # endif
54
55
56 static struct tag *params;
57 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
58
59 extern image_header_t header;           /* from cmd_bootm.c */
60
61
62 void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
63                 ulong addr, ulong *len_ptr, int   verify)
64 {
65         DECLARE_GLOBAL_DATA_PTR;
66
67     ulong len = 0, checksum;
68     ulong initrd_start, initrd_end;
69     ulong data;
70     void (*theKernel)(int zero, int arch);
71     image_header_t *hdr = &header;
72     bd_t *bd = gd->bd;
73 #ifdef CONFIG_CMDLINE_TAG
74     char *commandline = getenv("bootargs");
75 #endif
76
77     theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);
78
79     /*
80      * Check if there is an initrd image
81      */
82     if (argc >= 3) {
83         addr = simple_strtoul(argv[2], NULL, 16);
84
85         printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
86
87         /* Copy header so we can blank CRC field for re-calculation */
88         memcpy (&header, (char *)addr, sizeof(image_header_t));
89
90         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
91             printf ("Bad Magic Number\n");
92             do_reset (cmdtp, flag, argc, argv);
93         }
94
95         data = (ulong)&header;
96         len  = sizeof(image_header_t);
97
98         checksum = ntohl(hdr->ih_hcrc);
99         hdr->ih_hcrc = 0;
100
101         if (crc32 (0, (char *)data, len) != checksum) {
102             printf ("Bad Header Checksum\n");
103             do_reset (cmdtp, flag, argc, argv);
104         }
105
106         print_image_hdr (hdr);
107
108         data = addr + sizeof(image_header_t);
109         len  = ntohl(hdr->ih_size);
110
111         if (verify) {
112             ulong csum = 0;
113
114             printf ("   Verifying Checksum ... ");
115             csum = crc32 (0, (char *)data, len);
116             if (csum != ntohl(hdr->ih_dcrc)) {
117                 printf ("Bad Data CRC\n");
118                 do_reset (cmdtp, flag, argc, argv);
119             }
120             printf ("OK\n");
121         }
122
123         if ((hdr->ih_os   != IH_OS_LINUX)       ||
124             (hdr->ih_arch != IH_CPU_ARM)        ||
125             (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
126             printf ("No Linux ARM Ramdisk Image\n");
127             do_reset (cmdtp, flag, argc, argv);
128         }
129
130         /*
131          * Now check if we have a multifile image
132          */
133     } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
134         ulong tail    = ntohl(len_ptr[0]) % 4;
135         int i;
136
137         /* skip kernel length and terminator */
138         data = (ulong)(&len_ptr[2]);
139         /* skip any additional image length fields */
140         for (i=1; len_ptr[i]; ++i)
141           data += 4;
142         /* add kernel length, and align */
143         data += ntohl(len_ptr[0]);
144         if (tail) {
145             data += 4 - tail;
146         }
147
148         len   = ntohl(len_ptr[1]);
149
150     } else {
151         /*
152          * no initrd image
153          */
154         data = 0;
155     }
156
157 #ifdef  DEBUG
158     if (!data) {
159         printf ("No initrd\n");
160     }
161 #endif
162
163     if (data) {
164         initrd_start = data;
165         initrd_end   = initrd_start + len;
166     } else {
167         initrd_start = 0;
168         initrd_end = 0;
169     }
170
171 #ifdef DEBUG
172     printf ("## Transferring control to Linux (at address %08lx) ...\n",
173             (ulong)theKernel);
174 #endif
175
176 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
177     defined (CONFIG_CMDLINE_TAG) || \
178     defined (CONFIG_INITRD_TAG) || \
179     defined (CONFIG_VFD)
180     setup_start_tag(bd);
181 #ifdef CONFIG_SETUP_MEMORY_TAGS
182     setup_memory_tags(bd);
183 #endif
184 #ifdef CONFIG_CMDLINE_TAG
185     setup_commandline_tag(bd, commandline);
186 #endif
187 #ifdef CONFIG_INITRD_TAG
188     setup_initrd_tag(bd, initrd_start, initrd_end);
189 #endif
190 #if 0
191     setup_ramdisk_tag(bd);
192 #endif
193 #if defined (CONFIG_VFD)
194     setup_videolfb_tag(gd);
195 #endif
196     setup_end_tag(bd);
197 #endif
198
199     /* we assume that the kernel is in place */
200     printf("\nStarting kernel ...\n\n");
201
202     cleanup_before_linux();
203
204     theKernel(0, bd->bi_arch_number);
205 }
206
207
208 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
209     defined (CONFIG_CMDLINE_TAG) || \
210     defined (CONFIG_INITRD_TAG) || \
211     defined (CONFIG_VFD)
212 static void setup_start_tag(bd_t *bd)
213 {
214     params = (struct tag *)bd->bi_boot_params;
215
216     params->hdr.tag = ATAG_CORE;
217     params->hdr.size = tag_size(tag_core);
218
219     params->u.core.flags = 0;
220     params->u.core.pagesize = 0;
221     params->u.core.rootdev = 0;
222
223     params = tag_next(params);
224 }
225
226
227 #ifdef CONFIG_SETUP_MEMORY_TAGS
228 static void setup_memory_tags(bd_t *bd)
229 {
230     int i;
231
232     for(i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
233         params->hdr.tag = ATAG_MEM;
234         params->hdr.size = tag_size(tag_mem32);
235
236         params->u.mem.start = bd->bi_dram[i].start;
237         params->u.mem.size = bd->bi_dram[i].size;
238
239         params = tag_next(params);
240     }
241 }
242 #endif  /* CONFIG_SETUP_MEMORY_TAGS */
243
244
245 static void setup_commandline_tag(bd_t *bd, char *commandline)
246 {
247     char *p;
248
249     /* eat leading white space */
250     for(p = commandline; *p == ' '; p++)
251       ;
252
253     /* skip non-existent command lines so the kernel will still
254      * use its default command line.
255      */
256     if(*p == '\0')
257       return;
258
259     params->hdr.tag = ATAG_CMDLINE;
260     params->hdr.size = (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
261
262     strcpy(params->u.cmdline.cmdline, p);
263
264     params = tag_next(params);
265 }
266
267
268 #ifndef ATAG_INITRD2
269 #define ATAG_INITRD2    0x54420005
270 #endif
271
272 #ifdef CONFIG_INITRD_TAG
273 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
274 {
275     /* an ATAG_INITRD node tells the kernel where the compressed
276      * ramdisk can be found. ATAG_RDIMG is a better name, actually.
277      */
278     params->hdr.tag = ATAG_INITRD2;
279     params->hdr.size = tag_size(tag_initrd);
280
281     params->u.initrd.start = initrd_start;
282     params->u.initrd.size = initrd_end - initrd_start;
283
284     params = tag_next(params);
285 }
286 #endif  /* CONFIG_INITRD_TAG */
287
288
289 #if 0
290 static void setup_ramdisk_tag(bd_t *bd)
291 {
292     /* an ATAG_RAMDISK node tells the kernel how large the
293      * decompressed ramdisk will become.
294      */
295     params->hdr.tag = ATAG_RAMDISK;
296     params->hdr.size = tag_size(tag_ramdisk);
297
298     params->u.ramdisk.start = 0;
299     /*params->u.ramdisk.size = RAMDISK_SIZE; */
300     params->u.ramdisk.flags = 1;        /* automatically load ramdisk */
301
302     params = tag_next(params);
303 }
304 #endif /* 0 */
305
306 #if defined (CONFIG_VFD)
307 static void setup_videolfb_tag(gd_t *gd)
308 {
309     /* An ATAG_VIDEOLFB node tells the kernel where and how large
310      * the framebuffer for video was allocated (among other things).
311      * Note that a _physical_ address is passed !
312      *
313      * We only use it to pass the address and size, the other entries
314      * in the tag_videolfb are not of interest.
315      */
316     params->hdr.tag = ATAG_VIDEOLFB;
317     params->hdr.size = tag_size(tag_videolfb);
318
319     params->u.videolfb.lfb_base = (u32)gd->fb_base;
320     /* 7168 = 256*4*56/8 - actually 2 pages (8192 bytes) are allocated */
321     params->u.videolfb.lfb_size = 7168;
322
323     params = tag_next(params);
324 }
325 #endif
326
327 static void setup_end_tag(bd_t *bd)
328 {
329     params->hdr.tag = ATAG_NONE;
330     params->hdr.size = 0;
331 }
332
333 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */