From 216c1223c2c65bd1c119a28b9406f70a9ee7b063 Mon Sep 17 00:00:00 2001
From: Patrick Delaunay <patrick.delaunay@foss.st.com>
Date: Thu, 4 Nov 2021 15:13:33 +0100
Subject: [PATCH] fix(drivers/usb): add a optional ops
 get_other_speed_config_desc

Correctly handle USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION request
in USB driver and support a different result than
USB_DESC_TYPE_CONFIGURATION with the new optional ops
get_other_speed_config_desc().

The support of this descriptor is optionnal and is only
required when high-speed capable device which can operate at its
other possible speed.

This patch allows to remove the pbuf update in usb_core_get_desc()
and solves an issue on USB re-enumeration on STM32MP15 platform
as the result of get_config_desc() is a const array.
This issue is not see on normal use-case, as the USB enumeration
is only done in ROM code and TF-A reuse the same USB descritors.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Change-Id: I8edcc1e45065ab4e45d48f4bc37b49120674fdb0
---
 drivers/usb/usb_device.c            | 8 +++++---
 include/drivers/usb_device.h        | 2 ++
 plat/st/stm32mp1/stm32mp1_usb_dfu.c | 2 ++
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/usb_device.c b/drivers/usb/usb_device.c
index 7fcb39b15..7dd3f6069 100644
--- a/drivers/usb/usb_device.c
+++ b/drivers/usb/usb_device.c
@@ -74,7 +74,6 @@ static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req
 
 	case USB_DESC_TYPE_CONFIGURATION:
 		pbuf = pdev->desc->get_config_desc(&len);
-		pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
 		break;
 
 	case USB_DESC_TYPE_STRING:
@@ -116,8 +115,11 @@ static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req
 		break;
 
 	case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
-		pbuf = pdev->desc->get_config_desc(&len);
-		pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
+		if (pdev->desc->get_other_speed_config_desc == NULL) {
+			usb_core_ctl_error(pdev);
+			return;
+		}
+		pbuf = pdev->desc->get_other_speed_config_desc(&len);
 		break;
 
 	default:
diff --git a/include/drivers/usb_device.h b/include/drivers/usb_device.h
index e21e3155d..8fdb6ae13 100644
--- a/include/drivers/usb_device.h
+++ b/include/drivers/usb_device.h
@@ -166,6 +166,8 @@ struct usb_desc {
 	uint8_t *(*get_usr_desc)(uint8_t index, uint16_t *length);
 	uint8_t *(*get_config_desc)(uint16_t *length);
 	uint8_t *(*get_device_qualifier_desc)(uint16_t *length);
+	/* optional: high speed capable device operating at its other speed */
+	uint8_t *(*get_other_speed_config_desc)(uint16_t *length);
 };
 
 /* USB Device handle structure */
diff --git a/plat/st/stm32mp1/stm32mp1_usb_dfu.c b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
index 051d43532..70fbba6db 100644
--- a/plat/st/stm32mp1/stm32mp1_usb_dfu.c
+++ b/plat/st/stm32mp1/stm32mp1_usb_dfu.c
@@ -338,6 +338,8 @@ static const struct usb_desc dfu_desc = {
 	.get_usr_desc = stm32mp1_get_usr_desc,
 	.get_config_desc = stm32mp1_get_config_desc,
 	.get_device_qualifier_desc = stm32mp1_get_qualifier_desc,
+	/* only HS is supported, as ROM code */
+	.get_other_speed_config_desc = NULL,
 };
 
 static struct usb_handle usb_core_handle;