|
|
|
/*
|
|
|
|
* (C) Copyright 2008 - 2013 Tensilica Inc.
|
|
|
|
* (C) Copyright 2014 Cadence Design Systems Inc.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <command.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 bd_info *bd = gd->bd;
|
|
|
|
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 = bd->bi_memstart;
|
|
|
|
mem->end = bd->bi_memstart + bd->bi_memsize;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|