USB: XHCI: Add xHCI host controller stack driver
Subsystems (2)
cover USB: XHCI: Add xHCI host controller stack driver
This change adds necessary framework support for USB3.0 (Super-speed) and xHCI host controller stack layer. This stack will eventually interact with SOC specific USB 3.0 controllers.
Based on 'master' branch of u-boot tree.
Tested successfully with local patches on xHCI support for exynos5 with Kingston USB 2.0 data traveler (512 MB) and Corsair USB 3.0 flash voyager. However, also saw failures with Transcend USB 3.0 (8 GB) and a Jetflash 256 MB.
We are further debugging and testing this thoroughly. In the meantime can this be reviewed please?
This definitely needs further improvements ;-).
Although, code is based on linux's xHCI host controller driver, at certain points putting some delays seemed to make the device working (couldn't get proper explanation on delays in xHCI or USB 3.0 specifications :-(, any help in this regard will be very much appreciated).
Vivek Gautam (2):
USB: SS: Add support for Super Speed USB interface
USB: xHCI: Add stack support for xHCI
common/cmd_usb.c | 6 +- common/usb.c | 41 +- common/usb_hub.c | 26 +- common/usb_storage.c | 35 +- drivers/usb/host/xhci.c | 3330 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 1360 +++++++++++++++++++ include/common.h | 2 + include/linux/usb/ch9.h | 2 +- include/usb.h | 15 +- include/usb_defs.h | 26 +- include/usbdescriptors.h | 201 +++ 11 files changed, 5012 insertions(+), 32 deletions(-) create mode 100644 drivers/usb/host/xhci.c create mode 100644 drivers/usb/host/xhci.h
Signature · 1 line
1.7.6.5
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
This adds usb framework support for super-speed usb, which will further facilitate to add stack support for xHCI.
--- 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(-)
common/cmd_usb.c +4 -2
@@ -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" ;
common/usb.c +36 -5
95 lines not on this page · raw message
common/usb_hub.c +22 -4
@@ -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 ;
common/usb_storage.c +19 -16
@@ -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",
include/common.h +2 -0
@@ -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. *
include/linux/usb/ch9.h +1 -1
@@ -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) */ };
include/usb.h +13 -2
@@ -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);
include/usb_defs.h +24 -2
@@ -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
include/usbdescriptors.h +201 -0
211 lines not on this page · raw message
Signature · 1 line
1.7.6.5
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
Dear Vivek Gautam,
Quoted 5 lines
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 <[email protected]>Signedoff-by Vivek Gautam <[email protected]>
CCing Benoit, (help me! ;-) )
I'll be blunt and technical below, try not to take it personally please.
Quoted 18 lines
--- 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(-)
common/cmd_usb.c +0
-0
common/cmd_usb.c void usb_display_config(struct usb_device *dev) · line 265
Quoted 5 lines
common/cmd_usb.c +1
-1@@ -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;
Fix, split into separate patch
Quoted 4 lines
common/cmd_usb.c +0
-0usb_display_ep_desc (epdesc); } }
common/cmd_usb.c void usb_display_config(struct usb_device *dev) · line 279
Quoted 10 lines
common/cmd_usb.c +3
-1@@ -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" ;
Can you convert this into switch please?
Quoted 22 lines
common/usb.c +2
-1@@ -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 ;
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 408
Quoted 9 lines
common/usb.c +3
-2@@ -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,
This change is irrelevant, it's a fix so put it into separate patch with proper explanation.
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 413
Quoted 6 lines
common/usb.c +1
-1&buffer[index], buffer[index]); ep_wMaxPacketSize =get_unaligned (&dev->config.\ if_desc[ifno].\ ep_desc[epno].\ - wMaxPacketSize); + ep_desc.wMaxPacketSize);
What does this change do/fix ?
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 423
Quoted 11 lines
common/usb.c +4
-1put_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),
Do you need these braces in &(...) ?
Quoted 6 lines
common/usb.c +2
-0+ &buffer[index], buffer[index]); +break ;default :if (head->bLength ==0 )return 1 ;
common/usb.c static int usb_get_string(struct usb_device *dev, · line 674
Quoted 9 lines
common/usb.c +6
-0@@ -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" );
this is a debug print.
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 677
Quoted 3 lines
common/usb.c +3
-0+ res =usb_control_msg (dev,usb_sndctrlpipe (dev->parent,0 ), +USB_REQ_ALLOC_DEV ,0 ,0 ,0 , +NULL ,0 ,USB_CNTL_TIMEOUT );
How does this "allocate" a device? Please, do a proper documentation. Actually, take a look at include/linker_lists.h
Or see here:
http://git.denx.de/?p=u-
boot.git;a=blob;f=include/linker_lists.h;h=0b405d78ea34df1c528fbc4e24ed2aad756ac4a2;hb=HEAD
And here (U-Boot Code Documentation):
http://www.denx.de/wiki/U-Boot/CodingStyle
It'd be really nice if you could follow such pattern of documentation!
common/usb.c int usb_new_device(struct usb_device *dev) · line 876
Quoted 12 lines
common/usb.c +4
-0+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;
Use __maybe_unused instead so it's not poluted with these #ifdefs ?
common/usb.c int usb_new_device(struct usb_device *dev) · line 917
Quoted 12 lines
common/usb.c +5
-0+#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 +*/
Misaligned comment?
Quoted 19 lines
common/usb.c +5
-0+#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 common/usb_hub.c +0
-0
common/usb_hub.c int hub_port_reset(struct usb_device *dev, int port, · line 212
Quoted 10 lines
common/usb_hub.c +6
-1@@ -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)
Make it uint32_t flags so once usb4.0 (or MS's magic USB port where you can connect joystick :D ) arrives and it needs two and half resets of a port, we just add another flag.
Quoted 12 lines
common/usb_hub.c +5
-0{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 );
common/usb_hub.c void usb_hub_port_connect_change(struct usb_device · line 257
Quoted 10 lines
common/usb_hub.c +5
-0+ return; + } + } +#else /* Reset the port */ if (hub_port_reset (dev, port, &portstatus) <0 ) {printf ("cannot reset port %i!?\n" , port +1 );return ; } +#endif
I'm sure
#ifdef ...do_port_reset = 1
#endif
would work just fine ... then you'd avoid such massive blocks of ifdef'd code.
common/usb_hub.c static int usb_hub_configure(struct usb_device *dev) · line 428
Quoted 9 lines
common/usb_hub.c +2
-1mdelay (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 ) {
Magic constant ... NAK
Quoted 5 lines
common/usb_hub.c +2
-0+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",
[...]
common/usb_hub.c int usb_stor_scan(int mode) · line 281
Quoted 5 lines
common/usb_hub.c +0
-1@@ -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) {
common/usb_hub.c int usb_stor_scan(int mode) · line 281
Quoted 3 lines
common/usb_hub.c +1
-2- usb_max_devs++; - } + &usb_dev_desc[usb_max_devs]) ==
1) {
common/usb_hub.c int usb_stor_scan(int mode) · line 286
Quoted 5 lines
common/usb_hub.c +3
-0+ usb_max_devs++; + } } + }
Can we fix this depth of indend somehow?
common/usb_hub.c int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) · line 515
Quoted 8 lines
common/usb_hub.c +1
-1/* 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",
Fixes should certainly be submitted as separate patches prior to feature additions.
Quoted 35 lines
common/usb_hub.c +1
-0dir_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.
common/usb_hub.c +7
-6*/ 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? */
common/usb_hub.c
Quoted 10 lines
common/usb_hub.c +5
-5-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;
Are you just introducing new variable here?
include/common.h typedef void (interrupt_handler_t)(void *); · line 215
Quoted 13 lines
common/usb_hub.c +0
-0} } USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",include/common.h +2
-0@@ -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) +
Isn't this defined somewhere already?
[...]
Rest is just great.
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
Dear Marek,
CCing Simon Glass.
Quoted 25 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 5 lines
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 <[email protected]>Signedoff-by Vivek Gautam <[email protected]>CCing Benoit, (help me! ;-) )
I'll be blunt and technical below, try not to take it personally please.
Quoted 13 lines
--- 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(-)
Quoted 13 lines
common/cmd_usb.c void usb_display_config(struct usb_device *dev) · line 265
Quoted 10 lines
common/cmd_usb.c +1
-1@@ -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;Fix, split into separate patch
Sure, will split these fixes in a separate patch.
Quoted 5 lines
Quoted 5 lines
common/cmd_usb.c +0
-0usb_display_ep_desc (epdesc); } }@@ -271,7 +271,9 @@ void usb_display_config(struct usb_device *dev)
Quoted 12 lines
common/cmd_usb.c void usb_display_config(struct usb_device *dev) · line 279
Quoted 9 lines
common/cmd_usb.c +3
-1static 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" ;Can you convert this into switch please?
Sure, will make a switch for this. That whould be better.
Quoted 19 lines
Quoted 19 lines
common/usb.c +2
-1@@ -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 ;
Quoted 16 lines
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 408
Quoted 12 lines
common/usb.c +3
-2ifno =-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,This change is irrelevant, it's a fix so put it into separate patch with proper explanation.
Shall put all these fixes in a separate patch.
Quoted 9 lines
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 413
Quoted 6 lines
common/usb.c +1
-1&buffer[index], buffer[index]); ep_wMaxPacketSize =get_unaligned (&dev->config.\ if_desc[ifno].\ ep_desc[epno].\ - wMaxPacketSize); + ep_desc.wMaxPacketSize);What does this change do/fix ?
This comes as an affect of introduction of "struct usb_ep_desc" which eventually contains "struct usb_endpoint_descriptor" and "struct usb_ss_ep_comp_descriptor".
Quoted 12 lines
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 423
Quoted 11 lines
common/usb.c +4
-1put_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),
Quoted 2 lines
Do you need these braces in &(...) ?
True, we can remove these braces.
Quoted 9 lines
Quoted 9 lines
common/usb.c +2
-0+ &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; }
Quoted 9 lines
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 674
Quoted 6 lines
common/usb.c +6
-0+/* Allocate usb device */ +int usb_alloc_dev (struct usb_device *dev) +{ +int res; + +USB_PRINTF ("alloc device\n" );this is a debug print.
Isn't USB_PRINTF itself a conditional debug print ?
Quoted 8 lines
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 677
Quoted 3 lines
common/usb.c +3
-0+ res =usb_control_msg (dev,usb_sndctrlpipe (dev->parent,0 ), +USB_REQ_ALLOC_DEV ,0 ,0 ,0 , +NULL ,0 ,USB_CNTL_TIMEOUT );How does this "allocate" a device? Please, do a proper documentation. Actually, take a look at
include/linker_lists.h
Quoted 9 lines
Or see here:
http://git.denx.de/?p=u-
boot.git;a=blob;f=include/linker_lists.h;h=0b405d78ea34df1c528fbc4e24ed2aad756ac4a2;hb=HEADAnd here (U-Boot Code Documentation):
http://www.denx.de/wiki/U-Boot/CodingStyleIt'd be really nice if you could follow such pattern of documentation!
Yes, thanks for pointing out. Will document it properly to make things more understandable.
Quoted 15 lines
common/usb.c int usb_new_device(struct usb_device *dev) · line 876
Quoted 12 lines
common/usb.c +4
-0+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;Use
__maybe_unusedinstead so it's not poluted with these #ifdefs ?
Right. will change this accordingly.
Quoted 8 lines
Quoted 8 lines
common/usb.c +1
-0+#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 ; }
Quoted 7 lines
common/usb.c int usb_new_device(struct usb_device *dev) · line 917
Quoted 4 lines
common/usb.c +4
-0+/* +* Putting up the code here for slot assignment and initialization: +* xHCI spec sec 4.3.2, 4.3.3 +*/ Misaligned comment?
Sure, will correct it.
Quoted 22 lines
Quoted 22 lines
common/usb.c +5
-0+#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 common/usb_hub.c +0
-0@@ -204,7 +204,12 @@ int hub_port_reset(struct usb_device *dev, int port, }
Quoted 12 lines
common/usb_hub.c int hub_port_reset(struct usb_device *dev, int port, · line 212
Quoted 7 lines
common/usb_hub.c +6
-1-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)Make it
uint32_tflags so once usb4.0 (or MS's magic USB port where you can connect joystick :D ) arrives and it needs two and half resets of a port, we just add another flag.
Ok, will do this.
Quoted 25 lines
Quoted 12 lines
common/usb_hub.c +5
-0{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 );common/usb_hub.c void usb_hub_port_connect_change(struct usb_device · line 257
Quoted 10 lines
common/usb_hub.c +5
-0+ return; + } + } +#else /* Reset the port */ if (hub_port_reset (dev, port, &portstatus) <0 ) {printf ("cannot reset port %i!?\n" , port +1 );return ; } +#endif I'm sure
Quoted 6 lines
#ifdef ...
do_port_reset= 1
#endifwould work just fine ... then you'd avoid such massive blocks of ifdef'd code.
Will try to fix this.
Quoted 4 lines
Quoted 4 lines
common/usb_hub.c +0
-0mdelay (200 );@@ -409,7 +424,10 @@ static int usb_hub_configure(struct usb_device *dev)
Quoted 8 lines
common/usb_hub.c static int usb_hub_configure(struct usb_device *dev) · line 428
Quoted 5 lines
common/usb_hub.c +2
-1if (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 ) {Magic constant ... NAK
Sure, missed the proper macro here. ;) Will amend it.
Quoted 17 lines
Quoted 5 lines
common/usb_hub.c +2
-0+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",[...]
common/usb_hub.c int usb_stor_scan(int mode) · line 281
Quoted 5 lines
common/usb_hub.c +0
-1@@ -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) {
common/usb_hub.c int usb_stor_scan(int mode) · line 281
Quoted 3 lines
common/usb_hub.c +1
-2- usb_max_devs++; - } + &usb_dev_desc[usb_max_devs]) ==
Quoted 9 lines
1) {
common/usb_hub.c int usb_stor_scan(int mode) · line 286
Quoted 5 lines
common/usb_hub.c +3
-0+ usb_max_devs++; + } } + }Can we fix this depth of indend somehow?
Ok, will try to fix this chunk.
Quoted 5 lines
Quoted 5 lines
common/usb_hub.c +0
-0/* 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 ]);
Quoted 7 lines
common/usb_hub.c int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) · line 515
Quoted 3 lines
common/usb_hub.c +1
-1#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",Fixes should certainly be submitted as separate patches prior to feature additions.
Sure, fixes in a separate patch :-)
Quoted 34 lines
Quoted 34 lines
common/usb_hub.c +1
-0dir_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++) {common/usb_hub.c +7
-6+ 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 ; }
Quoted 14 lines
common/usb_hub.c
Quoted 11 lines
/* is it an interrupt endpoint? */common/usb_hub.c +5
-5-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;Are you just introducing new variable here?
This is again a fix. As pointed here "ep_desc = &iface->ep_desc[i].ep_desc", fixes
things around introduction of "struct usb_ep_desc".
Quoted 11 lines
Quoted 11 lines
} } USB_STOR_PRINTF("Endpoints In %d Out %d Int %d\n",include/common.h +0
-0@@ -211,6 +211,8 @@ typedef void (interrupt_handler_t)(void *);#define MIN (x, y) min(x, y)#define MAX (x, y) max(x, y)
Quoted 5 lines
include/common.h typedef void (interrupt_handler_t)(void *); · line 215
Quoted 2 lines
include/common.h +2
-0+#define min3 (a, b, c) min(min(a, b), c) +Isn't this defined somewhere already?
Can you please guide me here, i can see a similar inline function in ehci-hcd only :(
Quoted 3 lines
[...]
Rest is just great.
Thanks for reviewing this Marek. I shall update the patchset soon.
Thanks & Regards
Vivek
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
Dear Vivek Gautam,
[...]
Quoted 4 lines
This comes as an affect of introduction of "struct
usb_ep_desc" which eventually contains "structusb_endpoint_descriptor" and "structusb_ss_ep_comp_descriptor".
I see, can we split this? I really enjoy small incremental patches, it's much easier to bisect issues then.
Quoted 42 lines
Quoted 9 lines
Quoted 9 lines
put_unaligned(le16_to_cpu(ep_wMaxPacketSize), &dev->config.\ if_desc[ifno].\ ep_desc[epno].\(quoted diff) +1
-1- wMaxPacketSize); + ep_desc.wMaxPacketSize);Quoted 8 lines
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 423
Quoted 6 lines
USB_PRINTF("if %d, ep %d\n", ifno, epno); break;common/usb.c +3
-0+case USB_DT_SS_ENDPOINT_COMP : + if_desc = &dev->config.if_desc[ifno]; + memcpy(&(if_desc->ep_desc[epno].ss_ep_comp),Do you need these braces in &(...) ?
True, we can remove these braces.
Quoted 13 lines
Quoted 13 lines
common/usb.c +2
-0+ &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; }Quoted 8 lines
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 674
Quoted 6 lines
common/usb.c +6
-0+/* Allocate usb device */ +int usb_alloc_dev (struct usb_device *dev) +{ +int res; + +USB_PRINTF ("alloc device\n" );this is a debug print.
Quoted 1 line
Isn't
USB_PRINTFitself a conditional debug print ?
Yes, but I'd prefer to kill USB_PRINTF altogether in favor of debug().
Quoted 12 lines
Quoted 12 lines
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 677
Quoted 3 lines
common/usb.c +3
-0+ res =usb_control_msg (dev,usb_sndctrlpipe (dev->parent,0 ), +USB_REQ_ALLOC_DEV ,0 ,0 ,0 , +NULL ,0 ,USB_CNTL_TIMEOUT );How does this "allocate" a device? Please, do a proper documentation. Actually, take a look at
include/linker_lists.hOr see here:
http://git.denx.de/?p=u-
boot.git;a=blob;f=include/linker_lists.h;h=0b405d78ea34df1c528fbc4e24ed2a ad756ac4a2;hb=HEAD
Quoted 7 lines
Quoted 4 lines
And here (U-Boot Code Documentation):
http://www.denx.de/wiki/U-Boot/CodingStyleIt'd be really nice if you could follow such pattern of documentation!
Yes, thanks for pointing out. Will document it properly to make things more understandable.
_AWESOME_ !
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
common/usb.c +2
-0+return res; +}
[...]
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
include/common.h +0
-0@@ -211,6 +211,8 @@ typedef void (interrupt_handler_t)(void *);#define MIN (x, y) min(x, y)#define MAX (x, y) max(x, y)
Quoted 7 lines
Quoted 4 lines
include/common.h typedef void (interrupt_handler_t)(void *); · line 215
Quoted 2 lines
include/common.h +2
-0+#define min3 (a, b, c) min(min(a, b), c) +Isn't this defined somewhere already?
Can you please guide me here, i can see a similar inline function in ehci-hcd only :(
ICK, so we have ad-hoc implementation of this :-( I'd say, put it into common.h and remove the ehci's ad-hoc implementation.
Quoted 5 lines
Quoted 3 lines
[...]
Rest is just great.
Thanks for reviewing this Marek. I shall update the patchset soon.
Welcome, it's pleasure to work with you ;-)
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
Hi Marek,
Quoted 11 lines · Marek Vasut
Dear Vivek Gautam,
[...]
Quoted 4 lines
This comes as an affect of introduction of "struct
usb_ep_desc" which eventually contains "structusb_endpoint_descriptor" and "structusb_ss_ep_comp_descriptor".I see, can we split this? I really enjoy small incremental patches, it's much easier to bisect issues then.
Sure, will split this small change.
Quoted 42 lines
Quoted 42 lines
Quoted 9 lines
Quoted 9 lines
put_unaligned(le16_to_cpu(ep_wMaxPacketSize), &dev->config.\ if_desc[ifno].\ ep_desc[epno].\(quoted diff) +1
-1- wMaxPacketSize); + ep_desc.wMaxPacketSize);Quoted 8 lines
common/usb.c static int usb_parse_config(struct usb_device *dev, · line 423
Quoted 6 lines
USB_PRINTF("if %d, ep %d\n", ifno, epno); break;common/usb.c +3
-0+case USB_DT_SS_ENDPOINT_COMP : + if_desc = &dev->config.if_desc[ifno]; + memcpy(&(if_desc->ep_desc[epno].ss_ep_comp),Do you need these braces in &(...) ?
True, we can remove these braces.
Quoted 21 lines
Quoted 9 lines
common/usb.c +2
-0+ &buffer[index], buffer[index]); +break ;default :if (head->bLength ==0 )return 1 ;common/usb.c static int usb_get_string(struct usb_device *dev, · line 675
Quoted 10 lines
common/usb.c +6
-0@@ -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" );this is a debug print.
Quoted 4 lines
Quoted 1 line
Isn't
USB_PRINTFitself a conditional debug print ?Yes, but I'd prefer to kill
USB_PRINTFaltogether in favor ofdebug().
Ok, will switch to debug(...).
And may be in that case we may try to eliminate USB _PRINTF and other such macro altogether from sub framework ?
Quoted 42 lines
Quoted 12 lines
Quoted 12 lines
common/usb.c static int usb_get_string(struct usb_device *dev, unsigned short langid, · line 677
Quoted 3 lines
common/usb.c +3
-0+ res =usb_control_msg (dev,usb_sndctrlpipe (dev->parent,0 ), +USB_REQ_ALLOC_DEV ,0 ,0 ,0 , +NULL ,0 ,USB_CNTL_TIMEOUT );How does this "allocate" a device? Please, do a proper documentation. Actually, take a look at
include/linker_lists.hOr see here:
http://git.denx.de/?p=u-
boot.git;a=blob;f=include/linker_lists.h;h=0b405d78ea34df1c528fbc4e24ed2a ad756ac4a2;hb=HEADQuoted 7 lines
Quoted 4 lines
And here (U-Boot Code Documentation):
http://www.denx.de/wiki/U-Boot/CodingStyleIt'd be really nice if you could follow such pattern of documentation!
Yes, thanks for pointing out. Will document it properly to make things more understandable.
_AWESOME_ !
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
common/usb.c +2
-0+return res; +}[...]
Quoted 14 lines
Quoted 13 lines
include/common.h typedef void (interrupt_handler_t)(void *); · line 216
Quoted 11 lines
include/common.h +2
-0@@ -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) +Isn't this defined somewhere already?
Quoted 6 lines
Quoted 2 lines
Can you please guide me here, i can see a similar inline function in ehci-hcd only :(
ICK, so we have ad-hoc implementation of this :-( I'd say, put it into
common.hand remove the ehci's ad-hoc implementation.
Yeah, sure will keep this in common.h and update ehci-hcd.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
[...]
Rest is just great.
Thanks for reviewing this Marek. I shall update the patchset soon.
Welcome, it's pleasure to work with you ;-)
Signature · 2 lines
Thanks & Regards Vivek
RFC PATCH 1/2 USB: SS: Add support for Super Speed USB interface
Dear Vivek Gautam,
[...]
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
Isn't
USB_PRINTFitself a conditional debug print ?Yes, but I'd prefer to kill
USB_PRINTFaltogether in favor ofdebug().Ok, will switch to debug(...).
And may be in that case we may try to eliminate USB_PRINTFand other such macro altogether from sub framework ?
Yes, weed it out, be my guest ;-)
[...]
Thanks!
Best regards,
Marek Vasut
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
In reply to Vivek GautamThis adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding to xhci.c, xhci-mem.c, xhci-ring.c and xhci-hub.c in linux-kernel is grouped together here in single driver 'xhci.c'.
--- drivers/usb/host/xhci.c | 3330 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 1360 +++++++++++++++++++ 2 files changed, 4690 insertions(+), 0 deletions(-) create mode 100644 drivers/usb/host/xhci.c create mode 100644 drivers/usb/host/xhci.h
drivers/usb/host/xhci.c new file +3330 -0
@@ -0,0 +1,3330 @@ +/* +* USB HOST XHCI Controller stack +* +* Copyright (C) 2012 Samsung Electronics Co.Ltd +* Vivek Gautam <[email protected]> +* Vikas Sajjan <[email protected]> +* +* Based on xHCI host controller driver in linux-kernel +* by Sarah Sharp. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +* MA 02110-1301 USA +*/ + +/** +* This file gives the xhci stack for usb3.0 looking into +* xhci specification Rev1.0 (5/21/10). +* The quirk devices support hasn't been given yet. +*/ + +#include <common.h> +#include <asm/byteorder.h> +#include <usb.h> +#include <asm/io.h> +#include <malloc.h> +#include <watchdog.h> +#include <asm/cache.h> +#include <asm-generic/errno.h> +#include "xhci.h" + +#ifndef CONFIG_USB_MAX_CONTROLLER_COUNT +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1 +#endif + +#define XHCI_TRB 0xC0DEABCD +#define XHCI_CTX 0xCAFEABCD + +static struct descriptor { +struct usb_hub_descriptor hub; +struct usb_device_descriptor device; +struct usb_linux_config_descriptor config; +struct usb_linux_interface_descriptor interface; +struct usb_endpoint_descriptor endpoint; +struct usb_ss_ep_comp_descriptor ep_companion; +} __attribute__ ((packed)) descriptor = { + { +0xc ,/* bDescLength */ +0x2a ,/* bDescriptorType: hub descriptor */ +2 ,/* bNrPorts -- runtime modified */ +0 ,/* wHubCharacteristics */ +10 ,/* bPwrOn2PwrGood */ +0 ,/* bHubCntrCurrent */ + {},/* Device removable */ + {}/* at most 7 ports! XXX */ + }, + { +0x12 ,/* bLength */ +1 ,/* bDescriptorType: UDESC_DEVICE */ +cpu_to_le16 (0x0300 ),/* bcdUSB: v3.0 */ +9 ,/* bDeviceClass: UDCLASS_HUB */ +0 ,/* bDeviceSubClass: UDSUBCLASS_HUB */ +3 ,/* bDeviceProtocol: UDPROTO_SSHUBSTT */ +9 ,/* bMaxPacketSize: 512 bytes 2^9 */ +0x0000 ,/* idVendor */ +0x0000 ,/* idProduct */ +cpu_to_le16 (0x0100 ),/* bcdDevice */ +1 ,/* iManufacturer */ +2 ,/* iProduct */ +0 ,/* iSerialNumber */ +1 /* bNumConfigurations: 1 */ + }, + { +0x9 , +2 ,/* bDescriptorType: UDESC_CONFIG */ +cpu_to_le16 (0x19 ), +1 ,/* bNumInterface */ +1 ,/* bConfigurationValue */ +0 ,/* iConfiguration */ +0x40 ,/* bmAttributes: UC_SELF_POWER */ +0 /* bMaxPower */ + }, + { +0x9 ,/* bLength */ +4 ,/* bDescriptorType: UDESC_INTERFACE */ +0 ,/* bInterfaceNumber */ +0 ,/* bAlternateSetting */ +1 ,/* bNumEndpoints */ +9 ,/* bInterfaceClass: UICLASS_HUB */ +0 ,/* bInterfaceSubClass: UISUBCLASS_HUB */ +0 ,/* bInterfaceProtocol: UIPROTO_HSHUBSTT */ +0 /* iInterface */ + }, + { +0x7 ,/* bLength */ +5 ,/* bDescriptorType: UDESC_ENDPOINT */ +0x81 ,/* bEndpointAddress: IN endpoint 1 */ +3 ,/* bmAttributes: UE_INTERRUPT */ +8 ,/* wMaxPacketSize */ +255 /* bInterval */ + }, + { +0x06 ,/* ss_bLength */ +0x30 ,/* ss_bDescriptorType: SS EP Companion */ +0x00 ,/* ss_bMaxBurst: allows 1 TX between ACKs */ +/* ss_bmAttributes: 1 packet per service interval */ +0x00 , +/* ss_wBytesPerInterval: 15 bits for max 15 ports */ +0x02 , + }, +}; + +struct xhci_ctrl xhcic[CONFIG_USB_MAX_CONTROLLER_COUNT ]; + +/** +* Aligns the given length to 64 bytes +* +* @param length length to be aligned +* @return aligned length +*/ +unsigned int xhci_getalignedlength (unsigned int length) +{ + +unsigned int aligned_length =0 ; +unsigned int remain =0 ; +unsigned int toAdd =0 ; + + remain = (length %0x40 ); + toAdd = remain ? (0x40 - remain) :0 ; + aligned_length = length + toAdd; + +return aligned_length; +} + +/** +* flushs/invalidates the address passed till the length +* +* @param addr pointer to "segement" to be freed +* @param type_len holds either the Data structure type +* OR the length of the cache line to be flushed/invalidated +* @param flush boolean to hold the flag for flushing/invalidating +* @return none +*/ +void xhci_flush_inval_cache (uint32_t addr,u32 type_len,bool flush) +{ + +if ((void *)addr ==NULL || flush >1 || type_len ==0 ) { +debug ("addr %u flush %d type_len %u\n" , addr, flush, type_len); +return ; + } + +/* +* "type_len" holds either the Data structure type +* OR +* the length of the cache line to be flushed/invalidated +*/ +switch (type_len){ + +case XHCI_TRB : +if (flush) { +flush_dcache_range (addr, addr + +xhci_getalignedlength (sizeof (union xhci_trb ))); + }else { +invalidate_dcache_range (addr, addr + +xhci_getalignedlength (sizeof (union xhci_trb ))); + } +break ; +case XHCI_CTX : +if (flush) { +flush_dcache_range (addr, addr + +xhci_getalignedlength (sizeof (struct xhci_container_ctx ))); + }else { +invalidate_dcache_range (addr, addr + +xhci_getalignedlength (sizeof (struct xhci_container_ctx ))); + } +break ; +default : +if (flush) { +flush_dcache_range (addr, addr + +xhci_getalignedlength (type_len)); + }else { +invalidate_dcache_range (addr, addr + +xhci_getalignedlength (type_len)); + } +break ; + } + +return ; +} + +/** +* frees the "segment" pointer passed +* +* @param ptr pointer to "segement" to be freed +* @return none +*/ +static void xhci_segment_free (struct xhci_segment *seg) +{ +if (seg->trbs) { +free (seg->trbs); + seg->trbs =NULL ; + } + +free (seg); +} + +/** +* frees the "ring" pointer passed +* +* @param ptr pointer to "ring" to be freed +* @return none +*/ +void xhci_ring_free (struct xhci_ring *ring) +{ +struct xhci_segment *seg; +struct xhci_segment *first_seg; + +if (!ring) +return ; +if (ring->first_seg) { + first_seg = ring->first_seg; + seg = first_seg->next; +while (seg != first_seg) { +struct xhci_segment *next = seg->next; +xhci_segment_free (seg); + seg = next; + } +xhci_segment_free (first_seg); + ring->first_seg =NULL ; + } + +free (ring); +} + +/** +* frees the "xhci_container_ctx" pointer passed +* +* @param ptr pointer to "xhci_container_ctx" to be freed +* @return none +*/ +static void xhci_free_container_ctx (struct xhci_container_ctx *ctx) +{ +if (!ctx) +return ; +free (ctx->bytes); +free (ctx); +} + +/** +* frees the virtual devices for "xhci_ctrl" pointer passed +* +* @param ptr pointer to "xhci_ctrl" to be freed +* @return 0 for Success freeing else 1 if the pointer or slot id is invalid. +*/ +int xhci_free_virt_device (struct xhci_ctrl *ctrl) +{ +int i; +int slot_id =0 ; +struct xhci_virt_device *virt_dev; + +if (!ctrl) +return -1 ; + + slot_id = ctrl->slot_id; + +/* Slot ID 0 is reserved */ +if (slot_id ==0 || !ctrl->devs[slot_id]) { +debug ("Bad Slot ID %d\n" , slot_id); +return -1 ; + } + + virt_dev = ctrl->devs[slot_id]; + + ctrl->dcbaa->dev_context_ptrs[slot_id] =0 ; + +if (!virt_dev) +return -1 ; + +for (i =0 ; i <31 ; ++i) { +if (virt_dev->eps[i].ring) +xhci_ring_free (virt_dev->eps[i].ring); + } + +if (virt_dev->in_ctx) +xhci_free_container_ctx (virt_dev->in_ctx); +if (virt_dev->out_ctx) +xhci_free_container_ctx (virt_dev->out_ctx); + +free (ctrl->devs[slot_id]); + ctrl->devs[slot_id] =NULL ; + +return 0 ; +} + +/** +* frees all the memory allocated +* +* @param ptr pointer to "xhci_ctrl" to be cleaned up +* @return none +*/ +void xhci_cleanup (struct xhci_ctrl *ctrl) +{ +xhci_ring_free (ctrl->event_ring); +xhci_ring_free (ctrl->cmd_ring); +xhci_free_virt_device (ctrl); +free (ctrl->erst.entries); +free (ctrl->dcbaa); +memset (ctrl,'\0' ,sizeof (struct xhci_ctrl )); +} + +/** +* Malloc the aligned memory +* +* @param ptr pointer to "xhci_ctrl" to be cleaned up +* @return allocates the memory and returns the aligned pointer +*/ +void *xhci_malloc (unsigned int size) +{ +void *ptr =memalign (XHCI_ALIGNMENT , size); +memset (ptr,'\0' , size); +return ptr; +} + +/** +* Waits for as per specified amount of time +* for the "result" to match with "done" +* +* @param ptr pointer to the register to be read +* @param mask mask for the value read +* @param done value to be campared with result +* @param usec time to wait till +* @return 0 if handshake is success else -1 on failure +*/ +static int handshake (uint32_t volatile *ptr,uint32_t mask, +uint32_t done,int usec) +{ +uint32_t result; + +do { + result =xhci_readl (ptr); +if (result == ~(uint32_t )0 ) +return -ENODEV ; + result &= mask; +if (result == done) +return 0 ; + usec--; +udelay (1 ); + }while (usec >0 ); + +return -ETIMEDOUT ; +} + +/** +* Disable interrupts and begin the xHCI halting process. +* +* @param hcor pointer to host controller operation registers +* @return none +*/ +void xhci_quiesce (struct xhci_hcor *hcor) +{ +uint32_t halted; +uint32_t cmd; +uint32_t mask; + + mask = ~(XHCI_IRQS ); + halted =xhci_readl (&hcor->or_usbsts) &STS_HALT ; +if (!halted) + mask &= ~CMD_RUN ; + + cmd =xhci_readl (&hcor->or_usbcmd); + cmd &= mask; +xhci_writel (&hcor->or_usbcmd, cmd); +} + +/** +* Force HC into halt state. +* Disable any IRQs and clear the run/stop bit. +* HC will complete any current and actively pipelined transactions, and +* should halt within 16 ms of the run/stop bit being cleared. +* Read HC Halted bit in the status register to see when the HC is finished. +* +* @param hcor pointer to host controller operation registers +* @return status of the handshake +*/ +int xhci_halt (struct xhci_hcor *hcor) +{ +int ret; +debug ("Halt the HC\n" ); +xhci_quiesce (hcor); + + ret =handshake (&hcor->or_usbsts, +STS_HALT ,STS_HALT ,XHCI_MAX_HALT_USEC ); +if (ret) +debug ("Host not halted after %u microseconds.\n" , +XHCI_MAX_HALT_USEC ); +return ret; +} + +/** +* Set the run bit and wait for the host to be running. +* +* @param hcor pointer to host controller operation registers +* @return status of the Handshake +*/ +static int xhci_start (struct xhci_hcor *hcor) +{ +u32 temp; +int ret; + +printf ("Starting the controller\n" ); + temp =xhci_readl (&hcor->or_usbcmd); + temp |= (CMD_RUN ); +xhci_writel (&hcor->or_usbcmd, temp); + temp =xhci_readl (&hcor->or_usbcmd); + +/* +* Wait for the HCHalted Status bit to be 0 to indicate the host is +* running. +*/ + ret =handshake (&hcor->or_usbsts,STS_HALT ,0 ,XHCI_MAX_HALT_USEC ); +if (ret) +debug ("Host took too long to start, " +"waited %u microseconds.\n" , +XHCI_MAX_HALT_USEC ); +return ret; +} + +/** +* Resets the XHCI Controller +* +* @param hcor pointer to host controller operation registers +* @return -1 if XHCI Controller is halted else status of handshake +*/ +int xhci_reset (struct xhci_hcor *hcor) +{ +u32 command; +u32 state; +int ret; + + state =xhci_readl (&hcor->or_usbsts); +if ((state &STS_HALT ) ==0 ) { +debug ("Host controller not halted, aborting reset.\n" ); +return -1 ; + } + +debug ("// Reset the HC\n" ); + command =xhci_readl (&hcor->or_usbcmd); + command |=CMD_RESET ; +xhci_writel (&hcor->or_usbcmd, command); + + ret =handshake (&hcor->or_usbcmd,CMD_RESET ,0 ,XHCI_MAX_RESET_USEC ); +if (ret) +return ret; + +/* +* xHCI cannot write to any doorbells or operational registers other +* than status until the "Controller Not Ready" flag is cleared. +*/ +return handshake (&hcor->or_usbsts,STS_CNR ,0 ,XHCI_MAX_RESET_USEC ); +} + +/** +* Allocates a generic ring segment from the ring pool, sets the dma address, +* initializes the segment to zero, and sets the private next pointer to NULL. +* Section 4.11.1.1: +* "All components of all Command and Transfer TRBs shall be initialized to '0'" +* +* @param none +* @return pointer to the newly allocated SEGMENT +*/ +static struct xhci_segment *xhci_segment_alloc (void ) +{ +struct xhci_segment *seg; + + seg = (struct xhci_segment *)xhci_malloc (sizeof (struct xhci_segment )); +if (!seg) +return NULL ; + + seg->trbs = (union xhci_trb *)xhci_malloc (SEGMENT_SIZE ); + +if (!seg->trbs) +return NULL ; + + seg->next =NULL ; + +return seg; +} + +/** +* Make the prev segment point to the next segment. +* Change the last TRB in the prev segment to be a Link TRB which points to the +* address of the next segment. The caller needs to set any Link TRB +* related flags, such as End TRB, Toggle Cycle, and no snoop. +* +* @param prev pointer to the previous segment +* @param next pointer to the next segment +* @param link_trbs flag to indicate whether to link the trbs or NOT +* @return none +*/ +static void xhci_link_segments (struct xhci_segment *prev, +struct xhci_segment *next,bool link_trbs) +{ +u32 val; +u64 val_64 =0 ; + +if (!prev || !next) +return ; + prev->next = next; +if (link_trbs) { + val_64 = (uintptr_t )next->trbs; + prev->trbs[TRBS_PER_SEGMENT -1 ].link.segment_ptr = val_64; + +/* +* Set the last TRB in the segment to +* have a TRB type ID of Link TRB +*/ + val =le32_to_cpu (prev->trbs[TRBS_PER_SEGMENT -1 ].link.control); + val &= ~TRB_TYPE_BITMASK ; + val |= (TRB_LINK <<TRB_TYPE_SHIFT ); + +/* +* Always set the chain bit with 0.95 hardware +* Set chain bit for isoc rings on AMD 0.96 host +* NOT SUPPORTING ANY QUIRK DEVICE +*/ + prev->trbs[TRBS_PER_SEGMENT -1 ].link.control =cpu_to_le32 (val); + } +} + +/** +* Initialises the Ring's enqueue,dequeue,enq_seg pointers +* +* @param ring pointer to the RING to be intialised +* @return none +*/ +static void xhci_initialize_ring_info (struct xhci_ring *ring) +{ +/* +* The ring is empty, so the enqueue pointer == dequeue pointer +*/ + ring->enqueue = ring->first_seg->trbs; + ring->enq_seg = ring->first_seg; + ring->dequeue = ring->enqueue; + ring->deq_seg = ring->first_seg; + +/* +* The ring is initialized to 0. The producer must write 1 to the +* cycle bit to handover ownership of the TRB, so PCS = 1. +* The consumer must compare CCS to the cycle bit to +* check ownership, so CCS = 1. +*/ + ring->cycle_state =1 ; +/* +* Not necessary for new rings, but needed for re-initialized rings +*/ + ring->enq_updates =0 ; + ring->deq_updates =0 ; +} + +/** +* Create a new ring with zero or more segments. +* +* Link each segment together into a ring. +* Set the end flag and the cycle toggle bit on the last segment. +* See section 4.9.1 and figures 15 and 16. +* +* @param num_segs number of segments in the ring +* @param link_trbs flag to indicate whether to link the trbs or NOT +* @return pointer to the newly created RING +*/ +static struct xhci_ring *xhci_ring_alloc (unsigned int num_segs,bool link_trbs) +{ +struct xhci_ring *ring; +struct xhci_segment *prev; + + ring = (struct xhci_ring *)malloc (sizeof (struct xhci_ring )); +if (!ring) +return NULL ; + +if (num_segs ==0 ) +return ring; + + ring->first_seg =xhci_segment_alloc (); +if (!ring->first_seg) +return NULL ; + num_segs--; + + prev = ring->first_seg; +while (num_segs >0 ) { +struct xhci_segment *next; + + next =xhci_segment_alloc (); +if (!next) +return NULL ; +xhci_link_segments (prev, next, link_trbs); + + prev = next; + num_segs--; + } +xhci_link_segments (prev, ring->first_seg, link_trbs); +if (link_trbs) { +/* See section 4.9.2.1 and 6.4.4.1 */ + prev->trbs[TRBS_PER_SEGMENT -1 ].link.control |= +cpu_to_le32 (LINK_TOGGLE ); + } +xhci_initialize_ring_info (ring); + +return ring; +} + +/** +* Checks whether the enqueue trb is a link trb or NOT +* +* @param ring pointer to the RING +* @return 1 if the enqueue TRB is the link TRB else 0 +*/ +static int enqueue_is_link_trb (struct xhci_ring *ring) +{ +struct xhci_link_trb *link = &ring->enqueue->link; + +return ((link->control &cpu_to_le32 (TRB_TYPE_BITMASK )) == +cpu_to_le32 (TRB_LINK <<TRB_TYPE_SHIFT )); +} + +/** +* Is this TRB a link TRB or was the last TRB the last TRB in this event ring +* segment? I.e. would the updated event TRB pointer step off the end of the +* event seg ? +* +* @param ctrl Host controller data structure +* @param ring pointer to the ring +* @param seg poniter to the segment to which TRB belongs +* @return 1 if this TRB a link TRB else 0 +*/ +static int last_trb (struct xhci_ctrl *ctrl,struct xhci_ring *ring, +struct xhci_segment *seg,union xhci_trb *trb) +{ +if (ring == ctrl->event_ring) +return trb == &seg->trbs[TRBS_PER_SEGMENT ]; +else +return ((trb->link.control &cpu_to_le32 (TRB_TYPE_BITMASK )) == +cpu_to_le32 (TRB_LINK <<TRB_TYPE_SHIFT )); +} + +/** +* Does this link TRB point to the first segment in a ring, +* or was the previous TRB the last TRB on the last segment in the ERST? +* +* @param ctrl Host controller data structure +* @param ring pointer to the ring +* @param seg poniter to the segment to which TRB belongs +* @return 1 if this TRB is the last TRB on the last segment else 0 +*/ +static bool last_trb_on_last_seg (struct xhci_ctrl *ctrl,struct xhci_ring *ring, +struct xhci_segment *seg,union xhci_trb *trb) +{ +if (ring == ctrl->event_ring) +return ((trb == &seg->trbs[TRBS_PER_SEGMENT ]) && + (seg->next == ring->first_seg)); +else +return le32_to_cpu (trb->link.control) &LINK_TOGGLE ; +} + +/** +* See Cycle bit rules. SW is the consumer for the event ring only. +* Don't make a ring full of link TRBs. That would be dumb and this would loop. +* +* If we've just enqueued a TRB that is in the middle of a TD (meaning the +* chain bit is set), then set the chain bit in all the following link TRBs. +* If we've enqueued the last TRB in a TD, make sure the following link TRBs +* have their chain bit cleared (so that each Link TRB is a separate TD). +* +* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit +* set, but other sections talk about dealing with the chain bit set. This was +* fixed in the 0.96 specification errata, but we have to assume that all 0.95 +* xHCI hardware can't handle the chain bit being cleared on a link TRB. +* +* @param ctrl Host controller data structure +* @param ring pointer to the ring +* @param consumer flag to indicate whether caller is consumer or producer +* @param more_trbs_coming flag to indicate whether more trbs +* are expected or NOT. +* Will you enqueue more TRBs before calling +* prepare_ring()? +* @return none +*/ +static void inc_enq (struct xhci_ctrl *ctrl,struct xhci_ring *ring, +bool consumer,bool more_trbs_coming) +{ +u32 chain; +union xhci_trb *next; + + chain =le32_to_cpu (ring->enqueue->generic.field[3 ]) &TRB_CHAIN ; + next = ++(ring->enqueue); + + ring->enq_updates++; +/* +* Update the dequeue pointer further if that was a link TRB or we're at +* the end of an event ring segment (which doesn't have link TRBS) +*/ +while (last_trb (ctrl, ring, ring->enq_seg, next)) { +if (!consumer) { +if (ring != ctrl->event_ring) { +/* +* If the caller doesn't plan on enqueueing more +* TDs before ringing the doorbell, then we +* don't want to give the link TRB to the +* hardware just yet. We'll give the link TRB +* back in prepare_ring() just before we enqueue +* the TD at the top of the ring. +*/ +if (!chain && !more_trbs_coming) +break ; + +/* +* If we're not dealing with 0.95 hardware or +* isoc rings on AMD 0.96 host, +* carry over the chain bit of the previous TRB +* (which may mean the chain bit is cleared). +*/ + next->link.control &=cpu_to_le32 (~TRB_CHAIN ); + next->link.control |=cpu_to_le32 (chain); + + next->link.control ^=cpu_to_le32 (TRB_CYCLE ); + } +/* Toggle the cycle bit after the last ring segment. */ +if (last_trb_on_last_seg (ctrl, ring, + ring->enq_seg, next)) + ring->cycle_state = (ring->cycle_state ?0 :1 ); + } + ring->enq_seg = ring->enq_seg->next; + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); + } +} + +/** +* Generic function for queueing a TRB on a ring. +* The caller must have checked to make sure there's room on the ring. +* +* @param more_trbs_coming: Will you enqueue more TRBs before calling +* prepare_ring()? +* @param ctrl Host controller data structure +* @param ring pointer to the ring +* @param consumer flag to indicate whether caller is consumer or producer +* @param more_trbs_coming flag to indicate whether more trbs +* @param field4 field 4 of the Generic TRB +* @return pointer to the enqueued trb +*/ +static struct xhci_generic_trb *queue_trb (struct xhci_ctrl *ctrl, +struct xhci_ring *ring, +bool consumer, +bool more_trbs_coming, +u32 *trb_fields) +{ +struct xhci_generic_trb *trb; +int i; + + trb = &ring->enqueue->generic; + +for (i =0 ; i <4 ; i++) + trb->field[i] =cpu_to_le32 (trb_fields[i]); + +xhci_flush_inval_cache ((uint32_t )trb,XHCI_TRB ,1 ); + +inc_enq (ctrl, ring, consumer, more_trbs_coming); + +return trb; +} + +/** +* Does various checks on the endpoint ring, and makes it ready +* to queue num_trbs. +* +* @param ctrl Host controller data structure +* @param ep_ring pointer to the EP Transfer Ring +* @param ep_state State of the End Point +* @return none +*/ +static int prepare_ring (struct xhci_ctrl *ctrl,struct xhci_ring *ep_ring, +u32 ep_state) +{ +/* Make sure the endpoint has been added to xHC schedule */ +switch (ep_state) { +case EP_STATE_DISABLED : +/* +* USB core changed config/interfaces without notifying us, +* or hardware is reporting the wrong state. +*/ +debug ("WARN urb submitted to disabled ep\n" ); +return -ENOENT ; +case EP_STATE_ERROR : +debug ("WARN waiting for error on ep to be cleared\n" ); +return -EINVAL ; +case EP_STATE_HALTED : +debug ("WARN halted endpoint, queueing URB anyway.\n" ); +case EP_STATE_STOPPED : +case EP_STATE_RUNNING : +debug ("EP STATE RUNNING.\n" ); +break ; +default : +debug ("ERROR unknown endpoint state for ep\n" ); +return -EINVAL ; + } + +if (enqueue_is_link_trb (ep_ring)) { +struct xhci_ring *ring = ep_ring; +union xhci_trb *next; + + next = ring->enqueue; + +while (last_trb (ctrl, ring, ring->enq_seg, next)) { +/* +* If we're not dealing with 0.95 hardware or isoc rings +* on AMD 0.96 host, clear the chain bit. +*/ + next->link.control &=cpu_to_le32 (~TRB_CHAIN ); + + next->link.control ^=cpu_to_le32 (TRB_CYCLE ); + +/* Toggle the cycle bit after the last ring segment. */ +if (last_trb_on_last_seg (ctrl, ring, + ring->enq_seg, next)) + ring->cycle_state = (ring->cycle_state ?0 :1 ); + ring->enq_seg = ring->enq_seg->next; + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + } + } + +return 0 ; +} + +/** +* Generic function for queueing a command TRB on the command ring. +* Check to make sure there's room on the command ring for one command TRB. +* +* @param ctrl Host controller data structure +* @param trb_fields holds the field of the Generic TRB +* @return +*/ +static int queue_command (struct xhci_ctrl *ctrl,u32 *trb_fields) +{ +int ret; +u32 fields[4 ]; + + ret =prepare_ring (ctrl, ctrl->cmd_ring,EP_STATE_RUNNING ); +if (ret <0 ) { +debug ("ERR: No room for command on command ring\n" ); +return ret; + } + + fields[0 ] = trb_fields[0 ]; + fields[1 ] = trb_fields[1 ]; + fields[2 ] = trb_fields[2 ]; + fields[3 ] = trb_fields[3 ] | ctrl->cmd_ring->cycle_state; + +queue_trb (ctrl, ctrl->cmd_ring, false, false, fields); + +xhci_flush_inval_cache ((uint32_t )ctrl->cmd_ring->enqueue,XHCI_TRB ,1 ); + +return 0 ; +} + +/** +* Ring the host controller doorbell after placing a command on the ring +* +* @param ctrl Host controller data structure +* return none +*/ +void xhci_ring_cmd_db (struct xhci_ctrl *ctrl) +{ +xhci_writel (&ctrl->dba->doorbell[0 ],DB_VALUE_HOST ); + +/* Flush PCI posted writes */ +xhci_readl (&ctrl->dba->doorbell[0 ]); +} + +/** +* Ring the host controller doorbell after placing a command on the ring +* +* @param ctrl Host controller data structure +* @param slot_id slot id of the Device +* @param ep_index End point to be ringed +* @param stream_idx Stream ID +* return none +*/ +void xhci_ring_ep_doorbell (struct xhci_ctrl *ctrl, +unsigned int slot_id, +unsigned int ep_index, +unsigned int stream_id) +{ +xhci_writel (&ctrl->dba->doorbell[slot_id],DB_VALUE (ep_index,0 )); +} + +/** +* Give the address of "trb" in the segment "seg" +* +* @param seg pointer to the Segment +* @param trb Pointer to the TRB whose address is required +* @return 0 if the TRB isn't in this segment, otherwise it returns the +* address of the TRB. +*/ +unsigned long trb_addr (struct xhci_segment *seg, +union xhci_trb *trb) +{ +unsigned long segment_offset; + +if (!seg || !trb || trb < seg->trbs) +return 0 ; + +/* offset in TRBs */ + segment_offset = trb - seg->trbs; +if (segment_offset >TRBS_PER_SEGMENT ) +return 0 ; + +return (unsigned long )(seg->trbs + (segment_offset *sizeof (*trb))); +} + +/** +* The TD size is the number of bytes remaining in the TD (including this TRB), +* right shifted by 10. +* It must fit in bits 21:17, so it can't be bigger than 31. +* +* @param remainder remaining packets to be sent +* @return remainder if remainder is less than max else max +*/ +static u32 xhci_td_remainder (unsigned int remainder) +{ +u32 max = (1 << (21 -17 +1 )) -1 ; + +if ((remainder) >= max) +return max <<17 ; +else +return (remainder) <<17 ; +} + +/** +* Used for passing endpoint bitmasks between the core and HCDs. +* Find the index for an endpoint given its descriptor. +* Use the return value to right shift 1 for the bitmask. +* +* Index = (epnum * 2) + direction - 1, +* where direction = 0 for OUT, 1 for IN. +* For control endpoints, the IN index is used (OUT index is unused), so +* index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2) +* +* @param desc USB enpdoint Descriptor +* @param req Request Type +* @return index of the Endpoint +*/ +unsigned int xhci_get_ep_index (struct usb_endpoint_descriptor *desc, +struct devrequest *req) +{ +unsigned int index; +if (req !=NULL ) { + index = (unsigned int )((desc->bEndpointAddress & +USB_ENDPOINT_NUMBER_MASK )*2 ); + }else { + index = (unsigned int )((desc->bEndpointAddress & +USB_ENDPOINT_NUMBER_MASK )*2 ) + + (((desc->bEndpointAddress & +USB_ENDPOINT_DIR_MASK ) ==USB_DIR_IN ) ? +1 :0 ) -1 ; + } + +return index; +} + +/** +* Ring the doorbell of the End Point +* +* @param slot_id Slod id allocated by XHCI controller +* @param ep_index index of the endpoint +* @param ctrl Host controller data structure +* @param start_cycle cycle flag of the first TRB +* @param start_trb pionter to the first TRB +* @return none +*/ +static void giveback_first_trb (struct xhci_ctrl *ctrl,int slot_id, +unsigned int ep_index, +unsigned int stream_id, +int start_cycle, +struct xhci_generic_trb *start_trb) +{ +int delay; +/* +* Pass all the TRBs to the hardware at once and make sure this write +* isn't reordered. +*/ +if (start_cycle) + start_trb->field[3 ] |=cpu_to_le32 (start_cycle); +else + start_trb->field[3 ] &=cpu_to_le32 (~TRB_CYCLE ); + +xhci_flush_inval_cache ((uint32_t )start_trb,XHCI_TRB ,1 ); + +xhci_ring_ep_doorbell (ctrl, slot_id, ep_index, stream_id); + +/* +* Not a Super Speed Device , +* then give some time to Devices(FS/HS/LS) to respond +*/ + delay = (ctrl->speed !=USB_SPEED_SUPER ) ?110 :1 ; +mdelay (delay); + +return ; +} + +/** +* Gets the EP context from based on the ep_index +* +* @param ctrl Host controller data structure +* @param ctx context container +* @param ep_index index of the endpoint +* @return pointer to the End point context +*/ +struct xhci_ep_ctx *xhci_get_ep_ctx (struct xhci_ctrl *ctrl, +struct xhci_container_ctx *ctx, +unsigned int ep_index) +{ +/* increment ep index by offset of start of ep ctx array */ + ep_index++; +if (ctx->type ==XHCI_CTX_TYPE_INPUT ) + ep_index++; + +return (struct xhci_ep_ctx *) + (ctx->bytes + + (ep_index *CTX_SIZE (readl (&ctrl->hccr->cr_hccparams)))); +} + +/** +* Handles the result of the configure endpoint Request +* +* @param ctrl Host controller data structure +* @param cmd_status status of the Event +* @return negative number if failure 0 on success +*/ +static int xhci_configure_endpoint_result (struct xhci_ctrl *ctrl, +u32 *cmd_status) +{ +int ret =0 ; + +switch (*cmd_status) { +case COMP_ENOMEM : +debug ("Not enough host controller resources" +"for new device state.\n" ); + ret = -ENOMEM ; +break ; +case COMP_BW_ERR : +case COMP_2ND_BW_ERR : +debug ("Not enough bandwidth for new device state.\n" ); + ret = -ENOSPC ; +break ; +case COMP_TRB_ERR : +/* the HCD set up something wrong */ +debug ("ERROR: Endpoint drop flag = 0, add flag = 1," +"and endpoint is not disabled.\n" ); + ret = -EINVAL ; +break ; +case COMP_DEV_ERR : +debug ("ERROR: Incompatible device" +"for endpoint configure command.\n" ); + ret = -ENODEV ; +break ; +case COMP_SUCCESS : +debug ("Successful Endpoint Configure command\n" ); +break ; +default : +debug ("ERROR: unexpected command completion code 0x%x.\n" , + *cmd_status); + ret = -EINVAL ; +break ; + } + +return ret; +} + +/** +* Handles the result of the Evaluate endpoint Request +* +* @param cmd_status command status to be evaluated +* @return negative number if failure else 0 on success +*/ +static int xhci_evaluate_context_result (u32 *cmd_status) +{ +int ret; + +switch (*cmd_status) { +case COMP_EINVAL : +debug ("WARN: xHCI driver setup invalid evaluate" +"context command.\n" ); + ret = -EINVAL ; +break ; +case COMP_EBADSLT : +debug ("WARN: slot not enabled for evaluate" +"context command.\n" ); +case COMP_CTX_STATE : +debug ("WARN: invalid context state for evaluate" +"context command.\n" ); + + ret = -EINVAL ; +break ; +case COMP_DEV_ERR : +debug ("ERROR: Incompatible device for evaluate" +"context command.\n" ); + ret = -ENODEV ; +break ; +case COMP_MEL_ERR : +/* Max Exit Latency too large error */ +debug ("WARN: Max Exit Latency too large\n" ); + ret = -EINVAL ; +break ; +case COMP_SUCCESS : +debug ("Successful evaluate context command\n" ); + ret =0 ; +break ; +default : +debug ("ERROR: unexpected command completion code 0x%x.\n" , + *cmd_status); + ret = -EINVAL ; +break ; + } + +return ret; +} + +/** +* Queue a configure endpoint command TRB +* +* @param ctrl Host controller data structure +* @param in_ctx_bytes pointer to input context +* @param slot_id slot it allocated by XHCI controller +* @return status of the queue_command +*/ +int xhci_queue_configure_endpoint (struct xhci_ctrl *ctrl,u8 *in_ctx_bytes, +u32 slot_id) +{ +u64 val_64; +u32 trb_fields[4 ]; + + val_64 = (uintptr_t )in_ctx_bytes; + + trb_fields[0 ] =lower_32_bits (val_64); + trb_fields[1 ] =upper_32_bits (val_64); + trb_fields[2 ] =0 ; + trb_fields[3 ] = ((TRB_CONFIG_EP <<TRB_TYPE_SHIFT ) | + ((slot_id &SLOT_ID_FOR_TRB_MASK ) << +SLOT_ID_FOR_TRB_SHIFT )); + +return queue_command (ctrl, trb_fields); +} + +/** +* Queue an evaluate context command TRB +* +* @param ctrl Host controller data structure +* @param in_ctx_bytes pointer to input context +* @param slot_id slot it allocated by XHCI controller +* @return status of the queue_command +*/ +int xhci_queue_evaluate_context (struct xhci_ctrl *ctrl,u8 *in_ctx_bytes, +u32 slot_id) +{ +u64 val_64; +u32 trb_fields[4 ]; + + val_64 = (uintptr_t )in_ctx_bytes; + + trb_fields[0 ] =lower_32_bits (val_64); + trb_fields[1 ] =upper_32_bits (val_64); + trb_fields[2 ] =0 ; + trb_fields[3 ] = ((TRB_EVAL_CONTEXT <<TRB_TYPE_SHIFT ) | + ((slot_id &SLOT_ID_FOR_TRB_MASK ) << +SLOT_ID_FOR_TRB_SHIFT )); + +return queue_command (ctrl, trb_fields); +} + +/** +* Issue a configure endpoint command or evaluate context command +* and wait for it to finish. +* +* @param usbdev pointer to the Device Data Structure +* @param ctx_change flag to indicate the Context has changed or NOT +* @return -ENOMEM if xhci_queue_configure_endpoint or +* xhci_queue_evaluate_context fails else status of +* xhci_queue_configure_endpoint or xhci_queue_evaluate_context. +*/ +static int xhci_configure_endpoint (struct usb_device *usbdev,bool ctx_change) +{ +int ret; +struct xhci_container_ctx *in_ctx; +u32 *cmd_status; +struct xhci_virt_device *virt_dev; +struct xhci_ctrl *ctrl = usbdev->controller; + + virt_dev = ctrl->devs[ctrl->slot_id]; + in_ctx = virt_dev->in_ctx; + + cmd_status = &virt_dev->cmd_status; + +if (!ctx_change) + ret =xhci_queue_configure_endpoint (ctrl, in_ctx->bytes, + ctrl->slot_id); +else + ret =xhci_queue_evaluate_context (ctrl, in_ctx->bytes, + ctrl->slot_id); + +if (ret <0 ) +return -ENOMEM ; + +xhci_ring_cmd_db (ctrl); + +/* Give some time to the DEVICE to Respond */ +mdelay (5 ); + +xhci_poll_and_HandleEvent (usbdev); + +if (!ctx_change) + ret =xhci_configure_endpoint_result (ctrl, cmd_status); +else + ret =xhci_evaluate_context_result (cmd_status); + +return ret; +} + +/** +* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy. +* Useful when you want to change one particular aspect of the endpoint and then +* issue a configure endpoint command. + +* Full speed devices may have a max packet size greater than 8 bytes, but the +* USB core doesn't know that until it reads the first 8 bytes of the +* descriptor. If the usb_device's max packet size changes after that point, +* we need to issue an evaluate context command and wait on it. +* +* @param usbdev pointer to the USB device structure +* @return returns the status of the xhci_configure_endpoint +*/ +static int xhci_configure_ep (struct usb_device *usbdev) +{ +struct xhci_container_ctx *in_ctx; +struct xhci_container_ctx *out_ctx; +struct xhci_input_control_ctx *ctrl_ctx; +struct xhci_slot_ctx *slot_ctx; +struct xhci_ep_ctx *ep_ctx[MAX_EP_CTX_NUM ]; +int ret =0 ; +int cur_ep; +int max_ep_flag =0 ; +int ep_index; +unsigned int dir; +unsigned int ep_type; +struct xhci_ctrl *ctrl = usbdev->controller; +int num_of_ep; +int ep_flag =0 ; +u64 trb_64 =0 ; +int slot_id = ctrl->slot_id; +struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; +struct usb_interface *ifdesc; + + out_ctx = virt_dev->out_ctx; + in_ctx = virt_dev->in_ctx; + +xhci_flush_inval_cache ((uint32_t )in_ctx,XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )out_ctx,XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )in_ctx->bytes, in_ctx->size,0 ); +xhci_flush_inval_cache ((uint32_t )out_ctx->bytes, out_ctx->size,0 ); + + num_of_ep = usbdev->config.if_desc[0 ].no_of_ep; + ifdesc = &usbdev->config.if_desc[0 ]; + +/* +* STEP 1: Set up the input context flags for the command +* FIXME: This won't work if a non-default control endpoint +* changes max packet sizes. +*/ + ctrl_ctx =xhci_get_input_control_ctx (ctrl->devs[slot_id]->in_ctx); + +/* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */ +for (cur_ep =0 ; cur_ep < num_of_ep; cur_ep++) { + ep_flag =xhci_get_ep_index (&ifdesc->ep_desc[cur_ep].ep_desc, +NULL ); + ctrl_ctx->add_flags |=cpu_to_le32 (1 << (ep_flag +1 )); +if (max_ep_flag < ep_flag) + max_ep_flag = ep_flag; + } + ctrl_ctx->drop_flags =0 ; + +/* STEP2: slot context */ +xhci_slot_copy (ctrl, in_ctx, out_ctx); + slot_ctx =xhci_get_slot_ctx (ctrl, in_ctx); + slot_ctx->dev_info &= ~(0x1f <<27 ); + slot_ctx->dev_info |=cpu_to_le32 (LAST_CTX (max_ep_flag +1 ) |0 ); + +xhci_endpoint_copy (ctrl, in_ctx, out_ctx,0 ); + + ep_index =0 ; +/* STEP4 & 5: filling up ep contexts */ +for (cur_ep =0 ; cur_ep < num_of_ep; cur_ep++) { +struct usb_endpoint_descriptor *endpt_desc =NULL ; + + endpt_desc = &ifdesc->ep_desc[cur_ep].ep_desc; + trb_64 =0 ; + + ep_index =xhci_get_ep_index (endpt_desc,NULL ); + ep_ctx[ep_index] =xhci_get_ep_ctx (ctrl, in_ctx, ep_index); + +/* Allocate the ep rings */ + virt_dev->eps[ep_index].ring =xhci_ring_alloc (1 , true); +if (!virt_dev->eps[ep_index].ring) +return -1 ; + +/*NOTE: ep_desc[0] actually represents EP1 and so on */ + dir = (((endpt_desc->bEndpointAddress) & (0x80 )) >>7 ); + ep_type = (((endpt_desc->bmAttributes) & (0x3 )) | (dir <<2 )); + ep_ctx[ep_index]->ep_info2 = +cpu_to_le32 (ep_type <<EP_TYPE_SHIFT ); + ep_ctx[ep_index]->ep_info2 |= +cpu_to_le32 (MAX_PACKET (endpt_desc->wMaxPacketSize)); + +/* +* EP 0 can handle "burst" sizes of 1, +* so Max Burst Size field is 0 +*/ + ep_ctx[ep_index]->ep_info2 |= +cpu_to_le32 (((0 &MAX_BURST_MASK ) <<MAX_BURST_SHIFT ) | + ((3 &ERROR_COUNT_MASK ) <<ERROR_COUNT_SHIFT )); + + trb_64 = (uintptr_t ) + virt_dev->eps[ep_index].ring->first_seg->trbs; + ep_ctx[ep_index]->deq =cpu_to_le64 (trb_64 | + virt_dev->eps[ep_index].ring->cycle_state); + } + +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx,XHCI_CTX ,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx->bytes, + virt_dev->in_ctx->size,1 ); + + ret =xhci_configure_endpoint (usbdev, false); + +return ret; +} + +/** +* Finds out the remanining packets to be sent +* +* @param usbdev pointer to the USB device structure +* @param running_total total size sent so far +* @param trb_buff_len length of the TRB Buffer +* @param total_packet_count total packet count +* @param ep_desc end point Descriptor +* @return 0 if running_total or trb_buff_len is 0, else remainder +*/ +static u32 xhci_v1_0_td_remainder (struct usb_device *usbdev,int running_total, +int trb_buff_len, +unsigned int total_packet_count, +struct usb_endpoint_descriptor ep_desc) +{ +int packets_transferred; + +/* One TRB with a zero-length data packet. */ +if (running_total ==0 && trb_buff_len ==0 ) +return 0 ; + +/* +* All the TRB queueing functions don't count the current TRB in +* running_total. +*/ + +if ((running_total + trb_buff_len) >= +le16_to_cpu (ep_desc.wMaxPacketSize)) + packets_transferred = (running_total + trb_buff_len) / + (le16_to_cpu (ep_desc.wMaxPacketSize)); +else + packets_transferred =1 ; + +return xhci_td_remainder (total_packet_count - packets_transferred); +} + +/** +* Queues up the BULK Request +* +* @param usbdev pointer to the USB device structure +* @param pipe contains the DIR_IN or OUT , devnum +* @param buffer buffer to be read/written based on the request +* @param length length of the buffer +* @param req request type +* @param ring Ring on which request be queued +* @param ep_index index of the End point +* @return returns 0 if successful else 0 on failure +*/ +int xhci_queue_bulk_tx (struct usb_device *usbdev,unsigned long pipe, +struct xhci_ring *ring, +struct usb_endpoint_descriptor ep_desc, +struct devrequest *req,int length,void *buffer) +{ +int num_trbs =0 ; +struct xhci_generic_trb *start_trb; +bool first_trb =0 ; +bool more_trbs_coming =0 ; +int start_cycle; +u32 field =0 ; +u32 length_field =0 ; +struct xhci_ctrl *ctrl = usbdev->controller; +int slot_id = ctrl->slot_id; +int ep_index =0 ; + +int running_total, trb_buff_len; +unsigned int total_packet_count; +u64 addr; +u64 val_64 =0 ; +u32 trb_fields[4 ]; + val_64 = (uintptr_t )buffer; + + num_trbs =0 ; + +/* +* How much data is (potentially) left before the 64KB boundary? +* XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec) +* that the buffer should not span 64KB boundary. if so +* we send request in more than 1 TRB by chaining them. +*/ + running_total =TRB_MAX_BUFF_SIZE - + (lower_32_bits (val_64) & (TRB_MAX_BUFF_SIZE -1 )); + running_total &=TRB_MAX_BUFF_SIZE -1 ; + +/* +* If there's some data on this 64KB chunk, or we have to send a +* zero-length transfer, we need at least one TRB +*/ +if (running_total !=0 || length ==0 ) + num_trbs++; + +/* How many more 64KB chunks to transfer, how many more TRBs? */ +while (running_total < length) { + num_trbs++; + running_total +=TRB_MAX_BUFF_SIZE ; + } + +if (enqueue_is_link_trb (ring)) { +union xhci_trb *next; + next = ring->enqueue; + +while (last_trb (ctrl, ring, ring->enq_seg, next)) { +/* +* we're not dealing with 0.95 hardware or isoc rings +* on AMD 0.96 host, clear the chain bit. +*/ + next->link.control &=cpu_to_le32 (~TRB_CHAIN ); + + next->link.control ^=cpu_to_le32 (TRB_CYCLE ); + +xhci_flush_inval_cache ((uint32_t )next,XHCI_TRB ,1 ); + +/* Toggle the cycle bit after the last ring segment. */ +if (last_trb_on_last_seg (ctrl, ring, + ring->enq_seg, next)) + ring->cycle_state = (ring->cycle_state ?0 :1 ); + + ring->enq_seg = ring->enq_seg->next; + ring->enqueue = ring->enq_seg->trbs; + next = ring->enqueue; + +xhci_flush_inval_cache ((uint32_t )ring->enqueue, +XHCI_TRB ,1 ); + } + } + +/* +* Don't give the first TRB to the hardware (by toggling the cycle bit) +* until we've finished creating all the other TRBs. The ring's cycle +* state may change as we enqueue the other TRBs, so save it too. +*/ + start_trb = &ring->enqueue->generic; + start_cycle = ring->cycle_state; + + running_total =0 ; + total_packet_count =DIV_ROUND_UP (length, ep_desc.wMaxPacketSize); + + ep_index =xhci_get_ep_index (&ep_desc,NULL ); +/* How much data is in the first TRB? */ +/* +* How much data is (potentially) left before the 64KB boundary? +* XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec) +* that the buffer should not span 64KB boundary. if so +* we send request in more than 1 TRB by chaining them. +*/ + addr = val_64; + trb_buff_len =TRB_MAX_BUFF_SIZE - + (lower_32_bits (val_64) & (TRB_MAX_BUFF_SIZE -1 )); + +if (trb_buff_len > length) + trb_buff_len = length; + + first_trb = true; + +/* Queue the first TRB, even if it's zero-length */ +do { +u32 remainder =0 ; + field =0 ; +/* Don't change the cycle bit of the first TRB until later */ +if (first_trb) { + first_trb = false; +if (start_cycle ==0 ) + field |=0x1 ; + }else { + field |= ring->cycle_state; + } + +/* +* Chain all the TRBs together; clear the chain bit in the last +* TRB to indicate it's the last TRB in the chain. +*/ +if (num_trbs >1 ) + field |=TRB_CHAIN ; + +/* Only set interrupt on short packet for IN endpoints */ +if (usb_pipein (pipe)) + field |=TRB_ISP ; + +/* Set the TRB length, TD size, and interrupter fields. */ +if (HC_VERSION (xhci_readl (&ctrl->hccr->cr_capbase)) <0x100 ) + remainder =xhci_td_remainder (length - running_total); +else + remainder =xhci_v1_0_td_remainder (usbdev, + running_total, + trb_buff_len, + total_packet_count, + ep_desc); + + length_field = ((trb_buff_len &TRB_LEN_MASK ) | + remainder | + ((0 &TRB_INTR_TARGET_MASK ) << +TRB_INTR_TARGET_SHIFT )); + +if (num_trbs >1 ) + more_trbs_coming = true; +else + more_trbs_coming = false; + + trb_fields[0 ] =lower_32_bits (addr); + trb_fields[1 ] =upper_32_bits (addr); + trb_fields[2 ] = length_field; + trb_fields[3 ] = field | (TRB_NORMAL <<TRB_TYPE_SHIFT ); +queue_trb (ctrl, ring, false, more_trbs_coming, trb_fields); + + --num_trbs; + + running_total += trb_buff_len; + +/* Give some time before Queueing further more TRBs */ +mdelay (5 ); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (addr), + length,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (addr), + length,0 ); + +/* Calculate length for next transfer */ + addr += trb_buff_len; + trb_buff_len = length - running_total; +if (trb_buff_len >TRB_MAX_BUFF_SIZE ) + trb_buff_len =TRB_MAX_BUFF_SIZE ; + }while (running_total < length); + +giveback_first_trb (ctrl, slot_id, ep_index,0 , start_cycle, start_trb); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (addr), length,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (addr), length,0 ); + + usbdev->act_len = length; + usbdev->status =0 ; + +/* Not a Super Speed Device , give time to device to respond */ +if (ctrl->speed !=USB_SPEED_SUPER ) +mdelay (5 ); + +return 0 ; +} + +/** +* Queues up the Control Transfer Request +* +* @param usbdev pointer to the USB device structure +* @param pipe contains the DIR_IN or OUT , devnum +* @param buffer buffer to be read/written based on the request +* @param length length of the buffer +* @param req request type +* @param ring Ring on which request be queued +* @param ep_index index of the End point +* @return returns 0 if successful else 0 on failure +*/ +int xhci_queue_ctrl_tx (struct usb_device *usbdev,struct xhci_ring *ring, +unsigned long pipe,struct devrequest *req, +unsigned int length,unsigned int ep_index, +void *buffer) +{ +int ret; +int start_cycle; +int num_trbs; +u32 field; +u32 length_field; +u64 buf_64 =0 ; +struct xhci_ring *ep_ring = ring; +struct xhci_generic_trb *start_trb; +struct xhci_ctrl *ctrl = usbdev->controller; +int slot_id = ctrl->slot_id; +u32 trb_fields[4 ]; +struct xhci_virt_device *virt_dev = ctrl->devs[slot_id]; + +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx,XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size,0 ); +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,0 ); + +struct xhci_ep_ctx *ep_ctx =NULL ; + ep_ctx =xhci_get_ep_ctx (ctrl, ctrl->devs[slot_id]->out_ctx, ep_index); + +/* 1 TRB for setup, 1 for status */ + num_trbs =2 ; +/* +* Don't need to check if we need additional event data and normal TRBs, +* since data in control transfers will never get bigger than 16MB +* XXX: can we get a buffer that crosses 64KB boundaries? +*/ + +if (length >0 ) + num_trbs++; + + ret =prepare_ring (ctrl, ring, +le32_to_cpu (ep_ctx->ep_info) &EP_STATE_MASK ); + +if (ret <0 ) +return ret; + +/* +* Don't give the first TRB to the hardware (by toggling the cycle bit) +* until we've finished creating all the other TRBs. The ring's cycle +* state may change as we enqueue the other TRBs, so save it too. +*/ + start_trb = &ring->enqueue->generic; + start_cycle = ring->cycle_state; + +debug ("start_trb %p, start_cycle %d\n" , start_trb, start_cycle); + +/* Queue setup TRB - see section 6.4.1.2.1 */ +/* FIXME better way to translate setup_packet into two u32 fields? */ + field =0 ; + field |=TRB_IDT | (TRB_SETUP <<TRB_TYPE_SHIFT ); +if (start_cycle ==0 ) + field |=0x1 ; + +/* xHCI 1.0 6.4.1.2.1: Transfer Type field */ +if (HC_VERSION (xhci_readl (&ctrl->hccr->cr_capbase)) ==0x100 ) { +if (length >0 ) { +if (req->requesttype &USB_DIR_IN ) + field |= (TRB_DATA_IN <<TRB_TX_TYPE_SHIFT ); +else + field |= (TRB_DATA_OUT <<TRB_TX_TYPE_SHIFT ); + } + } + +debug ("req->requesttype = %d, req->request = %d," +"le16_to_cpu(req->value) = %d," +"le16_to_cpu(req->index) = %d," +"le16_to_cpu(req->length) = %d\n" , + req->requesttype, req->request,le16_to_cpu (req->value), +le16_to_cpu (req->index),le16_to_cpu (req->length)); + + trb_fields[0 ] = req->requesttype | req->request <<8 | +le16_to_cpu (req->value) <<16 ; + trb_fields[1 ] =le16_to_cpu (req->index) | +le16_to_cpu (req->length) <<16 ; +/* TRB_LEN | (TRB_INTR_TARGET) */ + trb_fields[2 ] = (8 | ((0 &TRB_INTR_TARGET_MASK ) << +TRB_INTR_TARGET_SHIFT )); +/* Immediate data in pointer */ + trb_fields[3 ] = field; +queue_trb (ctrl, ring, false, true, trb_fields); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); + +mdelay (1 ); + +/* Re-initializing field to zero */ + field =0 ; +/* If there's data, queue data TRBs */ +/* Only set interrupt on short packet for IN endpoints */ +if (usb_pipein (pipe)) + field =TRB_ISP | (TRB_DATA <<TRB_TYPE_SHIFT ); +else + field = (TRB_DATA <<TRB_TYPE_SHIFT ); + + length_field = (length &TRB_LEN_MASK ) |xhci_td_remainder (length) | + ((0 &TRB_INTR_TARGET_MASK ) <<TRB_INTR_TARGET_SHIFT ); +debug ("length_field = %d, length = %d," +"xhci_td_remainder(length) = %d , TRB_INTR_TARGET(0) = %d\n" , + length_field, (length &TRB_LEN_MASK ), +xhci_td_remainder (length),0 ); + +if (length >0 ) { +if (req->requesttype &USB_DIR_IN ) + field |=TRB_DIR_IN ; + buf_64 = (uintptr_t )buffer; + + trb_fields[0 ] =lower_32_bits (buf_64); + trb_fields[1 ] =upper_32_bits (buf_64); + trb_fields[2 ] = length_field; + trb_fields[3 ] = field | ep_ring->cycle_state; +queue_trb (ctrl, ring, false, true, trb_fields); + +mdelay (1 ); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (buf_64), + length,0 ); + } + +/* +* Queue status TRB - +* see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 +*/ + +/* If the device sent data, the status stage is an OUT transfer */ + field =0 ; +if (length >0 && req->requesttype &USB_DIR_IN ) + field =0 ; +else + field =TRB_DIR_IN ; + + trb_fields[0 ] =0 ; + trb_fields[1 ] =0 ; + trb_fields[2 ] = ((0 &TRB_INTR_TARGET_MASK ) <<TRB_INTR_TARGET_SHIFT ); +/* Event on completion */ + trb_fields[3 ] = field |TRB_IOC | + (TRB_STATUS <<TRB_TYPE_SHIFT ) | + ep_ring->cycle_state; + +queue_trb (ctrl, ring, false, false, trb_fields); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx,XHCI_CTX ,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size,1 ); + +mdelay (1 ); + +giveback_first_trb (ctrl, slot_id, ep_index,0 , start_cycle, start_trb); + +xhci_flush_inval_cache ((uint32_t )ring->enqueue,XHCI_TRB ,1 ); +xhci_flush_inval_cache ((uint32_t )lower_32_bits (buf_64), length,0 ); + + usbdev->act_len = length; + usbdev->status =0 ; + +/* Not a Super Speed Device , give time to device to respond */ +if (ctrl->speed !=USB_SPEED_SUPER ) +mdelay (5 ); + +return 0 ; +} + +/** +* Submits the asynchronous Control Requests to XHCI Host controller +* +* @param usbdev pointer to the USB device structure +* @param pipe contains the DIR_IN or OUT , devnum +* @param buffer buffer to be read/written based on the request +* @param length length of the buffer +* @param req request type +* @return returns 0 if successful else 0 on failure +* +*/ +int xhci_submit_async (struct usb_device *usbdev, +unsigned long pipe,void *buffer, +int length,struct devrequest *req) +{ +struct xhci_ctrl *ctrl = usbdev->controller; +unsigned int slot_id; +unsigned int ep_index; +int ret; +struct usb_endpoint_descriptor ep_descIN; +struct usb_endpoint_descriptor ep_descOUT; +struct usb_endpoint_descriptor ep_desc; +struct xhci_ring *ep_txring; +int cur_ep; +struct usb_interface *ifdesc; +struct xhci_virt_device *virt_dev; +struct xhci_container_ctx *out_ctx; +struct xhci_container_ctx *in_ctx; + + ifdesc = &usbdev->config.if_desc[0 ]; + +debug ("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n" , usbdev, pipe, + buffer, length, req); +if (req !=NULL ) +debug ("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n" , + req->request, req->request, + req->requesttype, req->requesttype, +le16_to_cpu (req->value),le16_to_cpu (req->value), +le16_to_cpu (req->index)); + + slot_id = ctrl->slot_id; + +if (ctrl->slot_id ==0 ) { +debug ("SLOT-ID IS NOT ALLOCATED YET\n" ); + usbdev->act_len =21 ; + usbdev->status =0 ; +return 0 ; + } + + virt_dev = ctrl->devs[slot_id]; + in_ctx = virt_dev->in_ctx; + out_ctx = virt_dev->out_ctx; + +if (usb_pipecontrol (pipe) && req !=NULL ) { +/* +* Check to see if the max packet size for the default control +* endpoint changed during FS device enumeration +*/ + ep_index =0 ; + ret =xhci_queue_ctrl_tx (usbdev, + ctrl->devs[slot_id]->eps[ep_index].ring, + pipe, req, length, ep_index, buffer); +if (ret) +return -1 ; + }else if (usb_pipebulk (pipe) && req ==NULL ) { + +xhci_flush_inval_cache ((uint32_t )in_ctx,XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )out_ctx,XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )in_ctx->bytes, + in_ctx->size,0 ); +xhci_flush_inval_cache ((uint32_t )out_ctx->bytes, + out_ctx->size,0 ); + +for (cur_ep =0 ; cur_ep < ifdesc->no_of_ep; cur_ep++) { +struct usb_endpoint_descriptor epdesc; + + epdesc = ifdesc->ep_desc[cur_ep].ep_desc; +if (usb_endpoint_is_bulk_in (&epdesc)) + ep_descIN = epdesc; +else if (usb_endpoint_is_bulk_out (&epdesc)) + ep_descOUT = epdesc; +else +BUG (); + } + +if (usb_pipein (pipe)) + ep_desc = ep_descIN; +else if (usb_pipeout (pipe)) + ep_desc = ep_descOUT; +else +BUG (); + + ep_index =xhci_get_ep_index (&ep_desc, req); + ep_txring = ctrl->devs[slot_id]->eps[ep_index].ring; + ret =xhci_queue_bulk_tx (usbdev, pipe, ep_txring, + ep_desc, req, length, buffer); +if (ret) +return -1 ; + } + +return 0 ; +} + +/** +* Clears the Change bits of the Port Status Register +* +* @param wValue request value +* @param wIndex request index +* @param addr address of posrt status register +* @param port_status state of port status register +* @return none +*/ +static void xhci_clear_port_change_bit (u16 wValue, +u16 wIndex,uint32_t *addr,u32 port_status) +{ +char *port_change_bit; +u32 status; + +switch (wValue) { +case USB_PORT_FEAT_C_RESET : + status =PORT_RC ; + port_change_bit ="reset" ; +break ; +case USB_PORT_FEAT_C_CONNECTION : + status =PORT_CSC ; + port_change_bit ="connect" ; +break ; +case USB_PORT_FEAT_C_OVER_CURRENT : + status =PORT_OCC ; + port_change_bit ="over-current" ; +break ; +case USB_PORT_FEAT_C_ENABLE : + status =PORT_PEC ; + port_change_bit ="enable/disable" ; +break ; +case USB_PORT_FEAT_C_SUSPEND : + status =PORT_PLC ; + port_change_bit ="suspend/resume" ; +break ; +default : +/* Should never happen */ +return ; + } + +/* Change bits are all write 1 to clear */ +xhci_writel (addr, port_status | status); + + port_status =xhci_readl (addr); +debug ("clear port %s change, actual port %d status = 0x%x\n" , + port_change_bit, wIndex, port_status); +} + +/** +* Save Read Only (RO) bits and save read/write bits where +* writing a 0 clears the bit and writing a 1 sets the bit (RWS). +* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect. +* +* @param state state of the Port Status and Control Regsiter +* @return a value that would result in the port being in the +* same state, if the value was written to the port +* status control register. +*/ +u32 xhci_port_state_to_neutral (u32 state) +{ +/* Save read-only status and port state */ +return (state &XHCI_PORT_RO ) | (state &XHCI_PORT_RWS ); +} + +/** +* Gets the Speed as per the Port Status +* @param usbdev pointer to USB device structure +* @param port_status state of port status register +* @return bit-set for usb speed for corresponding state of +* port status register +*/ +static unsigned int xhci_port_speed (struct usb_device *usbdev, +unsigned int port_status) +{ +struct xhci_ctrl *ctrl = usbdev->controller; + +if (DEV_FULLSPEED (port_status)) { + usbdev->speed =0 ; +debug ("SPEED = FULLSPEED\n" ); + ctrl->speed = usbdev->speed; +return 0x1 ; + } +if (DEV_LOWSPEED (port_status)) { +debug ("SPEED = LOWSPEED\n" ); + usbdev->speed =1 ; + ctrl->speed = usbdev->speed; +return 0x2 ; + } +if (DEV_HIGHSPEED (port_status)) { +debug ("SPEED = HIGHSPEED\n" ); + usbdev->speed =2 ; + ctrl->speed = usbdev->speed; +return 0x3 ; + } +if (DEV_SUPERSPEED (port_status)) { +debug ("SPEED = SUPERSPEED\n" ); + usbdev->speed =3 ; + ctrl->speed = usbdev->speed; +return 0x4 ; + } + +return 0 ; +} + +/** +* Submits the Requests to the XHCI Host Controller +* +* @param usbdev pointer to the USB device structure +* @param pipe contains the DIR_IN or OUT , devnum +* @param buffer buffer to be read/written based on the request +* @param length length of the buffer +* @return returns 0 if successful else -1 on failure +*/ +int xhci_submit_root (struct usb_device *usbdev,unsigned long pipe, +void *buffer,int length,struct devrequest *req) +{ +uint8_t tmpbuf[4 ]; +u16 typeReq; +void *srcptr =NULL ; +int len, srclen; +uint32_t reg; +uint32_t *status_reg; +struct xhci_ctrl *ctrl = usbdev->controller; +struct xhci_hcor *hcor = ctrl->hcor; + +if (le16_to_cpu (req->index) >CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS ) { +printf ("The request port(%d) is not configured\n" , +le16_to_cpu (req->index) -1 ); +return -1 ; + } + + status_reg = (uint32_t *) + (&hcor->PortRegs[le16_to_cpu (req->index) -1 ].or_portsc); + srclen =0 ; + + typeReq = req->request | req->requesttype <<8 ; + +switch (typeReq) { +case DeviceRequest |USB_REQ_GET_DESCRIPTOR : +switch (le16_to_cpu (req->value) >>8 ) { +case USB_DT_DEVICE : +debug ("USB_DT_DEVICE request\n" ); + srcptr = &descriptor.device; + srclen =0x12 ; +break ; +case USB_DT_CONFIG : +debug ("USB_DT_CONFIG config\n" ); + srcptr = &descriptor.config; + srclen =0x19 ; +break ; +case USB_DT_STRING : +debug ("USB_DT_STRING config\n" ); +switch (le16_to_cpu (req->value) &0xff ) { +case 0 :/* Language */ + srcptr ="\4\3\1\0" ; + srclen =4 ; +break ; +case 1 :/* Vendor String */ + srcptr ="\16\3u\0-\0b\0o\0o\0t\0" ; + srclen =14 ; +break ; +case 2 :/* Product Name */ + srcptr ="\52\3X\0H\0C\0I\0 " +"\0H\0o\0s\0t\0 " +"\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0" ; + srclen =42 ; +break ; +default : +debug ("unknown value DT_STRING %x\n" , +le16_to_cpu (req->value)); + goto unknown; + } +break ; +default : +debug ("unknown value %x\n" ,le16_to_cpu (req->value)); + goto unknown; + } +break ; +case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN |USB_RT_HUB ) <<8 ): +switch (le16_to_cpu (req->value) >>8 ) { +case USB_DT_HUB : +debug ("USB_DT_HUB config\n" ); + srcptr = &descriptor.hub; + srclen =0x8 ; +break ; +default : +debug ("unknown value %x\n" ,le16_to_cpu (req->value)); + goto unknown; + } +break ; +case USB_REQ_ALLOC_DEV | (USB_RECIP_DEVICE <<8 ): +xhci_alloc_dev (usbdev); +break ; +case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE <<8 ): +if (usbdev->devnum ==1 ) + ctrl->rootdev =le16_to_cpu (req->value); +else +xhci_address_device (usbdev); +break ; +case DeviceOutRequest |USB_REQ_SET_CONFIGURATION : +/* FIXME: need to put code for configuring endpoint here */ +xhci_configure_ep (usbdev); +break ; +case USB_REQ_GET_STATUS | ((USB_DIR_IN |USB_RT_HUB ) <<8 ): + tmpbuf[0 ] =1 ;/* USB_STATUS_SELFPOWERED */ + tmpbuf[1 ] =0 ; + srcptr = tmpbuf; + srclen =2 ; +break ; +case USB_REQ_GET_STATUS | ((USB_RT_PORT |USB_DIR_IN ) <<8 ): +memset (tmpbuf,0 ,4 ); + reg =xhci_readl (status_reg); +if (reg &PORT_CONNECT ) { + tmpbuf[0 ] |=USB_PORT_STAT_CONNECTION ; + tmpbuf[1 ] |= (xhci_port_speed (usbdev, reg) <<2 ); + } +if (reg &PORT_PE ) + tmpbuf[0 ] |=USB_PORT_STAT_ENABLE ; +if (reg &XDEV_U3 ) + tmpbuf[0 ] |=USB_PORT_STAT_SUSPEND ; +if (reg &PORT_OC ) + tmpbuf[0 ] |=USB_PORT_STAT_OVERCURRENT ; +if (reg &PORT_RESET ) + tmpbuf[0 ] |=USB_PORT_STAT_RESET ; +if (reg &PORT_POWER ) + tmpbuf[1 ] |=USB_SS_PORT_STAT_POWER >>8 ; +if ((reg &PORT_PLC )) + tmpbuf[2 ] |=USB_PORT_STAT_C_LINK_STATE ; +if ((reg &PORT_WRC )) + tmpbuf[2 ] |=USB_PORT_STAT_C_BH_RESET ; +if (reg &PORT_CSC ) + tmpbuf[2 ] |=USB_PORT_STAT_C_CONNECTION ; +if (reg &PORT_PEC ) + tmpbuf[2 ] |=USB_PORT_STAT_C_ENABLE ; +if (reg &PORT_OCC ) + tmpbuf[2 ] |=USB_PORT_STAT_C_OVERCURRENT ; +if (reg &PORT_RC ) + tmpbuf[2 ] |=USB_PORT_STAT_C_RESET ; + + srcptr = tmpbuf; + srclen =4 ; +break ; +case USB_REQ_SET_FEATURE | ((USB_DIR_OUT |USB_RT_PORT ) <<8 ): + reg =xhci_readl (status_reg); +switch (le16_to_cpu (req->value)) { +case USB_PORT_FEAT_ENABLE : + reg |=PORT_PE ; +xhci_writel (status_reg, reg); +break ; +case USB_PORT_FEAT_POWER : + reg |=PORT_POWER ; +xhci_writel (status_reg, reg); +break ; +case USB_PORT_FEAT_RESET : + reg =xhci_readl (status_reg); + reg |=PORT_RESET ; +xhci_writel (status_reg, reg); +xhci_poll_and_HandleEvent (usbdev); +break ; +default : +debug ("unknown feature %x\n" ,le16_to_cpu (req->value)); + goto unknown; + } +/* unblock posted writes */ +xhci_readl (&hcor->or_usbcmd); +break ; +case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT |USB_RT_PORT ) <<8 ): + reg =xhci_readl (status_reg); + reg =xhci_port_state_to_neutral (reg); +switch (le16_to_cpu (req->value)) { +case USB_PORT_FEAT_ENABLE : + reg &= ~PORT_PE ; +break ; +case USB_PORT_FEAT_C_RESET : +case USB_PORT_FEAT_C_CONNECTION : +case USB_PORT_FEAT_C_OVER_CURRENT : +case USB_PORT_FEAT_C_ENABLE : +xhci_clear_port_change_bit ((le16_to_cpu (req->value)), +le16_to_cpu (req->index), + status_reg, reg); +break ; +default : + goto unknown; + } +xhci_writel (status_reg, reg); +/* unblock posted write */ +xhci_readl (&hcor->or_usbcmd); +break ; +default : +debug ("Unknown request\n" ); + goto unknown; + } + +mdelay (5 ); + +debug ("scrlen = %d\n req->length = %d\n, length = %d\n" , + srclen,le16_to_cpu (req->length), length); + + len =min3 (srclen,le16_to_cpu (req->length), length); + +if (srcptr !=NULL && len >0 ) +memcpy (buffer, srcptr, len); +else +debug ("Len is 0\n" ); + + usbdev->act_len = len; + usbdev->status =0 ; + +return 0 ; + +unknown: + usbdev->act_len =0 ; + usbdev->status =USB_ST_STALLED ; + +return -1 ; +} + +/** +* Allocates the Container context +* +* @param ctrl Host controller data structure +* @param type type of Context +* @return NULL if fialed else pointer to the context on success +*/ +static struct +xhci_container_ctx *xhci_alloc_container_ctx (struct xhci_ctrl *ctrl, +int type) +{ +struct xhci_container_ctx *ctx; + + ctx = (struct xhci_container_ctx *) +xhci_malloc (sizeof (struct xhci_container_ctx )); + +if (!ctx) +return NULL ; + +BUG_ON ((type !=XHCI_CTX_TYPE_DEVICE ) && (type !=XHCI_CTX_TYPE_INPUT )); + ctx->type = type; + ctx->size =HCC_64BYTE_CONTEXT (readl (&ctrl->hccr->cr_hccparams)) ? +2048 :1024 ; +if (type ==XHCI_CTX_TYPE_INPUT ) + ctx->size +=CTX_SIZE (readl (&ctrl->hccr->cr_hccparams)); + + ctx->bytes = (u8 *)xhci_malloc (ctx->size); + +return ctx; +} + +/** +* Give the input control context for the passed container context +* +* @param ctx pointer to the context +* @return pointer to the Input control context data +*/ +struct xhci_input_control_ctx *xhci_get_input_control_ctx ( +struct xhci_container_ctx *ctx) +{ +BUG_ON (ctx->type !=XHCI_CTX_TYPE_INPUT ); +return (struct xhci_input_control_ctx *)ctx->bytes; +} + +/** +* Give the slot context for the passed container context +* +* @param ctx pointer to the context +* @param ctrl Host controller data structure +* @return pointer to the slot control context data +*/ +struct xhci_slot_ctx *xhci_get_slot_ctx (struct xhci_ctrl *ctrl, +struct xhci_container_ctx *ctx) +{ +if (ctx->type ==XHCI_CTX_TYPE_DEVICE ) +return (struct xhci_slot_ctx *)ctx->bytes; + +return (struct xhci_slot_ctx *) + (ctx->bytes +CTX_SIZE (readl (&ctrl->hccr->cr_hccparams))); +} + +/** +* See Cycle bit rules. SW is the consumer for the event ring only. +* Don't make a ring full of link TRBs. That would be dumb and this would loop. +* +* @param ctrl Host controller data structure +* @param ring Ring whose Dequeue TRB pointer needs to be incremented. +* @param consumer flag to indicate whether S/W is consumer of this RING or NOT +* return none +*/ +static void inc_deq (struct xhci_ctrl *ctrl,struct xhci_ring *ring, +bool consumer) +{ +union xhci_trb *next = ++(ring->dequeue); + + ring->deq_updates++; +/* +* Update the dequeue pointer further if that was a link TRB or we're at +* the end of an event ring segment (which doesn't have link TRBS) +*/ +while (last_trb (ctrl, ring, ring->deq_seg, next)) { +if (consumer && +last_trb_on_last_seg (ctrl, ring, ring->deq_seg, next)) + ring->cycle_state = (ring->cycle_state ?0 :1 ); + + ring->deq_seg = ring->deq_seg->next; + ring->dequeue = ring->deq_seg->trbs; + next = ring->dequeue; + } + +xhci_flush_inval_cache ((uint32_t )ring->dequeue,XHCI_TRB ,1 ); +} + +/** +* Handles the port status event +* +* @param ctrl Host controller data structure +* @param event event genrated by the XHCI controller +* @return none +*/ +static void handle_port_status (struct xhci_ctrl *ctrl,union xhci_trb *event) +{ +int max_ports; + +/* Port status change events always have a successful completion code */ +if (((le32_to_cpu (event->generic.field[2 ]) & +COMP_CODE_MASK ) >>COMP_CODE_SHIFT ) !=COMP_SUCCESS ) +return ; + + ctrl->port_id = (((le32_to_cpu (event->generic.field[0 ]) & +PORT_ID_MASK ) >>PORT_ID_SHIFT )); + + max_ports = ((readl (&ctrl->hccr->cr_hcsparams1) & +HCS_MAX_PORTS_MASK ) >>HCS_MAX_PORTS_SHIFT ); + +if ((ctrl->port_id <=0 ) || (ctrl->port_id > max_ports)) +debug ("Invalid port id %d\n" , ctrl->port_id); + +return ; +} + +/** +* Handles the command completion Event +* +* @param ctrl Host controller data structure +* @param event Event generated by the XHCI controller +* @return none +*/ +static void handle_cmd_completion (struct xhci_ctrl *ctrl, +struct xhci_event_cmd *event) +{ +int slot_id = ((le32_to_cpu (event->flags) & +TRB_TO_SLOT_ID_MASK ) >>TRB_TO_SLOT_ID_SHIFT ); +u64 cmd_addr; +unsigned long cmd_dequeue_addr; + +xhci_flush_inval_cache ((uint32_t )ctrl->cmd_ring->dequeue,XHCI_TRB ,0 ); + + cmd_addr =le64_to_cpu (event->cmd_trb); + cmd_dequeue_addr =trb_addr (ctrl->cmd_ring->deq_seg, + ctrl->cmd_ring->dequeue); + +/* Is the command ring deq ptr out of sync with the deq seg ptr? */ +if (cmd_dequeue_addr ==0 ) +return ; + +/* +* Does the cmd trb's address match our internal +* dequeue pointer address? +*/ +if (cmd_addr != (u64 ) cmd_dequeue_addr) +return ; + +switch ((le32_to_cpu (ctrl->cmd_ring->dequeue->generic.field[3 ]) & +TRB_TYPE_BITMASK ) >>TRB_TYPE_SHIFT ) { +case TRB_ENABLE_SLOT : +if (((le32_to_cpu (event->status) & +COMP_CODE_MASK ) >>COMP_CODE_SHIFT ) ==COMP_SUCCESS ) + ctrl->slot_id = slot_id; +else + ctrl->slot_id =0 ; +break ; + +case TRB_ADDR_DEV : + ctrl->devs[slot_id]->cmd_status = ((le32_to_cpu (event->status) & +COMP_CODE_MASK ) >> +COMP_CODE_SHIFT ); +break ; + +case TRB_RESET_DEV : +debug ("Completed reset device command.\n" ); +break ; + +case TRB_EVAL_CONTEXT : + ctrl->devs[slot_id]->cmd_status = +GET_COMP_CODE (le32_to_cpu (event->status)); +break ; + +case TRB_CONFIG_EP : +debug ("Configure Endpoint command completed .\n" ); +break ; +default : +/* Skip over unknown commands on the event ring */ +break ; + } + +inc_deq (ctrl, ctrl->cmd_ring, false); +} + +/** +* This function handles all CPU-owned events on the event ring. +* +* @param ctrl Host controller data structure +* @return 1 incase of success or -1 on failure +*/ +static int xhci_handle_event (struct xhci_ctrl *ctrl) +{ +union xhci_trb *event; +int update_ptrs =1 ; +unsigned long deq; +u64 temp_64; + +if (!ctrl->event_ring || !ctrl->event_ring->dequeue) +return -1 ; + +xhci_flush_inval_cache ((uint32_t )ctrl->event_ring->dequeue, +XHCI_TRB ,0 ); + + event = ctrl->event_ring->dequeue; + +/* FIXME: Handle more event types. */ +switch ((le32_to_cpu (event->event_cmd.flags) & +TRB_TYPE_BITMASK ) >>TRB_TYPE_SHIFT ) { +case TRB_COMPLETION : +handle_cmd_completion (ctrl, &event->event_cmd); +debug ("Handling commanding completion\n" ); +break ; + +case TRB_PORT_STATUS : +handle_port_status (ctrl, event); +break ; +default : +if ((le32_to_cpu (event->event_cmd.flags) & +TRB_TYPE_BITMASK ) ==0 ) + update_ptrs =0 ; +break ; + } + +if (update_ptrs) { +debug ("Upadting dequeue pointer\n" ); +/* Update SW event ring dequeue pointer */ +inc_deq (ctrl, ctrl->event_ring, true); + } + +xhci_flush_inval_cache ((uint32_t )ctrl->event_ring->dequeue, +XHCI_TRB ,0 ); + + temp_64 =xhci_readl_64 (&ctrl->ir_set->erst_dequeue); +/* If necessary, update the HW's version of the event ring deq ptr. */ + deq = (u32)(ctrl->event_ring->dequeue); + +xhci_flush_inval_cache ((uint32_t )deq,XHCI_TRB ,1 ); + +if (deq ==0 ) +debug ("WARN something wrong with SW event " +"ring dequeue ptr.\n" ); + +/* Update HC event ring dequeue pointer */ + temp_64 &=ERST_PTR_MASK ; + temp_64 |= ((u64 ) deq & (u64 ) ~ERST_PTR_MASK ); + +/* Clear the event handler busy flag (RW1C); event ring is empty. */ + temp_64 |=ERST_EHB ; +xhci_writel_64 (&ctrl->ir_set->erst_dequeue, temp_64); + +return 1 ; +} + +/** +* Checks the ownership of the Event Command +* +* @param ctrl Host controller data structure +* @return 0 if failure else 0 on success +*/ +static int xhci_check_ownership (struct xhci_ctrl *ctrl) +{ +union xhci_trb *event; + +if (!ctrl->event_ring || !ctrl->event_ring->dequeue) +return 0 ; + +xhci_flush_inval_cache ((uint32_t )ctrl->event_ring->dequeue, +XHCI_TRB ,0 ); + + event = ctrl->event_ring->dequeue; +/* Does the HC or OS own the TRB? */ +if ((le32_to_cpu (event->event_cmd.flags) &TRB_CYCLE ) != + ctrl->event_ring->cycle_state) +return 0 ; + +return 1 ; +} + +/** +* Checks the ownership of the Event Command +* +* @param ctrl Host controller data structure +* @return ownership flag +*/ +int xhci_poll (struct xhci_ctrl *ctrl) +{ +return xhci_check_ownership (ctrl); +} + +/** +* Queue a slot enable or disable request on the command ring +* +* @param ctrl Host controller data structure +* @param trb_type type of TRB to be queued in +* @param slot_id slot id allocated by the XHCI controller +* @return status of the "queue_command" +*/ +int xhci_queue_slot_control (struct xhci_ctrl *ctrl,u32 trb_type,u32 slot_id) +{ + +u32 trb_fields[4 ]; + + trb_fields[0 ] =0 ; + trb_fields[1 ] =0 ; + trb_fields[2 ] =0 ; + trb_fields[3 ] = ((trb_type <<TRB_TYPE_SHIFT ) | + ((slot_id &SLOT_ID_FOR_TRB_MASK ) << +SLOT_ID_FOR_TRB_SHIFT )); + +return queue_command (ctrl, trb_fields); +} + +/** +* Allocating virtual device +* +* @param usbdev pointer to USB deivce structure +* @param slot_id slot id allocated by the XHCI controller +* @return 0 on success else -1 on failure +*/ +int xhci_alloc_virt_device (struct usb_device *usbdev,int slot_id) +{ +u64 byte_64 =0 ; +struct xhci_virt_device *virt_dev; +struct xhci_ctrl *ctrl = usbdev->controller; + +/* Slot ID 0 is reserved */ +if (slot_id ==0 || ctrl->devs[slot_id]) { +debug ("Bad Slot ID %d\n" , slot_id); +return -1 ; + } + + ctrl->devs[slot_id] = (struct xhci_virt_device *) +malloc (sizeof (struct xhci_virt_device )); + +if (!ctrl->devs[slot_id]) { +debug ("Failed to allocate virtual device\n" ); +return -1 ; + } + +memset (ctrl->devs[slot_id],0 ,sizeof (struct xhci_virt_device )); + virt_dev = ctrl->devs[slot_id]; + +/* Allocate the (output) device context that will be used in the HC. */ + virt_dev->out_ctx =xhci_alloc_container_ctx (ctrl, +XHCI_CTX_TYPE_DEVICE ); +if (!virt_dev->out_ctx) { +debug ("Failed to allocate out context for virt dev\n" ); +return -1 ; + } + +/* Allocate the (input) device context for address device command */ + virt_dev->in_ctx =xhci_alloc_container_ctx (ctrl, +XHCI_CTX_TYPE_INPUT ); +if (!virt_dev->in_ctx) { +debug ("Failed to allocate in context for virt dev\n" ); +return -1 ; + } + +/* Allocate endpoint 0 ring */ + virt_dev->eps[0 ].ring =xhci_ring_alloc (1 , true); +if (!virt_dev->eps[0 ].ring) { +debug ("Failed to allocate EP(0) ring\n" ); +return -1 ; + } + + byte_64 = (uintptr_t )(virt_dev->out_ctx->bytes); + +/* Point to output device context in dcbaa. */ + ctrl->dcbaa->dev_context_ptrs[slot_id] = byte_64; + +xhci_flush_inval_cache ((uint32_t ) + &ctrl->dcbaa->dev_context_ptrs[slot_id], +sizeof (__le64),1 ); +return 0 ; +} + +/** +* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy. +* Useful when you want to change one particular aspect of the endpoint +* and then issue a configure endpoint command. +* +* @param ctrl Host controller data structure +* @param in_ctx contains the inpout context +* @param out_ctx contains the inpout context +* @param ep_index index of the end point +* @return none +*/ +void xhci_endpoint_copy (struct xhci_ctrl *ctrl, +struct xhci_container_ctx *in_ctx, +struct xhci_container_ctx *out_ctx, +unsigned int ep_index) +{ +struct xhci_ep_ctx *out_ep_ctx; +struct xhci_ep_ctx *in_ep_ctx; + + out_ep_ctx =xhci_get_ep_ctx (ctrl, out_ctx, ep_index); + in_ep_ctx =xhci_get_ep_ctx (ctrl, in_ctx, ep_index); + + in_ep_ctx->ep_info = out_ep_ctx->ep_info; + in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2; + in_ep_ctx->deq = out_ep_ctx->deq; + in_ep_ctx->tx_info = out_ep_ctx->tx_info; +} + +/** +* Copy output xhci_slot_ctx to the input xhci_slot_ctx. +* Useful when you want to change one particular aspect of the endpoint +* and then issue a configure endpoint command. +* Only the context entries field matters, but +* we'll copy the whole thing anyway. +* +* @param ctrl Host controller data structure +* @param in_ctx contains the inpout context +* @param out_ctx contains the inpout context +* @return none +*/ +void xhci_slot_copy (struct xhci_ctrl *ctrl,struct xhci_container_ctx *in_ctx, +struct xhci_container_ctx *out_ctx){ + +struct xhci_slot_ctx *in_slot_ctx; +struct xhci_slot_ctx *out_slot_ctx; + + in_slot_ctx =xhci_get_slot_ctx (ctrl, in_ctx); + out_slot_ctx =xhci_get_slot_ctx (ctrl, out_ctx); + + in_slot_ctx->dev_info = out_slot_ctx->dev_info; + in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2; + in_slot_ctx->tt_info = out_slot_ctx->tt_info; + in_slot_ctx->dev_state = out_slot_ctx->dev_state; +} + +/** +* Queue an address device command TRB +* +* @param ctrl Host controller data structure +* @param in_ctx_ptr +* @param slot_id +* @return status of the "queue_command" +*/ +int xhci_queue_address_device (struct xhci_ctrl *ctrl,u8 *in_ctx_ptr, +u32 slot_id) +{ +u64 val_64 =0 ; +u32 trb_fields[4 ]; + + val_64 = (uintptr_t )in_ctx_ptr; + trb_fields[0 ] =lower_32_bits (val_64); + trb_fields[1 ] =upper_32_bits (val_64); + trb_fields[2 ] =0 ; + trb_fields[3 ] = ((TRB_ADDR_DEV <<TRB_TYPE_SHIFT ) | + ((slot_id &SLOT_ID_FOR_TRB_MASK ) << +SLOT_ID_FOR_TRB_SHIFT )); + +return queue_command (ctrl, trb_fields); +} + +/** +* Copies the EP O Transfer ring to Input Context +* +* @param ctrl Host controller data structure +* @return none +*/ +void xhci_copy_ep0_dequeue_into_input_ctx (struct xhci_ctrl *ctrl) +{ +struct xhci_virt_device *virt_dev; +struct xhci_ep_ctx *ep0_ctx; +struct xhci_ring *ep_ring; + + virt_dev = ctrl->devs[ctrl->slot_id]; + ep0_ctx =xhci_get_ep_ctx (ctrl, virt_dev->in_ctx,0 ); + ep_ring = virt_dev->eps[0 ].ring; +/* +* FIXME we don't keep track of the dequeue pointer very well after a +* Set TR dequeue pointer, so we're setting the dequeue pointer of the +* host to our enqueue pointer. This should only be called after a +* configured device has reset, so all control transfers should have +* been completed or cancelled before the reset. +*/ + ep0_ctx->deq =cpu_to_le64 (trb_addr (ep_ring->enq_seg, + ep_ring->enqueue) | ep_ring->cycle_state); +} + +/** +* Setup an xHCI virtual device for a Set Address command +* +* @param usbdev pointer to the Device Data Structure +* @return returns negative value on failure else 0 on success +*/ +int xhci_setup_addressable_virt_dev (struct usb_device *usbdev) +{ +struct xhci_virt_device *virt_dev; +struct xhci_ep_ctx *ep0_ctx; +struct xhci_slot_ctx *slot_ctx; +u32 port_num =0 ; +u64 trb_64 =0 ; + +struct xhci_ctrl *ctrl = usbdev->controller; + + virt_dev = ctrl->devs[ctrl->slot_id]; + +/* Slot ID 0 is reserved */ +if (ctrl->slot_id ==0 || !virt_dev) { +debug ("Slot ID %d is not assigned to this device\n" , + ctrl->slot_id); +return -EINVAL ; + } + +/* Extract the EP0 and Slot Ctrl */ + ep0_ctx =xhci_get_ep_ctx (ctrl, virt_dev->in_ctx,0 ); + slot_ctx =xhci_get_slot_ctx (ctrl, virt_dev->in_ctx); + +/* 3) Only the control endpoint is valid - one endpoint context */ + slot_ctx->dev_info |=cpu_to_le32 (LAST_CTX (1 ) |0 ); + +switch (ctrl->speed) { + +case USB_SPEED_SUPER : + slot_ctx->dev_info |=cpu_to_le32 (SLOT_SPEED_SS ); +break ; +case USB_SPEED_HIGH : + slot_ctx->dev_info |=cpu_to_le32 (SLOT_SPEED_HS ); +break ; +case USB_SPEED_FULL : + slot_ctx->dev_info |=cpu_to_le32 (SLOT_SPEED_FS ); +break ; +case USB_SPEED_LOW : + slot_ctx->dev_info |=cpu_to_le32 (SLOT_SPEED_LS ); +break ; +default : +/* Speed was set earlier, this shouldn't happen. */ +BUG (); + } + + port_num = ctrl->port_id; +debug ("port_num = %d\n" , port_num); + + slot_ctx->dev_info2 |= +cpu_to_le32 (((port_num &ROOT_HUB_PORT_MASK ) << +ROOT_HUB_PORT_SHIFT )); + +/* Step 4 - ring already allocated */ +/* Step 5 */ + ep0_ctx->ep_info2 =cpu_to_le32 (CTRL_EP <<EP_TYPE_SHIFT ); +/* +* XXX: Not sure about wireless USB devices. +*/ +debug ("SPEED = %d\n" , ctrl->speed); + +switch (ctrl->speed) { +case USB_SPEED_SUPER : + ep0_ctx->ep_info2 |=cpu_to_le32 (((512 &MAX_PACKET_MASK ) << +MAX_PACKET_SHIFT )); +debug ("Setting Packet size = 512bytes\n" ); +break ; +case USB_SPEED_HIGH : +/* USB core guesses@a 64-byte max packet first for FS devices */ +case USB_SPEED_FULL : + ep0_ctx->ep_info2 |=cpu_to_le32 (((64 &MAX_PACKET_MASK ) << +MAX_PACKET_SHIFT )); +debug ("Setting Packet size = 64bytes\n" ); +break ; +case USB_SPEED_LOW : + ep0_ctx->ep_info2 |=cpu_to_le32 (((8 &MAX_PACKET_MASK ) << +MAX_PACKET_SHIFT )); +debug ("Setting Packet size = 8bytes\n" ); +break ; +default : +/* New speed? */ +BUG (); + } + +/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ + ep0_ctx->ep_info2 |= +cpu_to_le32 (((0 &MAX_BURST_MASK ) <<MAX_BURST_SHIFT ) | + ((3 &ERROR_COUNT_MASK ) <<ERROR_COUNT_SHIFT )); + + trb_64 = (uintptr_t )virt_dev->eps[0 ].ring->first_seg->trbs; + ep0_ctx->deq =cpu_to_le64 (trb_64 | virt_dev->eps[0 ].ring->cycle_state); + +/* Steps 7 and 8 were done in xhci_alloc_virt_device() */ + +return 0 ; +} + +/** +* Polls the XHCI controller +* and Handles the Event generated by the XHCI Controller +* +* @param usbdev pointer to the Device Data Structure +* @return none +*/ +void xhci_poll_and_HandleEvent (struct usb_device *usbdev) +{ +unsigned long ts; +struct xhci_ctrl *ctrl = usbdev->controller; +int event_occured =0 ; +union xhci_trb *event; +union xhci_trb *first_trb; + +xhci_flush_inval_cache ((uint32_t )ctrl->event_ring->dequeue, +XHCI_TRB ,0 ); + + event = ctrl->event_ring->dequeue; + + ts =get_timer (0 ); + +do { +if (xhci_poll (ctrl)) { +debug ("Poll success\n" ); + event_occured =1 ; +break ; + } + }while (get_timer (ts) <USB_CTRL_SET_TIMEOUT ); + +if (event_occured) { +while (((le32_to_cpu (event->event_cmd.flags) & +TRB_TYPE_BITMASK ) >> +TRB_TYPE_SHIFT ) ==TRB_PORT_STATUS ) { +if (xhci_handle_event (ctrl) <0 ) { +debug ("Error in handling the event\n" ); +return ; + } + + first_trb = ctrl->event_ring->first_seg->trbs; + +xhci_flush_inval_cache ((uint32_t )first_trb, + (sizeof (union xhci_trb ) *64 ),0 ); + + event = ctrl->event_ring->dequeue; + } +/* +* If this is the 1st time POLL is called +* then handle event one more time, since +* 1st event would be "PORT STATUS CHANGE EVENT" +*/ +if (xhci_handle_event (ctrl) <0 ) { +debug ("Error in handling the event\n" ); +return ; + } + usbdev->act_len =0 ; + usbdev->status =0 ; + }else { +debug ("NO EVENT OCCURED\n" ); + } + +return ; +} + +/** +* Issue an Address Device command (which will issue a SetAddress request to +* the device). +* We add one to the device address issued by the hardware because the USB core +* uses address 1 for the root hubs (even though they're not really devices). +* +* @param usbdev pointer to the Device Data Structure +* @return 0 if successful else error code on failure +*/ +int xhci_address_device (struct usb_device *usbdev) +{ +int ret =0 ; +struct xhci_ctrl *ctrl = usbdev->controller; +struct xhci_slot_ctx *slot_ctx; +struct xhci_input_control_ctx *ctrl_ctx; +struct xhci_virt_device *virt_dev; +int slot_id = ctrl->slot_id; + + virt_dev = ctrl->devs[slot_id]; + + slot_ctx =xhci_get_slot_ctx (ctrl, virt_dev->in_ctx); + +/* +* If this is the first Set Address since device plug-in or +* virt_device realloaction after a resume with an xHCI power loss, +* then set up the slot context. +*/ + +xhci_flush_inval_cache ((uint32_t )virt_dev->eps[0 ].ring->first_seg->trbs, +XHCI_TRB ,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx, +XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx, +XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx->bytes, + virt_dev->in_ctx->size,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size,0 ); + +if (!slot_ctx->dev_info) { +debug ("Setting up addressable devices\n" ); +xhci_setup_addressable_virt_dev (usbdev); + }else { +/* Otherwise, update the control EP ring enqueue pointer. */ +debug ("update the control endpoint ring enqueue pointer\n" ); +xhci_copy_ep0_dequeue_into_input_ctx (ctrl); + } + + ctrl_ctx =xhci_get_input_control_ctx (virt_dev->in_ctx); + ctrl_ctx->add_flags =cpu_to_le32 (SLOT_FLAG |EP0_FLAG ); + ctrl_ctx->drop_flags =0 ; + +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx, +XHCI_CTX ,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx, +XHCI_CTX ,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->in_ctx->bytes, + virt_dev->in_ctx->size,1 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size,1 ); + + ret =xhci_queue_address_device (ctrl, virt_dev->in_ctx->bytes, + slot_id); + +xhci_ring_cmd_db (ctrl); +mdelay (5 ); +xhci_poll_and_HandleEvent (usbdev); + +switch (virt_dev->cmd_status) { +case COMP_CTX_STATE : +case COMP_EBADSLT : +debug ("Setup ERROR: address device command for slot %d.\n" , + slot_id); + ret = -EINVAL ; +break ; +case COMP_TX_ERR : +debug ("Device not responding to set address.\n" ); + ret = -EPROTO ; +break ; +case COMP_DEV_ERR : +debug ("ERROR: Incompatible device" +"for address device command.\n" ); + ret = -ENODEV ; +break ; +case COMP_SUCCESS : +debug ("Successful Address Device command\n" ); +break ; +default : +debug ("ERROR: unexpected command completion code 0x%x.\n" , + virt_dev->cmd_status); +/*FIXME*/ + ret =0 ; +break ; + } +if (ret <0 ) +return ret; +/* +* USB core uses address 1 for the roothubs, so we add one to the +* address given back to us by the HC. +*/ + +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx, +XHCI_CTX ,0 ); +xhci_flush_inval_cache ((uint32_t )virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size,1 ); + + slot_ctx =xhci_get_slot_ctx (ctrl, virt_dev->out_ctx); + +/* store xHC assigned Address locally */ + virt_dev->address = (le32_to_cpu (slot_ctx->dev_state) & +DEV_ADDR_MASK ) +1 ; + +if (virt_dev->address ==1 ) +debug ("ADDRESS assigned is ZERO\n" ); + +/* Zero the input context control for later use */ + ctrl_ctx->add_flags =0 ; + ctrl_ctx->drop_flags =0 ; + +return 0 ; +} + +/** +* Issue Enable slot command to the controller to allocate +* device slot and assign the slot id. It fails if the xHC +* ran out of device slots, the Enable Slot command timed out, +* or allocating memory failed. +* +* @param usbdev pointer to the Device Data Structure +* @return Returns 0 on succes else return -1 on failure +*/ +int xhci_alloc_dev (struct usb_device *usbdev) +{ +struct xhci_ctrl *ctrl = usbdev->controller; +int ret; + ret =xhci_queue_slot_control (ctrl,TRB_ENABLE_SLOT ,0 ); +if (ret) { +debug ("FIXME: allocate a command ring segment\n" ); +return -1 ; + } +xhci_ring_cmd_db (ctrl); +mdelay (5 ); +xhci_poll_and_HandleEvent (usbdev); +if (!ctrl->slot_id) { +debug ("Error while assigning device slot ID\n" ); +return -1 ; + } +
Lines of this file are not shown. View the raw message.
drivers/usb/host/xhci.h new file +1360 -0
1,360 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.6.5
Part of the diff is not shown here. View the raw message.
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.
I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Quoted 3 lines
Signed-off-by Vikas C Sajjan <[email protected]>Signed-off-by Vivek Gautam <[email protected]>---
[...]
Best regards,
Marek Vasut
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Quoted 11 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.
Quoted 4 lines
I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Agreed, we want to figure out how to keep this code in sync with the kernel.
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121023/09d0cb5b/attachment.pgp>
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
HI,
Quoted 12 lines · Tom Rini
Quoted 11 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.
Quoted 8 lines
Quoted 4 lines
I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Agreed, we want to figure out how to keep this code in sync with the kernel.
Good that we split the file (having separate files xhci.c, xhci-mem.c, xhci-ring.c)
with certain changes and adjustments ?
This way we shall be able to keep track of it keep in-sync with kernel.
Signature · 2 lines
Thanks & Regards Vivek
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Quoted 31 lines · Vivek Gautam
HI,
Quoted 12 lines · Tom Rini
Quoted 11 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.Quoted 8 lines
Quoted 4 lines
I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Agreed, we want to figure out how to keep this code in sync with the kernel.
Good that we split the file (having separate files
xhci.c,xhci-mem.c,xhci-ring.c)
with certain changes and adjustments ?
This way we shall be able to keep track of it keep in-sync with kernel.--
Thanks & Regards
Vivek
Signature · 2 lines
Thanks & Regards Vivek
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
In reply to Vivek GautamDear Vivek Gautam,
Quoted 20 lines
HI,
Quoted 17 lines · Tom Rini
Quoted 15 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Quoted 7 lines
Quoted 2 lines
Agreed, we want to figure out how to keep this code in sync with the kernel.
Good that we split the file (having separate files
xhci.c,xhci-mem.c,xhci-ring.c)
with certain changes and adjustments ?
This way we shall be able to keep track of it keep in-sync with kernel.
Sounds good :)
Best regards,
Marek Vasut
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Hi Marek,
Quoted 25 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 23 lines
HI,
Quoted 19 lines · Tom Rini
Quoted 11 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 8 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
The code corresponding toxhci.c,xhci-mem.c,xhci-ring.candxhci-hub.cin linux-kernel is grouped together here in single driver 'xhci.c'.Quoted 4 lines
I wouldn't object keeping them separate so they can be easily synced with the Linux code actually. Can you try doing it that way ? (Pull it from Linux and do just minimal adjustments to wire it into U-Boot ... maybe implement some translation layer) ?
Agreed, we want to figure out how to keep this code in sync with the kernel.
Quoted 7 lines
Quoted 4 lines
Good that we split the file (having separate files
xhci.c,xhci-mem.c,xhci-ring.c)
with certain changes and adjustments ?
This way we shall be able to keep track of it keep in-sync with kernel.Sounds good :)
Sure, then i shall update on this asap. :)
Quoted 2 lines
Best regards,
Marek Vasut
Signature · 2 lines
Thanks & Regards Vivek
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
In reply to Vivek GautamDear Vivek Gautam,
Quoted 5 lines · In message <[email protected]> you…
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
When copying code from Linux, then please always provide exact reference. Please see especially bullet # 4 at
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_Sign
Best regards,
Wolfgang Denk
Signature · 8 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de EARTH smog | bricks AIR -- mud -- FIRE soda water | tequila WATER
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Hi,
Quoted 6 lines · Wolfgang Denk
Dear Vivek Gautam,
Quoted 3 lines · In message <[email protected]> you…
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
Quoted 7 lines
Quoted 2 lines
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
When copying code from Linux, then please always provide exact reference. Please see especially bullet # 4 at
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_Sign
Thanks for pointing out. I shall keep this in mind, and update proper references here also.
Quoted 4 lines
Best regards,
Wolfgang Denk
Quoted 13 lines
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
EARTH
smog | bricks
AIR -- mud -- FIRE
soda water | tequila
WATER
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
Thanks & Regards
Vivek
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Quoted 7 lines · Vivek Gautam <gautamvivek1987 <at> gmail.com> writes:
Hi,
Quoted 3 lines · On Tue, Oct 23, 2012 at 6:30 PM, Wolfgang Denk <wd <at> denx.de> wrote:
Dear Vivek Gautam,
In message <1350989687-32102-3-git-send-email-gautam.vivek <at> samsung.com>
Quoted 31 lines · you
Quoted 10 lines
Quoted 5 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
When copying code from Linux, then please always provide exact reference. Please see especially bullet # 4 at
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_SignThanks for pointing out. I shall keep this in mind, and update proper references here also.
Quoted 4 lines
Best regards,
Wolfgang Denk
Quoted 13 lines
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd <at> denx.de
EARTH
smog | bricks
AIR -- mud -- FIRE
soda water | tequila
WATER
_______________________________________________
U-Boot mailing list
U-Boot <at> lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
Quoted 3 lines
Thanks & Regards
Vivek
Hi Vivek,
I have been trying to port your xHCI patches from U-Boot to barebox. I took your xHCI patch from
http://patchwork.ozlabs.org/patch/193477/
Could you please let me know whether those are the latest patches? If not, could you please send me the latest patch?
What about xHCI testing?
Thanks,
Satendra
RFC PATCH 2/2 USB: xHCI: Add stack support for xHCI
Hi Satendra,
Quoted 29 lines · Satendra Pratap
Quoted 7 lines · Vivek Gautam <gautamvivek1987 <at> gmail.com> writes:
Hi,
Quoted 3 lines · On Tue, Oct 23, 2012 at 6:30 PM, Wolfgang Denk <wd <at> denx.de> wrote:
Dear Vivek Gautam,
In message <1350989687-32102-3-git-send-email-gautam.vivek <at> samsung.com>
Quoted 6 lines · you
Quoted 6 lines
Quoted 5 lines
This adds stack layer for eXtensible Host Controller Interface which facilitates use of USB 3.0 in host mode.
This work is based on xHCI host controller driver in linux-kernel by Sarah Sharp.
Quoted 7 lines
Quoted 4 lines
When copying code from Linux, then please always provide exact reference. Please see especially bullet # 4 at
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_SignThanks for pointing out. I shall keep this in mind, and update proper references here also.
Hi Vivek,
I have been trying to port your xHCI patches from U-Boot to barebox. I took your xHCI patch from
http://patchwork.ozlabs.org/patch/193477/
Quoted 5 lines
Could you please let me know whether those are the latest patches? If not, could you please send me the latest patch?
What about xHCI testing?
Please avoid top/bottom commenting :-)
Please find below the URLs for both the patches against the patch thread :
[RFC PATCH 0/2] USB: XHCI: Add xHCI host controller stack driver, adds just the xHCI stack support.
http://patchwork.ozlabs.org/patch/193476/
Patchwork [U-Boot,RFC,1/2] USB: SS: Add support for Super Speed USB interface
URL: http://patchwork.ozlabs.org/patch/193477/
Patchwork [U-Boot,RFC,2/2] USB: xHCI: Add stack support for xHCI
Theese were the initial set of patches, and i couldn't rework on them due to other responsibilities.
We tested them with few private set of patches for exynos5250 platform.
Signature · 2 lines
Thanks & Regards Vivek
cover USB: XHCI: Add xHCI host controller stack driver
In reply to Vivek GautamDear Vivek Gautam,
Quoted 7 lines
This change adds necessary framework support for USB3.0 (Super-speed) and xHCI host controller stack layer. This stack will eventually interact with SOC specific USB 3.0 controllers.
Based on 'master' branch of u-boot tree.
Quoted 7 lines
Tested successfully with local patches on xHCI support for exynos5 with Kingston USB 2.0 data traveler (512 MB) and Corsair USB 3.0 flash voyager. However, also saw failures with Transcend USB 3.0 (8 GB) and a Jetflash 256 MB.
We are further debugging and testing this thoroughly. In the meantime can this be reviewed please?
This definitely needs further improvements ;-).
Sure, can you get me one such ARM hardware with xHCI? I'm sure you have a pile of them so you can miss one. That's help greatly, thanks!
Quoted 10 lines
Although, code is based on linux's xHCI host controller driver, at certain points putting some delays seemed to make the device working (couldn't get proper explanation on delays in xHCI or USB 3.0 specifications :-(, any help in this regard will be very much appreciated).
Vivek Gautam (2):
USB: SS: Add support for Super Speed USB interface
USB: xHCI: Add stack support for xHCI
Quoted 15 lines
common/cmd_usb.c | 6 +- common/usb.c | 41 +- common/usb_hub.c | 26 +- common/usb_storage.c | 35 +- drivers/usb/host/xhci.c | 3330 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 1360 +++++++++++++++++++ include/common.h | 2 + include/linux/usb/ch9.h | 2 +- include/usb.h | 15 +- include/usb_defs.h | 26 +- include/usbdescriptors.h | 201 +++ 11 files changed, 5012 insertions(+), 32 deletions(-) create mode 100644 drivers/usb/host/xhci.c create mode 100644 drivers/usb/host/xhci.h
Best regards,
Marek Vasut
cover USB: XHCI: Add xHCI host controller stack driver
Hi Marek,
Quoted 17 lines · Marek Vasut
Dear Vivek Gautam,
Quoted 7 lines
This change adds necessary framework support for USB3.0 (Super-speed) and xHCI host controller stack layer. This stack will eventually interact with SOC specific USB 3.0 controllers.
Based on 'master' branch of u-boot tree.
Quoted 7 lines
Tested successfully with local patches on xHCI support for exynos5 with Kingston USB 2.0 data traveler (512 MB) and Corsair USB 3.0 flash voyager. However, also saw failures with Transcend USB 3.0 (8 GB) and a Jetflash 256 MB.
We are further debugging and testing this thoroughly. In the meantime can this be reviewed please?
This definitely needs further improvements ;-).
Quoted 3 lines
Sure, can you get me one such ARM hardware with xHCI? I'm sure you have a pile of them so you can miss one. That's help greatly, thanks!
Sure, I need to check the availability once. As of now i test things on smdk5250.
Quoted 26 lines
Quoted 10 lines
Although, code is based on linux's xHCI host controller driver, at certain points putting some delays seemed to make the device working (couldn't get proper explanation on delays in xHCI or USB 3.0 specifications :-(, any help in this regard will be very much appreciated).
Vivek Gautam (2):
USB: SS: Add support for Super Speed USB interface
USB: xHCI: Add stack support for xHCIQuoted 15 lines
common/cmd_usb.c | 6 +- common/usb.c | 41 +- common/usb_hub.c | 26 +- common/usb_storage.c | 35 +- drivers/usb/host/xhci.c | 3330 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.h | 1360 +++++++++++++++++++ include/common.h | 2 + include/linux/usb/ch9.h | 2 +- include/usb.h | 15 +- include/usb_defs.h | 26 +- include/usbdescriptors.h | 201 +++ 11 files changed, 5012 insertions(+), 32 deletions(-) create mode 100644 drivers/usb/host/xhci.c create mode 100644 drivers/usb/host/xhci.h
Quoted 6 lines
Best regards,
Marek Vasut
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
Thanks & Regards
Vivek