200 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * (C) Copyright 2008 - 2013 Tensilica Inc.
 | |
|  * (C) Copyright 2014 Cadence Design Systems Inc.
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <bootstage.h>
 | |
| #include <command.h>
 | |
| #include <cpu_func.h>
 | |
| #include <env.h>
 | |
| #include <asm/global_data.h>
 | |
| #include <u-boot/zlib.h>
 | |
| #include <asm/byteorder.h>
 | |
| #include <asm/addrspace.h>
 | |
| #include <asm/bootparam.h>
 | |
| #include <asm/cache.h>
 | |
| #include <image.h>
 | |
| 
 | |
| DECLARE_GLOBAL_DATA_PTR;
 | |
| 
 | |
| /*
 | |
|  * Setup boot-parameters.
 | |
|  */
 | |
| 
 | |
| static struct bp_tag *setup_first_tag(struct bp_tag *params)
 | |
| {
 | |
| 	params->id = BP_TAG_FIRST;
 | |
| 	params->size = sizeof(long);
 | |
| 	*(unsigned long *)¶ms->data = BP_VERSION;
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| static struct bp_tag *setup_last_tag(struct bp_tag *params)
 | |
| {
 | |
| 	params->id = BP_TAG_LAST;
 | |
| 	params->size = 0;
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| static struct bp_tag *setup_memory_tag(struct bp_tag *params)
 | |
| {
 | |
| 	struct meminfo *mem;
 | |
| 
 | |
| 	params->id = BP_TAG_MEMORY;
 | |
| 	params->size = sizeof(struct meminfo);
 | |
| 	mem = (struct meminfo *)params->data;
 | |
| 	mem->type = MEMORY_TYPE_CONVENTIONAL;
 | |
| 	mem->start = PHYSADDR(gd->ram_base);
 | |
| 	mem->end = PHYSADDR(gd->ram_base + gd->ram_size);
 | |
| 
 | |
| 	printf("   MEMORY:          tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n",
 | |
| 	       BP_TAG_MEMORY, mem->type, mem->start, mem->end);
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| static struct bp_tag *setup_commandline_tag(struct bp_tag *params,
 | |
| 					    char *cmdline)
 | |
| {
 | |
| 	int len;
 | |
| 
 | |
| 	if (!cmdline)
 | |
| 		return params;
 | |
| 
 | |
| 	len = strlen(cmdline);
 | |
| 
 | |
| 	params->id = BP_TAG_COMMAND_LINE;
 | |
| 	params->size = (len + 3) & -4;
 | |
| 	strcpy((char *)params->data, cmdline);
 | |
| 
 | |
| 	printf("   COMMAND_LINE:    tag:0x%04x, size:%u, data:'%s'\n",
 | |
| 	       BP_TAG_COMMAND_LINE, params->size, cmdline);
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params,
 | |
| 					unsigned long rd_start,
 | |
| 					unsigned long rd_end)
 | |
| {
 | |
| 	struct meminfo *mem;
 | |
| 
 | |
| 	if (rd_start == rd_end)
 | |
| 		return params;
 | |
| 
 | |
| 	/* Add a single banked memory */
 | |
| 
 | |
| 	params->id = BP_TAG_INITRD;
 | |
| 	params->size = sizeof(struct meminfo);
 | |
| 
 | |
| 	mem = (struct meminfo *)params->data;
 | |
| 	mem->type =  MEMORY_TYPE_CONVENTIONAL;
 | |
| 	mem->start = PHYSADDR(rd_start);
 | |
| 	mem->end = PHYSADDR(rd_end);
 | |
| 
 | |
| 	printf("   INITRD:          tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n",
 | |
| 	       BP_TAG_INITRD, mem->type, mem->start, mem->end);
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| static struct bp_tag *setup_serial_tag(struct bp_tag *params)
 | |
| {
 | |
| 	params->id = BP_TAG_SERIAL_BAUDRATE;
 | |
| 	params->size = sizeof(unsigned long);
 | |
| 	params->data[0] = gd->baudrate;
 | |
| 
 | |
| 	printf("   SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n",
 | |
| 	       BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]);
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_OF_LIBFDT
 | |
| 
 | |
| static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start)
 | |
| {
 | |
| 	params->id = BP_TAG_FDT;
 | |
| 	params->size = sizeof(unsigned long);
 | |
| 	params->data[0] = (unsigned long)fdt_start;
 | |
| 
 | |
| 	printf("   FDT:             tag:0x%04x, size:%u, start:0x%lx\n",
 | |
| 	       BP_TAG_FDT, params->size, params->data[0]);
 | |
| 
 | |
| 	return bp_tag_next(params);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Boot Linux.
 | |
|  */
 | |
| 
 | |
| int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
 | |
| {
 | |
| 	struct bp_tag *params, *params_start;
 | |
| 	ulong initrd_start, initrd_end;
 | |
| 	char *commandline = env_get("bootargs");
 | |
| 
 | |
| 	if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)))
 | |
| 		return 0;
 | |
| 
 | |
| 	show_boot_progress(15);
 | |
| 
 | |
| 	if (images->rd_start) {
 | |
| 		initrd_start = images->rd_start;
 | |
| 		initrd_end = images->rd_end;
 | |
| 	} else {
 | |
| 		initrd_start = 0;
 | |
| 		initrd_end = 0;
 | |
| 	}
 | |
| 
 | |
| 	params_start = (struct bp_tag *)gd->bd->bi_boot_params;
 | |
| 	params = params_start;
 | |
| 	params = setup_first_tag(params);
 | |
| 	params = setup_memory_tag(params);
 | |
| 	params = setup_commandline_tag(params, commandline);
 | |
| 	params = setup_serial_tag(params);
 | |
| 
 | |
| 	if (initrd_start)
 | |
| 		params = setup_ramdisk_tag(params, initrd_start, initrd_end);
 | |
| 
 | |
| #ifdef CONFIG_OF_LIBFDT
 | |
| 	if (images->ft_addr)
 | |
| 		params = setup_fdt_tag(params, images->ft_addr);
 | |
| #endif
 | |
| 
 | |
| 	printf("\n");
 | |
| 
 | |
| 	params = setup_last_tag(params);
 | |
| 
 | |
| 	show_boot_progress(15);
 | |
| 
 | |
| 	printf("Transferring Control to Linux @0x%08lx ...\n\n",
 | |
| 	       (ulong)images->ep);
 | |
| 
 | |
| 	flush_dcache_range((unsigned long)params_start, (unsigned long)params);
 | |
| 
 | |
| 	if (flag & BOOTM_STATE_OS_FAKE_GO)
 | |
| 		return 0;
 | |
| 
 | |
| 	/*
 | |
| 	 * _start() in vmlinux expects boot params in register a2.
 | |
| 	 * NOTE:
 | |
| 	 *    Disable/delete your u-boot breakpoints before stepping into linux.
 | |
| 	 */
 | |
| 	asm volatile ("mov	a2, %0\n\t"
 | |
| 		      "jx	%1\n\t"
 | |
| 		      : : "a" (params_start), "a" (images->ep)
 | |
| 		      : "a2");
 | |
| 
 | |
| 	/* Does not return */
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 |