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