1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <string.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <tools_share/firmware_image_package.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <stm32cubeprogrammer.h> 14*91f16700Schasinglulu #include <usb_dfu.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu /* Undefined download address */ 17*91f16700Schasinglulu #define UNDEFINED_DOWN_ADDR 0xFFFFFFFF 18*91f16700Schasinglulu 19*91f16700Schasinglulu struct dfu_state { 20*91f16700Schasinglulu uint8_t phase; 21*91f16700Schasinglulu uintptr_t base; 22*91f16700Schasinglulu size_t len; 23*91f16700Schasinglulu uintptr_t address; 24*91f16700Schasinglulu /* working buffer */ 25*91f16700Schasinglulu uint8_t buffer[UCHAR_MAX]; 26*91f16700Schasinglulu }; 27*91f16700Schasinglulu 28*91f16700Schasinglulu static struct dfu_state dfu_state; 29*91f16700Schasinglulu 30*91f16700Schasinglulu /* minimal size of Get Pḧase = offset for additionnl information */ 31*91f16700Schasinglulu #define GET_PHASE_LEN 9 32*91f16700Schasinglulu 33*91f16700Schasinglulu #define DFU_ERROR(...) \ 34*91f16700Schasinglulu { \ 35*91f16700Schasinglulu ERROR(__VA_ARGS__); \ 36*91f16700Schasinglulu if (dfu->phase != PHASE_RESET) { \ 37*91f16700Schasinglulu snprintf((char *)&dfu->buffer[GET_PHASE_LEN], \ 38*91f16700Schasinglulu sizeof(dfu->buffer) - GET_PHASE_LEN, \ 39*91f16700Schasinglulu __VA_ARGS__); \ 40*91f16700Schasinglulu dfu->phase = PHASE_RESET; \ 41*91f16700Schasinglulu dfu->address = UNDEFINED_DOWN_ADDR; \ 42*91f16700Schasinglulu dfu->len = 0; \ 43*91f16700Schasinglulu } \ 44*91f16700Schasinglulu } 45*91f16700Schasinglulu 46*91f16700Schasinglulu static bool is_valid_header(fip_toc_header_t *header) 47*91f16700Schasinglulu { 48*91f16700Schasinglulu if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0U)) { 49*91f16700Schasinglulu return true; 50*91f16700Schasinglulu } 51*91f16700Schasinglulu 52*91f16700Schasinglulu return false; 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu static int dfu_callback_upload(uint8_t alt, uintptr_t *buffer, uint32_t *len, 56*91f16700Schasinglulu void *user_data) 57*91f16700Schasinglulu { 58*91f16700Schasinglulu int result = 0; 59*91f16700Schasinglulu uint32_t length = 0; 60*91f16700Schasinglulu struct dfu_state *dfu = (struct dfu_state *)user_data; 61*91f16700Schasinglulu 62*91f16700Schasinglulu switch (usb_dfu_get_phase(alt)) { 63*91f16700Schasinglulu case PHASE_CMD: 64*91f16700Schasinglulu /* Get Pḧase */ 65*91f16700Schasinglulu dfu->buffer[0] = dfu->phase; 66*91f16700Schasinglulu dfu->buffer[1] = (uint8_t)(dfu->address); 67*91f16700Schasinglulu dfu->buffer[2] = (uint8_t)(dfu->address >> 8); 68*91f16700Schasinglulu dfu->buffer[3] = (uint8_t)(dfu->address >> 16); 69*91f16700Schasinglulu dfu->buffer[4] = (uint8_t)(dfu->address >> 24); 70*91f16700Schasinglulu dfu->buffer[5] = 0x00; 71*91f16700Schasinglulu dfu->buffer[6] = 0x00; 72*91f16700Schasinglulu dfu->buffer[7] = 0x00; 73*91f16700Schasinglulu dfu->buffer[8] = 0x00; 74*91f16700Schasinglulu length = GET_PHASE_LEN; 75*91f16700Schasinglulu if (dfu->phase == PHASE_FLASHLAYOUT && 76*91f16700Schasinglulu dfu->address == UNDEFINED_DOWN_ADDR) { 77*91f16700Schasinglulu INFO("Send detach request\n"); 78*91f16700Schasinglulu dfu->buffer[length++] = 0x01; 79*91f16700Schasinglulu } 80*91f16700Schasinglulu if (dfu->phase == PHASE_RESET) { 81*91f16700Schasinglulu /* error information is added by DFU_ERROR macro */ 82*91f16700Schasinglulu length += strnlen((char *)&dfu->buffer[GET_PHASE_LEN], 83*91f16700Schasinglulu sizeof(dfu->buffer) - GET_PHASE_LEN) 84*91f16700Schasinglulu - 1; 85*91f16700Schasinglulu } 86*91f16700Schasinglulu break; 87*91f16700Schasinglulu 88*91f16700Schasinglulu default: 89*91f16700Schasinglulu DFU_ERROR("phase ID :%i, alternate %i for phase %i\n", 90*91f16700Schasinglulu dfu->phase, alt, usb_dfu_get_phase(alt)); 91*91f16700Schasinglulu result = -EIO; 92*91f16700Schasinglulu break; 93*91f16700Schasinglulu } 94*91f16700Schasinglulu 95*91f16700Schasinglulu if (result == 0) { 96*91f16700Schasinglulu *len = length; 97*91f16700Schasinglulu *buffer = (uintptr_t)dfu->buffer; 98*91f16700Schasinglulu } 99*91f16700Schasinglulu 100*91f16700Schasinglulu return result; 101*91f16700Schasinglulu } 102*91f16700Schasinglulu 103*91f16700Schasinglulu static int dfu_callback_download(uint8_t alt, uintptr_t *buffer, uint32_t *len, 104*91f16700Schasinglulu void *user_data) 105*91f16700Schasinglulu { 106*91f16700Schasinglulu struct dfu_state *dfu = (struct dfu_state *)user_data; 107*91f16700Schasinglulu 108*91f16700Schasinglulu if ((dfu->phase != usb_dfu_get_phase(alt)) || 109*91f16700Schasinglulu (dfu->address == UNDEFINED_DOWN_ADDR)) { 110*91f16700Schasinglulu DFU_ERROR("phase ID :%i, alternate %i, address %x\n", 111*91f16700Schasinglulu dfu->phase, alt, (uint32_t)dfu->address); 112*91f16700Schasinglulu return -EIO; 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu VERBOSE("Download %d %lx %x\n", alt, dfu->address, *len); 116*91f16700Schasinglulu *buffer = dfu->address; 117*91f16700Schasinglulu dfu->address += *len; 118*91f16700Schasinglulu 119*91f16700Schasinglulu if (dfu->address - dfu->base > dfu->len) { 120*91f16700Schasinglulu return -EIO; 121*91f16700Schasinglulu } 122*91f16700Schasinglulu 123*91f16700Schasinglulu return 0; 124*91f16700Schasinglulu } 125*91f16700Schasinglulu 126*91f16700Schasinglulu static int dfu_callback_manifestation(uint8_t alt, void *user_data) 127*91f16700Schasinglulu { 128*91f16700Schasinglulu struct dfu_state *dfu = (struct dfu_state *)user_data; 129*91f16700Schasinglulu 130*91f16700Schasinglulu if (dfu->phase != usb_dfu_get_phase(alt)) { 131*91f16700Schasinglulu ERROR("Manifestation phase ID :%i, alternate %i, address %lx\n", 132*91f16700Schasinglulu dfu->phase, alt, dfu->address); 133*91f16700Schasinglulu return -EIO; 134*91f16700Schasinglulu } 135*91f16700Schasinglulu 136*91f16700Schasinglulu INFO("phase ID :%i, Manifestation %d at %lx\n", 137*91f16700Schasinglulu dfu->phase, alt, dfu->address); 138*91f16700Schasinglulu 139*91f16700Schasinglulu switch (dfu->phase) { 140*91f16700Schasinglulu case PHASE_SSBL: 141*91f16700Schasinglulu if (!is_valid_header((fip_toc_header_t *)dfu->base)) { 142*91f16700Schasinglulu DFU_ERROR("FIP Header check failed for phase %d\n", alt); 143*91f16700Schasinglulu return -EIO; 144*91f16700Schasinglulu } 145*91f16700Schasinglulu VERBOSE("FIP header looks OK.\n"); 146*91f16700Schasinglulu 147*91f16700Schasinglulu /* Configure End with request detach */ 148*91f16700Schasinglulu dfu->phase = PHASE_FLASHLAYOUT; 149*91f16700Schasinglulu dfu->address = UNDEFINED_DOWN_ADDR; 150*91f16700Schasinglulu dfu->len = 0; 151*91f16700Schasinglulu break; 152*91f16700Schasinglulu default: 153*91f16700Schasinglulu DFU_ERROR("Unknown phase\n"); 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu return 0; 157*91f16700Schasinglulu } 158*91f16700Schasinglulu 159*91f16700Schasinglulu /* Open a connection to the USB device */ 160*91f16700Schasinglulu static const struct usb_dfu_media usb_dfu_fops = { 161*91f16700Schasinglulu .upload = dfu_callback_upload, 162*91f16700Schasinglulu .download = dfu_callback_download, 163*91f16700Schasinglulu .manifestation = dfu_callback_manifestation, 164*91f16700Schasinglulu }; 165*91f16700Schasinglulu 166*91f16700Schasinglulu int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle, 167*91f16700Schasinglulu uintptr_t base, 168*91f16700Schasinglulu size_t len) 169*91f16700Schasinglulu { 170*91f16700Schasinglulu int ret; 171*91f16700Schasinglulu 172*91f16700Schasinglulu usb_core_handle->user_data = (void *)&dfu_state; 173*91f16700Schasinglulu 174*91f16700Schasinglulu INFO("DFU USB START...\n"); 175*91f16700Schasinglulu ret = usb_core_start(usb_core_handle); 176*91f16700Schasinglulu if (ret != USBD_OK) { 177*91f16700Schasinglulu return -EIO; 178*91f16700Schasinglulu } 179*91f16700Schasinglulu 180*91f16700Schasinglulu dfu_state.phase = PHASE_SSBL; 181*91f16700Schasinglulu dfu_state.address = base; 182*91f16700Schasinglulu dfu_state.base = base; 183*91f16700Schasinglulu dfu_state.len = len; 184*91f16700Schasinglulu 185*91f16700Schasinglulu ret = usb_dfu_loop(usb_core_handle, &usb_dfu_fops); 186*91f16700Schasinglulu if (ret != USBD_OK) { 187*91f16700Schasinglulu return -EIO; 188*91f16700Schasinglulu } 189*91f16700Schasinglulu 190*91f16700Schasinglulu INFO("DFU USB STOP...\n"); 191*91f16700Schasinglulu ret = usb_core_stop(usb_core_handle); 192*91f16700Schasinglulu if (ret != USBD_OK) { 193*91f16700Schasinglulu return -EIO; 194*91f16700Schasinglulu } 195*91f16700Schasinglulu 196*91f16700Schasinglulu return 0; 197*91f16700Schasinglulu } 198