aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
blob: a8372356b0e80440fde47d53d8196a5dc8dbea0a (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
 * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
 */

#include <common.h>
#include <command.h>
#include <dfu.h>
#include <image.h>
#include <asm/arch/stm32prog.h>
#include "stm32prog.h"

struct stm32prog_data *stm32prog_data;

static void enable_vidconsole(void)
{
	char *stdname;
	char buf[64];

	stdname = env_get("stdout");
	if (!stdname || !strstr(stdname, "vidconsole")) {
		if (!stdname)
			snprintf(buf, sizeof(buf), "serial,vidconsole");
		else
			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
		env_set("stdout", buf);
	}

	stdname = env_get("stderr");
	if (!stdname || !strstr(stdname, "vidconsole")) {
		if (!stdname)
			snprintf(buf, sizeof(buf), "serial,vidconsole");
		else
			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
		env_set("stderr", buf);
	}
}

static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc,
			char * const argv[])
{
	ulong	addr, size;
	int dev, ret;
	enum stm32prog_link_t link = LINK_UNDEFINED;
	bool reset = false;
	struct image_header_s header;
	struct stm32prog_data *data;

	if (argc < 3 ||  argc > 5)
		return CMD_RET_USAGE;

	if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && !strcmp(argv[1], "usb"))
		link = LINK_USB;
	else if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && !strcmp(argv[1], "serial"))
		link = LINK_SERIAL;

	if (link == LINK_UNDEFINED) {
		log_err("not supported link=%s\n", argv[1]);
		return CMD_RET_USAGE;
	}

	dev = (int)dectoul(argv[2], NULL);

	addr = CONFIG_SYS_LOAD_ADDR;
	size = 0;
	if (argc > 3) {
		addr = hextoul(argv[3], NULL);
		if (!addr)
			return CMD_RET_FAILURE;
	}
	if (argc > 4)
		size = hextoul(argv[4], NULL);

	/* check STM32IMAGE presence */
	if (size == 0) {
		stm32prog_header_check(addr, &header);
		if (header.type == HEADER_STM32IMAGE) {
			size = header.image_length + header.length;
		}
	}

	if (IS_ENABLED(CONFIG_VIDEO))
		enable_vidconsole();

	data = (struct stm32prog_data *)malloc(sizeof(*data));

	if (!data) {
		log_err("Alloc failed.");
		return CMD_RET_FAILURE;
	}
	stm32prog_data = data;

	ret = stm32prog_init(data, addr, size);
	if (ret)
		log_debug("Invalid or missing layout file at 0x%lx.\n", addr);

	/* prepare DFU for device read/write */
	ret = stm32prog_dfu_init(data);
	if (ret)
		goto cleanup;

	switch (link) {
	case LINK_SERIAL:
		ret = stm32prog_serial_init(data, dev);
		if (ret)
			goto cleanup;
		reset = stm32prog_serial_loop(data);
		break;
	case LINK_USB:
		reset = stm32prog_usb_loop(data, dev);
		break;
	default:
		goto cleanup;
	}

	stm32prog_clean(data);
	free(stm32prog_data);
	stm32prog_data = NULL;

	puts("Download done\n");

	if (data->uimage) {
		char boot_addr_start[20];
		char dtb_addr[20];
		char initrd_addr[40];
		char *bootm_argv[5] = {
			"bootm", boot_addr_start, "-", dtb_addr, NULL
		};
		const void *uimage = (void *)data->uimage;
		const void *dtb = (void *)data->dtb;
		const void *initrd = (void *)data->initrd;

		if (!dtb)
			bootm_argv[3] = env_get("fdtcontroladdr");
		else
			snprintf(dtb_addr, sizeof(dtb_addr) - 1,
				 "0x%p", dtb);

		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
			 "0x%p", uimage);

		if (initrd) {
			snprintf(initrd_addr, sizeof(initrd_addr) - 1, "0x%p:0x%zx",
				 initrd, data->initrd_size);
			bootm_argv[2] = initrd_addr;
		}

		printf("Booting kernel at %s %s %s...\n\n\n",
		       boot_addr_start, bootm_argv[2], bootm_argv[3]);
		/* Try bootm for legacy and FIT format image */
		if (genimg_get_format(uimage) != IMAGE_FORMAT_INVALID)
			do_bootm(cmdtp, 0, 4, bootm_argv);
		else if (CONFIG_IS_ENABLED(CMD_BOOTZ))
			do_bootz(cmdtp, 0, 4, bootm_argv);
	}
	if (data->script)
		cmd_source_script(data->script, NULL, NULL);

	if (reset) {
		puts("Reset...\n");
		run_command("reset", 0);
	}

	return CMD_RET_SUCCESS;

cleanup:
	stm32prog_clean(data);
	free(stm32prog_data);
	stm32prog_data = NULL;

	return CMD_RET_FAILURE;
}

U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
	   "start communication with tools STM32Cubeprogrammer",
	   "<link> <dev> [<addr>] [<size>]\n"
	   "  <link> = serial|usb\n"
	   "  <dev>  = device instance\n"
	   "  <addr> = address of flashlayout\n"
	   "  <size> = size of flashlayout (optional for image with STM32 header)\n"
);

#ifdef CONFIG_STM32MP15x_STM32IMAGE
bool stm32prog_get_tee_partitions(void)
{
	if (stm32prog_data)
		return stm32prog_data->tee_detected;

	return false;
}
#endif

bool stm32prog_get_fsbl_nor(void)
{
	if (stm32prog_data)
		return stm32prog_data->fsbl_nor_detected;

	return false;
}