455590e37dd6fbbee8f5a4af7108605671bb62d2
[platform/kernel/u-boot.git] / lib_avr32 / avr32_linux.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 extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
35
36 /* CPU-specific hook to allow flushing of caches, etc. */
37 extern void prepare_to_boot(void);
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                     image_header_t *hdr, int verify)
178 {
179         ulong rd_data, rd_len = 0;
180         ulong initrd_start, initrd_end;
181         image_header_t *rd_hdr;
182
183         void (*theKernel)(int magic, void *tagtable);
184         struct tag *params, *params_start;
185         char *commandline = getenv("bootargs");
186
187         theKernel = (void *)image_get_ep (hdr);
188
189         /*
190          * Check if there is an initrd image
191          */
192         if (argc >= 3) {
193                 show_boot_progress (9);
194
195                 rd_hdr = (image_header_t *)simple_strtoul (argv[2], NULL, 16);
196                 printf ("## Loading RAMDISK image at %08lx ...\n", rd_hdr);
197
198                 if (!image_check_magic (rd_hdr)) {
199                         puts("Bad Magic Number\n");
200                         show_boot_progress (-10);
201                         do_reset(cmdtp, flag, argc, argv);
202                 }
203
204                 if (!image_check_hcrc (rd_hdr)) {
205                         puts("Bad Header Checksum\n");
206                         show_boot_progress (-11);
207                         do_reset(cmdtp, flag, argc, argv);
208                 }
209
210                 show_boot_progress (10);
211                 print_image_hdr (rd_hdr);
212
213                 if (verify) {
214                         puts("   Verifying Checksum ... ");
215                         if (!image_check_dcrc (rd_hdr)) {
216                                 puts("Bad Data CRC\n");
217                                 show_boot_progress (-12);
218                                 do_reset(cmdtp, flag, argc, argv);
219                         }
220                         puts("OK\n");
221                 }
222
223                 show_boot_progress (11);
224
225                 if (!image_check_os (rd_hdr, IH_OS_LINUX) ||
226                     !image_check_arch (rd_hdr, IH_ARCH_AVR32) ||
227                     !image_check_type (rd_hdr, IH_TYPE_RAMDISK)) {
228                         puts("Not a Linux/AVR32 RAMDISK image\n");
229                         show_boot_progress (-13);
230                         do_reset(cmdtp, flag, argc, argv);
231                 }
232
233                 rd_data = image_get_data (rd_hdr);
234                 rd_len = image_get_data_size (rd_hdr);
235
236         } else if (image_check_type (hdr, IH_TYPE_MULTI)) {
237                 /*
238                  * Get second entry data start address and len
239                  */
240                 show_boot_progress (13);
241                 image_multi_getimg (hdr, 1, &rd_data, &rd_len);
242         } else {
243                 /* no initrd image */
244                 show_boot_progress (14);
245                 rd_len = rd_data = 0;
246         }
247
248         if (rd_data) {
249                 initrd_start = rd_data;
250                 initrd_end = initrd_start + rd_len;
251         } else {
252                 initrd_start = 0;
253                 initrd_end = 0;
254         }
255
256         show_boot_progress (15);
257
258         params = params_start = (struct tag *)gd->bd->bi_boot_params;
259         params = setup_start_tag(params);
260         params = setup_memory_tags(params);
261         if (initrd_start) {
262                 params = setup_ramdisk_tag(params,
263                                            PHYSADDR(initrd_start),
264                                            PHYSADDR(initrd_end));
265         }
266         params = setup_commandline_tag(params, commandline);
267         params = setup_clock_tags(params);
268         params = setup_ethernet_tags(params);
269         setup_end_tag(params);
270
271         printf("\nStarting kernel at %p (params at %p)...\n\n",
272                theKernel, params_start);
273
274         prepare_to_boot();
275
276         theKernel(ATAG_MAGIC, params_start);
277 }