1fb3e7985SPatrick Delaunay /*
2ef39709cSPatrick 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
uart_write(const uint8_t * addr,uint16_t size)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
uart_write_8(uint8_t byte)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
uart_write_32(uint32_t value)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
uart_read_8(uint8_t * byte)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
uart_send_result(uint8_t byte)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
is_valid_header(fip_toc_header_t * header)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
uart_receive_command(uint8_t * command)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
get_cmd_command(void)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
get_version_command(void)206fb3e7985SPatrick Delaunay static int get_version_command(void)
207fb3e7985SPatrick Delaunay {
208fb3e7985SPatrick Delaunay return uart_write_8(STM32_TF_VERSION);
209fb3e7985SPatrick Delaunay }
210fb3e7985SPatrick Delaunay
get_id_command(void)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
uart_send_phase(uint32_t address)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
uart_download_part(void)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
uart_start_cmd(uintptr_t buffer)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
uart_read(uint8_t id,uintptr_t buffer,size_t length)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
stm32cubeprog_uart_load(uintptr_t instance,uint8_t phase,uintptr_t base,size_t len)500ef39709cSPatrick Delaunay int stm32cubeprog_uart_load(uintptr_t instance, uint8_t phase, uintptr_t base,
501ef39709cSPatrick Delaunay size_t len)
502fb3e7985SPatrick Delaunay {
503fb3e7985SPatrick Delaunay int ret;
504*ed889791SPatrick Delaunay static bool init_done;
505*ed889791SPatrick Delaunay
506*ed889791SPatrick Delaunay if (init_done) {
507*ed889791SPatrick Delaunay goto skip_init;
508*ed889791SPatrick Delaunay }
509fb3e7985SPatrick Delaunay
510fb3e7985SPatrick Delaunay if (stm32_uart_init(&handle.uart, instance, &init) != 0) {
511fb3e7985SPatrick Delaunay return -EIO;
512fb3e7985SPatrick Delaunay }
513fb3e7985SPatrick Delaunay
514fb3e7985SPatrick Delaunay /*
515fb3e7985SPatrick Delaunay * The following NACK_BYTE is written because STM32CubeProgrammer has
516fb3e7985SPatrick Delaunay * already sent its command before TF-A has reached this point, and
517fb3e7985SPatrick Delaunay * because FIFO was not configured by BootROM.
518fb3e7985SPatrick Delaunay * The byte in the UART_RX register is then the checksum and not the
519fb3e7985SPatrick Delaunay * command. NACK_BYTE has to be written, so that the programmer will
520fb3e7985SPatrick Delaunay * re-send the good command.
521fb3e7985SPatrick Delaunay */
522fb3e7985SPatrick Delaunay ret = uart_send_result(NACK_BYTE);
523fb3e7985SPatrick Delaunay if (ret != 0) {
524fb3e7985SPatrick Delaunay return ret;
525fb3e7985SPatrick Delaunay }
526fb3e7985SPatrick Delaunay
527*ed889791SPatrick Delaunay init_done = true;
528*ed889791SPatrick Delaunay
529*ed889791SPatrick Delaunay skip_init:
530*ed889791SPatrick Delaunay
531ef39709cSPatrick Delaunay return uart_read(phase, base, len);
532fb3e7985SPatrick Delaunay }
533