aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorLi Jun <jun.li@nxp.com>2021-01-25 21:43:54 +0800
committerMarek Vasut <marex@denx.de>2021-01-31 14:08:56 +0100
commit8745b9ebccae599856045c5d6354463178604f72 (patch)
tree13468dcb0fb892e0477269c1c19fc9ec25215bcd /drivers/usb/gadget
parent42a594de14637f809050cd2e2ea8b4a7f51bb31a (diff)
downloadu-boot-8745b9ebccae599856045c5d6354463178604f72.zip
u-boot-8745b9ebccae599856045c5d6354463178604f72.tar.gz
u-boot-8745b9ebccae599856045c5d6354463178604f72.tar.bz2
usb: gadget: add super speed support
This patch is to add usb gadget super speed support in common driver, including BOS descriptor and select the super speed descriptor from function driver. Reviewed-by: Ye Li <ye.li@nxp.com> Reviewed-by: Peter Chen <peter.chen@nxp.com> Tested-by: faqiang.zhu <faqiang.zhu@nxp.com> Signed-off-by: Li Jun <jun.li@nxp.com> Signed-off-by: Peng Fan <peng.fan@nxp.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r--drivers/usb/gadget/composite.c85
1 files changed, 60 insertions, 25 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 404da12..1063c57 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -88,6 +88,8 @@ int usb_add_function(struct usb_configuration *config,
config->fullspeed = 1;
if (!config->highspeed && function->hs_descriptors)
config->highspeed = 1;
+ if (!config->superspeed && function->ss_descriptors)
+ config->superspeed = 1;
done:
if (value)
@@ -223,7 +225,9 @@ static int config_buf(struct usb_configuration *config,
/* add each function's descriptors */
list_for_each_entry(f, &config->functions, list) {
- if (speed == USB_SPEED_HIGH)
+ if (speed == USB_SPEED_SUPER)
+ descriptors = f->ss_descriptors;
+ else if (speed == USB_SPEED_HIGH)
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
@@ -251,7 +255,9 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
struct usb_configuration *c;
struct list_head *pos;
- if (gadget_is_dualspeed(gadget)) {
+ if (gadget_is_superspeed(gadget)) {
+ speed = gadget->speed;
+ } else if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -275,7 +281,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
continue;
check_config:
- if (speed == USB_SPEED_HIGH) {
+ if (speed == USB_SPEED_SUPER) {
+ if (!c->superspeed)
+ continue;
+ } else if (speed == USB_SPEED_HIGH) {
if (!c->highspeed)
continue;
} else {
@@ -294,8 +303,12 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
struct usb_gadget *gadget = cdev->gadget;
unsigned count = 0;
int hs = 0;
+ int ss = 0;
struct usb_configuration *c;
+ if (gadget->speed == USB_SPEED_SUPER)
+ ss = 1;
+
if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
@@ -304,7 +317,10 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
}
list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */
- if (hs) {
+ if (ss) {
+ if (!c->superspeed)
+ continue;
+ } else if (hs) {
if (!c->highspeed)
continue;
} else {
@@ -388,6 +404,9 @@ static int set_config(struct usb_composite_dev *cdev,
case USB_SPEED_HIGH:
speed = "high";
break;
+ case USB_SPEED_SUPER:
+ speed = "super";
+ break;
default:
speed = "?";
break;
@@ -412,7 +431,9 @@ static int set_config(struct usb_composite_dev *cdev,
* function's setup callback instead of the current
* configuration's setup callback.
*/
- if (gadget->speed == USB_SPEED_HIGH)
+ if (gadget->speed == USB_SPEED_SUPER)
+ descriptors = f->ss_descriptors;
+ else if (gadget->speed == USB_SPEED_HIGH)
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
@@ -492,8 +513,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
list_del(&config->list);
config->cdev = NULL;
} else {
- debug("cfg %d/%p speeds:%s%s\n",
+ debug("cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config,
+ config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
config->fullspeed
? (gadget_is_dualspeed(cdev->gadget)
@@ -751,6 +773,7 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
static int bos_desc(struct usb_composite_dev *cdev)
{
struct usb_ext_cap_descriptor *usb_ext;
+ struct usb_dcd_config_params dcd_config_params;
struct usb_bos_descriptor *bos = cdev->req->buf;
bos->bLength = USB_DT_BOS_SIZE;
@@ -794,9 +817,19 @@ static int bos_desc(struct usb_composite_dev *cdev)
USB_HIGH_SPEED_OPERATION |
USB_5GBPS_OPERATION);
ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
- ss_cap->bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
- ss_cap->bU2DevExitLat =
- cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+
+ /* Get Controller configuration */
+ if (cdev->gadget->ops->get_config_params) {
+ cdev->gadget->ops->get_config_params(
+ &dcd_config_params);
+ } else {
+ dcd_config_params.bU1devExitLat =
+ USB_DEFAULT_U1_DEV_EXIT_LAT;
+ dcd_config_params.bU2DevExitLat =
+ cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+ }
+ ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+ ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
}
return le16_to_cpu(bos->wTotalLength);
}
@@ -999,32 +1032,28 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
- /*
- * If the speed is Super speed, then the supported
- * max packet size is 512 and it should be sent as
- * exponent of 2. So, 9(2^9=512) should be filled in
- * bMaxPacketSize0. Also fill USB version as 3.0
- * if speed is Super speed.
- */
- if (cdev->gadget->speed == USB_SPEED_SUPER) {
+ cdev->desc.bMaxPacketSize0 =
+ cdev->gadget->ep0->maxpacket;
+ if (gadget->speed >= USB_SPEED_SUPER) {
+ cdev->desc.bcdUSB = cpu_to_le16(0x0310);
cdev->desc.bMaxPacketSize0 = 9;
- cdev->desc.bcdUSB = cpu_to_le16(0x0300);
} else {
- cdev->desc.bMaxPacketSize0 =
- cdev->gadget->ep0->maxpacket;
+ cdev->desc.bcdUSB = cpu_to_le16(0x0200);
}
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
case USB_DT_CONFIG:
@@ -1039,10 +1068,16 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
- if (gadget_is_superspeed(cdev->gadget))
+ /*
+ * Super speed connection should support BOS, and
+ * USB compliance test (USB 2.0 Command Verifier)
+ * also issues this request, return for now for
+ * USB 2.0 connection.
+ */
+ if (gadget->speed >= USB_SPEED_SUPER) {
value = bos_desc(cdev);
- if (value >= 0)
value = min(w_length, (u16)value);
+ }
break;
default:
goto unknown;
@@ -1421,7 +1456,7 @@ composite_resume(struct usb_gadget *gadget)
}
static struct usb_gadget_driver composite_driver = {
- .speed = USB_SPEED_HIGH,
+ .speed = USB_SPEED_SUPER,
.bind = composite_bind,
.unbind = composite_unbind,