Merge branch 'master' of /home/stefan/git/u-boot/u-boot into next
[kernel/u-boot.git] / lib_avr32 / bootm.c
1 /*
2  * Copyright (C) 2004-2006 Atmel Corporation
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #include <common.h>
23 #include <command.h>
24 #include <image.h>
25 #include <zlib.h>
26 #include <asm/byteorder.h>
27 #include <asm/addrspace.h>
28 #include <asm/io.h>
29 #include <asm/setup.h>
30 #include <asm/arch/clk.h>
31
32 DECLARE_GLOBAL_DATA_PTR;
33
34 /* CPU-specific hook to allow flushing of caches, etc. */
35 extern void prepare_to_boot(void);
36
37 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
38
39 static struct tag *setup_start_tag(struct tag *params)
40 {
41         params->hdr.tag = ATAG_CORE;
42         params->hdr.size = tag_size(tag_core);
43
44         params->u.core.flags = 0;
45         params->u.core.pagesize = 4096;
46         params->u.core.rootdev = 0;
47
48         return tag_next(params);
49 }
50
51 static struct tag *setup_memory_tags(struct tag *params)
52 {
53         bd_t *bd = gd->bd;
54         int i;
55
56         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
57                 params->hdr.tag = ATAG_MEM;
58                 params->hdr.size = tag_size(tag_mem_range);
59
60                 params->u.mem_range.addr = bd->bi_dram[i].start;
61                 params->u.mem_range.size = bd->bi_dram[i].size;
62
63                 params = tag_next(params);
64         }
65
66         return params;
67 }
68
69 static struct tag *setup_commandline_tag(struct tag *params, char *cmdline)
70 {
71         if (!cmdline)
72                 return params;
73
74         /* eat leading white space */
75         while (*cmdline == ' ') cmdline++;
76
77         /*
78          * Don't include tags for empty command lines; let the kernel
79          * use its default command line.
80          */
81         if (*cmdline == '\0')
82                 return params;
83
84         params->hdr.tag = ATAG_CMDLINE;
85         params->hdr.size =
86                 (sizeof (struct tag_header) + strlen(cmdline) + 1 + 3) >> 2;
87         strcpy(params->u.cmdline.cmdline, cmdline);
88
89         return tag_next(params);
90 }
91
92 static struct tag *setup_ramdisk_tag(struct tag *params,
93                                      unsigned long rd_start,
94                                      unsigned long rd_end)
95 {
96         if (rd_start == rd_end)
97                 return params;
98
99         params->hdr.tag = ATAG_RDIMG;
100         params->hdr.size = tag_size(tag_mem_range);
101
102         params->u.mem_range.addr = rd_start;
103         params->u.mem_range.size = rd_end - rd_start;
104
105         return tag_next(params);
106 }
107
108 static struct tag *setup_clock_tags(struct tag *params)
109 {
110         params->hdr.tag = ATAG_CLOCK;
111         params->hdr.size = tag_size(tag_clock);
112         params->u.clock.clock_id = ACLOCK_BOOTCPU;
113         params->u.clock.clock_flags = 0;
114         params->u.clock.clock_hz = gd->cpu_hz;
115
116 #ifdef CONFIG_AT32AP7000
117         /*
118          * New kernels don't need this, but we should be backwards
119          * compatible for a while...
120          */
121         params = tag_next(params);
122
123         params->hdr.tag = ATAG_CLOCK;
124         params->hdr.size = tag_size(tag_clock);
125         params->u.clock.clock_id = ACLOCK_HSB;
126         params->u.clock.clock_flags = 0;
127         params->u.clock.clock_hz = get_hsb_clk_rate();
128 #endif
129
130         return tag_next(params);
131 }
132
133 static struct tag *setup_ethernet_tag(struct tag *params,
134                                       char *addr, int index)
135 {
136         char *s, *e;
137         int i;
138
139         params->hdr.tag = ATAG_ETHERNET;
140         params->hdr.size = tag_size(tag_ethernet);
141
142         params->u.ethernet.mac_index = index;
143         params->u.ethernet.mii_phy_addr = gd->bd->bi_phy_id[index];
144
145         s = addr;
146         for (i = 0; i < 6; i++) {
147                 params->u.ethernet.hw_address[i] = simple_strtoul(s, &e, 16);
148                 s = e + 1;
149         }
150
151         return tag_next(params);
152 }
153
154 static struct tag *setup_ethernet_tags(struct tag *params)
155 {
156         char name[16] = "ethaddr";
157         char *addr;
158         int i = 0;
159
160         do {
161                 addr = getenv(name);
162                 if (addr)
163                         params = setup_ethernet_tag(params, addr, i);
164                 sprintf(name, "eth%daddr", ++i);
165         } while (i < 4);
166
167         return params;
168 }
169
170 static void setup_end_tag(struct tag *params)
171 {
172         params->hdr.tag = ATAG_NONE;
173         params->hdr.size = 0;
174 }
175
176 void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
177                     bootm_headers_t *images)
178 {
179         ulong   initrd_start, initrd_end;
180         ulong   ep = 0;
181         void    (*theKernel)(int magic, void *tagtable);
182         struct  tag *params, *params_start;
183         char    *commandline = getenv("bootargs");
184         int     ret;
185
186         /* find kernel entry point */
187         if (images->legacy_hdr_valid) {
188                 ep = image_get_ep (&images->legacy_hdr_os_copy);
189 #if defined(CONFIG_FIT)
190         } else if (images->fit_uname_os) {
191                 ret = fit_image_get_entry (images->fit_hdr_os,
192                                 images->fit_noffset_os, &ep);
193                 if (ret) {
194                         puts ("Can't get entry point property!\n");
195                         goto error;
196                 }
197 #endif
198         } else {
199                 puts ("Could not find kernel entry point!\n");
200                 goto error;
201         }
202         theKernel = (void *)ep;
203
204         ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_AVR32,
205                         &initrd_start, &initrd_end);
206         if (ret)
207                 goto error;
208
209         show_boot_progress (15);
210
211         params = params_start = (struct tag *)gd->bd->bi_boot_params;
212         params = setup_start_tag(params);
213         params = setup_memory_tags(params);
214         if (initrd_start) {
215                 params = setup_ramdisk_tag(params,
216                                            PHYSADDR(initrd_start),
217                                            PHYSADDR(initrd_end));
218         }
219         params = setup_commandline_tag(params, commandline);
220         params = setup_clock_tags(params);
221         params = setup_ethernet_tags(params);
222         setup_end_tag(params);
223
224         printf("\nStarting kernel at %p (params at %p)...\n\n",
225                theKernel, params_start);
226
227         prepare_to_boot();
228
229         theKernel(ATAG_MAGIC, params_start);
230         /* does not return */
231         return;
232
233 error:
234         do_reset (cmdtp, flag, argc, argv);
235         return;
236 }