blob: ab539f4036fe69b01f1003d15efbc7fb6e33fd4b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Macpaul Lin0d1f4742011-10-11 22:33:19 +00002/*
3 * Copyright (C) 2011 Andes Technology Corporation
4 * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
5 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
Macpaul Lin0d1f4742011-10-11 22:33:19 +00006 */
7
8#include <common.h>
Simon Glass1ea97892020-05-10 11:40:00 -06009#include <bootstage.h>
Macpaul Lin0d1f4742011-10-11 22:33:19 +000010#include <command.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060011#include <env.h>
Simon Glassf11478f2019-12-28 10:45:07 -070012#include <hang.h>
Macpaul Lin0d1f4742011-10-11 22:33:19 +000013#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Macpaul Lin0d1f4742011-10-11 22:33:19 +000015#include <u-boot/zlib.h>
16#include <asm/byteorder.h>
rickf1113c92017-05-18 14:37:53 +080017#include <asm/bootm.h>
Macpaul Lin0d1f4742011-10-11 22:33:19 +000018
19DECLARE_GLOBAL_DATA_PTR;
20
21#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
22 defined(CONFIG_CMDLINE_TAG) || \
23 defined(CONFIG_INITRD_TAG) || \
24 defined(CONFIG_SERIAL_TAG) || \
25 defined(CONFIG_REVISION_TAG)
26static void setup_start_tag(bd_t *bd);
27
28# ifdef CONFIG_SETUP_MEMORY_TAGS
29static void setup_memory_tags(bd_t *bd);
30# endif
31static void setup_commandline_tag(bd_t *bd, char *commandline);
32
33# ifdef CONFIG_INITRD_TAG
34static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
35# endif
36static void setup_end_tag(bd_t *bd);
37
38static struct tag *params;
39#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
40
41int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
42{
43 bd_t *bd = gd->bd;
44 char *s;
45 int machid = bd->bi_arch_number;
46 void (*theKernel)(int zero, int arch, uint params);
47
48#ifdef CONFIG_CMDLINE_TAG
Simon Glass64b723f2017-08-03 12:22:12 -060049 char *commandline = env_get("bootargs");
Macpaul Lin0d1f4742011-10-11 22:33:19 +000050#endif
51
Andreas Bießmannda233ce2013-07-02 13:57:44 +020052 /*
53 * allow the PREP bootm subcommand, it is required for bootm to work
54 */
55 if (flag & BOOTM_STATE_OS_PREP)
56 return 0;
57
Macpaul Lin0d1f4742011-10-11 22:33:19 +000058 if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
59 return 1;
60
61 theKernel = (void (*)(int, int, uint))images->ep;
62
Simon Glass64b723f2017-08-03 12:22:12 -060063 s = env_get("machid");
Macpaul Lin0d1f4742011-10-11 22:33:19 +000064 if (s) {
65 machid = simple_strtoul(s, NULL, 16);
66 printf("Using machid 0x%x from environment\n", machid);
67 }
68
Simon Glass0169e6b2012-02-13 13:51:18 +000069 bootstage_mark(BOOTSTAGE_ID_RUN_OS);
Macpaul Lin0d1f4742011-10-11 22:33:19 +000070
71 debug("## Transferring control to Linux (at address %08lx) ...\n",
72 (ulong)theKernel);
73
rickf1113c92017-05-18 14:37:53 +080074 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
75#ifdef CONFIG_OF_LIBFDT
76 debug("using: FDT\n");
77 if (image_setup_linux(images)) {
78 printf("FDT creation failed! hanging...");
79 hang();
80 }
81#endif
82 } else if (BOOTM_ENABLE_TAGS) {
Macpaul Lin0d1f4742011-10-11 22:33:19 +000083#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
84 defined(CONFIG_CMDLINE_TAG) || \
85 defined(CONFIG_INITRD_TAG) || \
86 defined(CONFIG_SERIAL_TAG) || \
87 defined(CONFIG_REVISION_TAG)
88 setup_start_tag(bd);
89#ifdef CONFIG_SERIAL_TAG
90 setup_serial_tag(&params);
91#endif
92#ifdef CONFIG_REVISION_TAG
93 setup_revision_tag(&params);
94#endif
95#ifdef CONFIG_SETUP_MEMORY_TAGS
96 setup_memory_tags(bd);
97#endif
98#ifdef CONFIG_CMDLINE_TAG
99 setup_commandline_tag(bd, commandline);
100#endif
101#ifdef CONFIG_INITRD_TAG
102 if (images->rd_start && images->rd_end)
103 setup_initrd_tag(bd, images->rd_start, images->rd_end);
104#endif
105 setup_end_tag(bd);
106#endif
107
108 /* we assume that the kernel is in place */
109 printf("\nStarting kernel ...\n\n");
110
111#ifdef CONFIG_USB_DEVICE
112 {
113 extern void udc_disconnect(void);
114 udc_disconnect();
115 }
116#endif
rickf1113c92017-05-18 14:37:53 +0800117 }
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000118 cleanup_before_linux();
rickf1113c92017-05-18 14:37:53 +0800119 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
120 theKernel(0, machid, (unsigned long)images->ft_addr);
121 else
122 theKernel(0, machid, bd->bi_boot_params);
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000123 /* does not return */
124
125 return 1;
126}
127
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000128#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
129 defined(CONFIG_CMDLINE_TAG) || \
130 defined(CONFIG_INITRD_TAG) || \
131 defined(CONFIG_SERIAL_TAG) || \
132 defined(CONFIG_REVISION_TAG)
133static void setup_start_tag(bd_t *bd)
134{
135 params = (struct tag *)bd->bi_boot_params;
136
137 params->hdr.tag = ATAG_CORE;
138 params->hdr.size = tag_size(tag_core);
139
140 params->u.core.flags = 0;
141 params->u.core.pagesize = 0;
142 params->u.core.rootdev = 0;
143
144 params = tag_next(params);
145}
146
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000147#ifdef CONFIG_SETUP_MEMORY_TAGS
148static void setup_memory_tags(bd_t *bd)
149{
150 int i;
151
152 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
153 params->hdr.tag = ATAG_MEM;
154 params->hdr.size = tag_size(tag_mem32);
155
156 params->u.mem.start = bd->bi_dram[i].start;
157 params->u.mem.size = bd->bi_dram[i].size;
158
159 params = tag_next(params);
160 }
161}
162#endif /* CONFIG_SETUP_MEMORY_TAGS */
163
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000164static void setup_commandline_tag(bd_t *bd, char *commandline)
165{
166 char *p;
167
168 if (!commandline)
169 return;
170
171 /* eat leading white space */
172 for (p = commandline; *p == ' '; p++)
173 ;
174
175 /* skip non-existent command lines so the kernel will still
176 * use its default command line.
177 */
178 if (*p == '\0')
179 return;
180
181 params->hdr.tag = ATAG_CMDLINE;
182 params->hdr.size =
183 (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
184
185 strcpy(params->u.cmdline.cmdline, p)
186 ;
187
188 params = tag_next(params);
189}
190
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000191#ifdef CONFIG_INITRD_TAG
192static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
193{
194 /* an ATAG_INITRD node tells the kernel where the compressed
195 * ramdisk can be found. ATAG_RDIMG is a better name, actually.
196 */
197 params->hdr.tag = ATAG_INITRD2;
198 params->hdr.size = tag_size(tag_initrd);
199
200 params->u.initrd.start = initrd_start;
201 params->u.initrd.size = initrd_end - initrd_start;
202
203 params = tag_next(params);
204}
205#endif /* CONFIG_INITRD_TAG */
206
207#ifdef CONFIG_SERIAL_TAG
208void setup_serial_tag(struct tag **tmp)
209{
210 struct tag *params = *tmp;
211 struct tag_serialnr serialnr;
212 void get_board_serial(struct tag_serialnr *serialnr);
213
214 get_board_serial(&serialnr);
215 params->hdr.tag = ATAG_SERIAL;
216 params->hdr.size = tag_size(tag_serialnr);
217 params->u.serialnr.low = serialnr.low;
218 params->u.serialnr.high = serialnr.high;
219 params = tag_next(params);
220 *tmp = params;
221}
222#endif
223
224#ifdef CONFIG_REVISION_TAG
225void setup_revision_tag(struct tag **in_params)
226{
227 u32 rev = 0;
228 u32 get_board_rev(void);
229
230 rev = get_board_rev();
231 params->hdr.tag = ATAG_REVISION;
232 params->hdr.size = tag_size(tag_revision);
233 params->u.revision.rev = rev;
234 params = tag_next(params);
235}
236#endif /* CONFIG_REVISION_TAG */
237
Macpaul Lin0d1f4742011-10-11 22:33:19 +0000238static void setup_end_tag(bd_t *bd)
239{
240 params->hdr.tag = ATAG_NONE;
241 params->hdr.size = 0;
242}
243
244#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */