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