]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/usb_storage.c
arm64: add support for Ka-Ro TXSD-410E
[karo-tx-uboot.git] / common / usb_storage.c
index b9784304086ecdc7ec7beaaeedb853af513824de..0345aa22eff5f79e6266b7ce7fd07a3207674d27 100644 (file)
 #include <errno.h>
 #include <inttypes.h>
 #include <mapmem.h>
+#include <memalign.h>
 #include <asm/byteorder.h>
 #include <asm/processor.h>
 #include <dm/device-internal.h>
+#include <dm/lists.h>
 
 #include <part.h>
 #include <usb.h>
@@ -64,10 +66,11 @@ static const unsigned char us_direction[256/8] = {
 static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
 static __u32 CBWTag;
 
-#define USB_MAX_STOR_DEV 5
 static int usb_max_devs; /* number of highest available usb device */
 
-static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV];
+#ifndef CONFIG_BLK
+static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
+#endif
 
 struct us_data;
 typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
@@ -108,28 +111,30 @@ struct us_data {
 #define USB_MAX_XFER_BLK       20
 #endif
 
+#ifndef CONFIG_BLK
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
+#endif
 
 #define USB_STOR_TRANSPORT_GOOD           0
 #define USB_STOR_TRANSPORT_FAILED -1
 #define USB_STOR_TRANSPORT_ERROR  -2
 
 int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
-                     block_dev_desc_t *dev_desc);
+                     struct blk_desc *dev_desc);
 int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
                      struct us_data *ss);
-unsigned long usb_stor_read(int device, lbaint_t blknr,
-                           lbaint_t blkcnt, void *buffer);
-unsigned long usb_stor_write(int device, lbaint_t blknr,
-                            lbaint_t blkcnt, const void *buffer);
-void uhci_show_temp_int_td(void);
-
-#ifdef CONFIG_PARTITIONS
-block_dev_desc_t *usb_stor_get_dev(int index)
-{
-       return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
-}
+#ifdef CONFIG_BLK
+static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
+                                  lbaint_t blkcnt, void *buffer);
+static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
+                                   lbaint_t blkcnt, const void *buffer);
+#else
+static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
+                                  lbaint_t blkcnt, void *buffer);
+static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
+                                   lbaint_t blkcnt, const void *buffer);
 #endif
+void uhci_show_temp_int_td(void);
 
 static void usb_show_progress(void)
 {
@@ -142,6 +147,20 @@ static void usb_show_progress(void)
  */
 int usb_stor_info(void)
 {
+       int count = 0;
+#ifdef CONFIG_BLK
+       struct udevice *dev;
+
+       for (blk_first_device(IF_TYPE_USB, &dev);
+            dev;
+            blk_next_device(&dev)) {
+               struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+               printf("  Device %d: ", desc->devnum);
+               dev_print(desc);
+               count++;
+       }
+#else
        int i;
 
        if (usb_max_devs > 0) {
@@ -151,9 +170,13 @@ int usb_stor_info(void)
                }
                return 0;
        }
+#endif
+       if (!count) {
+               printf("No storage devices, perhaps not 'usb start'ed..?\n");
+               return 1;
+       }
 
-       printf("No storage devices, perhaps not 'usb start'ed..?\n");
-       return 1;
+       return 0;
 }
 
 static unsigned int usb_get_max_lun(struct us_data *us)
@@ -171,52 +194,107 @@ static unsigned int usb_get_max_lun(struct us_data *us)
        return (len > 0) ? *result : 0;
 }
 
