Commit 363267844637123d4fcfb924d624882b02059082

Authored by Li Jun
Committed by Ye Li
1 parent e77bc59cf1

MLK-20493-1 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>
(cherry picked from commit b0bc5f6d1292158a068446771c10a4e7285f9623)

Showing 3 changed files with 139 additions and 24 deletions Side-by-side Diff

drivers/usb/gadget/composite.c
... ... @@ -77,6 +77,8 @@
77 77 config->fullspeed = 1;
78 78 if (!config->highspeed && function->hs_descriptors)
79 79 config->highspeed = 1;
  80 + if (!config->superspeed && function->ss_descriptors)
  81 + config->superspeed = 1;
80 82  
81 83 done:
82 84 if (value)
... ... @@ -212,7 +214,9 @@
212 214  
213 215 /* add each function's descriptors */
214 216 list_for_each_entry(f, &config->functions, list) {
215   - if (speed == USB_SPEED_HIGH)
  217 + if (speed == USB_SPEED_SUPER)
  218 + descriptors = f->ss_descriptors;
  219 + else if (speed == USB_SPEED_HIGH)
216 220 descriptors = f->hs_descriptors;
217 221 else
218 222 descriptors = f->descriptors;
... ... @@ -240,7 +244,9 @@
240 244 struct usb_configuration *c;
241 245 struct list_head *pos;
242 246  
243   - if (gadget_is_dualspeed(gadget)) {
  247 + if (gadget_is_superspeed(gadget)) {
  248 + speed = gadget->speed;
  249 + } else if (gadget_is_dualspeed(gadget)) {
244 250 if (gadget->speed == USB_SPEED_HIGH)
245 251 hs = 1;
246 252 if (type == USB_DT_OTHER_SPEED_CONFIG)
... ... @@ -264,7 +270,10 @@
264 270 continue;
265 271  
266 272 check_config:
267   - if (speed == USB_SPEED_HIGH) {
  273 + if (speed == USB_SPEED_SUPER) {
  274 + if (!c->superspeed)
  275 + continue;
  276 + } else if (speed == USB_SPEED_HIGH) {
268 277 if (!c->highspeed)
269 278 continue;
270 279 } else {
271 280  
... ... @@ -283,8 +292,12 @@
283 292 struct usb_gadget *gadget = cdev->gadget;
284 293 unsigned count = 0;
285 294 int hs = 0;
  295 + int ss = 0;
286 296 struct usb_configuration *c;
287 297  
  298 + if (gadget->speed == USB_SPEED_SUPER)
  299 + ss = 1;
  300 +
288 301 if (gadget_is_dualspeed(gadget)) {
289 302 if (gadget->speed == USB_SPEED_HIGH)
290 303 hs = 1;
... ... @@ -293,7 +306,10 @@
293 306 }
294 307 list_for_each_entry(c, &cdev->configs, list) {
295 308 /* ignore configs that won't work at this speed */
296   - if (hs) {
  309 + if (ss) {
  310 + if (!c->superspeed)
  311 + continue;
  312 + } else if (hs) {
297 313 if (!c->highspeed)
298 314 continue;
299 315 } else {
... ... @@ -305,6 +321,78 @@
305 321 return count;
306 322 }
307 323  
  324 +/**
  325 + * bos_desc() - prepares the BOS descriptor.
  326 + * @cdev: pointer to usb_composite device to generate the bos
  327 + * descriptor for
  328 + *
  329 + * This function generates the BOS (Binary Device Object)
  330 + * descriptor and its device capabilities descriptors. The BOS
  331 + * descriptor should be supported by a SuperSpeed device.
  332 + */
  333 +static int bos_desc(struct usb_composite_dev *cdev)
  334 +{
  335 + struct usb_ext_cap_descriptor *usb_ext;
  336 + struct usb_dcd_config_params dcd_config_params;
  337 + struct usb_bos_descriptor *bos = cdev->req->buf;
  338 +
  339 + bos->bLength = USB_DT_BOS_SIZE;
  340 + bos->bDescriptorType = USB_DT_BOS;
  341 +
  342 + bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
  343 + bos->bNumDeviceCaps = 0;
  344 +
  345 + /*
  346 + * A SuperSpeed device shall include the USB2.0 extension descriptor
  347 + * and shall support LPM when operating in USB2.0 HS mode.
  348 + */
  349 + usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
  350 + bos->bNumDeviceCaps++;
  351 + bos->wTotalLength = cpu_to_le16(le16_to_cpu(bos->wTotalLength) +
  352 + USB_DT_USB_EXT_CAP_SIZE);
  353 + usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
  354 + usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
  355 + usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
  356 + usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
  357 +
  358 + /*
  359 + * The Superspeed USB Capability descriptor shall be implemented by all
  360 + * SuperSpeed devices.
  361 + */
  362 + if (gadget_is_superspeed(cdev->gadget)) {
  363 + struct usb_ss_cap_descriptor *ss_cap;
  364 +
  365 + ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
  366 + bos->bNumDeviceCaps++;
  367 + bos->wTotalLength = cpu_to_le16(le16_to_cpu(bos->wTotalLength) +
  368 + USB_DT_USB_SS_CAP_SIZE);
  369 + ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
  370 + ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
  371 + ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
  372 + ss_cap->bmAttributes = 0; /* LTM is not supported yet */
  373 + ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
  374 + USB_FULL_SPEED_OPERATION |
  375 + USB_HIGH_SPEED_OPERATION |
  376 + USB_5GBPS_OPERATION);
  377 + ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
  378 +
  379 + /* Get Controller configuration */
  380 + if (cdev->gadget->ops->get_config_params) {
  381 + cdev->gadget->ops->get_config_params(
  382 + &dcd_config_params);
  383 + } else {
  384 + dcd_config_params.bU1devExitLat =
  385 + USB_DEFAULT_U1_DEV_EXIT_LAT;
  386 + dcd_config_params.bU2DevExitLat =
  387 + cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
  388 + }
  389 + ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
  390 + ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
  391 + }
  392 +
  393 + return le16_to_cpu(bos->wTotalLength);
  394 +}
  395 +
308 396 static void device_qual(struct usb_composite_dev *cdev)
309 397 {
310 398 struct usb_qualifier_descriptor *qual = cdev->req->buf;
... ... @@ -377,6 +465,9 @@
377 465 case USB_SPEED_HIGH:
378 466 speed = "high";
379 467 break;
  468 + case USB_SPEED_SUPER:
  469 + speed = "super";
  470 + break;
380 471 default:
381 472 speed = "?";
382 473 break;
... ... @@ -401,7 +492,9 @@
401 492 * function's setup callback instead of the current
402 493 * configuration's setup callback.
403 494 */
404   - if (gadget->speed == USB_SPEED_HIGH)
  495 + if (gadget->speed == USB_SPEED_SUPER)
  496 + descriptors = f->ss_descriptors;
  497 + else if (gadget->speed == USB_SPEED_HIGH)
405 498 descriptors = f->hs_descriptors;
406 499 else
407 500 descriptors = f->descriptors;
408 501  
... ... @@ -481,8 +574,9 @@
481 574 list_del(&config->list);
482 575 config->cdev = NULL;
483 576 } else {
484   - debug("cfg %d/%p speeds:%s%s\n",
  577 + debug("cfg %d/%p speeds:%s%s%s\n",
485 578 config->bConfigurationValue, config,
  579 + config->superspeed ? " super" : "",
486 580 config->highspeed ? " high" : "",
487 581 config->fullspeed
488 582 ? (gadget_is_dualspeed(cdev->gadget)
489 583  
490 584  
491 585  
492 586  
... ... @@ -934,32 +1028,28 @@
934 1028 cdev->desc.bNumConfigurations =
935 1029 count_configs(cdev, USB_DT_DEVICE);
936 1030  
937   - /*
938   - * If the speed is Super speed, then the supported
939   - * max packet size is 512 and it should be sent as
940   - * exponent of 2. So, 9(2^9=512) should be filled in
941   - * bMaxPacketSize0. Also fill USB version as 3.0
942   - * if speed is Super speed.
943   - */
944   - if (cdev->gadget->speed == USB_SPEED_SUPER) {
  1031 + cdev->desc.bMaxPacketSize0 =
  1032 + cdev->gadget->ep0->maxpacket;
  1033 + if (gadget->speed >= USB_SPEED_SUPER) {
  1034 + cdev->desc.bcdUSB = cpu_to_le16(0x0310);
945 1035 cdev->desc.bMaxPacketSize0 = 9;
946   - cdev->desc.bcdUSB = cpu_to_le16(0x0300);
947 1036 } else {
948   - cdev->desc.bMaxPacketSize0 =
949   - cdev->gadget->ep0->maxpacket;
  1037 + cdev->desc.bcdUSB = cpu_to_le16(0x0200);
950 1038 }
951 1039 value = min(w_length, (u16) sizeof cdev->desc);
952 1040 memcpy(req->buf, &cdev->desc, value);
953 1041 break;
954 1042 case USB_DT_DEVICE_QUALIFIER:
955   - if (!gadget_is_dualspeed(gadget))
  1043 + if (!gadget_is_dualspeed(gadget) ||
  1044 + gadget->speed >= USB_SPEED_SUPER)
956 1045 break;
957 1046 device_qual(cdev);
958 1047 value = min_t(int, w_length,
959 1048 sizeof(struct usb_qualifier_descriptor));
960 1049 break;
961 1050 case USB_DT_OTHER_SPEED_CONFIG:
962   - if (!gadget_is_dualspeed(gadget))
  1051 + if (!gadget_is_dualspeed(gadget) ||
  1052 + gadget->speed >= USB_SPEED_SUPER)
963 1053 break;
964 1054  
965 1055 case USB_DT_CONFIG:
966 1056  
... ... @@ -975,11 +1065,15 @@
975 1065 break;
976 1066 case USB_DT_BOS:
977 1067 /*
978   - * The USB compliance test (USB 2.0 Command Verifier)
979   - * issues this request. We should not run into the
980   - * default path here. But return for now until
981   - * the superspeed support is added.
  1068 + * Super speed connection should support BOS, and
  1069 + * USB compliance test (USB 2.0 Command Verifier)
  1070 + * also issues this request, return for now for
  1071 + * USB 2.0 connection.
982 1072 */
  1073 + if (gadget->speed >= USB_SPEED_SUPER) {
  1074 + value = bos_desc(cdev);
  1075 + value = min(w_length, (u16)value);
  1076 + }
983 1077 break;
984 1078 default:
985 1079 goto unknown;
... ... @@ -1354,7 +1448,7 @@
1354 1448 }
1355 1449  
1356 1450 static struct usb_gadget_driver composite_driver = {
1357   - .speed = USB_SPEED_HIGH,
  1451 + .speed = USB_SPEED_SUPER,
1358 1452  
1359 1453 .bind = composite_bind,
1360 1454 .unbind = composite_unbind,
include/linux/usb/composite.h
... ... @@ -146,6 +146,7 @@
146 146 struct usb_gadget_strings **strings;
147 147 struct usb_descriptor_header **descriptors;
148 148 struct usb_descriptor_header **hs_descriptors;
  149 + struct usb_descriptor_header **ss_descriptors;
149 150  
150 151 struct usb_configuration *config;
151 152  
... ... @@ -279,6 +280,7 @@
279 280 u8 next_interface_id;
280 281 unsigned highspeed:1;
281 282 unsigned fullspeed:1;
  283 + unsigned superspeed:1;
282 284 struct usb_function *interface[MAX_CONFIG_INTERFACES];
283 285 };
284 286  
... ... @@ -292,6 +294,7 @@
292 294 * identifiers.
293 295 * @strings: tables of strings, keyed by identifiers assigned during bind()
294 296 * and language IDs provided in control requests
  297 + * @max_speed: Highest speed the driver supports.
295 298 * @bind: (REQUIRED) Used to allocate resources that are shared across the
296 299 * whole device, such as string IDs, and add its configurations using
297 300 * @usb_add_config(). This may fail by returning a negative errno
... ... @@ -319,6 +322,7 @@
319 322 const char *name;
320 323 const struct usb_device_descriptor *dev;
321 324 struct usb_gadget_strings **strings;
  325 + enum usb_device_speed max_speed;
322 326  
323 327 /* REVISIT: bind() functions can be marked __init, which
324 328 * makes trouble for section mismatch analysis. See if
include/linux/usb/gadget.h
... ... @@ -429,6 +429,13 @@
429 429  
430 430 /*-------------------------------------------------------------------------*/
431 431  
  432 +struct usb_dcd_config_params {
  433 + __u8 bU1devExitLat; /* U1 Device exit Latency */
  434 +#define USB_DEFAULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */
  435 + __le16 bU2DevExitLat; /* U2 Device exit Latency */
  436 +#define USB_DEFAULT_U2_DEV_EXIT_LAT 0x1F4 /* Less then 500 microsec */
  437 +};
  438 +
432 439 struct usb_gadget;
433 440 struct usb_gadget_driver;
434 441  
... ... @@ -444,6 +451,7 @@
444 451 int (*pullup) (struct usb_gadget *, int is_on);
445 452 int (*ioctl)(struct usb_gadget *,
446 453 unsigned code, unsigned long param);
  454 + void (*get_config_params)(struct usb_dcd_config_params *);
447 455 int (*udc_start)(struct usb_gadget *,
448 456 struct usb_gadget_driver *);
449 457 int (*udc_stop)(struct usb_gadget *);
... ... @@ -551,6 +559,15 @@
551 559 #else
552 560 return 0;
553 561 #endif
  562 +}
  563 +
  564 +/**
  565 + * gadget_is_superspeed() - return true if the hardware handles superspeed
  566 + * @g: controller that might support superspeed
  567 + */
  568 +static inline int gadget_is_superspeed(struct usb_gadget *g)
  569 +{
  570 + return g->max_speed >= USB_SPEED_SUPER;
554 571 }
555 572  
556 573 /**