]>
Commit | Line | Data |
---|---|---|
7b64fef3 WD |
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> | |
df548d3c | 30 | #include <asm/arch/clk.h> |
7b64fef3 WD |
31 | |
32 | DECLARE_GLOBAL_DATA_PTR; | |
33 | ||
7b64fef3 WD |
34 | /* CPU-specific hook to allow flushing of caches, etc. */ |
35 | extern void prepare_to_boot(void); | |
36 | ||
d5934ad7 MB |
37 | extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); |
38 | ||
7b64fef3 WD |
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; | |
df548d3c | 127 | params->u.clock.clock_hz = get_hsb_clk_rate(); |
7b64fef3 WD |
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[], | |
8a5ea3e6 | 177 | bootm_headers_t *images) |
7b64fef3 | 178 | { |
d5934ad7 MB |
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"); | |
cd7c596e | 184 | int ret; |
d5934ad7 MB |
185 | |
186 | /* find kernel entry point */ | |
187 | if (images->legacy_hdr_valid) { | |
cb1c4896 | 188 | ep = image_get_ep (&images->legacy_hdr_os_copy); |
d5934ad7 MB |
189 | #if defined(CONFIG_FIT) |
190 | } else if (images->fit_uname_os) { | |
cd7c596e MB |
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 | } | |
d5934ad7 MB |
197 | #endif |
198 | } else { | |
199 | puts ("Could not find kernel entry point!\n"); | |
cd7c596e | 200 | goto error; |
d5934ad7 MB |
201 | } |
202 | theKernel = (void *)ep; | |
7b64fef3 | 203 | |
d985c849 MB |
204 | ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_AVR32, |
205 | &initrd_start, &initrd_end); | |
206 | if (ret) | |
cd7c596e | 207 | goto error; |
7b64fef3 | 208 | |
fad63407 | 209 | show_boot_progress (15); |
7b64fef3 WD |
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 | ||
75fa002c KG |
224 | if (!images->autostart) |
225 | return ; | |
226 | ||
7b64fef3 WD |
227 | printf("\nStarting kernel at %p (params at %p)...\n\n", |
228 | theKernel, params_start); | |
229 | ||
230 | prepare_to_boot(); | |
231 | ||
232 | theKernel(ATAG_MAGIC, params_start); | |
cd7c596e MB |
233 | /* does not return */ |
234 | return; | |
235 | ||
236 | error: | |
237 | if (images->autostart) | |
238 | do_reset (cmdtp, flag, argc, argv); | |
239 | return; | |
7b64fef3 | 240 | } |