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