@@ -104,6 +104,12 @@ void gpr_init(void);
#endif /* CONFIG_MX6 */
+struct memorymap {
+ unsigned long auxcore;
+ unsigned long host;
+ unsigned long size;
+};
+
u32 get_nr_cpus(void);
u32 get_cpu_rev(void);
u32 get_cpu_speed_grade_hz(void);
@@ -7,18 +7,91 @@
#include <asm/io.h>
#include <asm/mach-imx/sys_proto.h>
#include <command.h>
+#include <elf.h>
#include <imx_sip.h>
#include <linux/compiler.h>
-int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
+const __weak struct memorymap hostmap[] = { };
+
+static const struct memorymap *get_host_mapping(unsigned long auxcore)
+{
+ const struct memorymap *mmap = hostmap;
+
+ while (mmap) {
+ if (mmap->auxcore <= auxcore &&
+ mmap->auxcore + mmap->size > auxcore)
+ return mmap;
+ mmap++;
+ }
+
+ return NULL;
+}
+
+/*
+ * A very simple elf loader, assumes the image is valid, returns the
+ * entry point address.
+ */
+static unsigned long load_elf_image_phdr(unsigned long addr)
+{
+ Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+ Elf32_Phdr *phdr; /* Program header structure pointer */
+ int i;
+
+ ehdr = (Elf32_Ehdr *)addr;
+ phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
+
+ /* Load each program header */
+ for (i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
+ const struct memorymap *mmap = get_host_mapping(phdr->p_paddr);
+ void *dst, *src;
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (!mmap) {
+ printf("Invalid aux core address: %08x",
+ phdr->p_paddr);
+ return 0;
+ }
+
+ dst = (void *)(phdr->p_paddr - mmap->auxcore) + mmap->host;
+ src = (void *)addr + phdr->p_offset;
+ debug("Loading phdr %i to 0x%p (%i bytes)\n",
+ i, dst, phdr->p_filesz);
+ if (phdr->p_filesz)
+ memcpy(dst, src, phdr->p_filesz);
+ if (phdr->p_filesz != phdr->p_memsz)
+ memset(dst + phdr->p_filesz, 0x00,
+ phdr->p_memsz - phdr->p_filesz);
+ flush_cache((unsigned long)dst & ~(CONFIG_SYS_CACHELINE_SIZE-1),
+ ALIGN(phdr->p_filesz, CONFIG_SYS_CACHELINE_SIZE));
+ }
+
+ return ehdr->e_entry;
+}
+
+int arch_auxiliary_core_up(u32 core_id, ulong addr)
{
ulong stack, pc;
- if (!boot_private_data)
+ if (!addr)
return -EINVAL;
- stack = *(u32 *)boot_private_data;
- pc = *(u32 *)(boot_private_data + 4);
+ if (valid_elf_image(addr)) {
+ stack = 0x0;
+ pc = load_elf_image_phdr(addr);
+ if (!pc)
+ return CMD_RET_FAILURE;
+
+ } else {
+ /*
+ * Assume binary file with vector table at the beginning.
+ * Cortex-M4 vector tables start with the stack pointer (SP)
+ * and reset vector (initial PC).
+ */
+ stack = *(u32 *)addr;
+ pc = *(u32 *)(addr + 4);
+ }
/* Set the stack and pc to M4 bootROM */
writel(stack, M4_BOOTROM_BASE_ADDR);
@@ -80,6 +153,9 @@ static int do_bootaux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
addr = simple_strtoul(argv[1], NULL, 16);
+ if (!addr)
+ return CMD_RET_FAILURE;
+
printf("## Starting auxiliary core at 0x%08lX ...\n", addr);
ret = arch_auxiliary_core_up(0, addr);
@@ -193,6 +193,32 @@ static void init_cpu_basic(void)
#endif
}
+#ifdef CONFIG_IMX_BOOTAUX
+/*
+ * Table of mappings of of physical mem regions in both
+ * Cortex-A7 and Cortex-M4 address spaces.
+ *
+ * For additional details check sections 2.1.2 and 2.1.3 in
+ * i.MX7Dual Applications Processor Reference Manual
+ */
+const struct memorymap hostmap[] = {
+ { .auxcore = 0x00000000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+ { .auxcore = 0x00180000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+ { .auxcore = 0x20180000, .host = 0x00180000, .size = 0x8000 }, /* OCRAM_S */
+ { .auxcore = 0x1fff8000, .host = 0x007f8000, .size = 0x8000 }, /* TCML */
+ { .auxcore = 0x20000000, .host = 0x00800000, .size = 0x8000 }, /* TCMU */
+ { .auxcore = 0x00900000, .host = 0x00900000, .size = 0x20000 }, /* OCRAM_128KB */
+ { .auxcore = 0x20200000, .host = 0x00900000, .size = 0x20000 }, /* OCRAM_128KB */
+ { .auxcore = 0x00920000, .host = 0x00920000, .size = 0x20000 }, /* OCRAM_EPDC */
+ { .auxcore = 0x20220000, .host = 0x00920000, .size = 0x20000 }, /* OCRAM_EPDC */
+ { .auxcore = 0x00940000, .host = 0x00940000, .size = 0x20000 }, /* OCRAM_PXP */
+ { .auxcore = 0x20240000, .host = 0x00940000, .size = 0x20000 }, /* OCRAM_PXP */
+ { .auxcore = 0x10000000, .host = 0x80000000, .size = 0x0fff0000 }, /* DDR Code alias */
+ { .auxcore = 0x80000000, .host = 0x80000000, .size = 0xe0000000 }, /* DDRC */
+ { /* sentinel */ }
+};
+#endif
+
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/* enable all periherial can be accessed in nosec mode */
static void init_csu(void)