1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2022 NXP 4 */ 5 6#include <common.h> 7#include <command.h> 8#include <log.h> 9#include <imx_sip.h> 10#include <linux/arm-smccc.h> 11 12int arch_auxiliary_core_check_up(u32 core_id) 13{ 14 struct arm_smccc_res res; 15 16 arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STARTED, 0, 0, 17 0, 0, 0, 0, &res); 18 19 return res.a0; 20} 21 22int arch_auxiliary_core_down(u32 core_id) 23{ 24 struct arm_smccc_res res; 25 26 printf("## Stopping auxiliary core\n"); 27 28 arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STOP, 0, 0, 29 0, 0, 0, 0, &res); 30 31 return 0; 32} 33 34int arch_auxiliary_core_up(u32 core_id, ulong addr) 35{ 36 struct arm_smccc_res res; 37 38 if (!addr) 39 return -EINVAL; 40 41 printf("## Starting auxiliary core addr = 0x%08lX...\n", addr); 42 43 arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_START, addr, 0, 44 0, 0, 0, 0, &res); 45 46 return 0; 47} 48 49/* 50 * To i.MX6SX and i.MX7D, the image supported by bootaux needs 51 * the reset vector at the head for the image, with SP and PC 52 * as the first two words. 53 * 54 * Per the cortex-M reference manual, the reset vector of M4/M7 needs 55 * to exist at 0x0 (TCMUL/IDTCM). The PC and SP are the first two addresses 56 * of that vector. So to boot M4/M7, the A core must build the M4/M7's reset 57 * vector with getting the PC and SP from image and filling them to 58 * TCMUL/IDTCM. When M4/M7 is kicked, it will load the PC and SP by itself. 59 * The TCMUL/IDTCM is mapped to (MCU_BOOTROM_BASE_ADDR) at A core side for 60 * accessing the M4/M7 TCMUL/IDTCM. 61 */ 62static int do_bootaux(struct cmd_tbl *cmdtp, int flag, int argc, 63 char *const argv[]) 64{ 65 ulong addr; 66 int ret, up; 67 u32 core = 0; 68 u32 stop = 0; 69 70 if (argc < 2) 71 return CMD_RET_USAGE; 72 73 if (argc > 2) 74 core = simple_strtoul(argv[2], NULL, 10); 75 76 if (argc > 3) 77 stop = simple_strtoul(argv[3], NULL, 10); 78 79 up = arch_auxiliary_core_check_up(core); 80 if (up) { 81 printf("## Auxiliary core is already up\n"); 82 return CMD_RET_SUCCESS; 83 } 84 85 addr = simple_strtoul(argv[1], NULL, 16); 86 87 if (!addr) 88 return CMD_RET_FAILURE; 89 90 ret = arch_auxiliary_core_up(core, addr); 91 if (ret) 92 return CMD_RET_FAILURE; 93 94 return CMD_RET_SUCCESS; 95} 96 97static int do_stopaux(struct cmd_tbl *cmdtp, int flag, int argc, 98 char *const argv[]) 99{ 100 int ret, up; 101 102 up = arch_auxiliary_core_check_up(0); 103 if (!up) { 104 printf("## Auxiliary core is already down\n"); 105 return CMD_RET_SUCCESS; 106 } 107 108 ret = arch_auxiliary_core_down(0); 109 if (ret) 110 return CMD_RET_FAILURE; 111 112 return CMD_RET_SUCCESS; 113} 114 115U_BOOT_CMD( 116 stopaux, CONFIG_SYS_MAXARGS, 1, do_stopaux, 117 "Stop auxiliary core", 118 "<address> [<core>]\n" 119 " - start auxiliary core [<core>] (default 0),\n" 120 " at address <address>\n" 121); 122 123U_BOOT_CMD( 124 bootaux, CONFIG_SYS_MAXARGS, 1, do_bootaux, 125 "Start auxiliary core", 126 "<address> [<core>]\n" 127 " - start auxiliary core [<core>] (default 0),\n" 128 " at address <address> of auxiliary core view\n" 129); 130