[U-Boot,4/4] imx8: add bootaux support
diff mbox series

Message ID 20190716085034.30990-4-peng.fan@nxp.com
State New
Delegated to: Stefano Babic
Headers show
Series
  • [U-Boot,1/4] imx8: scu_api: add sc_pm_get_resource_power_mode
Related show

Commit Message

Peng Fan July 16, 2019, 8:35 a.m. UTC
Add bootaux to kick M4 and DSP. When M4 is not kicked by ROM/SCU,
we could use U-Boot to kick as i.MX6/7.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm/mach-imx/Kconfig        |   2 +-
 arch/arm/mach-imx/imx8/Makefile  |   1 +
 arch/arm/mach-imx/imx8/bootaux.c | 225 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/imx_bootaux.c  |   2 +
 4 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/imx8/bootaux.c

Patch
diff mbox series

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index d086230e9b..39f388ef93 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -23,7 +23,7 @@  config IMX_RDC
 
 config IMX_BOOTAUX
 	bool "Support boot auxiliary core"
-	depends on ARCH_IMX8M || ARCH_MX7 || ARCH_MX6 || ARCH_VF610
+	depends on ARCH_IMX8M || ARCH_IMX8 || ARCH_MX7 || ARCH_MX6 || ARCH_VF610
 	help
 	  bootaux [addr] to boot auxiliary core.
 
diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile
index 31ad169ccf..d8b0c2a7b9 100644
--- a/arch/arm/mach-imx/imx8/Makefile
+++ b/arch/arm/mach-imx/imx8/Makefile
@@ -5,3 +5,4 @@ 
 #
 
 obj-y += cpu.o iomux.o
