
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
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