]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - common/usb.c
powerpc: remove 4xx support
[people/ms/u-boot.git] / common / usb.c
index a4820d3e949a17c15c7deda9a3b0209abd0b3b74..0904259757371a25b2cb25f2d1189b6a53a43d17 100644 (file)
@@ -29,6 +29,7 @@
 #include <common.h>
 #include <command.h>
 #include <dm.h>
+#include <memalign.h>
 #include <asm/processor.h>
 #include <linux/compiler.h>
 #include <linux/ctype.h>
@@ -36,9 +37,6 @@
 #include <asm/unaligned.h>
 #include <errno.h>
 #include <usb.h>
-#ifdef CONFIG_4xx
-#include <asm/4xx_pci.h>
-#endif
 
 #define USB_BUFSIZ     512
 
@@ -148,6 +146,32 @@ int usb_stop(void)
        return 0;
 }
 
+/******************************************************************************
+ * Detect if a USB device has been plugged or unplugged.
+ */
+int usb_detect_change(void)
+{
+       int i, j;
+       int change = 0;
+
+       for (j = 0; j < USB_MAX_DEVICE; j++) {
+               for (i = 0; i < usb_dev[j].maxchild; i++) {
+                       struct usb_port_status status;
+
+                       if (usb_get_port_status(&usb_dev[j], i + 1,
+                                               &status) < 0)
+                               /* USB request failed */
+                               continue;
+
+                       if (le16_to_cpu(status.wPortChange) &
+                           USB_PORT_STAT_C_CONNECTION)
+                               change++;
+               }
+       }
+
+       return change;
+}
+
 /*
  * disables the asynch behaviour of the control message. This is used for data
  * transfers that uses the exclusiv access to the control and bulk messages.
@@ -183,7 +207,7 @@ int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe,
  * clear keyboards LEDs). For data transfers, (storage transfers) we don't
  * allow control messages with 0 timeout, by previousely resetting the flag
  * asynch_allowed (usb_disable_asynch(1)).
- * returns the transfered length if OK or -1 if error. The transfered length
+ * returns the transferred length if OK or -1 if error. The transferred length
  * and the current status are stored in the dev->act_len and dev->status.
  */
 int usb_control_msg(struct usb_device *dev, unsigned int pipe,
@@ -192,6 +216,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
                        void *data, unsigned short size, int timeout)
 {
        ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1);
+       int err;
 
        if ((timeout == 0) && (!asynch_allowed)) {
                /* request for a asynch control pipe is not allowed */
@@ -209,8 +234,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
              request, requesttype, value, index, size);
        dev->status = USB_ST_NOT_PROC; /*not yet processed */
 
-       if (submit_control_msg(dev, pipe, data, size, setup_packet) < 0)
-               return -EIO;
+       err = submit_control_msg(dev, pipe, data, size, setup_packet);
+       if (err < 0)
+               return err;
        if (timeout == 0)
                return (int)size;
 
@@ -427,7 +453,7 @@ static int usb_parse_config(struct usb_device *dev,
                        }
                        epno = dev->config.if_desc[ifno].no_of_ep;
                        if_desc = &dev->config.if_desc[ifno];
-                       if (epno > USB_MAXENDPOINTS) {
+                       if (epno >= USB_MAXENDPOINTS) {
                                printf("Interface %d has too many endpoints!\n",
                                        if_desc->desc.bInterfaceNumber);
                                return -EINVAL;
@@ -528,22 +554,19 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
 static int usb_get_descriptor(struct usb_device *dev, unsigned char type,
                        unsigned char index, void *buf, int size)
 {
-       int res;
-       res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-                       USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
-                       (type << 8) + index, 0,
-                       buf, size, USB_CNTL_TIMEOUT);
-       return res;
+       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                              USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+                              (type << 8) + index, 0, buf, size,
+                              USB_CNTL_TIMEOUT);
 }
 
 /**********************************************************************
- * gets configuration cfgno and store it in the buffer
+ * gets len of configuration cfgno
  */
-int usb_get_configuration_no(struct usb_device *dev,
-                            unsigned char *buffer, int cfgno)
+int usb_get_configuration_len(struct usb_device *dev, int cfgno)
 {
        int result;
-       unsigned int length;
+       ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 9);
        struct usb_config_descriptor *config;
 
        config = (struct usb_config_descriptor *)&buffer[0];
@@ -557,17 +580,23 @@ int usb_get_configuration_no(struct usb_device *dev,
                                "(expected %i, got %i)\n", 9, result);
                return -EIO;
        }
-       length = le16_to_cpu(config->wTotalLength);
+       return le16_to_cpu(config->wTotalLength);
+}
 
-       if (length > USB_BUFSIZ) {
-               printf("%s: failed to get descriptor - too long: %d\n",
-                       __func__, length);
-               return -EIO;
-       }
+/**********************************************************************
+ * gets configuration cfgno and store it in the buffer
+ */
+int usb_get_configuration_no(struct usb_device *dev, int cfgno,
+                            unsigned char *buffer, int length)
+{
+       int result;
+       struct usb_config_descriptor *config;
 
+       config = (struct usb_config_descriptor *)&buffer[0];
        result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, length);