-static int usb_stor_probe_device(struct usb_device *dev)
+static int usb_stor_probe_device(struct usb_device *udev)
 {
-       if (dev == NULL)
+       int lun, max_lun;
+
+#ifdef CONFIG_BLK
+       struct us_data *data;
+       int ret;
+#else
+       int start;
+
+       if (udev == NULL)
                return -ENOENT; /* no more devices available */
+#endif
 
        debug("\n\nProbing for storage\n");
-       if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
-               /* OK, it's a storage device.  Iterate over its LUNs
-                       * and populate `usb_dev_desc'.
-                       */
-               int lun, max_lun, start = usb_max_devs;
-
-               max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
-               for (lun = 0;
-                       lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
-                       lun++) {
-                       struct block_dev_desc *blkdev;
-
-                       blkdev = &usb_dev_desc[usb_max_devs];
-                       memset(blkdev, '\0', sizeof(block_dev_desc_t));
-                       blkdev->if_type = IF_TYPE_USB;
-                       blkdev->dev = usb_max_devs;
-                       blkdev->part_type = PART_TYPE_UNKNOWN;
-                       blkdev->target = 0xff;
-                       blkdev->type = DEV_TYPE_UNKNOWN;
-                       blkdev->block_read = usb_stor_read;
-                       blkdev->block_write = usb_stor_write;
-                       blkdev->lun = lun;
-                       blkdev->priv = dev;
-
-                       if (usb_stor_get_info(dev, &usb_stor[start],
-                                             &usb_dev_desc[usb_max_devs]) ==
-                                             1) {
-                               usb_max_devs++;
-                               debug("%s: Found device %p\n", __func__, dev);
-                       }
+#ifdef CONFIG_BLK
+       /*
+        * We store the us_data in the mass storage device's platdata. It
+        * is shared by all LUNs (block devices) attached to this mass storage
+        * device.
+        */
+       data = dev_get_platdata(udev->dev);
+       if (!usb_storage_probe(udev, 0, data))
+               return 0;
+       max_lun = usb_get_max_lun(data);
+       for (lun = 0; lun <= max_lun; lun++) {
+               struct blk_desc *blkdev;
+               struct udevice *dev;
+               char str[10];
+
+               snprintf(str, sizeof(str), "lun%d", lun);
+               ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
+                                        IF_TYPE_USB, usb_max_devs, 512, 0,
+                                        &dev);
+               if (ret) {
+                       debug("Cannot bind driver\n");
+                       return ret;
                }
-       }
 
-       /* if storage device */
+               blkdev = dev_get_uclass_platdata(dev);
+               blkdev->target = 0xff;
+               blkdev->lun = lun;
+
+               ret = usb_stor_get_info(udev, data, blkdev);
+               if (ret == 1)
+                       ret = blk_prepare_device(dev);
+               if (!ret) {
+                       usb_max_devs++;
+                       debug("%s: Found device %p\n", __func__, udev);
+               } else {
+                       debug("usb_stor_get_info: Invalid device\n");
+                       ret = device_unbind(dev);
+                       if (ret)
+                               return ret;
+               }
+       }
+#else
+       /* We don't have space to even probe if we hit the maximum */
        if (usb_max_devs == USB_MAX_STOR_DEV) {
                printf("max USB Storage Device reached: %d stopping\n",
                       usb_max_devs);
                return -ENOSPC;
        }
 
+       if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
+               return 0;
+
+       /*
+        * OK, it's a storage device.  Iterate over its LUNs and populate
+        * usb_dev_desc'
+        */
+       start = usb_max_devs;
+
+       max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
+       for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
+            lun++) {
+               struct blk_desc *blkdev;
+
+               blkdev = &usb_dev_desc[usb_max_devs];
+               memset(blkdev, '\0', sizeof(struct blk_desc));
+               blkdev->if_type = IF_TYPE_USB;
+               blkdev->devnum = usb_max_devs;
+               blkdev->part_type = PART_TYPE_UNKNOWN;
+               blkdev->target = 0xff;
+               blkdev->type = DEV_TYPE_UNKNOWN;
+               blkdev->block_read = usb_stor_read;
+               blkdev->block_write = usb_stor_write;
+               blkdev->lun = lun;
+               blkdev->priv = udev;
+
+               if (usb_stor_get_info(udev, &usb_stor[start],
+                                     &usb_dev_desc[usb_max_devs]) == 1) {
+                       debug("partype: %d\n", blkdev->part_type);
+                       part_init(blkdev);
+                       debug("partype: %d\n", blkdev->part_type);
+                       usb_max_devs++;
+                       debug("%s: Found device %p\n", __func__, udev);
+               }
+       }
+#endif
+
        return 0;
 }
 
@@ -599,7 +677,7 @@ static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
                us->ip_wanted = 0;
                return USB_STOR_TRANSPORT_ERROR;
        }
-       debug("Got interrupt data 0x%x, transfered %d status 0x%lX\n",
+       debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
              us->ip_data, us->pusb_dev->irq_act_len,
              us->pusb_dev->irq_status);
        /* UFI gives us ASC and ASCQ, like a request sense */
@@ -630,13 +708,10 @@ static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
 /* clear a stall on an endpoint - special for BBB devices */
 static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
 {
-       int result;
-
        /* ENDPOINT_HALT = 0, so set value to 0 */
-       result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
-                               USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
-                               0, endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
-       return result;
+       return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+                              USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+                              endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
 }
 
 static int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
@@ -1011,7 +1086,7 @@ static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
  * device with proper values (as reported by 'usb info').
  *
  * Vendor and product length limits are taken from the definition of
