1 /*
2 * Copyright (c) 2024-2025, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <limits.h>
8 #include <stddef.h>
9 #include <string.h>
10
11 #include <common/debug.h>
12 #include <drivers/st/usb_dwc3.h>
13 #include <drivers/usb_device.h>
14
15 #include <platform_def.h>
16 #include <stm32cubeprogrammer.h>
17 #include <stm32mp_common.h>
18 #include <usb_dfu.h>
19
20 /* String size (1 byte) + type (1 byte) + 24 UTF16 characters: 2 bytes each */
21 #define SIZ_STRING_SERIAL U(24)
22 #define USB_SIZ_STRING_SERIAL (1U + 1U + (SIZ_STRING_SERIAL * 2U))
23 #define USBD_MAX_STR_DESC_SIZ U(0x100)
24 #define USBD_VID U(0x0483)
25 #define USBD_PID U(0xDF11)
26 #define USBD_LANGID_STRING U(0x409)
27 #define USBD_MANUFACTURER_STRING "STMicroelectronics"
28 #define USBD_CONFIGURATION_STRING "DFU Config"
29 #define USBD_INTERFACE_STRING "DFU Interface"
30
31 #define USB_DFU_ITF_NUM U(3)
32
33 #define USB_DFU_CONFIG_DESC_SIZ USB_DFU_DESC_SIZ(USB_DFU_ITF_NUM)
34
35 /* DFU devices */
36 static struct usb_dfu_handle usb_dfu_handle;
37
38 /* USB Standard Device Descriptor */
39 static const uint8_t usb_stm32mp2_desc[USB_LEN_DEV_DESC] = {
40 USB_LEN_DEV_DESC, /* bLength */
41 USB_DESC_TYPE_DEVICE, /* bDescriptorType */
42 0x00, /* bcdUSB */
43 0x02, /* version */
44 0x00, /* bDeviceClass */
45 0x00, /* bDeviceSubClass */
46 0x00, /* bDeviceProtocol */
47 USB_MAX_EP0_SIZE, /* bMaxPacketSize */
48 LOBYTE(USBD_VID), /* idVendor */
49 HIBYTE(USBD_VID), /* idVendor */
50 LOBYTE(USBD_PID), /* idVendor */
51 HIBYTE(USBD_PID), /* idVendor */
52 0x00, /* bcdDevice rel. 2.00 */
53 0x02,
54 USBD_IDX_MFC_STR, /* Index of manufacturer string */
55 USBD_IDX_PRODUCT_STR, /* Index of product string */
56 USBD_IDX_SERIAL_STR, /* Index of serial number string */
57 USBD_MAX_NUM_CONFIGURATION /* bNumConfigurations */
58 }; /* USB_DeviceDescriptor */
59
60 /* USB Standard String Descriptor */
61 static const uint8_t usb_stm32mp2_lang_id_desc[USB_LEN_LANGID_STR_DESC] = {
62 USB_LEN_LANGID_STR_DESC,
63 USB_DESC_TYPE_STRING,
64 LOBYTE(USBD_LANGID_STRING),
65 HIBYTE(USBD_LANGID_STRING),
66 };
67
68 /* USB Standard Device Descriptor */
69 static const uint8_t usbd_stm32mp2_qualifier_desc[USB_LEN_DEV_QUALIFIER_DESC] = {
70 USB_LEN_DEV_QUALIFIER_DESC,
71 USB_DESC_TYPE_DEVICE_QUALIFIER,
72 0x00,
73 0x02,
74 0x00,
75 0x00,
76 0x00,
77 0x40,
78 0x01,
79 0x00,
80 };
81
82 /* USB serial number: build dynamically */
83 static uint8_t usb_stm32mp2_serial[USB_SIZ_STRING_SERIAL + 1];
84
85 /* USB DFU device Configuration Descriptor */
86 static const uint8_t usb_stm32mp2_config_desc[USB_DFU_CONFIG_DESC_SIZ] = {
87 0x09, /* bLength: Configuration Descriptor size */
88 USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
89 USB_DFU_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */
90 0x00, 0x01, /* bNumInterfaces: 1 interface */
91 0x01, /* bConfigurationValue: Configuration value */
92 0x02, /* iConfiguration: Index of string descriptor for configuration */
93 0xC0, /* bmAttributes: bus powered and Supprts Remote Wakeup */
94 0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
95
96 /* Descriptor of DFU interface 0 Alternate setting 0..N */
97 USBD_DFU_IF_DESC(0), USBD_DFU_IF_DESC(1), USBD_DFU_IF_DESC(2),
98 /* DFU Functional Descriptor */
99 0x09, /* blength = 9 Bytes */
100 DFU_DESCRIPTOR_TYPE, /* DFU Functional Descriptor */
101 DFU_BM_ATTRIBUTE, /* bmAttribute for DFU */
102 0xFF, /* DetachTimeOut = 255 ms */
103 0x00,
104 /* WARNING: In DMA mode the multiple MPS packets feature
105 * is still not supported ==> In this case,
106 * when using DMA USBD_DFU_XFER_SIZE should be set
107 * to 64 in usbd_conf.h
108 */
109 TRANSFER_SIZE_BYTES(USBD_DFU_XFER_SIZE), /* TransferSize = 1024 Byte */
110 ((USB_DFU_VERSION >> 0) & 0xFF), /* bcdDFUVersion */
111 ((USB_DFU_VERSION >> 8) & 0xFF)
112 };
113
114 const char *const if_desc_string[USB_DFU_ITF_NUM] = {
115 "@DDR FIP /0x02/1*32Ke", "@FIP /0x03/1*16Me", "@virtual /0xF1/1*512Ba"
116 };
117
118 /* Buffer to build the unicode string provided to USB device stack */
119 static uint8_t usb_str_dec[USBD_MAX_STR_DESC_SIZ];
120
121 /*
122 * Convert Ascii string into unicode one
123 * desc : descriptor buffer
124 * unicode : Formatted string buffer (unicode)
125 * len : descriptor length
126 */
stm32mp2_get_string(const char * desc,uint8_t * unicode,uint16_t * len)127 static void stm32mp2_get_string(const char *desc, uint8_t *unicode,
128 uint16_t *len)
129 {
130 uint8_t idx = 0U;
131
132 if (desc == NULL) {
133 return;
134 }
135
136 *len = strlen(desc) * 2U + 2U;
137 unicode[idx++] = *len;
138 unicode[idx++] = USB_DESC_TYPE_STRING;
139
140 while (*desc != '\0') {
141 unicode[idx++] = *desc++;
142 unicode[idx++] = 0x00U;
143 }
144 }
145
146 /*
147 * Create the serial number string descriptor
148 */
update_serial_num_string(void)149 static void update_serial_num_string(void)
150 {
151 char serial_string[SIZ_STRING_SERIAL + 2U];
152 /* serial number is set to 0 */
153 uint32_t deviceserial[UID_WORD_NB] = { 0U, 0U, 0U };
154 uint16_t length;
155
156 if (stm32_get_uid_otp(deviceserial) != 0) {
157 return;
158 }
159
160 /* build serial number with OTP value as in ROM code */
161 snprintf(serial_string, sizeof(serial_string), "%08X%08X%08X",
162 deviceserial[0], deviceserial[1], deviceserial[2]);
163
164 length = USB_SIZ_STRING_SERIAL;
165 stm32mp2_get_string(serial_string, usb_stm32mp2_serial, &length);
166 }
167
168 /*
169 * Return Device Qualifier descriptor
170 * length : pointer data length
171 * return : pointer to descriptor buffer
172 */
stm32mp2_get_qualifier_desc(uint16_t * length)173 static uint8_t *stm32mp2_get_qualifier_desc(uint16_t *length)
174 {
175 *length = sizeof(usbd_stm32mp2_qualifier_desc);
176
177 return (uint8_t *)usbd_stm32mp2_qualifier_desc;
178 }
179
180 /*
181 * Return configuration descriptor
182 * length : pointer data length
183 * return : pointer to descriptor buffer
184 */
stm32mp2_get_config_desc(uint16_t * length)185 static uint8_t *stm32mp2_get_config_desc(uint16_t *length)
186 {
187 *length = sizeof(usb_stm32mp2_config_desc);
188
189 return (uint8_t *)usb_stm32mp2_config_desc;
190 }
191
192 /*
193 * Returns the device descriptor.
194 * length: Pointer to data length variable
195 * return : Pointer to descriptor buffer
196 */
stm32mp2_device_desc(uint16_t * length)197 static uint8_t *stm32mp2_device_desc(uint16_t *length)
198 {
199 *length = sizeof(usb_stm32mp2_desc);
200
201 return (uint8_t *)usb_stm32mp2_desc;
202 }
203
204 /*
205 * Returns the LangID string descriptor.
206 * length: Pointer to data length variable
207 * return : Pointer to descriptor buffer
208 */
stm32mp2_lang_id_desc(uint16_t * length)209 static uint8_t *stm32mp2_lang_id_desc(uint16_t *length)
210 {
211 *length = sizeof(usb_stm32mp2_lang_id_desc);
212
213 return (uint8_t *)usb_stm32mp2_lang_id_desc;
214 }
215
216 /*
217 * Returns the product string descriptor.
218 * length: Pointer to data length variable
219 * return : Pointer to descriptor buffer
220 */
stm32mp2_product_desc(uint16_t * length)221 static uint8_t *stm32mp2_product_desc(uint16_t *length)
222 {
223 char name[STM32_SOC_NAME_SIZE];
224 char product[128];
225 uint32_t chip_id;
226 uint32_t chip_version;
227
228 stm32mp_get_soc_name(name);
229 chip_id = stm32mp_get_chip_dev_id();
230 chip_version = stm32mp_get_chip_version();
231
232 snprintf(product, sizeof(product),
233 "DFU @Device ID /0x%03X, @Revision ID /0x%04X, @Name /%s,",
234 chip_id, chip_version, name);
235
236 stm32mp2_get_string(product, usb_str_dec, length);
237
238 return usb_str_dec;
239 }
240
241 /*
242 * Returns the manufacturer string descriptor.
243 * length: Pointer to data length variable
244 * return : Pointer to descriptor buffer
245 */
stm32mp2_manufacturer_desc(uint16_t * length)246 static uint8_t *stm32mp2_manufacturer_desc(uint16_t *length)
247 {
248 stm32mp2_get_string(USBD_MANUFACTURER_STRING, usb_str_dec, length);
249
250 return usb_str_dec;
251 }
252
253 /*
254 * Returns the serial number string descriptor.
255 * length: Pointer to data length variable
256 * return : Pointer to descriptor buffer
257 */
stm32mp2_serial_desc(uint16_t * length)258 static uint8_t *stm32mp2_serial_desc(uint16_t *length)
259 {
260 *length = USB_SIZ_STRING_SERIAL;
261
262 return (uint8_t *)usb_stm32mp2_serial;
263 }
264
265 /*
266 * Returns the configuration string descriptor.
267 * length: Pointer to data length variable
268 * return : Pointer to descriptor buffer
269 */
stm32mp2_config_desc(uint16_t * length)270 static uint8_t *stm32mp2_config_desc(uint16_t *length)
271 {
272 stm32mp2_get_string(USBD_CONFIGURATION_STRING, usb_str_dec, length);
273
274 return usb_str_dec;
275 }
276
277 /*
278 * Returns the interface string descriptor.
279 * length : Pointer to data length variable
280 * return : Pointer to descriptor buffer
281 */
stm32mp2_interface_desc(uint16_t * length)282 static uint8_t *stm32mp2_interface_desc(uint16_t *length)
283 {
284 stm32mp2_get_string(USBD_INTERFACE_STRING, usb_str_dec, length);
285
286 return usb_str_dec;
287 }
288
289 /*
290 * Manages the transfer of memory interfaces string descriptors.
291 * index: descriptor index
292 * length : pointer data length
293 * return : pointer to the descriptor table or NULL if the descriptor
294 * is not supported.
295 */
stm32mp2_get_usr_desc(uint8_t index,uint16_t * length)296 static uint8_t *stm32mp2_get_usr_desc(uint8_t index, uint16_t *length)
297 {
298 if (index >= ARRAY_SIZE(if_desc_string)) {
299 return NULL;
300 }
301
302 stm32mp2_get_string(if_desc_string[index], usb_str_dec, length);
303
304 return usb_str_dec;
305 }
306
307 static const struct usb_desc dfu_desc = {
308 .get_device_desc = stm32mp2_device_desc,
309 .get_lang_id_desc = stm32mp2_lang_id_desc,
310 .get_manufacturer_desc = stm32mp2_manufacturer_desc,
311 .get_product_desc = stm32mp2_product_desc,
312 .get_configuration_desc = stm32mp2_config_desc,
313 .get_serial_desc = stm32mp2_serial_desc,
314 .get_interface_desc = stm32mp2_interface_desc,
315 .get_usr_desc = stm32mp2_get_usr_desc,
316 .get_config_desc = stm32mp2_get_config_desc,
317 .get_device_qualifier_desc = stm32mp2_get_qualifier_desc,
318 /* only HS is supported, as ROM code */
319 .get_other_speed_config_desc = NULL,
320 };
321
322 static struct usb_handle usb_core_handle;
323 static struct pcd_handle pcd_handle;
324 static dwc3_handle_t dwc3_handle;
325
usb_dfu_plat_init(void)326 struct usb_handle *usb_dfu_plat_init(void)
327 {
328 /* prepare USB Driver */
329 pcd_handle.in_ep[0].maxpacket = USB_MAX_EP0_SIZE;
330 pcd_handle.out_ep[0].maxpacket = USB_MAX_EP0_SIZE;
331 usb_dwc3_init_driver(&usb_core_handle, &pcd_handle, &dwc3_handle,
332 (void *)USB_DWC3_BASE);
333
334 /* keep the configuration from ROM code */
335 usb_core_handle.ep0_state = USBD_EP0_DATA_IN;
336 usb_core_handle.dev_state = USBD_STATE_CONFIGURED;
337
338 /* Update the serial number string descriptor from the unique ID */
339 update_serial_num_string();
340
341 /* Prepare USB DFU stack */
342 usb_dfu_register(&usb_core_handle, &usb_dfu_handle);
343
344 /* Register DFU descriptor in USB stack */
345 register_platform(&usb_core_handle, &dfu_desc);
346
347 return &usb_core_handle;
348 }
349
350 /* Link between USB alternate and STM32CubeProgramer phase */
usb_dfu_get_phase(uint8_t alt)351 uint8_t usb_dfu_get_phase(uint8_t alt)
352 {
353 uint8_t ret;
354
355 switch (alt) {
356 case 0:
357 ret = PHASE_DDR_FW;
358 break;
359 case 1:
360 ret = PHASE_SSBL;
361 break;
362 case 2:
363 ret = PHASE_CMD;
364 break;
365 default:
366 ret = PHASE_RESET;
367 break;
368 }
369
370 return ret;
371 }
372