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