- * block_dev_desc_t in include/part.h.
+ * struct blk_desc in include/part.h.
  */
 static void usb_bin_fixup(struct usb_device_descriptor descriptor,
                                unsigned char vendor[],
@@ -1026,38 +1101,50 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,
 }
 #endif /* CONFIG_USB_BIN_FIXUP */
 
-unsigned long usb_stor_read(int device, lbaint_t blknr,
-                           lbaint_t blkcnt, void *buffer)
+#ifdef CONFIG_BLK
+static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
+                                  lbaint_t blkcnt, void *buffer)
+#else
+static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
+                                  lbaint_t blkcnt, void *buffer)
+#endif
 {
        lbaint_t start, blks;
        uintptr_t buf_addr;
        unsigned short smallblks;
-       struct usb_device *dev;
+       struct usb_device *udev;
        struct us_data *ss;
        int retry;
        ccb *srb = &usb_ccb;
+#ifdef CONFIG_BLK
+       struct blk_desc *block_dev;
+#endif
 
        if (blkcnt == 0)
                return 0;
-
-       device &= 0xff;
        /* Setup  device */
-       debug("\nusb_read: dev %d\n", device);
-       dev = usb_dev_desc[device].priv;
-       if (!dev) {
+#ifdef CONFIG_BLK
+       block_dev = dev_get_uclass_platdata(dev);
+       udev = dev_get_parent_priv(dev_get_parent(dev));
+       debug("\nusb_read: udev %d\n", block_dev->devnum);
+#else
+       debug("\nusb_read: udev %d\n", block_dev->devnum);
+       udev = usb_dev_desc[block_dev->devnum].priv;
+       if (!udev) {
                debug("%s: No device\n", __func__);
                return 0;
        }
-       ss = (struct us_data *)dev->privptr;
+#endif
+       ss = (struct us_data *)udev->privptr;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
-       srb->lun = usb_dev_desc[device].lun;
+       srb->lun = block_dev->lun;
        buf_addr = (uintptr_t)buffer;
        start = blknr;
        blks = blkcnt;
 
-       debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF
-             " buffer %" PRIxPTR "\n", device, start, blks, buf_addr);
+       debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %"
+             PRIxPTR "\n", block_dev->devnum, start, blks, buf_addr);
 
        do {
                /* XXX need some comment here */
@@ -1070,7 +1157,7 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
 retry_it:
                if (smallblks == USB_MAX_XFER_BLK)
                        usb_show_progress();
-               srb->datalen = usb_dev_desc[device].blksz * smallblks;
+               srb->datalen = block_dev->blksz * smallblks;
                srb->pdata = (unsigned char *)buf_addr;
                if (usb_read_10(srb, ss, start, smallblks)) {
                        debug("Read ERROR\n");
@@ -1096,37 +1183,52 @@ retry_it:
        return blkcnt;
 }
 
-unsigned long usb_stor_write(int device, lbaint_t blknr,
-                               lbaint_t blkcnt, const void *buffer)
+#ifdef CONFIG_BLK
+static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
+                                   lbaint_t blkcnt, const void *buffer)
+#else
+static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
+                                   lbaint_t blkcnt, const void *buffer)
+#endif
 {
        lbaint_t start, blks;
        uintptr_t buf_addr;
        unsigned short smallblks;
-       struct usb_device *dev;
+       struct usb_device *udev;
        struct us_data *ss;
        int retry;
        ccb *srb = &usb_ccb;
+#ifdef CONFIG_BLK
+       struct blk_desc *block_dev;
+#endif
 
        if (blkcnt == 0)
                return 0;
 
-       device &= 0xff;
        /* Setup  device */
-       debug("\nusb_write: dev %d\n", device);
-       dev = usb_dev_desc[device].priv;
-       if (!dev)
+#ifdef CONFIG_BLK
+       block_dev = dev_get_uclass_platdata(dev);
+       udev = dev_get_parent_priv(dev_get_parent(dev));
+       debug("\nusb_read: udev %d\n", block_dev->devnum);
+#else
+       debug("\nusb_read: udev %d\n", block_dev->devnum);
+       udev = usb_dev_desc[block_dev->devnum].priv;
+       if (!udev) {
+               debug("%s: No device\n", __func__);
                return 0;
-       ss = (struct us_data *)dev->privptr;
+       }
+#endif
+       ss = (struct us_data *)udev->privptr;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
 
-       srb->lun = usb_dev_desc[device].lun;
+       srb->lun = block_dev->lun;
        buf_addr = (uintptr_t)buffer;
        start = blknr;
        blks = blkcnt;
 
-       debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF
-             " buffer %" PRIxPTR "\n", device, start, blks, buf_addr);
+       debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %"
+             PRIxPTR "\n", block_dev->devnum, start, blks, buf_addr);
 
        do {
                /* If write fails retry for max retry count else
@@ -1141,7 +1243,7 @@ unsigned long usb_stor_write(int device, lbaint_t blknr,
 retry_it:
                if (smallblks == USB_MAX_XFER_BLK)
                        usb_show_progress();
-               srb->datalen = usb_dev_desc[device].blksz * smallblks;
+               srb->datalen = block_dev->blksz * smallblks;
                srb->pdata = (unsigned char *)buf_addr;
                if (usb_write_10(srb, ss, start, smallblks)) {
                        debug("Write ERROR\n");
@@ -1176,25 +1278,9 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
        struct usb_endpoint_descriptor *ep_desc;
        unsigned int flags = 0;
 
-       int protocol = 0;
-       int subclass = 0;
-
        /* let's examine the device now */
        iface = &dev->config.if_desc[ifnum];
 
-#if 0
-       /* this is the place to patch some storage devices */
-       debug("iVendor %X iProduct %X\n", dev->descriptor.idVendor,
-                       dev->descriptor.idProduct);
-
-       if ((dev->descriptor.idVendor) == 0x066b &&
-           (dev->descriptor.idProduct) == 0x0103) {
-               debug("patched for E-USB\n");
-               protocol = US_PR_CB;
-               subclass = US_SC_UFI;       /* an assumption */
-       }
-#endif
-
        if (dev->descriptor.bDeviceClass != 0 ||
                        iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
                        iface->desc.bInterfaceSubClass < US_SC_MIN ||
@@ -1214,17 +1300,8 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
        ss->ifnum = ifnum;
        ss->pusb_dev = dev;
        ss->attention_done = 0;
-
-       /* If the device has subclass and protocol, then use that.  Otherwise,
-        * take data from the specific interface.
-        */
-       if (subclass) {
-               ss->subclass = subclass;
-               ss->protocol = protocol;
-       } else {
-               ss->subclass = iface->desc.bInterfaceSubClass;
-               ss->protocol = iface->desc.bInterfaceProtocol;
-       }
+       ss->subclass = iface->desc.bInterfaceSubClass;
+       ss->protocol = iface->desc.bInterfaceProtocol;
 
        /* set the handler pointers based on the protocol */
        debug("Transport: ");
@@ -1312,7 +1389,7 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
 }
 
 int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
-                     block_dev_desc_t *dev_desc)
+                     struct blk_desc *dev_desc)
 {
        unsigned char perq, modi;
        ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
@@ -1395,11 +1472,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
        dev_desc->log2blksz = LOG2(dev_desc->blksz);
        dev_desc->type = perq;
        debug(" address %d\n", dev_desc->target);
-       debug("partype: %d\n", dev_desc->part_type);
 
-       init_part(dev_desc);
-
-       debug("partype: %d\n", dev_desc->part_type);
        return 1;
 }
 
