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