This adds usb framework support for super-speed usb, which will further facilitate to add stack support for xHCI.
Signed-off-by: Vikas C Sajjan <vikas.saj...@samsung.com> Signedoff-by: Vivek Gautam <gautam.vi...@samsung.com> --- common/cmd_usb.c | 6 +- common/usb.c | 41 ++++++++- common/usb_hub.c | 26 +++++- common/usb_storage.c | 35 +++++---- include/common.h | 2 + include/linux/usb/ch9.h | 2 +- include/usb.h | 15 +++- include/usb_defs.h | 26 ++++++- include/usbdescriptors.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 322 insertions(+), 32 deletions(-) diff --git a/common/cmd_usb.c b/common/cmd_usb.c index c128455..013b2e8 100644 --- a/common/cmd_usb.c +++ b/common/cmd_usb.c @@ -262,7 +262,7 @@ void usb_display_config(struct usb_device *dev) ifdesc = &config->if_desc[i]; usb_display_if_desc(&ifdesc->desc, dev); for (ii = 0; ii < ifdesc->no_of_ep; ii++) { - epdesc = &ifdesc->ep_desc[ii]; + epdesc = &ifdesc->ep_desc[ii].ep_desc; usb_display_ep_desc(epdesc); } } @@ -271,7 +271,9 @@ void usb_display_config(struct usb_device *dev) static inline char *portspeed(int speed) { - if (speed == USB_SPEED_HIGH) + if (speed == USB_SPEED_SUPER) + return "5 Gb/s"; + else if (speed == USB_SPEED_HIGH) return "480 Mb/s"; else if (speed == USB_SPEED_LOW) return "1.5 Mb/s"; diff --git a/common/usb.c b/common/usb.c index 50b8175..691d9ac 100644 --- a/common/usb.c +++ b/common/usb.c @@ -304,7 +304,7 @@ usb_set_maxpacket_ep(struct usb_device *dev, int if_idx, int ep_idx) struct usb_endpoint_descriptor *ep; u16 ep_wMaxPacketSize; - ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx]; + ep = &dev->config.if_desc[if_idx].ep_desc[ep_idx].ep_desc; b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_wMaxPacketSize = get_unaligned(&ep->wMaxPacketSize); @@ -360,6 +360,7 @@ static int usb_parse_config(struct usb_device *dev, int index, ifno, epno, curr_if_num; int i; u16 ep_wMaxPacketSize; + struct usb_interface *if_desc = NULL; ifno = -1; epno = -1; @@ -401,21 +402,27 @@ static int usb_parse_config(struct usb_device *dev, break; case USB_DT_ENDPOINT: epno = dev->config.if_desc[ifno].no_of_ep; + if_desc = &dev->config.if_desc[ifno]; /* found an endpoint */ - dev->config.if_desc[ifno].no_of_ep++; - memcpy(&dev->config.if_desc[ifno].ep_desc[epno], + if_desc->no_of_ep++; + memcpy(&if_desc->ep_desc[epno].ep_desc, &buffer[index], buffer[index]); ep_wMaxPacketSize = get_unaligned(&dev->config.\ if_desc[ifno].\ ep_desc[epno].\ - wMaxPacketSize); + ep_desc.wMaxPacketSize); put_unaligned(le16_to_cpu(ep_wMaxPacketSize), &dev->config.\ if_desc[ifno].\ ep_desc[epno].\ - wMaxPacketSize); + ep_desc.wMaxPacketSize); USB_PRINTF("if %d, ep %d\n", ifno, epno); break; + case USB_DT_SS_ENDPOINT_COMP: + if_desc = &dev->config.if_desc[ifno]; + memcpy(&(if_desc->ep_desc[epno].ss_ep_comp), + &buffer[index], buffer[index]); + break; default: if (head->bLength == 0) return 1; @@ -659,6 +666,18 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid, return result; } +/* Allocate usb device */ +int usb_alloc_dev(struct usb_device *dev) +{ + int res; + + USB_PRINTF("alloc device\n"); + res = usb_control_msg(dev, usb_sndctrlpipe(dev->parent, 0), + USB_REQ_ALLOC_DEV, 0, 0, 0, + NULL, 0, USB_CNTL_TIMEOUT); + + return res; +} static void usb_try_string_workarounds(unsigned char *buf, int *length) { @@ -852,7 +871,10 @@ int usb_new_device(struct usb_device *dev) struct usb_device_descriptor *desc; int port = -1; struct usb_device *parent = dev->parent; + +#ifndef CONFIG_USB_XHCI unsigned short portstatus; +#endif /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is * only 18 bytes long, this will terminate with a short packet. But if @@ -889,12 +911,21 @@ int usb_new_device(struct usb_device *dev) return 1; } + /* + * Putting up the code here for slot assignment and initialization: + * xHCI spec sec 4.3.2, 4.3.3 + */ +#ifdef CONFIG_USB_XHCI + /* Call if and only if device is attached and detected */ + usb_alloc_dev(dev); +#else /* reset the port for the second time */ err = hub_port_reset(dev->parent, port, &portstatus); if (err < 0) { printf("\n Couldn't reset port %i\n", port); return 1; } +#endif } #endif diff --git a/common/usb_hub.c b/common/usb_hub.c index e4a1201..8a00894 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -204,7 +204,12 @@ int hub_port_reset(struct usb_device *dev, int port, } -void usb_hub_port_connect_change(struct usb_device *dev, int port) +/* + * Adding the flag do_port_reset: USB 2.0 device requires port reset + * while USB 3.0 device does not. + */ +void usb_hub_port_connect_change(struct usb_device *dev, int port, + int do_port_reset) { struct usb_device *usb; ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); @@ -235,11 +240,21 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) } mdelay(200); +#ifdef CONFIG_USB_XHCI + /* Reset the port */ + if (do_port_reset) { + if (hub_port_reset(dev, port, &portstatus) < 0) { + printf("cannot reset port %i!?\n", port + 1); + return; + } + } +#else /* Reset the port */ if (hub_port_reset(dev, port, &portstatus) < 0) { printf("cannot reset port %i!?\n", port + 1); return; } +#endif mdelay(200); @@ -409,7 +424,10 @@ static int usb_hub_configure(struct usb_device *dev) if (portchange & USB_PORT_STAT_C_CONNECTION) { USB_HUB_PRINTF("port %d connection change\n", i + 1); - usb_hub_port_connect_change(dev, i); + usb_hub_port_connect_change(dev, i, 0); + } else if ((portstatus & 0x1) == 1) { + USB_HUB_PRINTF("port %d connection change\n", i + 1); + usb_hub_port_connect_change(dev, i, 1); } if (portchange & USB_PORT_STAT_C_ENABLE) { USB_HUB_PRINTF("port %d enable change, status %x\n", @@ -426,7 +444,7 @@ static int usb_hub_configure(struct usb_device *dev) USB_HUB_PRINTF("already running port %i " \ "disabled by hub (EMI?), " \ "re-enabling...\n", i + 1); - usb_hub_port_connect_change(dev, i); + usb_hub_port_connect_change(dev, i, 0); } } if (portstatus & USB_PORT_STAT_SUSPEND) { @@ -470,7 +488,7 @@ int usb_hub_probe(struct usb_device *dev, int ifnum) /* Multiple endpoints? What kind of mutant ninja-hub is this? */ if (iface->desc.bNumEndpoints != 1) return 0; - ep = &iface->ep_desc[0]; + ep = &iface->ep_desc[0].ep_desc; /* Output endpoint? Curiousier and curiousier.. */ if (!(ep->bEndpointAddress & USB_DIR_IN)) return 0; diff --git a/common/usb_storage.c b/common/usb_storage.c index 0c2a4c7..53d41d8 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -262,7 +262,7 @@ int usb_stor_scan(int mode) usb_max_devs = 0; for (i = 0; i < USB_MAX_DEVICE; i++) { dev = usb_get_dev_index(i); /* get device */ - USB_STOR_PRINTF("i=%d\n", i); + USB_STOR_PRINTF("i=%d, dev_num=%d\n", i, dev->devnum); if (dev == NULL) break; /* no more devices available */ @@ -278,10 +278,11 @@ int usb_stor_scan(int mode) lun++) { usb_dev_desc[usb_max_devs].lun = lun; if (usb_stor_get_info(dev, &usb_stor[start], - &usb_dev_desc[usb_max_devs]) == 1) { - usb_max_devs++; - } + &usb_dev_desc[usb_max_devs]) == 1) { + usb_max_devs++; + } } + } /* if storage device */ if (usb_max_devs == USB_MAX_STOR_DEV) { @@ -511,7 +512,7 @@ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) dir_in = US_DIRECTION(srb->cmd[0]); #ifdef BBB_COMDAT_TRACE - printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", + printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); if (srb->cmdlen) { @@ -1208,6 +1209,7 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum, { struct usb_interface *iface; int i; + struct usb_endpoint_descriptor *ep_desc; unsigned int flags = 0; int protocol = 0; @@ -1290,24 +1292,25 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum, * We will ignore any others. */ for (i = 0; i < iface->desc.bNumEndpoints; i++) { + ep_desc = &iface->ep_desc[i].ep_desc; /* is it an BULK endpoint? */ - if ((iface->ep_desc[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { - if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) - ss->ep_in = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; + if ((ep_desc->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { + if (ep_desc->bEndpointAddress & USB_DIR_IN) + ss->ep_in = ep_desc->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; else ss->ep_out = - iface->ep_desc[i].bEndpointAddress & + ep_desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } /* is it an interrupt endpoint? */ - if ((iface->ep_desc[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { - ss->ep_int = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - ss->irqinterval = iface->ep_desc[i].bInterval; + if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { + ss->ep_int = ep_desc->bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + ss->irqinterval = ep_desc->bInterval; } } USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n", diff --git a/include/common.h b/include/common.h index b23e90b..ef5f687 100644 --- a/include/common.h +++ b/include/common.h @@ -211,6 +211,8 @@ typedef void (interrupt_handler_t)(void *); #define MIN(x, y) min(x, y) #define MAX(x, y) max(x, y) +#define min3(a, b, c) min(min(a, b), c) + /* * Return the absolute value of a number. * diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index ce1d1e1..33af2f4 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -122,7 +122,6 @@ #define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ - /** * struct usb_ctrlrequest - SETUP data for a USB device control request * @bRequestType: matches the USB bmRequestType field @@ -491,6 +490,7 @@ enum usb_device_speed { USB_SPEED_UNKNOWN = 0, /* enumerating */ USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_SUPER, /* usb 3.0 */ USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ }; diff --git a/include/usb.h b/include/usb.h index 9dd8791..a7a0f22 100644 --- a/include/usb.h +++ b/include/usb.h @@ -73,6 +73,16 @@ struct usb_descriptor_header { unsigned char bDescriptorType; } __attribute__ ((packed)); +struct usb_ep_desc { + struct usb_endpoint_descriptor ep_desc; + /* + * Super Speed Device will have Super Speed Endpoint + * Companion Descriptor (section 9.6.7 of usb 3.0 spec) + * Revision 1.0 June 6th 2011 + */ + struct usb_ss_ep_comp_descriptor ss_ep_comp; +}; + /* Interface */ struct usb_interface { struct usb_interface_descriptor desc; @@ -81,7 +91,7 @@ struct usb_interface { unsigned char num_altsetting; unsigned char act_altsetting; - struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS]; + struct usb_ep_desc ep_desc[USB_MAXENDPOINTS]; } __attribute__ ((packed)); /* Configuration information.. */ @@ -153,7 +163,8 @@ struct usb_device { defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \ defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \ defined(CONFIG_USB_OMAP3) || defined(CONFIG_USB_DA8XX) || \ - defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X) + defined(CONFIG_USB_BLACKFIN) || defined(CONFIG_USB_AM35X) || \ + defined(CONFIG_USB_XHCI) int usb_lowlevel_init(int index, void **controller); int usb_lowlevel_stop(int index); diff --git a/include/usb_defs.h b/include/usb_defs.h index 8032e57..e681609 100644 --- a/include/usb_defs.h +++ b/include/usb_defs.h @@ -84,7 +84,8 @@ #define USB_SPEED_FULL 0x0 /* 12Mbps */ #define USB_SPEED_LOW 0x1 /* 1.5Mbps */ #define USB_SPEED_HIGH 0x2 /* 480Mbps */ -#define USB_SPEED_RESERVED 0x3 +#define USB_SPEED_SUPER 0x3 /* 5Gbps */ +#define USB_SPEED_RESERVED 0x4 /* Descriptor types */ #define USB_DT_DEVICE 0x01 @@ -93,6 +94,9 @@ #define USB_DT_INTERFACE 0x04 #define USB_DT_ENDPOINT 0x05 +/* From the USB 3.0 spec */ +#define USB_DT_SS_ENDPOINT_COMP 0x30 + #define USB_DT_HID (USB_TYPE_CLASS | 0x01) #define USB_DT_REPORT (USB_TYPE_CLASS | 0x02) #define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) @@ -156,6 +160,7 @@ #define USB_REQ_SET_IDLE 0x0A #define USB_REQ_SET_PROTOCOL 0x0B +#define USB_REQ_ALLOC_DEV 0xDE /* "pipe" definitions */ @@ -227,6 +232,23 @@ #define USB_PORT_STAT_SPEED \ (USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED) +/* + * Additions to wPortStatus bit field from USB 3.0 + * See USB 3.0 spec Table 10-10 + */ +#define USB_PORT_STAT_LINK_STATE 0x01e0 +#define USB_SS_PORT_STAT_POWER 0x0200 +#define USB_SS_PORT_STAT_SPEED 0x1c00 +#define USB_PORT_STAT_SPEED_5GBPS 0x0000 + +/* + * USB 3.0 wPortChange bit fields + * See USB 3.0 spec Table 10-11 + */ +#define USB_PORT_STAT_C_BH_RESET 0x0020 +#define USB_PORT_STAT_C_LINK_STATE 0x0040 +#define USB_PORT_STAT_C_CONFIG_ERROR 0x0080 + /* wPortChange bits */ #define USB_PORT_STAT_C_CONNECTION 0x0001 #define USB_PORT_STAT_C_ENABLE 0x0002 @@ -240,7 +262,7 @@ #define HUB_CHAR_OCPM 0x0018 /* - *Hub Status & Hub Change bit masks + * Hub Status & Hub Change bit masks */ #define HUB_STATUS_LOCAL_POWER 0x0001 #define HUB_STATUS_OVERCURRENT 0x0002 diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h index de1069f..527e895 100644 --- a/include/usbdescriptors.h +++ b/include/usbdescriptors.h @@ -192,6 +192,15 @@ * standard usb descriptor structures */ +/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */ +struct usb_ss_ep_comp_descriptor { + u8 bLength; + u8 bDescriptorType; /* 0x30 */ + u8 bMaxBurst; + u8 bmAttributes; + u16 wBytesPerInterval; +} __attribute__ ((packed)); + struct usb_endpoint_descriptor { u8 bLength; u8 bDescriptorType; /* 0x5 */ @@ -545,4 +554,196 @@ static inline void print_device_descriptor(struct usb_device_descriptor *d) #define print_device_descriptor(d) #endif /* DEBUG */ + +/*-------------------------------------------------------------------------*/ + +/** + * Get the endpoint's number + * + * @param epd Endpoint descriptor to be checked + * @return epd's number, 0 to 15. + */ +static inline int usb_endpoint_num(struct usb_endpoint_descriptor *epd) +{ + return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; +} + +/** + * Get the endpoint's transfer type + * + * @param epd Endpoint to be checked + * @return One of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according + * to @epd's transfer type. + */ +static inline int usb_endpoint_type(struct usb_endpoint_descriptor *epd) +{ + return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +} + +/** + * usb_endpoint_dir_in - check if the endpoint has IN direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type IN, otherwise it returns false. + */ +static inline int usb_endpoint_dir_in(struct usb_endpoint_descriptor *epd) +{ + return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; +} + +/** + * usb_endpoint_dir_out - check if the endpoint has OUT direction + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type OUT, otherwise it returns false. + */ +static inline int usb_endpoint_dir_out( + struct usb_endpoint_descriptor *epd) +{ + return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; +} + +/** + * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type bulk, otherwise it returns false. + */ +static inline int usb_endpoint_xfer_bulk( + struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK; +} + +/** + * usb_endpoint_xfer_control - check if the endpoint has control transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type control, otherwise it returns false. + */ +static inline int usb_endpoint_xfer_control( + struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL; +} + +/** + * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type interrupt, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_int( + struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_INT; +} + +/** + * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type isochronous, otherwise it returns + * false. + */ +static inline int usb_endpoint_xfer_isoc( + struct usb_endpoint_descriptor *epd) +{ + return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC; +} + +/** + * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_in( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has bulk transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_bulk_out( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_is_int_in - check if the endpoint is interrupt IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_in( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has interrupt transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_int_out( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and IN direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_in( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd); +} + +/** + * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT + * @epd: endpoint to be checked + * + * Returns true if the endpoint has isochronous transfer type and OUT direction, + * otherwise it returns false. + */ +static inline int usb_endpoint_is_isoc_out( + struct usb_endpoint_descriptor *epd) +{ + return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd); +} + +/** + * usb_endpoint_maxp - get endpoint's max packet size + * @epd: endpoint to be checked + * + * Returns @epd's max packet + */ +static inline int usb_endpoint_maxp(struct usb_endpoint_descriptor *epd) +{ + return le16_to_cpu(epd->wMaxPacketSize); +} + #endif -- 1.7.6.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot