1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
4 */
5
6#include <common.h>
7#include <bootm.h>
8#include <command.h>
9#include <dfu.h>
10#include <image.h>
11#include <asm/arch/stm32prog.h>
12#include <linux/printk.h>
13#include "stm32prog.h"
14
15struct stm32prog_data *stm32prog_data;
16
17static void enable_vidconsole(void)
18{
19	char *stdname;
20	char buf[64];
21
22	stdname = env_get("stdout");
23	if (!stdname || !strstr(stdname, "vidconsole")) {
24		if (!stdname)
25			snprintf(buf, sizeof(buf), "serial,vidconsole");
26		else
27			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
28		env_set("stdout", buf);
29	}
30
31	stdname = env_get("stderr");
32	if (!stdname || !strstr(stdname, "vidconsole")) {
33		if (!stdname)
34			snprintf(buf, sizeof(buf), "serial,vidconsole");
35		else
36			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
37		env_set("stderr", buf);
38	}
39}
40
41static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc,
42			char * const argv[])
43{
44	ulong	addr, size;
45	int dev, ret;
46	enum stm32prog_link_t link = LINK_UNDEFINED;
47	bool reset = false;
48	struct image_header_s header;
49	struct stm32prog_data *data;
50
51	if (argc < 3 ||  argc > 5)
52		return CMD_RET_USAGE;
53
54	if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && !strcmp(argv[1], "usb"))
55		link = LINK_USB;
56	else if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && !strcmp(argv[1], "serial"))
57		link = LINK_SERIAL;
58
59	if (link == LINK_UNDEFINED) {
60		log_err("not supported link=%s\n", argv[1]);
61		return CMD_RET_USAGE;
62	}
63
64	dev = (int)dectoul(argv[2], NULL);
65
66	addr = CONFIG_SYS_LOAD_ADDR;
67	size = 0;
68	if (argc > 3) {
69		addr = hextoul(argv[3], NULL);
70		if (!addr)
71			return CMD_RET_FAILURE;
72	}
73	if (argc > 4)
74		size = hextoul(argv[4], NULL);
75
76	/* check STM32IMAGE presence */
77	if (size == 0) {
78		stm32prog_header_check(addr, &header);
79		if (header.type == HEADER_STM32IMAGE) {
80			size = header.image_length + header.length;
81		}
82	}
83
84	if (IS_ENABLED(CONFIG_VIDEO))
85		enable_vidconsole();
86
87	data = (struct stm32prog_data *)malloc(sizeof(*data));
88
89	if (!data) {
90		log_err("Alloc failed.");
91		return CMD_RET_FAILURE;
92	}
93	stm32prog_data = data;
94
95	ret = stm32prog_init(data, addr, size);
96	if (ret)
97		log_debug("Invalid or missing layout file at 0x%lx.\n", addr);
98
99	/* prepare DFU for device read/write */
100	ret = stm32prog_dfu_init(data);
101	if (ret)
102		goto cleanup;
103
104	switch (link) {
105	case LINK_SERIAL:
106		ret = stm32prog_serial_init(data, dev);
107		if (ret)
108			goto cleanup;
109		reset = stm32prog_serial_loop(data);
110		break;
111	case LINK_USB:
112		reset = stm32prog_usb_loop(data, dev);
113		break;
114	default:
115		goto cleanup;
116	}
117
118	stm32prog_clean(data);
119	free(stm32prog_data);
120	stm32prog_data = NULL;
121
122	puts("Download done\n");
123
124	if (data->uimage) {
125		char boot_addr_start[20];
126		char dtb_addr[20];
127		char initrd_addr[40];
128		char *fdt_arg, *initrd_arg;
129		const void *uimage = (void *)data->uimage;
130		const void *dtb = (void *)data->dtb;
131		const void *initrd = (void *)data->initrd;
132		struct bootm_info bmi;
133
134		fdt_arg = dtb_addr;
135		if (!dtb)
136			fdt_arg = env_get("fdtcontroladdr");
137		else
138			snprintf(dtb_addr, sizeof(dtb_addr) - 1, "0x%p", dtb);
139
140		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
141			 "0x%p", uimage);
142
143		initrd_arg = NULL;
144		if (initrd) {
145			snprintf(initrd_addr, sizeof(initrd_addr) - 1,
146				 "0x%p:0x%zx", initrd, data->initrd_size);
147			initrd_arg = initrd_addr;
148		}
149
150		printf("Booting kernel at %s %s %s...\n\n\n", boot_addr_start,
151		       initrd_arg ?: "-", fdt_arg);
152
153		bootm_init(&bmi);
154		bmi.addr_img = boot_addr_start;
155		bmi.conf_ramdisk = initrd_arg;
156		bmi.conf_fdt = fdt_arg;
157
158		/* Try bootm for legacy and FIT format image */
159		if (genimg_get_format(uimage) != IMAGE_FORMAT_INVALID)
160			bootm_run(&bmi);
161		else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
162			bootz_run(&bmi);
163	}
164	if (data->script)
165		cmd_source_script(data->script, NULL, NULL);
166
167	if (reset) {
168		puts("Reset...\n");
169		run_command("reset", 0);
170	}
171
172	return CMD_RET_SUCCESS;
173
174cleanup:
175	stm32prog_clean(data);
176	free(stm32prog_data);
177	stm32prog_data = NULL;
178
179	return CMD_RET_FAILURE;
180}
181
182U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
183	   "start communication with tools STM32Cubeprogrammer",
184	   "<link> <dev> [<addr>] [<size>]\n"
185	   "  <link> = serial|usb\n"
186	   "  <dev>  = device instance\n"
187	   "  <addr> = address of flashlayout\n"
188	   "  <size> = size of flashlayout (optional for image with STM32 header)\n"
189);
190
191
192bool stm32prog_get_fsbl_nor(void)
193{
194	if (stm32prog_data)
195		return stm32prog_data->fsbl_nor_detected;
196
197	return false;
198}
199