xref: /openbmc/u-boot/arch/xtensa/lib/bootm.c (revision e8f80a5a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2008 - 2013 Tensilica Inc.
4  * (C) Copyright 2014 Cadence Design Systems Inc.
5  */
6 
7 #include <common.h>
8 #include <command.h>
9 #include <u-boot/zlib.h>
10 #include <asm/byteorder.h>
11 #include <asm/addrspace.h>
12 #include <asm/bootparam.h>
13 #include <asm/cache.h>
14 #include <image.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 /*
19  * Setup boot-parameters.
20  */
21 
setup_first_tag(struct bp_tag * params)22 static struct bp_tag *setup_first_tag(struct bp_tag *params)
23 {
24 	params->id = BP_TAG_FIRST;
25 	params->size = sizeof(long);
26 	*(unsigned long *)&params->data = BP_VERSION;
27 
28 	return bp_tag_next(params);
29 }
30 
setup_last_tag(struct bp_tag * params)31 static struct bp_tag *setup_last_tag(struct bp_tag *params)
32 {
33 	params->id = BP_TAG_LAST;
34 	params->size = 0;
35 
36 	return bp_tag_next(params);
37 }
38 
setup_memory_tag(struct bp_tag * params)39 static struct bp_tag *setup_memory_tag(struct bp_tag *params)
40 {
41 	struct bd_info *bd = gd->bd;
42 	struct meminfo *mem;
43 
44 	params->id = BP_TAG_MEMORY;
45 	params->size = sizeof(struct meminfo);
46 	mem = (struct meminfo *)params->data;
47 	mem->type = MEMORY_TYPE_CONVENTIONAL;
48 	mem->start = bd->bi_memstart;
49 	mem->end = bd->bi_memstart + bd->bi_memsize;
50 
51 	printf("   MEMORY:          tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n",
52 	       BP_TAG_MEMORY, mem->type, mem->start, mem->end);
53 
54 	return bp_tag_next(params);
55 }
56 
setup_commandline_tag(struct bp_tag * params,char * cmdline)57 static struct bp_tag *setup_commandline_tag(struct bp_tag *params,
58 					    char *cmdline)
59 {
60 	int len;
61 
62 	if (!cmdline)
63 		return params;
64 
65 	len = strlen(cmdline);
66 
67 	params->id = BP_TAG_COMMAND_LINE;
68 	params->size = (len + 3) & -4;
69 	strcpy((char *)params->data, cmdline);
70 
71 	printf("   COMMAND_LINE:    tag:0x%04x, size:%u, data:'%s'\n",
72 	       BP_TAG_COMMAND_LINE, params->size, cmdline);
73 
74 	return bp_tag_next(params);
75 }
76 
setup_ramdisk_tag(struct bp_tag * params,unsigned long rd_start,unsigned long rd_end)77 static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params,
78 					unsigned long rd_start,
79 					unsigned long rd_end)
80 {
81 	struct meminfo *mem;
82 
83 	if (rd_start == rd_end)
84 		return params;
85 
86 	/* Add a single banked memory */
87 
88 	params->id = BP_TAG_INITRD;
89 	params->size = sizeof(struct meminfo);
90 
91 	mem = (struct meminfo *)params->data;
92 	mem->type =  MEMORY_TYPE_CONVENTIONAL;
93 	mem->start = PHYSADDR(rd_start);
94 	mem->end = PHYSADDR(rd_end);
95 
96 	printf("   INITRD:          tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n",
97 	       BP_TAG_INITRD, mem->type, mem->start, mem->end);
98 
99 	return bp_tag_next(params);
100 }
101 
setup_serial_tag(struct bp_tag * params)102 static struct bp_tag *setup_serial_tag(struct bp_tag *params)
103 {
104 	params->id = BP_TAG_SERIAL_BAUDRATE;
105 	params->size = sizeof(unsigned long);
106 	params->data[0] = gd->baudrate;
107 
108 	printf("   SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n",
109 	       BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]);
110 
111 	return bp_tag_next(params);
112 }
113 
114 #ifdef CONFIG_OF_LIBFDT
115 
setup_fdt_tag(struct bp_tag * params,void * fdt_start)116 static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start)
117 {
118 	params->id = BP_TAG_FDT;
119 	params->size = sizeof(unsigned long);
120 	params->data[0] = (unsigned long)fdt_start;
121 
122 	printf("   FDT:             tag:0x%04x, size:%u, start:0x%lx\n",
123 	       BP_TAG_FDT, params->size, params->data[0]);
124 
125 	return bp_tag_next(params);
126 }
127 
128 #endif
129 
130 /*
131  * Boot Linux.
132  */
133 
do_bootm_linux(int flag,int argc,char * argv[],bootm_headers_t * images)134 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
135 {
136 	struct bp_tag *params, *params_start;
137 	ulong initrd_start, initrd_end;
138 	char *commandline = env_get("bootargs");
139 
140 	if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)))
141 		return 0;
142 
143 	show_boot_progress(15);
144 
145 	if (images->rd_start) {
146 		initrd_start = images->rd_start;
147 		initrd_end = images->rd_end;
148 	} else {
149 		initrd_start = 0;
150 		initrd_end = 0;
151 	}
152 
153 	params_start = (struct bp_tag *)gd->bd->bi_boot_params;
154 	params = params_start;
155 	params = setup_first_tag(params);
156 	params = setup_memory_tag(params);
157 	params = setup_commandline_tag(params, commandline);
158 	params = setup_serial_tag(params);
159 
160 	if (initrd_start)
161 		params = setup_ramdisk_tag(params, initrd_start, initrd_end);
162 
163 #ifdef CONFIG_OF_LIBFDT
164 	if (images->ft_addr)
165 		params = setup_fdt_tag(params, images->ft_addr);
166 #endif
167 
168 	printf("\n");
169 
170 	params = setup_last_tag(params);
171 
172 	show_boot_progress(15);
173 
174 	printf("Transferring Control to Linux @0x%08lx ...\n\n",
175 	       (ulong)images->ep);
176 
177 	flush_dcache_range((unsigned long)params_start, (unsigned long)params);
178 
179 	if (flag & BOOTM_STATE_OS_FAKE_GO)
180 		return 0;
181 
182 	/*
183 	 * _start() in vmlinux expects boot params in register a2.
184 	 * NOTE:
185 	 *    Disable/delete your u-boot breakpoints before stepping into linux.
186 	 */
187 	asm volatile ("mov	a2, %0\n\t"
188 		      "jx	%1\n\t"
189 		      : : "a" (params_start), "a" (images->ep)
190 		      : "a2");
191 
192 	/* Does not return */
193 
194 	return 1;
195 }
196 
197