blob: eedab9d11944e9d78b028d12770a13f3003eff31 [file] [log] [blame]
Wolfgang Denk83c15852006-10-24 14:21:16 +02001/*
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>
Jean-Christophe PLAGNIOL-VILLARD6bb94492009-04-04 12:49:11 +020025#include <u-boot/zlib.h>
Wolfgang Denk83c15852006-10-24 14:21:16 +020026#include <asm/byteorder.h>
Olav Morken51b2ec92009-01-23 12:56:28 +010027#include <asm/arch/addrspace.h>
Wolfgang Denk83c15852006-10-24 14:21:16 +020028#include <asm/io.h>
29#include <asm/setup.h>
Haavard Skinnemoen0a2743f2006-11-19 18:06:53 +010030#include <asm/arch/clk.h>
Wolfgang Denk83c15852006-10-24 14:21:16 +020031
32DECLARE_GLOBAL_DATA_PTR;
33
Wolfgang Denk83c15852006-10-24 14:21:16 +020034/* CPU-specific hook to allow flushing of caches, etc. */
35extern void prepare_to_boot(void);
36
Wolfgang Denk83c15852006-10-24 14:21:16 +020037static struct tag *setup_start_tag(struct tag *params)
38{
39 params->hdr.tag = ATAG_CORE;
40 params->hdr.size = tag_size(tag_core);
41
42 params->u.core.flags = 0;
43 params->u.core.pagesize = 4096;
44 params->u.core.rootdev = 0;
45
46 return tag_next(params);
47}
48
49static struct tag *setup_memory_tags(struct tag *params)
50{
51 bd_t *bd = gd->bd;
52 int i;
53
54 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
55 params->hdr.tag = ATAG_MEM;
56 params->hdr.size = tag_size(tag_mem_range);
57
58 params->u.mem_range.addr = bd->bi_dram[i].start;
59 params->u.mem_range.size = bd->bi_dram[i].size;
60
61 params = tag_next(params);
62 }
63
64 return params;
65}
66
67static struct tag *setup_commandline_tag(struct tag *params, char *cmdline)
68{
69 if (!cmdline)
70 return params;
71
72 /* eat leading white space */
73 while (*cmdline == ' ') cmdline++;
74
75 /*
76 * Don't include tags for empty command lines; let the kernel
77 * use its default command line.
78 */
79 if (*cmdline == '\0')
80 return params;
81
82 params->hdr.tag = ATAG_CMDLINE;
83 params->hdr.size =
84 (sizeof (struct tag_header) + strlen(cmdline) + 1 + 3) >> 2;
85 strcpy(params->u.cmdline.cmdline, cmdline);
86
87 return tag_next(params);
88}
89
90static struct tag *setup_ramdisk_tag(struct tag *params,
91 unsigned long rd_start,
92 unsigned long rd_end)
93{
94 if (rd_start == rd_end)
95 return params;
96
97 params->hdr.tag = ATAG_RDIMG;
98 params->hdr.size = tag_size(tag_mem_range);
99
100 params->u.mem_range.addr = rd_start;
101 params->u.mem_range.size = rd_end - rd_start;
102
103 return tag_next(params);
104}
105
106static struct tag *setup_clock_tags(struct tag *params)
107{
108 params->hdr.tag = ATAG_CLOCK;
109 params->hdr.size = tag_size(tag_clock);
110 params->u.clock.clock_id = ACLOCK_BOOTCPU;
111 params->u.clock.clock_flags = 0;
Simon Glass421b7c02012-12-13 20:49:10 +0000112 params->u.clock.clock_hz = gd->arch.cpu_hz;
Wolfgang Denk83c15852006-10-24 14:21:16 +0200113
114#ifdef CONFIG_AT32AP7000
115 /*
116 * New kernels don't need this, but we should be backwards
117 * compatible for a while...
118 */
119 params = tag_next(params);
120
121 params->hdr.tag = ATAG_CLOCK;
122 params->hdr.size = tag_size(tag_clock);
123 params->u.clock.clock_id = ACLOCK_HSB;
124 params->u.clock.clock_flags = 0;
Haavard Skinnemoen0a2743f2006-11-19 18:06:53 +0100125 params->u.clock.clock_hz = get_hsb_clk_rate();
Wolfgang Denk83c15852006-10-24 14:21:16 +0200126#endif
127
128 return tag_next(params);
129}
130
131static struct tag *setup_ethernet_tag(struct tag *params,
132 char *addr, int index)
133{
134 char *s, *e;
135 int i;
136
137 params->hdr.tag = ATAG_ETHERNET;
138 params->hdr.size = tag_size(tag_ethernet);
139
140 params->u.ethernet.mac_index = index;
141 params->u.ethernet.mii_phy_addr = gd->bd->bi_phy_id[index];
142
143 s = addr;
144 for (i = 0; i < 6; i++) {
145 params->u.ethernet.hw_address[i] = simple_strtoul(s, &e, 16);
146 s = e + 1;
147 }
148
149 return tag_next(params);
150}
151
152static struct tag *setup_ethernet_tags(struct tag *params)
153{
154 char name[16] = "ethaddr";
155 char *addr;
156 int i = 0;
157
158 do {
159 addr = getenv(name);
160 if (addr)
161 params = setup_ethernet_tag(params, addr, i);
162 sprintf(name, "eth%daddr", ++i);
163 } while (i < 4);
164
165 return params;
166}
167
Andreas Bießmannebc39932011-04-12 23:25:41 +0000168static struct tag *setup_boardinfo_tag(struct tag *params)
169{
170 params->hdr.tag = ATAG_BOARDINFO;
171 params->hdr.size = tag_size(tag_boardinfo);
172
173 params->u.boardinfo.board_number = gd->bd->bi_board_number;
174
175 return tag_next(params);
176}
177
Wolfgang Denk83c15852006-10-24 14:21:16 +0200178static void setup_end_tag(struct tag *params)
179{
180 params->hdr.tag = ATAG_NONE;
181 params->hdr.size = 0;
182}
183
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200184int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
Wolfgang Denk83c15852006-10-24 14:21:16 +0200185{
Marian Balakowiczdbdd16a2008-02-04 08:28:09 +0100186 void (*theKernel)(int magic, void *tagtable);
187 struct tag *params, *params_start;
188 char *commandline = getenv("bootargs");
Wolfgang Denk83c15852006-10-24 14:21:16 +0200189
Andreas Bießmannda233ce2013-07-02 13:57:44 +0200190 /*
191 * allow the PREP bootm subcommand, it is required for bootm to work
192 *
193 * TODO: Andreas Bießmann <andreas.devel@googlemail.com> refactor the
194 * do_bootm_linux() for avr32
195 */
196 if (flag & BOOTM_STATE_OS_PREP)
197 return 0;
198
Kumar Gala18178bc2008-10-21 17:25:45 -0500199 if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
200 return 1;
201
Kumar Gala93467bc2008-08-15 08:24:36 -0500202 theKernel = (void *)images->ep;
Wolfgang Denk83c15852006-10-24 14:21:16 +0200203
Simon Glass0169e6b2012-02-13 13:51:18 +0000204 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
Wolfgang Denk83c15852006-10-24 14:21:16 +0200205
206 params = params_start = (struct tag *)gd->bd->bi_boot_params;
207 params = setup_start_tag(params);
208 params = setup_memory_tags(params);
Kumar Galafffb1432008-08-15 08:24:37 -0500209 if (images->rd_start) {
Wolfgang Denk83c15852006-10-24 14:21:16 +0200210 params = setup_ramdisk_tag(params,
Kumar Galafffb1432008-08-15 08:24:37 -0500211 PHYSADDR(images->rd_start),
212 PHYSADDR(images->rd_end));
Wolfgang Denk83c15852006-10-24 14:21:16 +0200213 }
214 params = setup_commandline_tag(params, commandline);
215 params = setup_clock_tags(params);
216 params = setup_ethernet_tags(params);
Andreas Bießmannebc39932011-04-12 23:25:41 +0000217 params = setup_boardinfo_tag(params);
Wolfgang Denk83c15852006-10-24 14:21:16 +0200218 setup_end_tag(params);
219
Wolfgang Denk83c15852006-10-24 14:21:16 +0200220 printf("\nStarting kernel at %p (params at %p)...\n\n",
221 theKernel, params_start);
222
223 prepare_to_boot();
224
225 theKernel(ATAG_MAGIC, params_start);
Marian Balakowiczdf8ff332008-03-12 10:33:00 +0100226 /* does not return */
Jean-Christophe PLAGNIOL-VILLARD7ed7a272008-09-10 22:48:09 +0200227
Kumar Gala48626aa2008-08-15 08:24:45 -0500228 return 1;
Wolfgang Denk83c15852006-10-24 14:21:16 +0200229}