1// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause 2/* 3 * Copyright (C) 2020, STMicroelectronics - All Rights Reserved 4 */ 5 6#include <common.h> 7#include <dfu.h> 8#include <g_dnl.h> 9#include <usb.h> 10#include <asm/arch/stm32prog.h> 11#include <asm/arch/sys_proto.h> 12#include <linux/printk.h> 13#include "stm32prog.h" 14 15static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase, 16 u32 offset) 17{ 18 struct stm32prog_part_t *part; 19 int i; 20 21 if (phase == data->phase) { 22 data->offset = offset; 23 data->dfu_seq = 0; 24 return 0; 25 } 26 27 /* found partition for phase */ 28 for (i = 0; i < data->part_nb; i++) { 29 part = &data->part_array[i]; 30 if (part->id == phase) { 31 data->cur_part = part; 32 data->phase = phase; 33 data->offset = offset; 34 data->dfu_seq = 0; 35 return 0; 36 } 37 } 38 39 return -EINVAL; 40} 41 42static int stm32prog_cmd_write(u64 offset, void *buf, long *len) 43{ 44 u8 phase; 45 uintptr_t address; 46 u8 *pt = buf; 47 void (*entry)(void); 48 int ret; 49 50 if (*len < 5) { 51 log_err("size not allowed\n"); 52 return -EINVAL; 53 } 54 if (offset) { 55 log_err("invalid offset\n"); 56 return -EINVAL; 57 } 58 phase = pt[0]; 59 address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4]; 60 if (phase == PHASE_RESET) { 61 entry = (void *)address; 62 printf("## Starting application at 0x%p ...\n", entry); 63 (*entry)(); 64 printf("## Application terminated\n"); 65 return 0; 66 } 67 /* set phase and offset */ 68 ret = stm32prog_set_phase(stm32prog_data, phase, address); 69 if (ret) 70 log_err("failed: %d\n", ret); 71 return ret; 72} 73 74#define PHASE_MIN_SIZE 9 75static int stm32prog_cmd_read(u64 offset, void *buf, long *len) 76{ 77 u32 destination = DEFAULT_ADDRESS; /* destination address */ 78 u32 dfu_offset; 79 u8 *pt_buf = buf; 80 int phase; 81 char *err_msg; 82 int length; 83 84 if (*len < PHASE_MIN_SIZE) { 85 log_err("request exceeds allowed area\n"); 86 return -EINVAL; 87 } 88 if (offset) { 89 *len = 0; /* EOF for second request */ 90 return 0; 91 } 92 phase = stm32prog_data->phase; 93 if (phase == PHASE_FLASHLAYOUT) 94 destination = CONFIG_SYS_LOAD_ADDR; 95 dfu_offset = stm32prog_data->offset; 96 97 /* mandatory header, size = PHASE_MIN_SIZE */ 98 *pt_buf++ = (u8)(phase & 0xFF); 99 *pt_buf++ = (u8)(destination); 100 *pt_buf++ = (u8)(destination >> 8); 101 *pt_buf++ = (u8)(destination >> 16); 102 *pt_buf++ = (u8)(destination >> 24); 103 *pt_buf++ = (u8)(dfu_offset); 104 *pt_buf++ = (u8)(dfu_offset >> 8); 105 *pt_buf++ = (u8)(dfu_offset >> 16); 106 *pt_buf++ = (u8)(dfu_offset >> 24); 107 108 if (phase == PHASE_RESET || phase == PHASE_DO_RESET) { 109 err_msg = stm32prog_get_error(stm32prog_data); 110 length = strlen(err_msg); 111 if (length + PHASE_MIN_SIZE > *len) 112 length = *len - PHASE_MIN_SIZE; 113 114 memcpy(pt_buf, err_msg, length); 115 *len = PHASE_MIN_SIZE + length; 116 stm32prog_do_reset(stm32prog_data); 117 } else if (phase == PHASE_FLASHLAYOUT) { 118 *pt_buf++ = stm32prog_data->part_nb ? 1 : 0; 119 *len = PHASE_MIN_SIZE + 1; 120 } else { 121 *len = PHASE_MIN_SIZE; 122 } 123 124 return 0; 125} 126 127int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset, 128 void *buf, long *len) 129{ 130 if (dfu->dev_type != DFU_DEV_VIRT) 131 return -EINVAL; 132 133 switch (dfu->data.virt.dev_num) { 134 case PHASE_CMD: 135 return stm32prog_cmd_write(offset, buf, len); 136 137 case PHASE_OTP: 138 return stm32prog_otp_write(stm32prog_data, (u32)offset, 139 buf, len); 140 141 case PHASE_PMIC: 142 return stm32prog_pmic_write(stm32prog_data, (u32)offset, 143 buf, len); 144 } 145 *len = 0; 146 return 0; 147} 148 149int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset, 150 void *buf, long *len) 151{ 152 if (dfu->dev_type != DFU_DEV_VIRT) 153 return -EINVAL; 154 155 switch (dfu->data.virt.dev_num) { 156 case PHASE_CMD: 157 return stm32prog_cmd_read(offset, buf, len); 158 159 case PHASE_OTP: 160 return stm32prog_otp_read(stm32prog_data, (u32)offset, 161 buf, len); 162 163 case PHASE_PMIC: 164 return stm32prog_pmic_read(stm32prog_data, (u32)offset, 165 buf, len); 166 } 167 *len = 0; 168 return 0; 169} 170 171int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size) 172{ 173 if (dfu->dev_type != DFU_DEV_VIRT) { 174 *size = 0; 175 log_debug("%s, invalid dev_type = %d\n", 176 __func__, dfu->dev_type); 177 return -EINVAL; 178 } 179 180 switch (dfu->data.virt.dev_num) { 181 case PHASE_CMD: 182 *size = CMD_SIZE; 183 break; 184 case PHASE_OTP: 185 *size = stm32prog_data->tee ? OTP_SIZE_TA : OTP_SIZE_SMC; 186 break; 187 case PHASE_PMIC: 188 *size = PMIC_SIZE; 189 break; 190 } 191 192 return 0; 193} 194 195bool stm32prog_usb_loop(struct stm32prog_data *data, int dev) 196{ 197 int ret; 198 bool result; 199 /* USB download gadget for STM32 Programmer */ 200 char product[128]; 201 char name[SOC_NAME_SIZE]; 202 203 get_soc_name(name); 204 snprintf(product, sizeof(product), 205 "USB download gadget@Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,", 206 get_cpu_dev(), get_cpu_rev(), name); 207 g_dnl_set_product(product); 208 209 if (stm32prog_data->phase == PHASE_FLASHLAYOUT) { 210 /* forget any previous Control C */ 211 clear_ctrlc(); 212 ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu"); 213 /* DFU reset received, no error or CtrlC */ 214 if (ret || stm32prog_data->phase != PHASE_FLASHLAYOUT || had_ctrlc()) 215 return ret; /* true = reset on DFU error */ 216 /* prepare the second enumeration with the FlashLayout */ 217 stm32prog_dfu_init(data); 218 } 219 220 ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu"); 221 222 result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET); 223 224 g_dnl_set_product(NULL); 225 226 return result; 227} 228 229int g_dnl_get_board_bcd_device_number(int gcnum) 230{ 231 log_debug("%s\n", __func__); 232 return 0x200; 233} 234