+obj-$(CONFIG_IMX_BOOTAUX) += bootaux.o
diff --git a/arch/arm/mach-imx/imx8/bootaux.c b/arch/arm/mach-imx/imx8/bootaux.c
new file mode 100644
index 0000000000..3bbe679120
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/bootaux.c
@@ -0,0 +1,225 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <elf.h>
+#include <errno.h>
+#include <power-domain.h>
+
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+
+#ifdef CONFIG_IMX8QM
+int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
+{
+	sc_rsrc_t core_rsrc, mu_rsrc;
+	sc_faddr_t tcml_addr;
+	u32 tcm_size = SZ_256K; /* TCML + TCMU */
+	ulong addr;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		tcml_addr = 0x34FE0000;
+		mu_rsrc = SC_R_M4_0_MU_1A;
+		break;
+	case 1:
+		core_rsrc = SC_R_M4_1_PID0;
+		tcml_addr = 0x38FE0000;
+		mu_rsrc = SC_R_M4_1_MU_1A;
+		break;
+	default:
+		printf("Not support this core boot up, ID:%u\n", core_id);
+		return -EINVAL;
+	}
+
+	addr = (sc_faddr_t)boot_private_data;
+
+	if (addr >= tcml_addr && addr <= tcml_addr + tcm_size) {
+		printf("Wrong image address 0x%lx, should not in TCML\n",
+		       addr);
+		return -EINVAL;
+	}
+
+	printf("Power on M4 and MU\n");
+
+	if (sc_pm_set_resource_power_mode(-1, core_rsrc,
+					  SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	if (sc_pm_set_resource_power_mode(-1, mu_rsrc,
+					  SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("Copy M4 image from 0x%lx to TCML 0x%lx\n",
+	       addr, (ulong)tcml_addr);
+
+	if (addr != tcml_addr)
+		memcpy((void *)tcml_addr, (void *)addr, tcm_size);
+
+	printf("Start M4 %u\n", core_id);
+	if (sc_pm_cpu_start(-1, core_rsrc, true, tcml_addr) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("bootaux complete\n");
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_IMX8QXP
+static unsigned long load_elf_image_shdr(unsigned long addr)
+{
+	Elf32_Ehdr *ehdr; /* Elf header structure pointer */
+	Elf32_Shdr *shdr; /* Section header structure pointer */
+	unsigned char *strtab = 0; /* String table pointer */
+	unsigned char *image; /* Binary image pointer */
+	int i; /* Loop counter */
+
+	ehdr = (Elf32_Ehdr *)addr;
+
+	/* Find the section header string table for output info */
+	shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
+			     (ehdr->e_shstrndx * sizeof(Elf32_Shdr)));
+
+	if (shdr->sh_type == SHT_STRTAB)
+		strtab = (unsigned char *)(addr + shdr->sh_offset);
+
+	/* Load each appropriate section */
+	for (i = 0; i < ehdr->e_shnum; ++i) {
+		shdr = (Elf32_Shdr *)(addr + ehdr->e_shoff +
+				     (i * sizeof(Elf32_Shdr)));
+
+		if (!(shdr->sh_flags & SHF_ALLOC) ||
+		    shdr->sh_addr == 0 || shdr->sh_size == 0) {
+			continue;
+		}
+
+		if (strtab) {
+			debug("%sing %s @ 0x%08lx (%ld bytes)\n",
+			      (shdr->sh_type == SHT_NOBITS) ? "Clear" : "Load",
+			      &strtab[shdr->sh_name],
+			      (unsigned long)shdr->sh_addr,
+			      (long)shdr->sh_size);
+		}
+
+		if (shdr->sh_type == SHT_NOBITS) {
+			memset((void *)(uintptr_t)shdr->sh_addr, 0,
+			       shdr->sh_size);
+		} else {
+			image = (unsigned char *)addr + shdr->sh_offset;
+			memcpy((void *)(uintptr_t)shdr->sh_addr,
+			       (const void *)image, shdr->sh_size);
+		}
+		flush_cache(shdr->sh_addr, shdr->sh_size);
+	}
+
+	return ehdr->e_entry;
+}
+
+int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
+{
+	struct power_domain pd;
+	sc_rsrc_t core_rsrc, mu_rsrc = -1;
+	sc_faddr_t aux_core_ram;
+	u32 size;
+	ulong addr;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		aux_core_ram = 0x34FE0000;
+		mu_rsrc = SC_R_M4_0_MU_1A;
+		size = SZ_256K;
+		break;
+	case 1:
+		core_rsrc = SC_R_DSP;
+		aux_core_ram = 0x596f8000;
+		size = SZ_2K;
+		break;
+	default:
+		printf("Not support this core boot up, ID:%u\n", core_id);
+		return -EINVAL;
+	}
+
+	addr = (sc_faddr_t)boot_private_data;
+
+	if (addr >= aux_core_ram && addr <= aux_core_ram + size) {
+		printf("Wrong image address 0x%lx, should not in aux core ram\n",
+		       addr);
+		return -EINVAL;
+	}
+
+	printf("Power on aux core %d\n", core_id);
+
+	if (sc_pm_set_resource_power_mode(-1, core_rsrc,
+					  SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	if (mu_rsrc != -1) {
+		if (sc_pm_set_resource_power_mode(-1, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+			return -EIO;
+	}
+
+	if (core_id == 1) {
+		if (sc_pm_clock_enable(-1, core_rsrc, SC_PM_CLK_PER,
+				       true, false) != SC_ERR_NONE) {
+			printf("Error enable clock\n");
+			return -EIO;
+		}
+
+		/* TODO : add power domain support */
+
+		return -EIO:
+	}
+
+	printf("Copy image from 0x%lx to 0x%lx\n", addr, (ulong)aux_core_ram);
+	if (core_id == 0) {
+		/* M4 use bin file */
+		memcpy((void *)aux_core_ram, (void *)addr, size);
+	} else {
+		/* HIFI use elf file */
+		if (!valid_elf_image(addr))
+			return -1;
+		addr = load_elf_image_shdr(addr);
+	}
+
+	printf("Start %s\n", core_id == 0 ? "M4" : "HIFI");
+
+	if (sc_pm_cpu_start(-1, core_rsrc, true, aux_core_ram) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("bootaux complete\n");
+	return 0;
+}
+#endif
+
+int arch_auxiliary_core_check_up(u32 core_id)
+{
+	sc_rsrc_t core_rsrc;
+	sc_pm_power_mode_t power_mode;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		break;
+#ifdef CONFIG_IMX8QM
+	case 1:
+		core_rsrc = SC_R_M4_1_PID0;
+		break;
+#endif
+	default:
+		printf("Not support this core, ID:%u\n", core_id);
+		return 0;
+	}
+
+	if (sc_pm_get_resource_power_mode(-1, core_rsrc,
+					  &power_mode) != SC_ERR_NONE)
+		return 0;
+
+	if (power_mode != SC_PM_PW_MODE_OFF)
+		return 1;
+
+	return 0;
+}
diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c
index 18d7e6819c..267bc08ca4 100644
--- a/arch/arm/mach-imx/imx_bootaux.c
+++ b/arch/arm/mach-imx/imx_bootaux.c
@@ -10,6 +10,7 @@ 
 #include <imx_sip.h>
 #include <linux/compiler.h>
 
+#ifndef CONFIG_IMX8
 int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
 {
 	ulong stack, pc;
@@ -50,6 +51,7 @@  int arch_auxiliary_core_check_up(u32 core_id)
 	return 1;
 #endif
 }
+#endif
 
 /*
  * To i.MX6SX and i.MX7D, the image supported by bootaux needs