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