xref: /rk3399_rockchip-uboot/arch/mips/lib/bootm.c (revision c9639421fd877fa0e95d7744dade002042eb721e)
1ea0364f1SPeter Tyser /*
2ea0364f1SPeter Tyser  * (C) Copyright 2003
3ea0364f1SPeter Tyser  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4ea0364f1SPeter Tyser  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6ea0364f1SPeter Tyser  */
7ea0364f1SPeter Tyser 
8ea0364f1SPeter Tyser #include <common.h>
9ea0364f1SPeter Tyser #include <command.h>
10ea0364f1SPeter Tyser #include <image.h>
11ea0364f1SPeter Tyser #include <u-boot/zlib.h>
12ea0364f1SPeter Tyser #include <asm/byteorder.h>
13ea0364f1SPeter Tyser #include <asm/addrspace.h>
14ea0364f1SPeter Tyser 
15ea0364f1SPeter Tyser DECLARE_GLOBAL_DATA_PTR;
16ea0364f1SPeter Tyser 
17ea0364f1SPeter Tyser #define	LINUX_MAX_ENVS		256
18ea0364f1SPeter Tyser #define	LINUX_MAX_ARGS		256
19ea0364f1SPeter Tyser 
207a9d109bSPaul Burton #if defined(CONFIG_MALTA)
217a9d109bSPaul Burton #define mips_boot_malta		1
22b87493f4SDaniel Schwierzeck #else
237a9d109bSPaul Burton #define mips_boot_malta		0
24b87493f4SDaniel Schwierzeck #endif
25b87493f4SDaniel Schwierzeck 
26ea0364f1SPeter Tyser static int linux_argc;
27ea0364f1SPeter Tyser static char **linux_argv;
2859e8cbdbSDaniel Schwierzeck static char *linux_argp;
29ea0364f1SPeter Tyser 
30ea0364f1SPeter Tyser static char **linux_env;
31ea0364f1SPeter Tyser static char *linux_env_p;
32ea0364f1SPeter Tyser static int linux_env_idx;
33ea0364f1SPeter Tyser 
34f66cc1e3SDaniel Schwierzeck static ulong arch_get_sp(void)
35f66cc1e3SDaniel Schwierzeck {
36f66cc1e3SDaniel Schwierzeck 	ulong ret;
37f66cc1e3SDaniel Schwierzeck 
38f66cc1e3SDaniel Schwierzeck 	__asm__ __volatile__("move %0, $sp" : "=r"(ret) : );
39f66cc1e3SDaniel Schwierzeck 
40f66cc1e3SDaniel Schwierzeck 	return ret;
41f66cc1e3SDaniel Schwierzeck }
42f66cc1e3SDaniel Schwierzeck 
43f66cc1e3SDaniel Schwierzeck void arch_lmb_reserve(struct lmb *lmb)
44f66cc1e3SDaniel Schwierzeck {
45f66cc1e3SDaniel Schwierzeck 	ulong sp;
46f66cc1e3SDaniel Schwierzeck 
47f66cc1e3SDaniel Schwierzeck 	sp = arch_get_sp();
48f66cc1e3SDaniel Schwierzeck 	debug("## Current stack ends at 0x%08lx\n", sp);
49f66cc1e3SDaniel Schwierzeck 
50f66cc1e3SDaniel Schwierzeck 	/* adjust sp by 4K to be safe */
51f66cc1e3SDaniel Schwierzeck 	sp -= 4096;
52f66cc1e3SDaniel Schwierzeck 	lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
53f66cc1e3SDaniel Schwierzeck }
54f66cc1e3SDaniel Schwierzeck 
55*c9639421SDaniel Schwierzeck static int boot_setup_linux(bootm_headers_t *images)
56*c9639421SDaniel Schwierzeck {
57*c9639421SDaniel Schwierzeck 	int ret;
58*c9639421SDaniel Schwierzeck 	ulong rd_len;
59*c9639421SDaniel Schwierzeck 
60*c9639421SDaniel Schwierzeck 	rd_len = images->rd_end - images->rd_start;
61*c9639421SDaniel Schwierzeck 	ret = boot_ramdisk_high(&images->lmb, images->rd_start,
62*c9639421SDaniel Schwierzeck 		rd_len, &images->initrd_start, &images->initrd_end);
63*c9639421SDaniel Schwierzeck 	if (ret)
64*c9639421SDaniel Schwierzeck 		return ret;
65*c9639421SDaniel Schwierzeck 
66*c9639421SDaniel Schwierzeck 	return 0;
67*c9639421SDaniel Schwierzeck }
68*c9639421SDaniel Schwierzeck 
6959e8cbdbSDaniel Schwierzeck static void linux_cmdline_init(void)
7059e8cbdbSDaniel Schwierzeck {
7159e8cbdbSDaniel Schwierzeck 	linux_argc = 1;
7259e8cbdbSDaniel Schwierzeck 	linux_argv = (char **)UNCACHED_SDRAM(gd->bd->bi_boot_params);
7359e8cbdbSDaniel Schwierzeck 	linux_argv[0] = 0;
7459e8cbdbSDaniel Schwierzeck 	linux_argp = (char *)(linux_argv + LINUX_MAX_ARGS);
7559e8cbdbSDaniel Schwierzeck }
7659e8cbdbSDaniel Schwierzeck 
7759e8cbdbSDaniel Schwierzeck static void linux_cmdline_set(const char *value, size_t len)
7859e8cbdbSDaniel Schwierzeck {
7959e8cbdbSDaniel Schwierzeck 	linux_argv[linux_argc] = linux_argp;
8059e8cbdbSDaniel Schwierzeck 	memcpy(linux_argp, value, len);
8159e8cbdbSDaniel Schwierzeck 	linux_argp[len] = 0;
8259e8cbdbSDaniel Schwierzeck 
8359e8cbdbSDaniel Schwierzeck 	linux_argp += len + 1;
8459e8cbdbSDaniel Schwierzeck 	linux_argc++;
8559e8cbdbSDaniel Schwierzeck }
8659e8cbdbSDaniel Schwierzeck 
8759e8cbdbSDaniel Schwierzeck static void linux_cmdline_dump(void)
8859e8cbdbSDaniel Schwierzeck {
8959e8cbdbSDaniel Schwierzeck 	int i;
9059e8cbdbSDaniel Schwierzeck 
9159e8cbdbSDaniel Schwierzeck 	debug("## cmdline argv at 0x%p, argp at 0x%p\n",
9259e8cbdbSDaniel Schwierzeck 	      linux_argv, linux_argp);
9359e8cbdbSDaniel Schwierzeck 
9459e8cbdbSDaniel Schwierzeck 	for (i = 1; i < linux_argc; i++)
9559e8cbdbSDaniel Schwierzeck 		debug("   arg %03d: %s\n", i, linux_argv[i]);
9659e8cbdbSDaniel Schwierzeck }
9759e8cbdbSDaniel Schwierzeck 
9859e8cbdbSDaniel Schwierzeck static void boot_cmdline_linux(bootm_headers_t *images)
9959e8cbdbSDaniel Schwierzeck {
10059e8cbdbSDaniel Schwierzeck 	const char *bootargs, *next, *quote;
10159e8cbdbSDaniel Schwierzeck 
10259e8cbdbSDaniel Schwierzeck 	linux_cmdline_init();
10359e8cbdbSDaniel Schwierzeck 
10459e8cbdbSDaniel Schwierzeck 	bootargs = getenv("bootargs");
10559e8cbdbSDaniel Schwierzeck 	if (!bootargs)
10659e8cbdbSDaniel Schwierzeck 		return;
10759e8cbdbSDaniel Schwierzeck 
10859e8cbdbSDaniel Schwierzeck 	next = bootargs;
10959e8cbdbSDaniel Schwierzeck 
11059e8cbdbSDaniel Schwierzeck 	while (bootargs && *bootargs && linux_argc < LINUX_MAX_ARGS) {
11159e8cbdbSDaniel Schwierzeck 		quote = strchr(bootargs, '"');
11259e8cbdbSDaniel Schwierzeck 		next = strchr(bootargs, ' ');
11359e8cbdbSDaniel Schwierzeck 
11459e8cbdbSDaniel Schwierzeck 		while (next && quote && quote < next) {
11559e8cbdbSDaniel Schwierzeck 			/*
11659e8cbdbSDaniel Schwierzeck 			 * we found a left quote before the next blank
11759e8cbdbSDaniel Schwierzeck 			 * now we have to find the matching right quote
11859e8cbdbSDaniel Schwierzeck 			 */
11959e8cbdbSDaniel Schwierzeck 			next = strchr(quote + 1, '"');
12059e8cbdbSDaniel Schwierzeck 			if (next) {
12159e8cbdbSDaniel Schwierzeck 				quote = strchr(next + 1, '"');
12259e8cbdbSDaniel Schwierzeck 				next = strchr(next + 1, ' ');
12359e8cbdbSDaniel Schwierzeck 			}
12459e8cbdbSDaniel Schwierzeck 		}
12559e8cbdbSDaniel Schwierzeck 
12659e8cbdbSDaniel Schwierzeck 		if (!next)
12759e8cbdbSDaniel Schwierzeck 			next = bootargs + strlen(bootargs);
12859e8cbdbSDaniel Schwierzeck 
12959e8cbdbSDaniel Schwierzeck 		linux_cmdline_set(bootargs, next - bootargs);
13059e8cbdbSDaniel Schwierzeck 
13159e8cbdbSDaniel Schwierzeck 		if (*next)
13259e8cbdbSDaniel Schwierzeck 			next++;
13359e8cbdbSDaniel Schwierzeck 
13459e8cbdbSDaniel Schwierzeck 		bootargs = next;
13559e8cbdbSDaniel Schwierzeck 	}
13659e8cbdbSDaniel Schwierzeck 
13759e8cbdbSDaniel Schwierzeck 	linux_cmdline_dump();
13859e8cbdbSDaniel Schwierzeck }
13959e8cbdbSDaniel Schwierzeck 
14015f8aa90SDaniel Schwierzeck static void linux_env_init(void)
14115f8aa90SDaniel Schwierzeck {
14215f8aa90SDaniel Schwierzeck 	linux_env = (char **)(((ulong) linux_argp + 15) & ~15);
14315f8aa90SDaniel Schwierzeck 	linux_env[0] = 0;
14415f8aa90SDaniel Schwierzeck 	linux_env_p = (char *)(linux_env + LINUX_MAX_ENVS);
14515f8aa90SDaniel Schwierzeck 	linux_env_idx = 0;
14615f8aa90SDaniel Schwierzeck }
14715f8aa90SDaniel Schwierzeck 
14815f8aa90SDaniel Schwierzeck static void linux_env_set(const char *env_name, const char *env_val)
14915f8aa90SDaniel Schwierzeck {
15015f8aa90SDaniel Schwierzeck 	if (linux_env_idx < LINUX_MAX_ENVS - 1) {
15115f8aa90SDaniel Schwierzeck 		linux_env[linux_env_idx] = linux_env_p;
15215f8aa90SDaniel Schwierzeck 
15315f8aa90SDaniel Schwierzeck 		strcpy(linux_env_p, env_name);
15415f8aa90SDaniel Schwierzeck 		linux_env_p += strlen(env_name);
15515f8aa90SDaniel Schwierzeck 
1567a9d109bSPaul Burton 		if (mips_boot_malta) {
157b87493f4SDaniel Schwierzeck 			linux_env_p++;
158b87493f4SDaniel Schwierzeck 			linux_env[++linux_env_idx] = linux_env_p;
159b87493f4SDaniel Schwierzeck 		} else {
16015f8aa90SDaniel Schwierzeck 			*linux_env_p++ = '=';
161b87493f4SDaniel Schwierzeck 		}
16215f8aa90SDaniel Schwierzeck 
16315f8aa90SDaniel Schwierzeck 		strcpy(linux_env_p, env_val);
16415f8aa90SDaniel Schwierzeck 		linux_env_p += strlen(env_val);
16515f8aa90SDaniel Schwierzeck 
16615f8aa90SDaniel Schwierzeck 		linux_env_p++;
16715f8aa90SDaniel Schwierzeck 		linux_env[++linux_env_idx] = 0;
16815f8aa90SDaniel Schwierzeck 	}
16915f8aa90SDaniel Schwierzeck }
17015f8aa90SDaniel Schwierzeck 
1710ea7213fSGabor Juhos static void boot_prep_linux(bootm_headers_t *images)
172ea0364f1SPeter Tyser {
173ea0364f1SPeter Tyser 	char env_buf[12];
17415f8aa90SDaniel Schwierzeck 	const char *cp;
1756c154552SDaniel Schwierzeck 	ulong rd_start, rd_size;
176ea0364f1SPeter Tyser 
177ea0364f1SPeter Tyser #ifdef CONFIG_MEMSIZE_IN_BYTES
178ea0364f1SPeter Tyser 	sprintf(env_buf, "%lu", (ulong)gd->ram_size);
179ea0364f1SPeter Tyser 	debug("## Giving linux memsize in bytes, %lu\n", (ulong)gd->ram_size);
180ea0364f1SPeter Tyser #else
181ea0364f1SPeter Tyser 	sprintf(env_buf, "%lu", (ulong)(gd->ram_size >> 20));
182e51a6b7aSDaniel Schwierzeck 	debug("## Giving linux memsize in MB, %lu\n",
183e51a6b7aSDaniel Schwierzeck 	      (ulong)(gd->ram_size >> 20));
184ea0364f1SPeter Tyser #endif /* CONFIG_MEMSIZE_IN_BYTES */
185ea0364f1SPeter Tyser 
1866c154552SDaniel Schwierzeck 	rd_start = UNCACHED_SDRAM(images->initrd_start);
1876c154552SDaniel Schwierzeck 	rd_size = images->initrd_end - images->initrd_start;
1886c154552SDaniel Schwierzeck 
18915f8aa90SDaniel Schwierzeck 	linux_env_init();
19015f8aa90SDaniel Schwierzeck 
191ea0364f1SPeter Tyser 	linux_env_set("memsize", env_buf);
192ea0364f1SPeter Tyser 
1936c154552SDaniel Schwierzeck 	sprintf(env_buf, "0x%08lX", rd_start);
194ea0364f1SPeter Tyser 	linux_env_set("initrd_start", env_buf);
195ea0364f1SPeter Tyser 
1966c154552SDaniel Schwierzeck 	sprintf(env_buf, "0x%lX", rd_size);
197ea0364f1SPeter Tyser 	linux_env_set("initrd_size", env_buf);
198ea0364f1SPeter Tyser 
199ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%08X", (uint) (gd->bd->bi_flashstart));
200ea0364f1SPeter Tyser 	linux_env_set("flash_start", env_buf);
201ea0364f1SPeter Tyser 
202ea0364f1SPeter Tyser 	sprintf(env_buf, "0x%X", (uint) (gd->bd->bi_flashsize));
203ea0364f1SPeter Tyser 	linux_env_set("flash_size", env_buf);
204ea0364f1SPeter Tyser 
205ea0364f1SPeter Tyser 	cp = getenv("ethaddr");
206e51a6b7aSDaniel Schwierzeck 	if (cp)
207ea0364f1SPeter Tyser 		linux_env_set("ethaddr", cp);
208ea0364f1SPeter Tyser 
209ea0364f1SPeter Tyser 	cp = getenv("eth1addr");
210e51a6b7aSDaniel Schwierzeck 	if (cp)
211ea0364f1SPeter Tyser 		linux_env_set("eth1addr", cp);
212b87493f4SDaniel Schwierzeck 
213d18d49d7SPaul Burton 	if (mips_boot_malta) {
214d18d49d7SPaul Burton 		sprintf(env_buf, "%un8r", gd->baudrate);
215d18d49d7SPaul Burton 		linux_env_set("modetty0", env_buf);
216d18d49d7SPaul Burton 	}
2170ea7213fSGabor Juhos }
218ea0364f1SPeter Tyser 
2190ea7213fSGabor Juhos static void boot_jump_linux(bootm_headers_t *images)
2200ea7213fSGabor Juhos {
221c4b37847SDaniel Schwierzeck 	typedef void __noreturn (*kernel_entry_t)(int, ulong, ulong, ulong);
222c4b37847SDaniel Schwierzeck 	kernel_entry_t kernel = (kernel_entry_t) images->ep;
223b87493f4SDaniel Schwierzeck 	ulong linux_extra = 0;
2240ea7213fSGabor Juhos 
225c4b37847SDaniel Schwierzeck 	debug("## Transferring control to Linux (at address %p) ...\n", kernel);
2260ea7213fSGabor Juhos 
2270ea7213fSGabor Juhos 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
2280ea7213fSGabor Juhos 
2297a9d109bSPaul Burton 	if (mips_boot_malta)
230b87493f4SDaniel Schwierzeck 		linux_extra = gd->ram_size;
231b87493f4SDaniel Schwierzeck 
2320ea7213fSGabor Juhos 	/* we assume that the kernel is in place */
2330ea7213fSGabor Juhos 	printf("\nStarting kernel ...\n\n");
2340ea7213fSGabor Juhos 
235b87493f4SDaniel Schwierzeck 	kernel(linux_argc, (ulong)linux_argv, (ulong)linux_env, linux_extra);
2360ea7213fSGabor Juhos }
2370ea7213fSGabor Juhos 
2380ea7213fSGabor Juhos int do_bootm_linux(int flag, int argc, char * const argv[],
2390ea7213fSGabor Juhos 			bootm_headers_t *images)
2400ea7213fSGabor Juhos {
241*c9639421SDaniel Schwierzeck 	int ret;
242*c9639421SDaniel Schwierzeck 
2439c170e2eSGabor Juhos 	/* No need for those on MIPS */
24459e8cbdbSDaniel Schwierzeck 	if (flag & BOOTM_STATE_OS_BD_T)
2459c170e2eSGabor Juhos 		return -1;
2469c170e2eSGabor Juhos 
24759e8cbdbSDaniel Schwierzeck 	if (flag & BOOTM_STATE_OS_CMDLINE) {
24859e8cbdbSDaniel Schwierzeck 		boot_cmdline_linux(images);
24959e8cbdbSDaniel Schwierzeck 		return 0;
25059e8cbdbSDaniel Schwierzeck 	}
25159e8cbdbSDaniel Schwierzeck 
2529c170e2eSGabor Juhos 	if (flag & BOOTM_STATE_OS_PREP) {
2539c170e2eSGabor Juhos 		boot_prep_linux(images);
2549c170e2eSGabor Juhos 		return 0;
2559c170e2eSGabor Juhos 	}
2569c170e2eSGabor Juhos 
2579c170e2eSGabor Juhos 	if (flag & BOOTM_STATE_OS_GO) {
2589c170e2eSGabor Juhos 		boot_jump_linux(images);
2599c170e2eSGabor Juhos 		return 0;
2609c170e2eSGabor Juhos 	}
2610ea7213fSGabor Juhos 
262*c9639421SDaniel Schwierzeck 	ret = boot_setup_linux(images);
263*c9639421SDaniel Schwierzeck 	if (ret)
264*c9639421SDaniel Schwierzeck 		return ret;
265*c9639421SDaniel Schwierzeck 
26659e8cbdbSDaniel Schwierzeck 	boot_cmdline_linux(images);
2670ea7213fSGabor Juhos 	boot_prep_linux(images);
268e08634c7SGabor Juhos 	boot_jump_linux(images);
269e51a6b7aSDaniel Schwierzeck 
270ea0364f1SPeter Tyser 	/* does not return */
271ea0364f1SPeter Tyser 	return 1;
272ea0364f1SPeter Tyser }
273