mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 07:34:31 +00:00
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>
This commit is contained in:
parent
42a594de14
commit
8745b9ebcc
3 changed files with 70 additions and 25 deletions
|
@ -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,
|
||||
|
|
|
@ -146,6 +146,7 @@ struct usb_function {
|
|||
struct usb_gadget_strings **strings;
|
||||
struct usb_descriptor_header **descriptors;
|
||||
struct usb_descriptor_header **hs_descriptors;
|
||||
struct usb_descriptor_header **ss_descriptors;
|
||||
|
||||
struct usb_configuration *config;
|
||||
|
||||
|
@ -279,6 +280,7 @@ struct usb_configuration {
|
|||
u8 next_interface_id;
|
||||
unsigned highspeed:1;
|
||||
unsigned fullspeed:1;
|
||||
unsigned superspeed:1;
|
||||
struct usb_function *interface[MAX_CONFIG_INTERFACES];
|
||||
};
|
||||
|
||||
|
@ -292,6 +294,7 @@ int usb_add_config(struct usb_composite_dev *,
|
|||
* identifiers.
|
||||
* @strings: tables of strings, keyed by identifiers assigned during bind()
|
||||
* and language IDs provided in control requests
|
||||
* @max_speed: Highest speed the driver supports.
|
||||
* @bind: (REQUIRED) Used to allocate resources that are shared across the
|
||||
* whole device, such as string IDs, and add its configurations using
|
||||
* @usb_add_config(). This may fail by returning a negative errno
|
||||
|
@ -319,6 +322,7 @@ struct usb_composite_driver {
|
|||
const char *name;
|
||||
const struct usb_device_descriptor *dev;
|
||||
struct usb_gadget_strings **strings;
|
||||
enum usb_device_speed max_speed;
|
||||
|
||||
/* REVISIT: bind() functions can be marked __init, which
|
||||
* makes trouble for section mismatch analysis. See if
|
||||
|
|
|
@ -449,6 +449,11 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
struct usb_dcd_config_params {
|
||||
__u8 bU1devExitLat; /* U1 Device exit Latency */
|
||||
__le16 bU2DevExitLat; /* U2 Device exit Latency */
|
||||
};
|
||||
|
||||
struct usb_gadget;
|
||||
struct usb_gadget_driver;
|
||||
|
||||
|
@ -464,6 +469,7 @@ struct usb_gadget_ops {
|
|||
int (*pullup) (struct usb_gadget *, int is_on);
|
||||
int (*ioctl)(struct usb_gadget *,
|
||||
unsigned code, unsigned long param);
|
||||
void (*get_config_params)(struct usb_dcd_config_params *);
|
||||
int (*udc_start)(struct usb_gadget *,
|
||||
struct usb_gadget_driver *);
|
||||
int (*udc_stop)(struct usb_gadget *);
|
||||
|
|
Loading…
Reference in a new issue