-       debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result, length);
-       config->wTotalLength = length; /* validated, with CPU byte order */
+       debug("get_conf_no %d Result %d, wLength %d\n", cfgno, result,
+             le16_to_cpu(config->wTotalLength));
+       config->wTotalLength = result; /* validated, with CPU byte order */
 
        return result;
 }
@@ -578,14 +607,10 @@ int usb_get_configuration_no(struct usb_device *dev,
  */
 static int usb_set_address(struct usb_device *dev)
 {
-       int res;
-
        debug("set address %d\n", dev->devnum);
-       res = usb_control_msg(dev, usb_snddefctrl(dev),
-                               USB_REQ_SET_ADDRESS, 0,
-                               (dev->devnum), 0,
-                               NULL, 0, USB_CNTL_TIMEOUT);
-       return res;
+
+       return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
+                              0, (dev->devnum), 0, NULL, 0, USB_CNTL_TIMEOUT);
 }
 
 /********************************************************************
@@ -883,26 +908,13 @@ __weak int usb_alloc_device(struct usb_device *udev)
 }
 #endif /* !CONFIG_DM_USB */
 
-#ifndef CONFIG_DM_USB
-int usb_legacy_port_reset(struct usb_device *hub, int portnr)
+static int usb_hub_port_reset(struct usb_device *dev, struct usb_device *hub)
 {
-       if (hub) {
-               unsigned short portstatus;
-               int err;
-
-               /* reset the port for the second time */
-               err = legacy_hub_port_reset(hub, portnr - 1, &portstatus);
-               if (err < 0) {
-                       printf("\n     Couldn't reset port %i\n", portnr);
-                       return err;
-               }
-       } else {
-               usb_reset_root_port();
-       }
+       if (!hub)
+               usb_reset_root_port(dev);
 
        return 0;
 }
