1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Freescale Semiconductor, Inc. 4 */ 5 6 #include <common.h> 7 #include <asm/io.h> 8 #include <asm/mach-imx/sys_proto.h> 9 #include <command.h> 10 #include <imx_sip.h> 11 #include <linux/compiler.h> 12 13 int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data) 14 { 15 ulong stack, pc; 16 17 if (!boot_private_data) 18 return -EINVAL; 19 20 stack = *(u32 *)boot_private_data; 21 pc = *(u32 *)(boot_private_data + 4); 22 23 /* Set the stack and pc to M4 bootROM */ 24 writel(stack, M4_BOOTROM_BASE_ADDR); 25 writel(pc, M4_BOOTROM_BASE_ADDR + 4); 26 27 /* Enable M4 */ 28 #ifdef CONFIG_IMX8M 29 call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0); 30 #else 31 clrsetbits_le32(SRC_BASE_ADDR + SRC_M4_REG_OFFSET, 32 SRC_M4C_NON_SCLR_RST_MASK, SRC_M4_ENABLE_MASK); 33 #endif 34 35 return 0; 36 } 37 38 int arch_auxiliary_core_check_up(u32 core_id) 39 { 40 #ifdef CONFIG_IMX8M 41 return call_imx_sip(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0); 42 #else 43 unsigned int val; 44 45 val = readl(SRC_BASE_ADDR + SRC_M4_REG_OFFSET); 46 47 if (val & SRC_M4C_NON_SCLR_RST_MASK) 48 return 0; /* assert in reset */ 49 50 return 1; 51 #endif 52 } 53 54 /* 55 * To i.MX6SX and i.MX7D, the image supported by bootaux needs 56 * the reset vector at the head for the image, with SP and PC 57 * as the first two words. 58 * 59 * Per the cortex-M reference manual, the reset vector of M4 needs 60 * to exist at 0x0 (TCMUL). The PC and SP are the first two addresses 61 * of that vector. So to boot M4, the A core must build the M4's reset 62 * vector with getting the PC and SP from image and filling them to 63 * TCMUL. When M4 is kicked, it will load the PC and SP by itself. 64 * The TCMUL is mapped to (M4_BOOTROM_BASE_ADDR) at A core side for 65 * accessing the M4 TCMUL. 66 */ 67 static int do_bootaux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 68 { 69 ulong addr; 70 int ret, up; 71 72 if (argc < 2) 73 return CMD_RET_USAGE; 74 75 up = arch_auxiliary_core_check_up(0); 76 if (up) { 77 printf("## Auxiliary core is already up\n"); 78 return CMD_RET_SUCCESS; 79 } 80 81 addr = simple_strtoul(argv[1], NULL, 16); 82 83 printf("## Starting auxiliary core at 0x%08lX ...\n", addr); 84 85 ret = arch_auxiliary_core_up(0, addr); 86 if (ret) 87 return CMD_RET_FAILURE; 88 89 return CMD_RET_SUCCESS; 90 } 91 92 U_BOOT_CMD( 93 bootaux, CONFIG_SYS_MAXARGS, 1, do_bootaux, 94 "Start auxiliary core", 95 "" 96 ); 97