@@ -1407,7 +1480,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
 
 static int usb_mass_storage_probe(struct udevice *dev)
 {
-       struct usb_device *udev = dev_get_parentdata(dev);
+       struct usb_device *udev = dev_get_parent_priv(dev);
        int ret;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
@@ -1427,6 +1500,9 @@ U_BOOT_DRIVER(usb_mass_storage) = {
        .id     = UCLASS_MASS_STORAGE,
        .of_match = usb_mass_storage_ids,
        .probe = usb_mass_storage_probe,
+#ifdef CONFIG_BLK
+       .platdata_auto_alloc_size       = sizeof(struct us_data),
+#endif
 };
 
 UCLASS_DRIVER(usb_mass_storage) = {
@@ -1443,5 +1519,24 @@ static const struct usb_device_id mass_storage_id_table[] = {
 };
 
 U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
+#endif
+
+#ifdef CONFIG_BLK
+static const struct blk_ops usb_storage_ops = {
+       .read   = usb_stor_read,
+       .write  = usb_stor_write,
+};
 
+U_BOOT_DRIVER(usb_storage_blk) = {
+       .name           = "usb_storage_blk",
+       .id             = UCLASS_BLK,
+       .ops            = &usb_storage_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(usb) = {
+       .if_typename    = "usb",
+       .if_type        = IF_TYPE_USB,
+       .max_devs       = USB_MAX_STOR_DEV,
+       .desc           = usb_dev_desc,
+};
 #endif