bootm: refactor entry point code
[platform/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         void    (*theKernel)(int magic, void *tagtable);
181         struct  tag *params, *params_start;
182         char    *commandline = getenv("bootargs");
183         int     ret;
184
185         theKernel = (void *)images->ep;
186
187         ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_AVR32,
188                         &initrd_start, &initrd_end);
189         if (ret)
190                 goto error;
191
192         show_boot_progress (15);
193
194         params = params_start = (struct tag *)gd->bd->bi_boot_params;
195         params = setup_start_tag(params);
196         params = setup_memory_tags(params);
197         if (initrd_start) {
198                 params = setup_ramdisk_tag(params,
199                                            PHYSADDR(initrd_start),
200                                            PHYSADDR(initrd_end));
201         }
202         params = setup_commandline_tag(params, commandline);
203         params = setup_clock_tags(params);
204         params = setup_ethernet_tags(params);
205         setup_end_tag(params);
206
207         printf("\nStarting kernel at %p (params at %p)...\n\n",
208                theKernel, params_start);
209
210         prepare_to_boot();
211
212         theKernel(ATAG_MAGIC, params_start);
213         /* does not return */
214         return;
215
216 error:
217         do_reset (cmdtp, flag, argc, argv);
218         return;
219 }