xref: /rk3399_ARM-atf/plat/st/common/stm32cubeprogrammer_uart.c (revision ef39709c04e74d4957ff3c3e6343210d1873ddc2)
1fb3e7985SPatrick Delaunay /*
2*ef39709cSPatrick Delaunay  * Copyright (c) 2021-2025, STMicroelectronics - All Rights Reserved
3fb3e7985SPatrick Delaunay  *
4fb3e7985SPatrick Delaunay  * SPDX-License-Identifier: BSD-3-Clause
5fb3e7985SPatrick Delaunay  */
6fb3e7985SPatrick Delaunay 
7fb3e7985SPatrick Delaunay #include <assert.h>
8fb3e7985SPatrick Delaunay #include <endian.h>
9fb3e7985SPatrick Delaunay #include <errno.h>
10fb3e7985SPatrick Delaunay #include <string.h>
11fb3e7985SPatrick Delaunay 
12fb3e7985SPatrick Delaunay #include <arch_helpers.h>
13fb3e7985SPatrick Delaunay #include <common/debug.h>
14fb3e7985SPatrick Delaunay #include <drivers/delay_timer.h>
15fb3e7985SPatrick Delaunay #include <drivers/st/stm32_iwdg.h>
16fb3e7985SPatrick Delaunay #include <drivers/st/stm32_uart.h>
17fb3e7985SPatrick Delaunay #include <drivers/st/stm32_uart_regs.h>
18fb3e7985SPatrick Delaunay #include <lib/mmio.h>
19fb3e7985SPatrick Delaunay #include <tools_share/firmware_image_package.h>
20fb3e7985SPatrick Delaunay 
21fb3e7985SPatrick Delaunay #include <platform_def.h>
22fb3e7985SPatrick Delaunay #include <stm32cubeprogrammer.h>
23fb3e7985SPatrick Delaunay 
24fb3e7985SPatrick Delaunay /* USART bootloader protocol version V4.0 */
25fb3e7985SPatrick Delaunay #define USART_BL_VERSION	0x40U
26fb3e7985SPatrick Delaunay 
27fb3e7985SPatrick Delaunay /* Command definition */
28fb3e7985SPatrick Delaunay #define GET_CMD_COMMAND		0x00U
29fb3e7985SPatrick Delaunay #define GET_VER_COMMAND		0x01U
30fb3e7985SPatrick Delaunay #define GET_ID_COMMAND		0x02U
31fb3e7985SPatrick Delaunay #define PHASE_COMMAND		0x03U
32fb3e7985SPatrick Delaunay #define READ_PART_COMMAND	0x12U
33fb3e7985SPatrick Delaunay #define START_COMMAND		0x21U
34fb3e7985SPatrick Delaunay #define DOWNLOAD_COMMAND	0x31U
35fb3e7985SPatrick Delaunay 
36fb3e7985SPatrick Delaunay /* Answer defines */
37fb3e7985SPatrick Delaunay #define INIT_BYTE		0x7FU
38fb3e7985SPatrick Delaunay #define ACK_BYTE		0x79U
39fb3e7985SPatrick Delaunay #define NACK_BYTE		0x1FU
40fb3e7985SPatrick Delaunay #define ABORT			0x5FU
41fb3e7985SPatrick Delaunay 
42fb3e7985SPatrick Delaunay #define UNDEFINED_DOWN_ADDR	U(0xFFFFFFFF)
43fb3e7985SPatrick Delaunay #define PROGRAMMER_TIMEOUT_US	20000U
44fb3e7985SPatrick Delaunay 
45fb3e7985SPatrick Delaunay static const uint8_t command_tab[] = {
46fb3e7985SPatrick Delaunay 	GET_CMD_COMMAND,
47fb3e7985SPatrick Delaunay 	GET_VER_COMMAND,
48fb3e7985SPatrick Delaunay 	GET_ID_COMMAND,
49fb3e7985SPatrick Delaunay 	PHASE_COMMAND,
50fb3e7985SPatrick Delaunay 	START_COMMAND,
51fb3e7985SPatrick Delaunay 	DOWNLOAD_COMMAND
52fb3e7985SPatrick Delaunay };
53fb3e7985SPatrick Delaunay 
54fb3e7985SPatrick Delaunay /* STM32CubeProgrammer over UART handle */
55fb3e7985SPatrick Delaunay struct stm32prog_uart_handle_s {
56fb3e7985SPatrick Delaunay 	struct stm32_uart_handle_s uart;
57fb3e7985SPatrick Delaunay 	uint32_t packet;
58fb3e7985SPatrick Delaunay 	uint8_t *addr;
59fb3e7985SPatrick Delaunay 	uint32_t len;
60fb3e7985SPatrick Delaunay 	uint8_t phase;
61fb3e7985SPatrick Delaunay 	/* Error msg buffer: max 255 in UART protocol, reduced in TF-A */
62fb3e7985SPatrick Delaunay 	uint8_t error[64];
63fb3e7985SPatrick Delaunay } handle;
64fb3e7985SPatrick Delaunay 
65fb3e7985SPatrick Delaunay /* Trace and handle unrecoverable UART protocol error */
66fb3e7985SPatrick Delaunay #define STM32PROG_ERROR(...) \
67fb3e7985SPatrick Delaunay 	{ \
68fb3e7985SPatrick Delaunay 		ERROR(__VA_ARGS__); \
69fb3e7985SPatrick Delaunay 		if (handle.phase != PHASE_RESET) { \
70fb3e7985SPatrick Delaunay 			snprintf((char *)&handle.error, sizeof(handle.error), __VA_ARGS__); \
71fb3e7985SPatrick Delaunay 			handle.phase = PHASE_RESET; \
72fb3e7985SPatrick Delaunay 			handle.addr = (uint8_t *)UNDEFINED_DOWN_ADDR; \
73fb3e7985SPatrick Delaunay 			handle.len = 0U; \
74fb3e7985SPatrick Delaunay 			handle.packet = 0U; \
75fb3e7985SPatrick Delaunay 		} \
76fb3e7985SPatrick Delaunay 	}
77fb3e7985SPatrick Delaunay 
78fb3e7985SPatrick Delaunay static int uart_write(const uint8_t *addr, uint16_t size)
79fb3e7985SPatrick Delaunay {
80fb3e7985SPatrick Delaunay 	while (size != 0U) {
81fb3e7985SPatrick Delaunay 		if (stm32_uart_putc(&handle.uart, *addr) != 0) {
82fb3e7985SPatrick Delaunay 			return -EIO;
83fb3e7985SPatrick Delaunay 		}
84fb3e7985SPatrick Delaunay 		size--;
85fb3e7985SPatrick Delaunay 		addr++;
86fb3e7985SPatrick Delaunay 	}
87fb3e7985SPatrick Delaunay 
88fb3e7985SPatrick Delaunay 	return 0;
89fb3e7985SPatrick Delaunay }
90fb3e7985SPatrick Delaunay 
91fb3e7985SPatrick Delaunay static int uart_write_8(uint8_t byte)
92fb3e7985SPatrick Delaunay {
93fb3e7985SPatrick Delaunay 	return stm32_uart_putc(&handle.uart, byte);
94fb3e7985SPatrick Delaunay }
95fb3e7985SPatrick Delaunay 
96fb3e7985SPatrick Delaunay static int uart_write_32(uint32_t value)
97fb3e7985SPatrick Delaunay {
98fb3e7985SPatrick Delaunay 	return uart_write((uint8_t *)&value, 4U);
99fb3e7985SPatrick Delaunay }
100fb3e7985SPatrick Delaunay 
101fb3e7985SPatrick Delaunay static int uart_read_8(uint8_t *byte)
102fb3e7985SPatrick Delaunay {
103fb3e7985SPatrick Delaunay 	int ret;
104fb3e7985SPatrick Delaunay 	uint64_t timeout_ref = timeout_init_us(PROGRAMMER_TIMEOUT_US);
105fb3e7985SPatrick Delaunay 
106fb3e7985SPatrick Delaunay 	do {
107fb3e7985SPatrick Delaunay 		ret = stm32_uart_getc(&handle.uart);
108fb3e7985SPatrick Delaunay 		if (ret == -EAGAIN) {
109fb3e7985SPatrick Delaunay 			if (timeout_elapsed(timeout_ref)) {
110fb3e7985SPatrick Delaunay 				return -ETIMEDOUT;
111fb3e7985SPatrick Delaunay 			}
112fb3e7985SPatrick Delaunay 		} else if (ret < 0) {
113fb3e7985SPatrick Delaunay 			return ret;
114fb3e7985SPatrick Delaunay 		}
115fb3e7985SPatrick Delaunay 	} while (ret == -EAGAIN);
116fb3e7985SPatrick Delaunay 
117fb3e7985SPatrick Delaunay 	*byte = (uint8_t)ret;
118fb3e7985SPatrick Delaunay 
119fb3e7985SPatrick Delaunay 	return 0;
120fb3e7985SPatrick Delaunay }
121fb3e7985SPatrick Delaunay 
122fb3e7985SPatrick Delaunay static int uart_send_result(uint8_t byte)
123fb3e7985SPatrick Delaunay {
124fb3e7985SPatrick Delaunay 	int ret;
125fb3e7985SPatrick Delaunay 
126fb3e7985SPatrick Delaunay 	/* Always flush fifo before to send result = read all pending data */
127fb3e7985SPatrick Delaunay 	do {
128fb3e7985SPatrick Delaunay 		ret = stm32_uart_getc(&handle.uart);
129fb3e7985SPatrick Delaunay 	} while (ret >= 0);
130fb3e7985SPatrick Delaunay 
131fb3e7985SPatrick Delaunay 	return uart_write_8(byte);
132fb3e7985SPatrick Delaunay }
133fb3e7985SPatrick Delaunay 
134fb3e7985SPatrick Delaunay static bool is_valid_header(fip_toc_header_t *header)
135fb3e7985SPatrick Delaunay {
136fb3e7985SPatrick Delaunay 	return (header->name == TOC_HEADER_NAME) &&
137fb3e7985SPatrick Delaunay 	       (header->serial_number != 0U);
138fb3e7985SPatrick Delaunay }
139fb3e7985SPatrick Delaunay 
140fb3e7985SPatrick Delaunay static int uart_receive_command(uint8_t *command)
141fb3e7985SPatrick Delaunay {
142fb3e7985SPatrick Delaunay 	uint8_t byte = 0U;
143fb3e7985SPatrick Delaunay 	uint8_t xor = 0U;
144fb3e7985SPatrick Delaunay 	unsigned int count;
145fb3e7985SPatrick Delaunay 	bool found = false;
146fb3e7985SPatrick Delaunay 	int ret;
147fb3e7985SPatrick Delaunay 
148fb3e7985SPatrick Delaunay 	/* Repeat read until something is received */
149fb3e7985SPatrick Delaunay 	do {
150fb3e7985SPatrick Delaunay 		stm32_iwdg_refresh();
151fb3e7985SPatrick Delaunay 		ret = uart_read_8(&byte);
152fb3e7985SPatrick Delaunay 	} while (ret == -ETIMEDOUT);
153fb3e7985SPatrick Delaunay 
154fb3e7985SPatrick Delaunay 	if (ret != 0) {
155fb3e7985SPatrick Delaunay 		return ret;
156fb3e7985SPatrick Delaunay 	}
157fb3e7985SPatrick Delaunay 
158fb3e7985SPatrick Delaunay 	/* Handle reconnection request */
159fb3e7985SPatrick Delaunay 	if (byte == INIT_BYTE) {
160fb3e7985SPatrick Delaunay 		*command = byte;
161fb3e7985SPatrick Delaunay 		return 0;
162fb3e7985SPatrick Delaunay 	}
163fb3e7985SPatrick Delaunay 
164fb3e7985SPatrick Delaunay 	for (count = 0U; count < ARRAY_SIZE(command_tab); count++) {
165fb3e7985SPatrick Delaunay 		if (command_tab[count] == byte) {
166fb3e7985SPatrick Delaunay 			found = true;
167fb3e7985SPatrick Delaunay 			break;
168fb3e7985SPatrick Delaunay 		}
169fb3e7985SPatrick Delaunay 	}
170fb3e7985SPatrick Delaunay 	if (!found) {
171fb3e7985SPatrick Delaunay 		VERBOSE("UART: Command unknown (byte=0x%x)\n", byte);
172fb3e7985SPatrick Delaunay 		return -EPROTO;
173fb3e7985SPatrick Delaunay 	}
174fb3e7985SPatrick Delaunay 
175fb3e7985SPatrick Delaunay 	ret = uart_read_8(&xor);
176fb3e7985SPatrick Delaunay 	if (ret != 0) {
177fb3e7985SPatrick Delaunay 		return ret;
178fb3e7985SPatrick Delaunay 	}
179fb3e7985SPatrick Delaunay 	if ((byte ^ xor) != 0xFF) {
180fb3e7985SPatrick Delaunay 		VERBOSE("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n",
181fb3e7985SPatrick Delaunay 			byte, xor);
182fb3e7985SPatrick Delaunay 		return -EPROTO;
183fb3e7985SPatrick Delaunay 	}
184fb3e7985SPatrick Delaunay 
185fb3e7985SPatrick Delaunay 	*command = byte;
186fb3e7985SPatrick Delaunay 
187fb3e7985SPatrick Delaunay 	return 0;
188fb3e7985SPatrick Delaunay }
189fb3e7985SPatrick Delaunay 
190fb3e7985SPatrick Delaunay static int get_cmd_command(void)
191fb3e7985SPatrick Delaunay {
192fb3e7985SPatrick Delaunay 	const uint8_t msg[2] = {
193fb3e7985SPatrick Delaunay 		sizeof(command_tab), /* Length of data - 1 */
194fb3e7985SPatrick Delaunay 		USART_BL_VERSION
195fb3e7985SPatrick Delaunay 	};
196fb3e7985SPatrick Delaunay 	int ret;
197fb3e7985SPatrick Delaunay 
198fb3e7985SPatrick Delaunay 	ret = uart_write(msg, sizeof(msg));
199fb3e7985SPatrick Delaunay 	if (ret != 0) {
200fb3e7985SPatrick Delaunay 		return ret;
201fb3e7985SPatrick Delaunay 	}
202fb3e7985SPatrick Delaunay 
203fb3e7985SPatrick Delaunay 	return uart_write(command_tab, sizeof(command_tab));
204fb3e7985SPatrick Delaunay }
205fb3e7985SPatrick Delaunay 
206fb3e7985SPatrick Delaunay static int get_version_command(void)
207fb3e7985SPatrick Delaunay {
208fb3e7985SPatrick Delaunay 	return uart_write_8(STM32_TF_VERSION);
209fb3e7985SPatrick Delaunay }
210fb3e7985SPatrick Delaunay 
211fb3e7985SPatrick Delaunay static int get_id_command(void)
212fb3e7985SPatrick Delaunay {
213fb3e7985SPatrick Delaunay 	uint8_t msg[3] = {
214fb3e7985SPatrick Delaunay 		sizeof(msg) - 1 /* Length of data - 1 */
215fb3e7985SPatrick Delaunay 	};
216fb3e7985SPatrick Delaunay 	uint32_t chip_id = stm32mp_get_chip_dev_id();
217fb3e7985SPatrick Delaunay 
218fb3e7985SPatrick Delaunay 	be16enc(&msg[1], chip_id);
219fb3e7985SPatrick Delaunay 
220fb3e7985SPatrick Delaunay 	return uart_write(msg, sizeof(msg));
221fb3e7985SPatrick Delaunay }
222fb3e7985SPatrick Delaunay 
223fb3e7985SPatrick Delaunay static int uart_send_phase(uint32_t address)
224fb3e7985SPatrick Delaunay {
225fb3e7985SPatrick Delaunay 	int ret;
226fb3e7985SPatrick Delaunay 	uint8_t msg_size = 5U; /* Length of data - 1 */
227fb3e7985SPatrick Delaunay 	uint8_t error_size = 0U;
228fb3e7985SPatrick Delaunay 
229fb3e7985SPatrick Delaunay 	/* Additional information only for RESET phase */
230fb3e7985SPatrick Delaunay 	if (handle.phase == PHASE_RESET) {
231fb3e7985SPatrick Delaunay 		error_size = strnlen((char *)&handle.error, sizeof(handle.error));
232fb3e7985SPatrick Delaunay 	}
233fb3e7985SPatrick Delaunay 	ret = uart_write_8(msg_size + error_size);
234fb3e7985SPatrick Delaunay 	if (ret != 0) {
235fb3e7985SPatrick Delaunay 		return ret;
236fb3e7985SPatrick Delaunay 	}
237fb3e7985SPatrick Delaunay 
238fb3e7985SPatrick Delaunay 	/* Send the ID of next partition */
239fb3e7985SPatrick Delaunay 	ret = uart_write_8(handle.phase);
240fb3e7985SPatrick Delaunay 	if (ret != 0) {
241fb3e7985SPatrick Delaunay 		return ret;
242fb3e7985SPatrick Delaunay 	}
243fb3e7985SPatrick Delaunay 
244fb3e7985SPatrick Delaunay 	/* Destination address */
245fb3e7985SPatrick Delaunay 	ret = uart_write_32(address);
246fb3e7985SPatrick Delaunay 	if (ret != 0) {
247fb3e7985SPatrick Delaunay 		return ret;
248fb3e7985SPatrick Delaunay 	}
249fb3e7985SPatrick Delaunay 
250fb3e7985SPatrick Delaunay 	ret = uart_write_8(error_size);
251fb3e7985SPatrick Delaunay 	if (ret != 0) {
252fb3e7985SPatrick Delaunay 		return ret;
253fb3e7985SPatrick Delaunay 	}
254fb3e7985SPatrick Delaunay 
255fb3e7985SPatrick Delaunay 	/* Additional information: message error */
256fb3e7985SPatrick Delaunay 	if (error_size > 0U) {
257fb3e7985SPatrick Delaunay 		ret = uart_write(handle.error, error_size);
258fb3e7985SPatrick Delaunay 	}
259fb3e7985SPatrick Delaunay 
260fb3e7985SPatrick Delaunay 	return ret;
261fb3e7985SPatrick Delaunay }
262fb3e7985SPatrick Delaunay 
263fb3e7985SPatrick Delaunay static int uart_download_part(void)
264fb3e7985SPatrick Delaunay {
265fb3e7985SPatrick Delaunay 	uint8_t operation = 0U;
266fb3e7985SPatrick Delaunay 	uint8_t xor;
267fb3e7985SPatrick Delaunay 	uint8_t byte = 0U;
268fb3e7985SPatrick Delaunay 	uint32_t packet_number = 0U;
269fb3e7985SPatrick Delaunay 	uint32_t packet_size = 0U;
270fb3e7985SPatrick Delaunay 	uint32_t i = 0U;
271fb3e7985SPatrick Delaunay 	int ret;
272fb3e7985SPatrick Delaunay 
273fb3e7985SPatrick Delaunay 	/* Get operation number */
274fb3e7985SPatrick Delaunay 	ret = uart_read_8(&operation);
275fb3e7985SPatrick Delaunay 	if (ret != 0) {
276fb3e7985SPatrick Delaunay 		return ret;
277fb3e7985SPatrick Delaunay 	}
278fb3e7985SPatrick Delaunay 
279fb3e7985SPatrick Delaunay 	xor = operation;
280fb3e7985SPatrick Delaunay 
281fb3e7985SPatrick Delaunay 	/* Get packet number */
282fb3e7985SPatrick Delaunay 	for (i = 3U; i != 0U; i--) {
283fb3e7985SPatrick Delaunay 		ret = uart_read_8(&byte);
284fb3e7985SPatrick Delaunay 		if (ret != 0) {
285fb3e7985SPatrick Delaunay 			return ret;
286fb3e7985SPatrick Delaunay 		}
287fb3e7985SPatrick Delaunay 
288fb3e7985SPatrick Delaunay 		xor ^= byte;
289fb3e7985SPatrick Delaunay 		packet_number = (packet_number << 8) | byte;
290fb3e7985SPatrick Delaunay 	}
291fb3e7985SPatrick Delaunay 
292fb3e7985SPatrick Delaunay 	if (packet_number != handle.packet) {
293fb3e7985SPatrick Delaunay 		WARN("UART: Bad packet number receive: %u, expected %u\n",
294fb3e7985SPatrick Delaunay 		     packet_number, handle.packet);
295fb3e7985SPatrick Delaunay 		return -EPROTO;
296fb3e7985SPatrick Delaunay 	}
297fb3e7985SPatrick Delaunay 
298fb3e7985SPatrick Delaunay 	/* Checksum */
299fb3e7985SPatrick Delaunay 	ret = uart_read_8(&byte);
300fb3e7985SPatrick Delaunay 	if (ret != 0) {
301fb3e7985SPatrick Delaunay 		return ret;
302fb3e7985SPatrick Delaunay 	}
303fb3e7985SPatrick Delaunay 	if (xor != byte) {
304fb3e7985SPatrick Delaunay 		VERBOSE("UART: Download Command checksum xor: %x, received %x\n",
305fb3e7985SPatrick Delaunay 			xor, byte);
306fb3e7985SPatrick Delaunay 		return -EPROTO;
307fb3e7985SPatrick Delaunay 	}
308fb3e7985SPatrick Delaunay 
309fb3e7985SPatrick Delaunay 	ret = uart_send_result(ACK_BYTE);
310fb3e7985SPatrick Delaunay 	if (ret != 0) {
311fb3e7985SPatrick Delaunay 		return ret;
312fb3e7985SPatrick Delaunay 	}
313fb3e7985SPatrick Delaunay 
314fb3e7985SPatrick Delaunay 	ret = uart_read_8(&byte);
315fb3e7985SPatrick Delaunay 	if (ret != 0) {
316fb3e7985SPatrick Delaunay 		return ret;
317fb3e7985SPatrick Delaunay 	}
318fb3e7985SPatrick Delaunay 	xor = byte;
319fb3e7985SPatrick Delaunay 	packet_size = byte + 1U;
320fb3e7985SPatrick Delaunay 	if (handle.len < packet_size) {
321fb3e7985SPatrick Delaunay 		STM32PROG_ERROR("Download overflow at %p\n", handle.addr + packet_size);
322fb3e7985SPatrick Delaunay 		return 0;
323fb3e7985SPatrick Delaunay 	}
324fb3e7985SPatrick Delaunay 
325fb3e7985SPatrick Delaunay 	for (i = 0U; i < packet_size; i++) {
326fb3e7985SPatrick Delaunay 		ret = uart_read_8(&byte);
327fb3e7985SPatrick Delaunay 		if (ret != 0) {
328fb3e7985SPatrick Delaunay 			return ret;
329fb3e7985SPatrick Delaunay 		}
330fb3e7985SPatrick Delaunay 
331fb3e7985SPatrick Delaunay 		*(handle.addr + i) = byte;
332fb3e7985SPatrick Delaunay 		xor ^= byte;
333fb3e7985SPatrick Delaunay 	}
334fb3e7985SPatrick Delaunay 
335fb3e7985SPatrick Delaunay 	/* Checksum */
336fb3e7985SPatrick Delaunay 	ret = uart_read_8(&byte) != 0;
337fb3e7985SPatrick Delaunay 	if (ret != 0) {
338fb3e7985SPatrick Delaunay 		return ret;
339fb3e7985SPatrick Delaunay 	}
340fb3e7985SPatrick Delaunay 	if (xor != byte) {
341fb3e7985SPatrick Delaunay 		VERBOSE("UART: Download Data checksum xor: %x, received %x\n",
342fb3e7985SPatrick Delaunay 			xor, byte);
343fb3e7985SPatrick Delaunay 		return -EPROTO;
344fb3e7985SPatrick Delaunay 	}
345fb3e7985SPatrick Delaunay 
346fb3e7985SPatrick Delaunay 	/* Packet treated */
347fb3e7985SPatrick Delaunay 	handle.packet++;
348fb3e7985SPatrick Delaunay 	handle.addr += packet_size;
349fb3e7985SPatrick Delaunay 	handle.len -= packet_size;
350fb3e7985SPatrick Delaunay 
351fb3e7985SPatrick Delaunay 	return 0;
352fb3e7985SPatrick Delaunay }
353fb3e7985SPatrick Delaunay 
354fb3e7985SPatrick Delaunay static int uart_start_cmd(uintptr_t buffer)
355fb3e7985SPatrick Delaunay {
356fb3e7985SPatrick Delaunay 	uint8_t byte = 0U;
357fb3e7985SPatrick Delaunay 	uint8_t xor = 0U;
358fb3e7985SPatrick Delaunay 	uint32_t i;
359fb3e7985SPatrick Delaunay 	uint32_t start_address = 0U;
360fb3e7985SPatrick Delaunay 	int ret;
361fb3e7985SPatrick Delaunay 
362fb3e7985SPatrick Delaunay 	/* Get address */
363fb3e7985SPatrick Delaunay 	for (i = 4U; i != 0U; i--) {
364fb3e7985SPatrick Delaunay 		ret = uart_read_8(&byte);
365fb3e7985SPatrick Delaunay 		if (ret != 0U) {
366fb3e7985SPatrick Delaunay 			return ret;
367fb3e7985SPatrick Delaunay 		}
368fb3e7985SPatrick Delaunay 
369fb3e7985SPatrick Delaunay 		xor ^= byte;
370fb3e7985SPatrick Delaunay 		start_address = (start_address << 8) | byte;
371fb3e7985SPatrick Delaunay 	}
372fb3e7985SPatrick Delaunay 
373fb3e7985SPatrick Delaunay 	/* Checksum */
374fb3e7985SPatrick Delaunay 	ret = uart_read_8(&byte);
375fb3e7985SPatrick Delaunay 	if (ret != 0) {
376fb3e7985SPatrick Delaunay 		return ret;
377fb3e7985SPatrick Delaunay 	}
378fb3e7985SPatrick Delaunay 
379fb3e7985SPatrick Delaunay 	if (xor != byte) {
380fb3e7985SPatrick Delaunay 		VERBOSE("UART: Start Command checksum xor: %x, received %x\n",
381fb3e7985SPatrick Delaunay 			xor, byte);
382fb3e7985SPatrick Delaunay 		return -EPROTO;
383fb3e7985SPatrick Delaunay 	}
384fb3e7985SPatrick Delaunay 
385fb3e7985SPatrick Delaunay 	if (start_address != UNDEFINED_DOWN_ADDR) {
386fb3e7985SPatrick Delaunay 		STM32PROG_ERROR("Invalid start at %x, for phase %u\n",
387fb3e7985SPatrick Delaunay 				start_address, handle.phase);
388fb3e7985SPatrick Delaunay 		return 0;
389fb3e7985SPatrick Delaunay 	}
390fb3e7985SPatrick Delaunay 
391fb3e7985SPatrick Delaunay 	if (!is_valid_header((fip_toc_header_t *)buffer)) {
392fb3e7985SPatrick Delaunay 		STM32PROG_ERROR("FIP Header check failed %lx, for phase %u\n",
393fb3e7985SPatrick Delaunay 				buffer, handle.phase);
394fb3e7985SPatrick Delaunay 		return -EIO;
395fb3e7985SPatrick Delaunay 	}
396fb3e7985SPatrick Delaunay 	VERBOSE("FIP header looks OK.\n");
397fb3e7985SPatrick Delaunay 
398fb3e7985SPatrick Delaunay 	return 0;
399fb3e7985SPatrick Delaunay }
400fb3e7985SPatrick Delaunay 
401fb3e7985SPatrick Delaunay static int uart_read(uint8_t id, uintptr_t buffer, size_t length)
402fb3e7985SPatrick Delaunay {
403fb3e7985SPatrick Delaunay 	bool start_done = false;
404fb3e7985SPatrick Delaunay 	int ret;
405fb3e7985SPatrick Delaunay 	uint8_t command = 0U;
406fb3e7985SPatrick Delaunay 
407fb3e7985SPatrick Delaunay 	handle.phase = id;
408fb3e7985SPatrick Delaunay 	handle.packet = 0U;
409fb3e7985SPatrick Delaunay 	handle.addr = (uint8_t *)buffer;
410fb3e7985SPatrick Delaunay 	handle.len = length;
411fb3e7985SPatrick Delaunay 
4126fef0f67SYann Gautier 	INFO("UART: read phase %u at 0x%lx size 0x%zx\n",
413fb3e7985SPatrick Delaunay 	     id, buffer, length);
414fb3e7985SPatrick Delaunay 	while (!start_done) {
415fb3e7985SPatrick Delaunay 		ret = uart_receive_command(&command);
416fb3e7985SPatrick Delaunay 		if (ret != 0) {
417fb3e7985SPatrick Delaunay 			/* Delay to wait STM32CubeProgrammer end of transmission */
418fb3e7985SPatrick Delaunay 			mdelay(3);
419fb3e7985SPatrick Delaunay 
420fb3e7985SPatrick Delaunay 			ret = uart_send_result(NACK_BYTE);
421fb3e7985SPatrick Delaunay 			if (ret != 0U) {
422fb3e7985SPatrick Delaunay 				return ret;
423fb3e7985SPatrick Delaunay 			}
424fb3e7985SPatrick Delaunay 
425fb3e7985SPatrick Delaunay 			continue;
426fb3e7985SPatrick Delaunay 		}
427fb3e7985SPatrick Delaunay 
428fb3e7985SPatrick Delaunay 		uart_send_result(ACK_BYTE);
429fb3e7985SPatrick Delaunay 
430fb3e7985SPatrick Delaunay 		switch (command) {
431fb3e7985SPatrick Delaunay 		case INIT_BYTE:
432fb3e7985SPatrick Delaunay 			INFO("UART: Connected\n");
433fb3e7985SPatrick Delaunay 			/* Nothing to do */
434fb3e7985SPatrick Delaunay 			continue;
435fb3e7985SPatrick Delaunay 
436fb3e7985SPatrick Delaunay 		case GET_CMD_COMMAND:
437fb3e7985SPatrick Delaunay 			ret = get_cmd_command();
438fb3e7985SPatrick Delaunay 			break;
439fb3e7985SPatrick Delaunay 
440fb3e7985SPatrick Delaunay 		case GET_VER_COMMAND:
441fb3e7985SPatrick Delaunay 			ret = get_version_command();
442fb3e7985SPatrick Delaunay 			break;
443fb3e7985SPatrick Delaunay 
444fb3e7985SPatrick Delaunay 		case GET_ID_COMMAND:
445fb3e7985SPatrick Delaunay 			ret = get_id_command();
446fb3e7985SPatrick Delaunay 			break;
447fb3e7985SPatrick Delaunay 
448fb3e7985SPatrick Delaunay 		case PHASE_COMMAND:
449fb3e7985SPatrick Delaunay 			ret = uart_send_phase((uint32_t)buffer);
450fb3e7985SPatrick Delaunay 			if ((ret == 0) && (handle.phase == PHASE_RESET)) {
451fb3e7985SPatrick Delaunay 				start_done = true;
452fb3e7985SPatrick Delaunay 				INFO("UART: Reset\n");
453fb3e7985SPatrick Delaunay 			}
454fb3e7985SPatrick Delaunay 			break;
455fb3e7985SPatrick Delaunay 
456fb3e7985SPatrick Delaunay 		case DOWNLOAD_COMMAND:
457fb3e7985SPatrick Delaunay 			ret = uart_download_part();
458fb3e7985SPatrick Delaunay 			break;
459fb3e7985SPatrick Delaunay 
460fb3e7985SPatrick Delaunay 		case START_COMMAND:
461fb3e7985SPatrick Delaunay 			ret = uart_start_cmd(buffer);
462fb3e7985SPatrick Delaunay 			if ((ret == 0) && (handle.phase == id)) {
463fb3e7985SPatrick Delaunay 				INFO("UART: Start phase %u\n", handle.phase);
464fb3e7985SPatrick Delaunay 				start_done = true;
465fb3e7985SPatrick Delaunay 			}
466fb3e7985SPatrick Delaunay 			break;
467fb3e7985SPatrick Delaunay 
468fb3e7985SPatrick Delaunay 		default:
469fb3e7985SPatrick Delaunay 			WARN("UART: Unknown command\n");
470fb3e7985SPatrick Delaunay 			ret = -EINVAL;
471fb3e7985SPatrick Delaunay 			break;
472fb3e7985SPatrick Delaunay 		}
473fb3e7985SPatrick Delaunay 
474fb3e7985SPatrick Delaunay 		if (ret == 0) {
475fb3e7985SPatrick Delaunay 			ret = uart_send_result(ACK_BYTE);
476fb3e7985SPatrick Delaunay 		} else {
477fb3e7985SPatrick Delaunay 			ret = uart_send_result(NACK_BYTE);
478fb3e7985SPatrick Delaunay 		}
479fb3e7985SPatrick Delaunay 		if (ret != 0) {
480fb3e7985SPatrick Delaunay 			return ret;
481fb3e7985SPatrick Delaunay 		}
482fb3e7985SPatrick Delaunay 	}
483fb3e7985SPatrick Delaunay 
484a9cb7d00SYann Gautier 	stm32_uart_flush(&handle.uart);
485a9cb7d00SYann Gautier 
486fb3e7985SPatrick Delaunay 	return 0;
487fb3e7985SPatrick Delaunay }
488fb3e7985SPatrick Delaunay 
489fb3e7985SPatrick Delaunay /* Init UART: 115200, 8bit 1stop parity even and enable FIFO mode */
490fb3e7985SPatrick Delaunay const struct stm32_uart_init_s init = {
491e7705e9aSPatrick Delaunay 	.baud_rate = STM32MP_UART_BAUDRATE,
492fb3e7985SPatrick Delaunay 	.word_length = STM32_UART_WORDLENGTH_9B,
493fb3e7985SPatrick Delaunay 	.stop_bits = STM32_UART_STOPBITS_1,
494fb3e7985SPatrick Delaunay 	.parity = STM32_UART_PARITY_EVEN,
495fb3e7985SPatrick Delaunay 	.hw_flow_control = STM32_UART_HWCONTROL_NONE,
496fb3e7985SPatrick Delaunay 	.mode = STM32_UART_MODE_TX_RX,
497fb3e7985SPatrick Delaunay 	.fifo_mode = STM32_UART_FIFOMODE_EN,
498fb3e7985SPatrick Delaunay };
499fb3e7985SPatrick Delaunay 
500*ef39709cSPatrick Delaunay int stm32cubeprog_uart_load(uintptr_t instance, uint8_t phase, uintptr_t base,
501*ef39709cSPatrick Delaunay 			    size_t len)
502fb3e7985SPatrick Delaunay {
503fb3e7985SPatrick Delaunay 	int ret;
504fb3e7985SPatrick Delaunay 
505fb3e7985SPatrick Delaunay 	if (stm32_uart_init(&handle.uart, instance, &init) != 0) {
506fb3e7985SPatrick Delaunay 		return -EIO;
507fb3e7985SPatrick Delaunay 	}
508fb3e7985SPatrick Delaunay 
509fb3e7985SPatrick Delaunay 	/*
510fb3e7985SPatrick Delaunay 	 * The following NACK_BYTE is written because STM32CubeProgrammer has
511fb3e7985SPatrick Delaunay 	 * already sent its command before TF-A has reached this point, and
512fb3e7985SPatrick Delaunay 	 * because FIFO was not configured by BootROM.
513fb3e7985SPatrick Delaunay 	 * The byte in the UART_RX register is then the checksum and not the
514fb3e7985SPatrick Delaunay 	 * command. NACK_BYTE has to be written, so that the programmer will
515fb3e7985SPatrick Delaunay 	 * re-send the good command.
516fb3e7985SPatrick Delaunay 	 */
517fb3e7985SPatrick Delaunay 	ret = uart_send_result(NACK_BYTE);
518fb3e7985SPatrick Delaunay 	if (ret != 0) {
519fb3e7985SPatrick Delaunay 		return ret;
520fb3e7985SPatrick Delaunay 	}
521fb3e7985SPatrick Delaunay 
522*ef39709cSPatrick Delaunay 	return uart_read(phase, base, len);
523fb3e7985SPatrick Delaunay }
524