summaryrefslogtreecommitdiff
path: root/arch/xtensa/lib/bootm.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/xtensa/lib/bootm.c')
-rw-r--r--arch/xtensa/lib/bootm.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/arch/xtensa/lib/bootm.c b/arch/xtensa/lib/bootm.c
new file mode 100644
index 0000000000..1604bb9536
--- /dev/null
+++ b/arch/xtensa/lib/bootm.c
@@ -0,0 +1,197 @@
+/*
+ * (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 *)&params->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 = getenv("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;
+}
+