-#endif
 
 static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
 {
@@ -931,8 +943,6 @@ static int get_descriptor_len(struct usb_device *dev, int len, int expect_len)
 
 static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 {
-       __maybe_unused struct usb_device_descriptor *desc;
-
        /*
         * This is a Windows scheme of initialization sequence, with double
         * reset of the device (Linux uses the same sequence)
@@ -946,13 +956,18 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
         * send 64-byte GET-DEVICE-DESCRIPTOR request.  Since the descriptor is
         * only 18 bytes long, this will terminate with a short packet.  But if
         * the maxpacket size is 8 or 16 the device may be waiting to transmit
-        * some more, or keeps on retransmitting the 8 byte header. */
+        * some more, or keeps on retransmitting the 8 byte header.
+        */
 
-       dev->descriptor.bMaxPacketSize0 = 64;       /* Start off at 64 bytes  */
-       /* Default to 64 byte max packet size */
-       dev->maxpacketsize = PACKET_SIZE_64;
-       dev->epmaxpacketin[0] = 64;
-       dev->epmaxpacketout[0] = 64;
+       if (dev->speed == USB_SPEED_LOW) {
+               dev->descriptor.bMaxPacketSize0 = 8;
+               dev->maxpacketsize = PACKET_SIZE_8;
+       } else {
+               dev->descriptor.bMaxPacketSize0 = 64;
+               dev->maxpacketsize = PACKET_SIZE_64;
+       }
+       dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0;
+       dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
 
        if (do_read) {
                int err;
@@ -1001,7 +1016,7 @@ static int usb_setup_descriptor(struct usb_device *dev, bool do_read)
 }
 
 static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
-                             struct usb_device *parent, int portnr)
+                             struct usb_device *parent)
 {
        int err;
 
@@ -1019,7 +1034,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
        err = usb_setup_descriptor(dev, do_read);
        if (err)
                return err;
-       err = usb_legacy_port_reset(parent, portnr);
+       err = usb_hub_port_reset(dev, parent);
        if (err)
                return err;
 
@@ -1040,7 +1055,7 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
 
 int usb_select_config(struct usb_device *dev)
 {
-       ALLOC_CACHE_ALIGN_BUFFER(unsigned char, tmpbuf, USB_BUFSIZ);
+       unsigned char *tmpbuf = NULL;
        int err;
 
        err = get_descriptor_len(dev, USB_DT_DEVICE_SIZE, USB_DT_DEVICE_SIZE);
@@ -1053,15 +1068,32 @@ int usb_select_config(struct usb_device *dev)
        le16_to_cpus(&dev->descriptor.idProduct);
        le16_to_cpus(&dev->descriptor.bcdDevice);
 
+       /*
+        * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
+        * about this first Get Descriptor request. If there are any other
+        * requests in the first microframe, the stick crashes. Wait about
+        * one microframe duration here (1mS for USB 1.x , 125uS for USB 2.0).
+        */
+       mdelay(1);
+
        /* only support for one config for now */
-       err = usb_get_configuration_no(dev, tmpbuf, 0);
+       err = usb_get_configuration_len(dev, 0);
+       if (err >= 0) {
+               tmpbuf = (unsigned char *)malloc_cache_aligned(err);
+               if (!tmpbuf)
+                       err = -ENOMEM;
+               else
+                       err = usb_get_configuration_no(dev, 0, tmpbuf, err);
+       }
        if (err < 0) {
                printf("usb_new_device: Cannot read configuration, " \
                       "skipping device %04x:%04x\n",
                       dev->descriptor.idVendor, dev->descriptor.idProduct);
+               free(tmpbuf);
                return err;
        }
        usb_parse_config(dev, tmpbuf, 0);
+       free(tmpbuf);
        usb_set_maxpacket(dev);
        /*
         * we set the default configuration here
@@ -1074,6 +1106,14 @@ int usb_select_config(struct usb_device *dev)
                        "len %d, status %lX\n", dev->act_len, dev->status);
                return err;
        }
+
+       /*
+        * Wait until the Set Configuration request gets processed by the
+        * device. This is required by at least SanDisk Cruzer Pop USB 2.0
+        * and Kingston DT Ultimate 32GB USB 3.0 on DWC2 OTG controller.
+        */
+       mdelay(10);
+
        debug("new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
              dev->descriptor.iManufacturer, dev->descriptor.iProduct,
              dev->descriptor.iSerialNumber);
@@ -1097,7 +1137,7 @@ int usb_select_config(struct usb_device *dev)
 }
 
 int usb_setup_device(struct usb_device *dev, bool do_read,
-                    struct usb_device *parent, int portnr)
+                    struct usb_device *parent)
 {
        int addr;
        int ret;
@@ -1106,7 +1146,7 @@ int usb_setup_device(struct usb_device *dev, bool do_read,
        addr = dev->devnum;
        dev->devnum = 0;
 
-       ret = usb_prepare_device(dev, addr, do_read, parent, portnr);
+       ret = usb_prepare_device(dev, addr, do_read, parent);
        if (ret)
                return ret;
        ret = usb_select_config(dev);
@@ -1133,10 +1173,10 @@ int usb_new_device(struct usb_device *dev)
         * with the device. So a get_descriptor will fail before any
         * of that is done for XHCI unlike EHCI.
         */
-#ifdef CONFIG_USB_XHCI
+#ifdef CONFIG_USB_XHCI_HCD
        do_read = false;
 #endif
-       err = usb_setup_device(dev, do_read, dev->parent, dev->portnr);
+       err = usb_setup_device(dev, do_read, dev->parent);
        if (err)
                return err;
 
@@ -1170,4 +1210,60 @@ bool usb_device_has_child_on_port(struct usb_device *parent, int port)
 #endif
 }
 
+#ifdef CONFIG_DM_USB
+void usb_find_usb2_hub_address_port(struct usb_device *udev,
+                              uint8_t *hub_address, uint8_t *hub_port)
+{
+       struct udevice *parent;
+       struct usb_device *uparent, *ttdev;
+
+       /*
+        * When called from usb-uclass.c: usb_scan_device() udev->dev points
+        * to the parent udevice, not the actual udevice belonging to the
+        * udev as the device is not instantiated yet. So when searching
+        * for the first usb-2 parent start with udev->dev not
+        * udev->dev->parent .
+        */
+       ttdev = udev;
+       parent = udev->dev;
+       uparent = dev_get_parent_priv(parent);
+
+       while (uparent->speed != USB_SPEED_HIGH) {
+               struct udevice *dev = parent;
+
+               if (device_get_uclass_id(dev->parent) != UCLASS_USB_HUB) {
+                       printf("Error: Cannot find high speed parent of usb-1 device\n");
+                       *hub_address = 0;
+                       *hub_port = 0;
+                       return;
+               }
+
+               ttdev = dev_get_parent_priv(dev);
+               parent = dev->parent;
+               uparent = dev_get_parent_priv(parent);
+       }
+       *hub_address = uparent->devnum;
+       *hub_port = ttdev->portnr;
+}
+#else
+void usb_find_usb2_hub_address_port(struct usb_device *udev,
+                              uint8_t *hub_address, uint8_t *hub_port)
+{
+       /* Find out the nearest parent which is high speed */
+       while (udev->parent->parent != NULL)
+               if (udev->parent->speed != USB_SPEED_HIGH) {
+                       udev = udev->parent;
+               } else {
+                       *hub_address = udev->parent->devnum;
+                       *hub_port = udev->portnr;
+                       return;
+               }
+
+       printf("Error: Cannot find high speed parent of usb-1 device\n");
+       *hub_address = 0;
+       *hub_port = 0;
+}
+#endif
+
+
 /* EOF */