xref: /rk3399_ARM-atf/plat/st/common/usb_dfu.c (revision c8e1a2d9d27d4f7e3a919b7994e82f2a886f3e6a)
1 /*
2  * Copyright (c) 2021-2025, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 #include <string.h>
9 
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12 
13 #include <platform_def.h>
14 #include <usb_dfu.h>
15 
16 /* Device states as defined in DFU spec */
17 #define STATE_APP_IDLE			0
18 #define STATE_APP_DETACH		1
19 #define STATE_DFU_IDLE			2
20 #define STATE_DFU_DNLOAD_SYNC		3
21 #define STATE_DFU_DNLOAD_BUSY		4
22 #define STATE_DFU_DNLOAD_IDLE		5
23 #define STATE_DFU_MANIFEST_SYNC		6
24 #define STATE_DFU_MANIFEST		7
25 #define STATE_DFU_MANIFEST_WAIT_RESET	8
26 #define STATE_DFU_UPLOAD_IDLE		9
27 #define STATE_DFU_ERROR			10
28 
29 /* DFU errors */
30 #define DFU_ERROR_NONE			0x00
31 #define DFU_ERROR_TARGET		0x01
32 #define DFU_ERROR_FILE			0x02
33 #define DFU_ERROR_WRITE			0x03
34 #define DFU_ERROR_ERASE			0x04
35 #define DFU_ERROR_CHECK_ERASED		0x05
36 #define DFU_ERROR_PROG			0x06
37 #define DFU_ERROR_VERIFY		0x07
38 #define DFU_ERROR_ADDRESS		0x08
39 #define DFU_ERROR_NOTDONE		0x09
40 #define DFU_ERROR_FIRMWARE		0x0A
41 #define DFU_ERROR_VENDOR		0x0B
42 #define DFU_ERROR_USB			0x0C
43 #define DFU_ERROR_POR			0x0D
44 #define DFU_ERROR_UNKNOWN		0x0E
45 #define DFU_ERROR_STALLEDPKT		0x0F
46 
47 /* DFU request */
48 #define DFU_DETACH			0
49 #define DFU_DNLOAD			1
50 #define DFU_UPLOAD			2
51 #define DFU_GETSTATUS			3
52 #define DFU_CLRSTATUS			4
53 #define DFU_GETSTATE			5
54 #define DFU_ABORT			6
55 
56 static bool usb_dfu_detach_req;
57 static uint64_t detach_timeout;
58 
59 /*
60  * usb_dfu_init
61  *         Initialize the DFU interface
62  * pdev: device instance
63  * cfgidx: Configuration index
64  * return: status
65  */
usb_dfu_init(struct usb_handle * pdev,uint8_t cfgidx)66 static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx)
67 {
68 	(void)pdev;
69 	(void)cfgidx;
70 
71 	/* Nothing to do in this stage */
72 	return USBD_OK;
73 }
74 
75 /*
76  * usb_dfu_de_init
77  *         De-Initialize the DFU layer
78  * pdev: device instance
79  * cfgidx: Configuration index
80  * return: status
81  */
usb_dfu_de_init(struct usb_handle * pdev,uint8_t cfgidx)82 static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx)
83 {
84 	(void)pdev;
85 	(void)cfgidx;
86 
87 	/* Nothing to do in this stage */
88 	return USBD_OK;
89 }
90 
91 /*
92  * usb_dfu_data_in
93  *         handle data IN Stage
94  * pdev: device instance
95  * epnum: endpoint index
96  * return: status
97  */
usb_dfu_data_in(struct usb_handle * pdev,uint8_t epnum)98 static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum)
99 {
100 	(void)pdev;
101 	(void)epnum;
102 
103 	return USBD_OK;
104 }
105 
106 /*
107  * usb_dfu_ep0_rx_ready
108  *         handle EP0 Rx Ready event
109  * pdev: device
110  * return: status
111  */
usb_dfu_ep0_rx_ready(struct usb_handle * pdev)112 static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev)
113 {
114 	(void)pdev;
115 
116 	return USBD_OK;
117 }
118 
119 /*
120  * usb_dfu_ep0_tx_ready
121  *         handle EP0 TRx Ready event
122  * pdev: device instance
123  * return: status
124  */
usb_dfu_ep0_tx_ready(struct usb_handle * pdev)125 static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev)
126 {
127 	(void)pdev;
128 
129 	return USBD_OK;
130 }
131 
132 /*
133  * usb_dfu_sof
134  *         handle SOF event
135  * pdev: device instance
136  * return: status
137  */
usb_dfu_sof(struct usb_handle * pdev)138 static uint8_t usb_dfu_sof(struct usb_handle *pdev)
139 {
140 	(void)pdev;
141 
142 	return USBD_OK;
143 }
144 
145 /*
146  * usb_dfu_iso_in_incomplete
147  *         handle data ISO IN Incomplete event
148  * pdev: device instance
149  * epnum: endpoint index
150  * return: status
151  */
usb_dfu_iso_in_incomplete(struct usb_handle * pdev,uint8_t epnum)152 static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum)
153 {
154 	(void)pdev;
155 	(void)epnum;
156 
157 	return USBD_OK;
158 }
159 
160 /*
161  * usb_dfu_iso_out_incomplete
162  *         handle data ISO OUT Incomplete event
163  * pdev: device instance
164  * epnum: endpoint index
165  * return: status
166  */
usb_dfu_iso_out_incomplete(struct usb_handle * pdev,uint8_t epnum)167 static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev,
168 					  uint8_t epnum)
169 {
170 	(void)pdev;
171 	(void)epnum;
172 
173 	return USBD_OK;
174 }
175 
176 /*
177  * usb_dfu_data_out
178  *         handle data OUT Stage
179  * pdev: device instance
180  * epnum: endpoint index
181  * return: status
182  */
usb_dfu_data_out(struct usb_handle * pdev,uint8_t epnum)183 static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum)
184 {
185 	(void)pdev;
186 	(void)epnum;
187 
188 	return USBD_OK;
189 }
190 
191 /*
192  * usb_dfu_detach
193  *         Handles the DFU DETACH request.
194  * pdev: device instance
195  * req: pointer to the request structure.
196  */
usb_dfu_detach(struct usb_handle * pdev,struct usb_setup_req * req)197 static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req)
198 {
199 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
200 
201 	INFO("Receive DFU Detach\n");
202 
203 	if ((hdfu->dev_state == STATE_DFU_IDLE) ||
204 	    (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
205 	    (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
206 	    (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
207 	    (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
208 		/* Update the state machine */
209 		hdfu->dev_state = STATE_DFU_IDLE;
210 		hdfu->dev_status = DFU_ERROR_NONE;
211 	}
212 
213 	/* Timeout that lets the core handle interrupts before detach */
214 	detach_timeout = timeout_init_us(100); /* usec */
215 	usb_dfu_detach_req = true;
216 }
217 
218 /*
219  * usb_dfu_download
220  *         Handles the DFU DNLOAD request.
221  * pdev: device instance
222  * req: pointer to the request structure
223  */
usb_dfu_download(struct usb_handle * pdev,struct usb_setup_req * req)224 static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req)
225 {
226 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
227 	uintptr_t data_ptr;
228 	uint32_t length;
229 	int ret;
230 
231 	/* Data setup request */
232 	if (req->length > 0) {
233 		/* Unsupported state */
234 		if ((hdfu->dev_state != STATE_DFU_IDLE) &&
235 		    (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) {
236 			/* Call the error management function (command will be nacked) */
237 			usb_core_ctl_error(pdev);
238 			return;
239 		}
240 
241 		/* Get the data address */
242 		length = req->length;
243 		ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr,
244 					       &length, pdev->user_data);
245 		if (ret == 0U) {
246 			/* Update the state machine */
247 			hdfu->dev_state = STATE_DFU_DNLOAD_SYNC;
248 			/* Start the transfer */
249 			usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length);
250 		} else {
251 			usb_core_ctl_error(pdev);
252 		}
253 	} else {
254 		/* End of DNLOAD operation*/
255 		if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) {
256 			/* Call the error management function (command will be nacked) */
257 			usb_core_ctl_error(pdev);
258 			return;
259 		}
260 		/* End of DNLOAD operation*/
261 		hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
262 		ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data);
263 		if (ret == 0U) {
264 			hdfu->dev_state = STATE_DFU_MANIFEST_SYNC;
265 		} else {
266 			usb_core_ctl_error(pdev);
267 		}
268 	}
269 }
270 
271 /*
272  * usb_dfu_upload
273  *         Handles the DFU UPLOAD request.
274  * pdev: instance
275  * req: pointer to the request structure
276  */
usb_dfu_upload(struct usb_handle * pdev,struct usb_setup_req * req)277 static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req)
278 {
279 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
280 	uintptr_t data_ptr;
281 	uint32_t length;
282 	int ret;
283 
284 	/* Data setup request */
285 	if (req->length == 0) {
286 		/* No Data setup request */
287 		hdfu->dev_state = STATE_DFU_IDLE;
288 		return;
289 	}
290 
291 	/* Unsupported state */
292 	if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) {
293 		ERROR("UPLOAD : Unsupported State\n");
294 		/* Call the error management function (command will be nacked) */
295 		usb_core_ctl_error(pdev);
296 		return;
297 	}
298 
299 	/* Update the data address */
300 	length = req->length;
301 	ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data);
302 	if (ret == 0U) {
303 		/* Short frame */
304 		hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE;
305 
306 		/* Start the transfer */
307 		usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length);
308 	} else {
309 		ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index);
310 		hdfu->dev_state = STATE_DFU_ERROR;
311 		hdfu->dev_status = DFU_ERROR_STALLEDPKT;
312 
313 		/* Call the error management function (command will be nacked) */
314 		usb_core_ctl_error(pdev);
315 	}
316 }
317 
318 /*
319  * usb_dfu_get_status
320  *         Handles the DFU GETSTATUS request.
321  * pdev: instance
322  */
usb_dfu_get_status(struct usb_handle * pdev)323 static void usb_dfu_get_status(struct usb_handle *pdev)
324 {
325 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
326 
327 	hdfu->status[0] = hdfu->dev_status;	/* bStatus */
328 	hdfu->status[1] = 0;			/* bwPollTimeout[3] */
329 	hdfu->status[2] = 0;
330 	hdfu->status[3] = 0;
331 	hdfu->status[4] = hdfu->dev_state;	/* bState */
332 	hdfu->status[5] = 0;			/* iString */
333 
334 	/* next step */
335 	switch (hdfu->dev_state) {
336 	case STATE_DFU_DNLOAD_SYNC:
337 		hdfu->dev_state = STATE_DFU_DNLOAD_IDLE;
338 		break;
339 	case STATE_DFU_MANIFEST_SYNC:
340 		/* the device is 'ManifestationTolerant' */
341 		hdfu->status[4] = STATE_DFU_MANIFEST;
342 		hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */
343 		hdfu->dev_state = STATE_DFU_IDLE;
344 		break;
345 
346 	default:
347 		break;
348 	}
349 
350 	/* Start the transfer */
351 	usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status));
352 }
353 
354 /*
355  * usb_dfu_clear_status
356  *         Handles the DFU CLRSTATUS request.
357  * pdev: device instance
358  */
usb_dfu_clear_status(struct usb_handle * pdev)359 static void usb_dfu_clear_status(struct usb_handle *pdev)
360 {
361 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
362 
363 	if (hdfu->dev_state == STATE_DFU_ERROR) {
364 		hdfu->dev_state = STATE_DFU_IDLE;
365 		hdfu->dev_status = DFU_ERROR_NONE;
366 	} else {
367 		/* State Error */
368 		hdfu->dev_state = STATE_DFU_ERROR;
369 		hdfu->dev_status = DFU_ERROR_UNKNOWN;
370 	}
371 }
372 
373 /*
374  * usb_dfu_get_state
375  *         Handles the DFU GETSTATE request.
376  * pdev: device instance
377  */
usb_dfu_get_state(struct usb_handle * pdev)378 static void usb_dfu_get_state(struct usb_handle *pdev)
379 {
380 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
381 
382 	/* Return the current state of the DFU interface */
383 	usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1);
384 }
385 
386 /*
387  * usb_dfu_abort
388  *         Handles the DFU ABORT request.
389  * pdev: device instance
390  */
usb_dfu_abort(struct usb_handle * pdev)391 static void usb_dfu_abort(struct usb_handle *pdev)
392 {
393 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
394 
395 	if ((hdfu->dev_state == STATE_DFU_IDLE) ||
396 	    (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) ||
397 	    (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) ||
398 	    (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) ||
399 	    (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) {
400 		hdfu->dev_state = STATE_DFU_IDLE;
401 		hdfu->dev_status = DFU_ERROR_NONE;
402 	}
403 }
404 
405 /*
406  * usb_dfu_setup
407  *         Handle the DFU specific requests
408  * pdev: instance
409  * req: usb requests
410  * return: status
411  */
usb_dfu_setup(struct usb_handle * pdev,struct usb_setup_req * req)412 static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req)
413 {
414 	uint8_t *pbuf = NULL;
415 	uint16_t len = 0U;
416 	uint8_t ret = USBD_OK;
417 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
418 
419 	switch (req->bm_request & USB_REQ_TYPE_MASK) {
420 	case USB_REQ_TYPE_CLASS:
421 		switch (req->b_request) {
422 		case DFU_DNLOAD:
423 			usb_dfu_download(pdev, req);
424 			break;
425 
426 		case DFU_UPLOAD:
427 			usb_dfu_upload(pdev, req);
428 			break;
429 
430 		case DFU_GETSTATUS:
431 			usb_dfu_get_status(pdev);
432 			break;
433 
434 		case DFU_CLRSTATUS:
435 			usb_dfu_clear_status(pdev);
436 			break;
437 
438 		case DFU_GETSTATE:
439 			usb_dfu_get_state(pdev);
440 			break;
441 
442 		case DFU_ABORT:
443 			usb_dfu_abort(pdev);
444 			break;
445 
446 		case DFU_DETACH:
447 			usb_dfu_detach(pdev, req);
448 			break;
449 
450 		default:
451 			ERROR("unknown request %x on alternate %i\n",
452 			      req->b_request, hdfu->alt_setting);
453 			usb_core_ctl_error(pdev);
454 			ret = USBD_FAIL;
455 			break;
456 		}
457 		break;
458 	case USB_REQ_TYPE_STANDARD:
459 		switch (req->b_request) {
460 		case USB_REQ_GET_DESCRIPTOR:
461 			if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) {
462 				pbuf = pdev->desc->get_config_desc(&len);
463 				/* DFU descriptor at the end of the USB */
464 				pbuf += len - 9U;
465 				len = 9U;
466 				len = MIN(len, req->length);
467 			}
468 
469 			/* Start the transfer */
470 			usb_core_transmit_ep0(pdev, pbuf, len);
471 
472 			break;
473 
474 		case USB_REQ_GET_INTERFACE:
475 			/* Start the transfer */
476 			usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U);
477 			break;
478 
479 		case USB_REQ_SET_INTERFACE:
480 			hdfu->alt_setting = LOBYTE(req->value);
481 			break;
482 
483 		default:
484 			usb_core_ctl_error(pdev);
485 			ret = USBD_FAIL;
486 			break;
487 		}
488 	default:
489 		break;
490 	}
491 
492 	return ret;
493 }
494 
495 static const struct usb_class usb_dfu = {
496 	.init = usb_dfu_init,
497 	.de_init = usb_dfu_de_init,
498 	.setup = usb_dfu_setup,
499 	.ep0_tx_sent = usb_dfu_ep0_tx_ready,
500 	.ep0_rx_ready = usb_dfu_ep0_rx_ready,
501 	.data_in = usb_dfu_data_in,
502 	.data_out = usb_dfu_data_out,
503 	.sof = usb_dfu_sof,
504 	.iso_in_incomplete = usb_dfu_iso_in_incomplete,
505 	.iso_out_incomplete = usb_dfu_iso_out_incomplete,
506 };
507 
usb_dfu_register(struct usb_handle * pdev,struct usb_dfu_handle * phandle)508 void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle)
509 {
510 	pdev->class = (struct usb_class *)&usb_dfu;
511 	pdev->class_data = phandle;
512 
513 	phandle->dev_state = STATE_DFU_IDLE;
514 	phandle->dev_status = DFU_ERROR_NONE;
515 }
516 
usb_dfu_loop(struct usb_handle * pdev,const struct usb_dfu_media * pmedia)517 int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia)
518 {
519 	enum usb_status ret;
520 	struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data;
521 
522 	hdfu->callback = pmedia;
523 	usb_dfu_detach_req = false;
524 
525 	/* DFU infinite loop until DETACH_REQ */
526 	for (;;) {
527 		ret = usb_core_handle_it(pdev);
528 		if (ret != USBD_OK) {
529 			return -EIO;
530 		}
531 
532 		/*
533 		 * Detach request received, continue to handle USB core IT
534 		 * to assure complete data transmission
535 		 */
536 		if (usb_dfu_detach_req && timeout_elapsed(detach_timeout)) {
537 			break;
538 		}
539 	}
540 
541 	return 0;
542 }
543