aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/imx9/imx_bootaux.c
blob: 73f2e72263d6edd8d6873fae952c72bcc0959858 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2022 NXP
 */

#include <command.h>
#include <log.h>
#include <imx_sip.h>
#include <vsprintf.h>
#include <linux/arm-smccc.h>
#include <linux/errno.h>

int arch_auxiliary_core_check_up(u32 core_id)
{
	struct arm_smccc_res res;

	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STARTED, 0, 0,
		      0, 0, 0, 0, &res);

	return res.a0;
}

int arch_auxiliary_core_down(u32 core_id)
{
	struct arm_smccc_res res;

	printf("## Stopping auxiliary core\n");

	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STOP, 0, 0,
		      0, 0, 0, 0, &res);

	return 0;
}

int arch_auxiliary_core_up(u32 core_id, ulong addr)
{
	struct arm_smccc_res res;

	if (!addr)
		return -EINVAL;

	printf("## Starting auxiliary core addr = 0x%08lX...\n", addr);

	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_START, addr, 0,
		      0, 0, 0, 0, &res);

	return 0;
}

/*
 * To i.MX6SX and i.MX7D, the image supported by bootaux needs
 * the reset vector at the head for the image, with SP and PC
 * as the first two words.
 *
 * Per the cortex-M reference manual, the reset vector of M4/M7 needs
 * to exist at 0x0 (TCMUL/IDTCM). The PC and SP are the first two addresses
 * of that vector.  So to boot M4/M7, the A core must build the M4/M7's reset
 * vector with getting the PC and SP from image and filling them to
 * TCMUL/IDTCM. When M4/M7 is kicked, it will load the PC and SP by itself.
 * The TCMUL/IDTCM is mapped to (MCU_BOOTROM_BASE_ADDR) at A core side for
 * accessing the M4/M7 TCMUL/IDTCM.
 */
static int do_bootaux(struct cmd_tbl *cmdtp, int flag, int argc,
		      char *const argv[])
{
	ulong addr;
	int ret, up;
	u32 core = 0;
	u32 stop = 0;

	if (argc < 2)
		return CMD_RET_USAGE;

	if (argc > 2)
		core = simple_strtoul(argv[2], NULL, 10);

	if (argc > 3)
		stop = simple_strtoul(argv[3], NULL, 10);

	up = arch_auxiliary_core_check_up(core);
	if (up) {
		printf("## Auxiliary core is already up\n");
		return CMD_RET_SUCCESS;
	}

	addr = simple_strtoul(argv[1], NULL, 16);

	if (!addr)
		return CMD_RET_FAILURE;

	ret = arch_auxiliary_core_up(core, addr);
	if (ret)
		return CMD_RET_FAILURE;

	return CMD_RET_SUCCESS;
}

static int do_stopaux(struct cmd_tbl *cmdtp, int flag, int argc,
		      char *const argv[])
{
	int ret, up;

	up = arch_auxiliary_core_check_up(0);
	if (!up) {
		printf("## Auxiliary core is already down\n");
		return CMD_RET_SUCCESS;
	}

	ret = arch_auxiliary_core_down(0);
	if (ret)
		return CMD_RET_FAILURE;

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
	stopaux, CONFIG_SYS_MAXARGS, 1,	do_stopaux,
	"Stop auxiliary core",
	"<address> [<core>]\n"
	"   - start auxiliary core [<core>] (default 0),\n"
	"     at address <address>\n"
);

U_BOOT_CMD(
	bootaux, CONFIG_SYS_MAXARGS, 1,	do_bootaux,
	"Start auxiliary core",
	"<address> [<core>]\n"
	"   - start auxiliary core [<core>] (default 0),\n"
	"     at address <address> of auxiliary core view\n"
);