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