Merge tag 'dwc3-for-v3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 Mar 2012 23:56:33 +0000 (15:56 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 Mar 2012 23:56:33 +0000 (15:56 -0800)
usb: dwc3: changes for v3.4 merge window

Here are the changes for v3.4 merge window.

It includes a new glue layer for Samsung's Exynos platform, a simplification of
memory management on DWC3 driver by using dev_xxx functions, a few
optimizations to IRQ handling by dropping memcpy() and using bitshifts, a fix
for TI's OMAP5430 TX Fifo Allocation, two fixes on USB2 test mode
implementation (one on debugfs and one on ep0), and several minor changes such
as whitespace cleanups, simplification of a few parts of the code, decreasing a
long delay to something a bit saner, dropping a header which was included twice
and so on.

The highlight on this merge is the support for Samsung's Exynos platform,
increasing the number of different users for this driver to three.

Note that Samsung Exynos glue layer will only compile on platforms which
provide implementation for the clk API for now. Once Samsung supports
pm_runtime, that limitation can be dropped from the Makefile.

Conflicts:
drivers/usb/dwc3/gadget.c

12 files changed:
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-exynos.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c
include/linux/platform_data/dwc3-exynos.h [new file with mode: 0644]

index 900ae74357f1583b342a2e96f3a05d6aab635221..d441fe4c180b9f9d15c1c34f8428a82a5f20d638 100644 (file)
@@ -28,6 +28,19 @@ endif
 
 obj-$(CONFIG_USB_DWC3)         += dwc3-omap.o
 
+##
+# REVISIT Samsung Exynos platform needs the clk API which isn't
+# defined on all architectures. If we allow dwc3-exynos.c compile
+# always we will fail the linking phase on those architectures
+# which don't provide clk api implementation and that's unnaceptable.
+#
+# When Samsung's platform start supporting pm_runtime, this check
+# for HAVE_CLK should be removed.
+##
+ifneq ($(CONFIG_HAVE_CLK),)
+       obj-$(CONFIG_USB_DWC3)          += dwc3-exynos.o
+endif
+
 ifneq ($(CONFIG_PCI),)
        obj-$(CONFIG_USB_DWC3)          += dwc3-pci.o
 endif
index 7c9df630dbe4f848be07dda04a3f2a295a78d7c7..fd6917b8d0d73ec302e10b17cdaffa067da5adfc 100644 (file)
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/module.h>
 
 #include "core.h"
 #include "gadget.h"
@@ -86,7 +86,7 @@ again:
                id = -ENOMEM;
        }
 
-       return 0;
+       return id;
 }
 EXPORT_SYMBOL_GPL(dwc3_get_device_id);
 
@@ -167,11 +167,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
 }
 
 /**
- * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
  * @dwc: Pointer to our controller context structure
  * @length: size of the event buffer
  *
- * Returns a pointer to the allocated event buffer structure on succes
+ * Returns a pointer to the allocated event buffer structure on success
  * otherwise ERR_PTR(errno).
  */
 static struct dwc3_event_buffer *__devinit
@@ -215,10 +215,10 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
 
 /**
  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  * @length: size of event buffer
  *
- * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * Returns 0 on success otherwise negative errno. In the error case, dwc
  * may contain some buffers allocated but not all which were requested.
  */
 static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
@@ -251,7 +251,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 
 /**
  * dwc3_event_buffers_setup - setup our allocated event buffers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
@@ -350,7 +350,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
        dwc3_cache_hwparams(dwc);
 
        reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-       reg &= ~DWC3_GCTL_SCALEDOWN(3);
+       reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
        reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
        switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
@@ -363,9 +363,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 
        /*
         * WORKAROUND: DWC3 revisions <1.90a have a bug
-        * when The device fails to connect at SuperSpeed
+        * where the device can fail to connect at SuperSpeed
         * and falls back to high-speed mode which causes
-        * the device to enter in a Connect/Disconnect loop
+        * the device to enter a Connect/Disconnect loop
         */
        if (dwc->revision < DWC3_REVISION_190A)
                reg |= DWC3_GCTL_U2RSTECN;
@@ -404,8 +404,10 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
+       struct device_node      *node = pdev->dev.of_node;
        struct resource         *res;
        struct dwc3             *dwc;
+       struct device           *dev = &pdev->dev;
 
        int                     ret = -ENOMEM;
        int                     irq;
@@ -415,39 +417,39 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
 
        u8                      mode;
 
-       mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+       mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
        if (!mem) {
-               dev_err(&pdev->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
        dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
        dwc->mem = mem;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               dev_err(&pdev->dev, "missing resource\n");
-               goto err1;
+               dev_err(dev, "missing resource\n");
+               return -ENODEV;
        }
 
        dwc->res = res;
 
-       res = request_mem_region(res->start, resource_size(res),
-                       dev_name(&pdev->dev));
+       res = devm_request_mem_region(dev, res->start, resource_size(res),
+                       dev_name(dev));
        if (!res) {
-               dev_err(&pdev->dev, "can't request mem region\n");
-               goto err1;
+               dev_err(dev, "can't request mem region\n");
+               return -ENOMEM;
        }
 
-       regs = ioremap(res->start, resource_size(res));
+       regs = devm_ioremap(dev, res->start, resource_size(res));
        if (!regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               goto err2;
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ\n");
-               goto err3;
+               dev_err(dev, "missing IRQ\n");
+               return -ENODEV;
        }
 
        spin_lock_init(&dwc->lock);
@@ -455,7 +457,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
 
        dwc->regs       = regs;
        dwc->regs_size  = resource_size(res);
-       dwc->dev        = &pdev->dev;
+       dwc->dev        = dev;
        dwc->irq        = irq;
 
        if (!strncmp("super", maximum_speed, 5))
@@ -469,14 +471,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
        else
                dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
-       pm_runtime_forbid(&pdev->dev);
+       if (of_get_property(node, "tx-fifo-resize", NULL))
+               dwc->needs_fifo_resize = true;
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       pm_runtime_forbid(dev);
 
        ret = dwc3_core_init(dwc);
        if (ret) {
-               dev_err(&pdev->dev, "failed to initialize core\n");
-               goto err3;
+               dev_err(dev, "failed to initialize core\n");
+               return ret;
        }
 
        mode = DWC3_MODE(dwc->hwparams.hwparams0);
@@ -486,49 +491,49 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize gadget\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize gadget\n");
+                       goto err1;
                }
                break;
        case DWC3_MODE_HOST:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize host\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize host\n");
+                       goto err1;
                }
                break;
        case DWC3_MODE_DRD:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize host\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize host\n");
+                       goto err1;
                }
 
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize gadget\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize gadget\n");
+                       goto err1;
                }
                break;
        default:
-               dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
-               goto err4;
+               dev_err(dev, "Unsupported mode of operation %d\n", mode);
+               goto err1;
        }
        dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
-               dev_err(&pdev->dev, "failed to initialize debugfs\n");
-               goto err5;
+               dev_err(dev, "failed to initialize debugfs\n");
+               goto err2;
        }
 
-       pm_runtime_allow(&pdev->dev);
+       pm_runtime_allow(dev);
 
        return 0;
 
-err5:
+err2:
        switch (mode) {
        case DWC3_MODE_DEVICE:
                dwc3_gadget_exit(dwc);
@@ -545,19 +550,9 @@ err5:
                break;
        }
 
-err4:
-       dwc3_core_exit(dwc);
-
-err3:
-       iounmap(regs);
-
-err2:
-       release_mem_region(res->start, resource_size(res));
-
 err1:
-       kfree(dwc->mem);
+       dwc3_core_exit(dwc);
 
-err0:
        return ret;
 }
 
@@ -590,9 +585,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
        }
 
        dwc3_core_exit(dwc);
-       release_mem_region(res->start, resource_size(res));
-       iounmap(dwc->regs);
-       kfree(dwc->mem);
 
        return 0;
 }
index a72f42ffbbee9e44dbad8250bc9c2c182fcc6f65..6c7945b4cad323f6019919e40c68b2b0991d9867 100644 (file)
 /* Bit fields */
 
 /* Global Configuration Register */
-#define DWC3_GCTL_PWRDNSCALE(n)        (n << 19)
+#define DWC3_GCTL_PWRDNSCALE(n)        ((n) << 19)
 #define DWC3_GCTL_U2RSTECN     (1 << 16)
-#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS      (0)
 #define DWC3_GCTL_CLK_PIPE     (1)
 #define DWC3_GCTL_CLK_PIPEHALF (2)
 #define DWC3_GCTL_CLK_MASK     (3)
 
 #define DWC3_GCTL_PRTCAP(n)    (((n) & (3 << 12)) >> 12)
-#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
+#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
 #define DWC3_GCTL_PRTCAP_HOST  1
 #define DWC3_GCTL_PRTCAP_DEVICE        2
 #define DWC3_GCTL_PRTCAP_OTG   3
 
 #define DWC3_GCTL_CORESOFTRESET        (1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
+#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
 #define DWC3_GCTL_DISSCRAMBLE  (1 << 3)
 #define DWC3_GCTL_DSBLCLKGTNG  (1 << 0)
 
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
 
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
 /* Global HWPARAMS1 Register */
-#define DWC3_GHWPARAMS1_EN_PWROPT(n)   ((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)   (((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO   0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK  1
 
 
 #define DWC3_DCTL_APPL1RES     (1 << 23)
 
+#define DWC3_DCTL_TRGTULST_MASK        (0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)  ((n) << 17)
+
+#define DWC3_DCTL_TRGTULST_U2  (DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3  (DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+
 #define DWC3_DCTL_INITU2ENA    (1 << 12)
 #define DWC3_DCTL_ACCEPTU2ENA  (1 << 11)
 #define DWC3_DCTL_INITU1ENA    (1 << 10)
 
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT                16
-#define DWC3_DEPCMD_PARAM(x)           (x << DWC3_DEPCMD_PARAM_SHIFT)
-#define DWC3_DEPCMD_GET_RSC_IDX(x)     ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_PARAM(x)           ((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
 #define DWC3_DEPCMD_STATUS_MASK                (0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x)          ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x)          (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
 #define DWC3_DEPCMD_HIPRI_FORCERM      (1 << 11)
 #define DWC3_DEPCMD_CMDACT             (1 << 10)
 #define DWC3_DEPCMD_CMDIOC             (1 << 8)
 
 /* Structures */
 
-struct dwc3_trb_hw;
+struct dwc3_trb;
 
 /**
  * struct dwc3_event_buffer - Software event buffer representation
@@ -343,7 +357,7 @@ struct dwc3_ep {
        struct list_head        request_list;
        struct list_head        req_queued;
 
-       struct dwc3_trb_hw      *trb_pool;
+       struct dwc3_trb         *trb_pool;
        dma_addr_t              trb_pool_dma;
        u32                     free_slot;
        u32                     busy_slot;
@@ -418,102 +432,49 @@ enum dwc3_device_state {
        DWC3_CONFIGURED_STATE,
 };
 
-/**
- * struct dwc3_trb - transfer request block
- * @bpl: lower 32bit of the buffer
- * @bph: higher 32bit of the buffer
- * @length: buffer size (up to 16mb - 1)
- * @pcm1: packet count m1
- * @trbsts: trb status
- *     0 = ok
- *     1 = missed isoc
- *     2 = setup pending
- * @hwo: hardware owner of descriptor
- * @lst: last trb
- * @chn: chain buffers
- * @csp: continue on short packets (only supported on isoc eps)
- * @trbctl: trb control
- *     1 = normal
- *     2 = control-setup
- *     3 = control-status-2
- *     4 = control-status-3
- *     5 = control-data (first trb of data stage)
- *     6 = isochronous-first (first trb of service interval)
- *     7 = isochronous
- *     8 = link trb
- *     others = reserved
- * @isp_imi: interrupt on short packet / interrupt on missed isoc
- * @ioc: interrupt on complete
- * @sid_sofn: Stream ID / SOF Number
- */
-struct dwc3_trb {
-       u64             bplh;
-
-       union {
-               struct {
-                       u32             length:24;
-                       u32             pcm1:2;
-                       u32             reserved27_26:2;
-                       u32             trbsts:4;
-#define DWC3_TRB_STS_OKAY                       0
-#define DWC3_TRB_STS_MISSED_ISOC                1
-#define DWC3_TRB_STS_SETUP_PENDING              2
-               };
-               u32 len_pcm;
-       };
-
-       union {
-               struct {
-                       u32             hwo:1;
-                       u32             lst:1;
-                       u32             chn:1;
-                       u32             csp:1;
-                       u32             trbctl:6;
-                       u32             isp_imi:1;
-                       u32             ioc:1;
-                       u32             reserved13_12:2;
-                       u32             sid_sofn:16;
-                       u32             reserved31_30:2;
-               };
-               u32 control;
-       };
-} __packed;
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK     (0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n)        ((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n)  (((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n)        (((n) & (0x0f << 28) >> 28))
+
+#define DWC3_TRBSTS_OK                 0
+#define DWC3_TRBSTS_MISSED_ISOC                1
+#define DWC3_TRBSTS_SETUP_PENDING      2
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO              (1 << 0)
+#define DWC3_TRB_CTRL_LST              (1 << 1)
+#define DWC3_TRB_CTRL_CHN              (1 << 2)
+#define DWC3_TRB_CTRL_CSP              (1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n)                (((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI          (1 << 10)
+#define DWC3_TRB_CTRL_IOC              (1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)      (((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL             DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP      DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2    DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3    DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA       DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST  DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS                DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB           DWC3_TRB_CTRL_TRBCTL(8)
 
 /**
- * struct dwc3_trb_hw - transfer request block (hw format)
+ * struct dwc3_trb - transfer request block (hw format)
  * @bpl: DW0-3
  * @bph: DW4-7
  * @size: DW8-B
  * @trl: DWC-F
  */
-struct dwc3_trb_hw {
-       __le32          bpl;
-       __le32          bph;
-       __le32          size;
-       __le32          ctrl;
+struct dwc3_trb {
+       u32             bpl;
+       u32             bph;
+       u32             size;
+       u32             ctrl;
 } __packed;
 
-static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
-{
-       hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
-       hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
-       hw->size = cpu_to_le32p(&nat->len_pcm);
-       /* HWO is written last */
-       hw->ctrl = cpu_to_le32p(&nat->control);
-}
-
-static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
-{
-       u64 bplh;
-
-       bplh = le32_to_cpup(&hw->bpl);
-       bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
-       nat->bplh = bplh;
-
-       nat->len_pcm = le32_to_cpup(&hw->size);
-       nat->control = le32_to_cpup(&hw->ctrl);
-}
-
 /**
  * dwc3_hwparams - copy of HWPARAMS registers
  * @hwparams0 - GHWPARAMS0
@@ -546,8 +507,13 @@ struct dwc3_hwparams {
 #define DWC3_MODE_DRD          2
 #define DWC3_MODE_HUB          3
 
+#define DWC3_MDWIDTH(n)                (((n) & 0xff00) >> 8)
+
 /* HWPARAMS1 */
-#define DWC3_NUM_INT(n)        (((n) & (0x3f << 15)) >> 15)
+#define DWC3_NUM_INT(n)                (((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)     ((n) & 0xffff)
 
 struct dwc3_request {
        struct usb_request      request;
@@ -555,7 +521,7 @@ struct dwc3_request {
        struct dwc3_ep          *dep;
 
        u8                      epnum;
-       struct dwc3_trb_hw      *trb;
+       struct dwc3_trb         *trb;
        dma_addr_t              trb_dma;
 
        unsigned                direction:1;
@@ -593,6 +559,8 @@ struct dwc3_request {
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -603,7 +571,7 @@ struct dwc3_request {
  */
 struct dwc3 {
        struct usb_ctrlrequest  *ctrl_req;
-       struct dwc3_trb_hw      *ep0_trb;
+       struct dwc3_trb         *ep0_trb;
        void                    *ep0_bounce;
        u8                      *setup_buf;
        dma_addr_t              ctrl_req_addr;
@@ -649,6 +617,8 @@ struct dwc3 {
        unsigned                start_config_issued:1;
        unsigned                setup_packet_pending:1;
        unsigned                delayed_status:1;
+       unsigned                needs_fifo_resize:1;
+       unsigned                resize_fifos:1;
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
@@ -660,23 +630,13 @@ struct dwc3 {
 
        struct dwc3_hwparams    hwparams;
        struct dentry           *root;
+
+       u8                      test_mode;
+       u8                      test_mode_nr;
 };
 
 /* -------------------------------------------------------------------------- */
 
-#define DWC3_TRBSTS_OK                 0
-#define DWC3_TRBSTS_MISSED_ISOC                1
-#define DWC3_TRBSTS_SETUP_PENDING      2
-
-#define DWC3_TRBCTL_NORMAL             1
-#define DWC3_TRBCTL_CONTROL_SETUP      2
-#define DWC3_TRBCTL_CONTROL_STATUS2    3
-#define DWC3_TRBCTL_CONTROL_STATUS3    4
-#define DWC3_TRBCTL_CONTROL_DATA       5
-#define DWC3_TRBCTL_ISOCHRONOUS_FIRST  6
-#define DWC3_TRBCTL_ISOCHRONOUS                7
-#define DWC3_TRBCTL_LINK_TRB           8
-
 /* -------------------------------------------------------------------------- */
 
 struct dwc3_event_type {
@@ -717,9 +677,14 @@ struct dwc3_event_depevt {
        u32     endpoint_event:4;
        u32     reserved11_10:2;
        u32     status:4;
-#define DEPEVT_STATUS_BUSERR    (1 << 0)
-#define DEPEVT_STATUS_SHORT     (1 << 1)
-#define DEPEVT_STATUS_IOC       (1 << 2)
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE  (1 << 3)
+
+/* Within XferComplete */
+#define DEPEVT_STATUS_BUSERR   (1 << 0)
+#define DEPEVT_STATUS_SHORT    (1 << 1)
+#define DEPEVT_STATUS_IOC      (1 << 2)
 #define DEPEVT_STATUS_LST      (1 << 3)
 
 /* Stream event only */
@@ -805,6 +770,7 @@ union dwc3_event {
 
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
index 433c97c15fc5447f6cbfb4c5b974ae3fbe674ff2..d4a30f11872425018176196ddbade2eeb92ef6ff 100644 (file)
@@ -46,6 +46,8 @@
 #include <linux/delay.h>
 #include <linux/uaccess.h>
 
+#include <linux/usb/ch9.h>
+
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
@@ -464,6 +466,192 @@ static const struct file_operations dwc3_mode_fops = {
        .release                = single_release,
 };
 
+static int dwc3_testmode_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= DWC3_DCTL_TSTCTRL_MASK;
+       reg >>= 1;
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (reg) {
+       case 0:
+               seq_printf(s, "no test\n");
+               break;
+       case TEST_J:
+               seq_printf(s, "test_j\n");
+               break;
+       case TEST_K:
+               seq_printf(s, "test_k\n");
+               break;
+       case TEST_SE0_NAK:
+               seq_printf(s, "test_se0_nak\n");
+               break;
+       case TEST_PACKET:
+               seq_printf(s, "test_packet\n");
+               break;
+       case TEST_FORCE_EN:
+               seq_printf(s, "test_force_enable\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", reg);
+       }
+
+       return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     testmode = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "test_j", 6))
+               testmode = TEST_J;
+       else if (!strncmp(buf, "test_k", 6))
+               testmode = TEST_K;
+       else if (!strncmp(buf, "test_se0_nak", 12))
+               testmode = TEST_SE0_NAK;
+       else if (!strncmp(buf, "test_packet", 11))
+               testmode = TEST_PACKET;
+       else if (!strncmp(buf, "test_force_enable", 17))
+               testmode = TEST_FORCE_EN;
+       else
+               testmode = 0;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_gadget_set_test_mode(dwc, testmode);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+       .open                   = dwc3_testmode_open,
+       .write                  = dwc3_testmode_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
+static int dwc3_link_state_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       enum dwc3_link_state    state;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+       state = DWC3_DSTS_USBLNKST(reg);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (state) {
+       case DWC3_LINK_STATE_U0:
+               seq_printf(s, "U0\n");
+               break;
+       case DWC3_LINK_STATE_U1:
+               seq_printf(s, "U1\n");
+               break;
+       case DWC3_LINK_STATE_U2:
+               seq_printf(s, "U2\n");
+               break;
+       case DWC3_LINK_STATE_U3:
+               seq_printf(s, "U3\n");
+               break;
+       case DWC3_LINK_STATE_SS_DIS:
+               seq_printf(s, "SS.Disabled\n");
+               break;
+       case DWC3_LINK_STATE_RX_DET:
+               seq_printf(s, "Rx.Detect\n");
+               break;
+       case DWC3_LINK_STATE_SS_INACT:
+               seq_printf(s, "SS.Inactive\n");
+               break;
+       case DWC3_LINK_STATE_POLL:
+               seq_printf(s, "Poll\n");
+               break;
+       case DWC3_LINK_STATE_RECOV:
+               seq_printf(s, "Recovery\n");
+               break;
+       case DWC3_LINK_STATE_HRESET:
+               seq_printf(s, "HRESET\n");
+               break;
+       case DWC3_LINK_STATE_CMPLY:
+               seq_printf(s, "Compliance\n");
+               break;
+       case DWC3_LINK_STATE_LPBK:
+               seq_printf(s, "Loopback\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", reg);
+       }
+
+       return 0;
+}
+
+static int dwc3_link_state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_link_state_show, inode->i_private);
+}
+
+static ssize_t dwc3_link_state_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       enum dwc3_link_state    state = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "SS.Disabled", 11))
+               state = DWC3_LINK_STATE_SS_DIS;
+       else if (!strncmp(buf, "Rx.Detect", 9))
+               state = DWC3_LINK_STATE_RX_DET;
+       else if (!strncmp(buf, "SS.Inactive", 11))
+               state = DWC3_LINK_STATE_SS_INACT;
+       else if (!strncmp(buf, "Recovery", 8))
+               state = DWC3_LINK_STATE_RECOV;
+       else if (!strncmp(buf, "Compliance", 10))
+               state = DWC3_LINK_STATE_CMPLY;
+       else if (!strncmp(buf, "Loopback", 8))
+               state = DWC3_LINK_STATE_LPBK;
+       else
+               return -EINVAL;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_gadget_set_link_state(dwc, state);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return count;
+}
+
+static const struct file_operations dwc3_link_state_fops = {
+       .open                   = dwc3_link_state_open,
+       .write                  = dwc3_link_state_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
        struct dentry           *root;
@@ -471,8 +659,8 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
        int                     ret;
 
        root = debugfs_create_dir(dev_name(dwc->dev), NULL);
-       if (IS_ERR(root)) {
-               ret = PTR_ERR(root);
+       if (!root) {
+               ret = -ENOMEM;
                goto err0;
        }
 
@@ -480,15 +668,29 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 
        file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
                        &dwc3_regdump_fops);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
+       if (!file) {
+               ret = -ENOMEM;
                goto err1;
        }
 
        file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
                        dwc, &dwc3_mode_fops);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+                       dwc, &dwc3_testmode_fops);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+                       dwc, &dwc3_link_state_fops);
+       if (!file) {
+               ret = -ENOMEM;
                goto err1;
        }
 
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
new file mode 100644 (file)
index 0000000..d190301
--- /dev/null
@@ -0,0 +1,151 @@
+/**
+ * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-exynos.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#include "core.h"
+
+struct dwc3_exynos {
+       struct platform_device  *dwc3;
+       struct device           *dev;
+
+       struct clk              *clk;
+};
+
+static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
+{
+       struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+       struct platform_device  *dwc3;
+       struct dwc3_exynos      *exynos;
+       struct clk              *clk;
+
+       int                     devid;
+       int                     ret = -ENOMEM;
+
+       exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
+       if (!exynos) {
+               dev_err(&pdev->dev, "not enough memory\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, exynos);
+
+       devid = dwc3_get_device_id();
+       if (devid < 0)
+               goto err1;
+
+       dwc3 = platform_device_alloc("dwc3", devid);
+       if (!dwc3) {
+               dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+               goto err2;
+       }
+
+       clk = clk_get(&pdev->dev, "usbdrd30");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "couldn't get clock\n");
+               ret = -EINVAL;
+               goto err3;
+       }
+
+       dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+       dwc3->dev.parent = &pdev->dev;
+       dwc3->dev.dma_mask = pdev->dev.dma_mask;
+       dwc3->dev.dma_parms = pdev->dev.dma_parms;
+       exynos->dwc3    = dwc3;
+       exynos->dev     = &pdev->dev;
+       exynos->clk     = clk;
+
+       clk_enable(exynos->clk);
+
+       /* PHY initialization */
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "missing platform data\n");
+       } else {
+               if (pdata->phy_init)
+                       pdata->phy_init(pdev, pdata->phy_type);
+       }
+
+       ret = platform_device_add_resources(dwc3, pdev->resource,
+                       pdev->num_resources);
+       if (ret) {
+               dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+               goto err4;
+       }
+
+       ret = platform_device_add(dwc3);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register dwc3 device\n");
+               goto err4;
+       }
+
+       return 0;
+
+err4:
+       if (pdata && pdata->phy_exit)
+               pdata->phy_exit(pdev, pdata->phy_type);
+
+       clk_disable(clk);
+       clk_put(clk);
+err3:
+       platform_device_put(dwc3);
+err2:
+       dwc3_put_device_id(devid);
+err1:
+       kfree(exynos);
+err0:
+       return ret;
+}
+
+static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
+{
+       struct dwc3_exynos      *exynos = platform_get_drvdata(pdev);
+       struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+
+       platform_device_unregister(exynos->dwc3);
+
+       dwc3_put_device_id(exynos->dwc3->id);
+
+       if (pdata && pdata->phy_exit)
+               pdata->phy_exit(pdev, pdata->phy_type);
+
+       clk_disable(exynos->clk);
+       clk_put(exynos->clk);
+
+       kfree(exynos);
+
+       return 0;
+}
+
+static struct platform_driver dwc3_exynos_driver = {
+       .probe          = dwc3_exynos_probe,
+       .remove         = __devexit_p(dwc3_exynos_remove),
+       .driver         = {
+               .name   = "exynos-dwc3",
+       },
+};
+
+module_platform_driver(dwc3_exynos_driver);
+
+MODULE_ALIAS("platform:exynos-dwc3");
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
index 3274ac8f12004f215734bf4be8c42758ec6b22db..d7d9c0ec9515c60fb6705d987df0ca651424d1fe 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "io.h"
@@ -197,91 +197,99 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 static int __devinit dwc3_omap_probe(struct platform_device *pdev)
 {
        struct dwc3_omap_data   *pdata = pdev->dev.platform_data;
+       struct device_node      *node = pdev->dev.of_node;
+
        struct platform_device  *dwc3;
        struct dwc3_omap        *omap;
        struct resource         *res;
+       struct device           *dev = &pdev->dev;
 
        int                     devid;
+       int                     size;
        int                     ret = -ENOMEM;
        int                     irq;
 
+       const u32               *utmi_mode;
        u32                     reg;
 
        void __iomem            *base;
        void                    *context;
 
-       omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+       omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
        if (!omap) {
-               dev_err(&pdev->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
 
        platform_set_drvdata(pdev, omap);
 
        irq = platform_get_irq(pdev, 1);
        if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ resource\n");
-               ret = -EINVAL;
-               goto err1;
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!res) {
-               dev_err(&pdev->dev, "missing memory base resource\n");
-               ret = -EINVAL;
-               goto err1;
+               dev_err(dev, "missing memory base resource\n");
+               return -EINVAL;
        }
 
-       base = ioremap_nocache(res->start, resource_size(res));
+       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
        if (!base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               goto err1;
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
        }
 
        devid = dwc3_get_device_id();
        if (devid < 0)
-               goto err2;
+               return -ENODEV;
 
        dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
-               dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-               goto err3;
+               dev_err(dev, "couldn't allocate dwc3 device\n");
+               goto err1;
        }
 
-       context = kzalloc(resource_size(res), GFP_KERNEL);
+       context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
        if (!context) {
-               dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
-               goto err4;
+               dev_err(dev, "couldn't allocate dwc3 context memory\n");
+               goto err2;
        }
 
        spin_lock_init(&omap->lock);
-       dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+       dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-       dwc3->dev.parent = &pdev->dev;
-       dwc3->dev.dma_mask = pdev->dev.dma_mask;
-       dwc3->dev.dma_parms = pdev->dev.dma_parms;
+       dwc3->dev.parent = dev;
+       dwc3->dev.dma_mask = dev->dma_mask;
+       dwc3->dev.dma_parms = dev->dma_parms;
        omap->resource_size = resource_size(res);
        omap->context   = context;
-       omap->dev       = &pdev->dev;
+       omap->dev       = dev;
        omap->irq       = irq;
        omap->base      = base;
        omap->dwc3      = dwc3;
 
        reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
-       if (!pdata) {
-               dev_dbg(&pdev->dev, "missing platform data\n");
+       utmi_mode = of_get_property(node, "utmi-mode", &size);
+       if (utmi_mode && size == sizeof(*utmi_mode)) {
+               reg |= *utmi_mode;
        } else {
-               switch (pdata->utmi_mode) {
-               case DWC3_OMAP_UTMI_MODE_SW:
-                       reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                       break;
-               case DWC3_OMAP_UTMI_MODE_HW:
-                       reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                       break;
-               default:
-                       dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
-                                       pdata->utmi_mode);
+               if (!pdata) {
+                       dev_dbg(dev, "missing platform data\n");
+               } else {
+                       switch (pdata->utmi_mode) {
+                       case DWC3_OMAP_UTMI_MODE_SW:
+                               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+                               break;
+                       case DWC3_OMAP_UTMI_MODE_HW:
+                               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+                               break;
+                       default:
+                               dev_dbg(dev, "UNKNOWN utmi mode %d\n",
+                                               pdata->utmi_mode);
+                       }
                }
        }
 
@@ -300,12 +308,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
 
        dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
 
-       ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+       ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
                        "dwc3-omap", omap);
        if (ret) {
-               dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+               dev_err(dev, "failed to request IRQ #%d --> %d\n",
                                omap->irq, ret);
-               goto err5;
+               goto err2;
        }
 
        /* enable all IRQs */
@@ -327,37 +335,24 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
        ret = platform_device_add_resources(dwc3, pdev->resource,
                        pdev->num_resources);
        if (ret) {
-               dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-               goto err6;
+               dev_err(dev, "couldn't add resources to dwc3 device\n");
+               goto err2;
        }
 
        ret = platform_device_add(dwc3);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register dwc3 device\n");
-               goto err6;
+               dev_err(dev, "failed to register dwc3 device\n");
+               goto err2;
        }
 
        return 0;
 
-err6:
-       free_irq(omap->irq, omap);
-
-err5:
-       kfree(omap->context);
-
-err4:
-       platform_device_put(dwc3);
-
-err3:
-       dwc3_put_device_id(devid);
-
 err2:
-       iounmap(base);
+       platform_device_put(dwc3);
 
 err1:
-       kfree(omap);
+       dwc3_put_device_id(devid);
 
-err0:
        return ret;
 }
 
@@ -368,11 +363,6 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
        platform_device_unregister(omap->dwc3);
 
        dwc3_put_device_id(omap->dwc3->id);
-       free_irq(omap->irq, omap);
-       iounmap(omap->base);
-
-       kfree(omap->context);
-       kfree(omap);
 
        return 0;
 }
index 64e1f7c67b08ed374f36428868ad29fd42557bd9..dcc64791b4e15ff1cd75035de5f784f34b29202b 100644 (file)
@@ -61,32 +61,35 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
        struct dwc3_pci         *glue;
        int                     ret = -ENOMEM;
        int                     devid;
+       struct device           *dev = &pci->dev;
 
-       glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+       glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
        if (!glue) {
-               dev_err(&pci->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
 
-       glue->dev       = &pci->dev;
+       glue->dev dev;
 
        ret = pci_enable_device(pci);
        if (ret) {
-               dev_err(&pci->dev, "failed to enable pci device\n");
-               goto err1;
+               dev_err(dev, "failed to enable pci device\n");
+               return -ENODEV;
        }
 
        pci_set_power_state(pci, PCI_D0);
        pci_set_master(pci);
 
        devid = dwc3_get_device_id();
-       if (devid < 0)
-               goto err2;
+       if (devid < 0) {
+               ret = -ENOMEM;
+               goto err1;
+       }
 
        dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
-               dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
-               goto err3;
+               dev_err(dev, "couldn't allocate dwc3 device\n");
+               goto err1;
        }
 
        memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -102,41 +105,37 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 
        ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
        if (ret) {
-               dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
-               goto err4;
+               dev_err(dev, "couldn't add resources to dwc3 device\n");
+               goto err2;
        }
 
        pci_set_drvdata(pci, glue);
 
-       dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+       dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-       dwc3->dev.dma_mask = pci->dev.dma_mask;
-       dwc3->dev.dma_parms = pci->dev.dma_parms;
-       dwc3->dev.parent = &pci->dev;
-       glue->dwc3      = dwc3;
+       dwc3->dev.dma_mask = dev->dma_mask;
+       dwc3->dev.dma_parms = dev->dma_parms;
+       dwc3->dev.parent = dev;
+       glue->dwc3 = dwc3;
 
        ret = platform_device_add(dwc3);
        if (ret) {
-               dev_err(&pci->dev, "failed to register dwc3 device\n");
-               goto err4;
+               dev_err(dev, "failed to register dwc3 device\n");
+               goto err3;
        }
 
        return 0;
 
-err4:
+err3:
        pci_set_drvdata(pci, NULL);
        platform_device_put(dwc3);
 
-err3:
-       dwc3_put_device_id(devid);
-
 err2:
-       pci_disable_device(pci);
+       dwc3_put_device_id(devid);
 
 err1:
-       kfree(glue);
+       pci_disable_device(pci);
 
-err0:
        return ret;
 }
 
@@ -148,7 +147,6 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
        platform_device_unregister(glue->dwc3);
        pci_set_drvdata(pci, NULL);
        pci_disable_device(pci);
-       kfree(glue);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
index d5c568e91874834b5cc1369164946eda16e136be..25910e251c04b4fb7ce0ef8bb9685573e859b9b9 100644 (file)
@@ -76,8 +76,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
                u32 len, u32 type)
 {
        struct dwc3_gadget_ep_cmd_params params;
-       struct dwc3_trb_hw              *trb_hw;
-       struct dwc3_trb                 trb;
+       struct dwc3_trb                 *trb;
        struct dwc3_ep                  *dep;
 
        int                             ret;
@@ -88,19 +87,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
                return 0;
        }
 
-       trb_hw = dwc->ep0_trb;
-       memset(&trb, 0, sizeof(trb));
+       trb = dwc->ep0_trb;
 
-       trb.trbctl = type;
-       trb.bplh = buf_dma;
-       trb.length = len;
+       trb->bpl = lower_32_bits(buf_dma);
+       trb->bph = upper_32_bits(buf_dma);
+       trb->size = len;
+       trb->ctrl = type;
 
-       trb.hwo = 1;
-       trb.lst = 1;
-       trb.ioc = 1;
-       trb.isp_imi = 1;
-
-       dwc3_trb_to_hw(&trb, trb_hw);
+       trb->ctrl |= (DWC3_TRB_CTRL_HWO
+                       | DWC3_TRB_CTRL_LST
+                       | DWC3_TRB_CTRL_IOC
+                       | DWC3_TRB_CTRL_ISP_IMI);
 
        memset(&params, 0, sizeof(params));
        params.param0 = upper_32_bits(dwc->ep0_trb_addr);
@@ -315,9 +312,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        u32                     recip;
        u32                     wValue;
        u32                     wIndex;
-       u32                     reg;
        int                     ret;
-       u32                     mode;
 
        wValue = le16_to_cpu(ctrl->wValue);
        wIndex = le16_to_cpu(ctrl->wIndex);
@@ -356,25 +351,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
                        if (!set)
                                return -EINVAL;
 
-                       mode = wIndex >> 8;
-                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-                       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-
-                       switch (mode) {
-                       case TEST_J:
-                       case TEST_K:
-                       case TEST_SE0_NAK:
-                       case TEST_PACKET:
-                       case TEST_FORCE_EN:
-                               reg |= mode << 1;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-                       break;
-               default:
-                       return -EINVAL;
+                       dwc->test_mode_nr = wIndex >> 8;
+                       dwc->test_mode = true;
                }
                break;
 
@@ -396,7 +374,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        case USB_RECIP_ENDPOINT:
                switch (wValue) {
                case USB_ENDPOINT_HALT:
-                       dep =  dwc3_wIndex_to_dep(dwc, wIndex);
+                       dep = dwc3_wIndex_to_dep(dwc, wIndex);
                        if (!dep)
                                return -EINVAL;
                        ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -470,8 +448,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        case DWC3_ADDRESS_STATE:
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
                /* if the cfg matches and the cfg is non zero */
-               if (!ret && cfg)
+               if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
                        dwc->dev_state = DWC3_CONFIGURED_STATE;
+                       dwc->resize_fifos = true;
+                       dev_dbg(dwc->dev, "resize fifos flag SET\n");
+               }
                break;
 
        case DWC3_CONFIGURED_STATE:
@@ -560,9 +541,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 {
        struct dwc3_request     *r = NULL;
        struct usb_request      *ur;
-       struct dwc3_trb         trb;
+       struct dwc3_trb         *trb;
        struct dwc3_ep          *ep0;
        u32                     transferred;
+       u32                     length;
        u8                      epnum;
 
        epnum = event->endpoint_number;
@@ -573,16 +555,16 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        r = next_request(&ep0->request_list);
        ur = &r->request;
 
-       dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+       trb = dwc->ep0_trb;
+       length = trb->size & DWC3_TRB_SIZE_MASK;
 
        if (dwc->ep0_bounced) {
-
                transferred = min_t(u32, ur->length,
-                               ep0->endpoint.maxpacket - trb.length);
+                               ep0->endpoint.maxpacket - length);
                memcpy(ur->buf, dwc->ep0_bounce, transferred);
                dwc->ep0_bounced = false;
        } else {
-               transferred = ur->length - trb.length;
+               transferred = ur->length - length;
                ur->actual += transferred;
        }
 
@@ -614,6 +596,17 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
                dwc3_gadget_giveback(dep, r, 0);
        }
 
+       if (dwc->test_mode) {
+               int ret;
+
+               ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+               if (ret < 0) {
+                       dev_dbg(dwc->dev, "Invalid Test #%d\n",
+                                       dwc->test_mode_nr);
+                       dwc3_ep0_stall_and_restart(dwc);
+               }
+       }
+
        dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 }
@@ -624,6 +617,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
        struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
 
        dep->flags &= ~DWC3_EP_BUSY;
+       dep->res_trans_idx = 0;
        dwc->setup_packet_pending = false;
 
        switch (dwc->ep0state) {
@@ -730,6 +724,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
 {
        struct dwc3_ep          *dep = dwc->eps[epnum];
 
+       if (dwc->resize_fifos) {
+               dev_dbg(dwc->dev, "starting to resize fifos\n");
+               dwc3_gadget_resize_tx_fifos(dwc);
+               dwc->resize_fifos = 0;
+       }
+
        WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
index 1009e7e47a248f5f4b492889c8997ac6555a47ba..5255fe975ea1c5aa9e2ffecccd80618d5ad4332b 100644 (file)
 #include "gadget.h"
 #include "io.h"
 
+/**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+ * @dwc: pointer to our context structure
+ * @mode: the mode to set (J, K SE0 NAK, Force Enable)
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL if wrong Test Selector
+ * is passed
+ */
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
+{
+       u32             reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+       switch (mode) {
+       case TEST_J:
+       case TEST_K:
+       case TEST_SE0_NAK:
+       case TEST_PACKET:
+       case TEST_FORCE_EN:
+               reg |= mode << 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       return 0;
+}
+
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
+{
+       int             retries = 10000;
+       u32             reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+
+       /* set requested state */
+       reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       /* wait for a change in DSTS */
+       while (--retries) {
+               reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+               if (DWC3_DSTS_USBLNKST(reg) == state)
+                       return 0;
+
+               udelay(5);
+       }
+
+       dev_vdbg(dwc->dev, "link state change request timed out\n");
+
+       return -ETIMEDOUT;
+}
+
+/**
+ * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
+ * @dwc: pointer to our context structure
+ *
+ * This function will a best effort FIFO allocation in order
+ * to improve FIFO usage and throughput, while still allowing
+ * us to enable as many endpoints as possible.
+ *
+ * Keep in mind that this operation will be highly dependent
+ * on the configured size for RAM1 - which contains TxFifo -,
+ * the amount of endpoints enabled on coreConsultant tool, and
+ * the width of the Master Bus.
+ *
+ * In the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * Unfortunately, due to many variables that's not always the case.
+ */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
+{
+       int             last_fifo_depth = 0;
+       int             ram1_depth;
+       int             fifo_size;
+       int             mdwidth;
+       int             num;
+
+       if (!dwc->needs_fifo_resize)
+               return 0;
+
+       ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+       mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
+
+       /* MDWIDTH is represented in bits, we need it in bytes */
+       mdwidth >>= 3;
+
+       /*
+        * FIXME For now we will only allocate 1 wMaxPacketSize space
+        * for each enabled endpoint, later patches will come to
+        * improve this algorithm so that we better use the internal
+        * FIFO space
+        */
+       for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) {
+               struct dwc3_ep  *dep = dwc->eps[num];
+               int             fifo_number = dep->number >> 1;
+               int             mult = 1;
+               int             tmp;
+
+               if (!(dep->number & 1))
+                       continue;
+
+               if (!(dep->flags & DWC3_EP_ENABLED))
+                       continue;
+
+               if (usb_endpoint_xfer_bulk(dep->desc)
+                               || usb_endpoint_xfer_isoc(dep->desc))
+                       mult = 3;
+
+               /*
+                * REVISIT: the following assumes we will always have enough
+                * space available on the FIFO RAM for all possible use cases.
+                * Make sure that's true somehow and change FIFO allocation
+                * accordingly.
+                *
+                * If we have Bulk or Isochronous endpoints, we want
+                * them to be able to be very, very fast. So we're giving
+                * those endpoints a fifo_size which is enough for 3 full
+                * packets
+                */
+               tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+               tmp += mdwidth;
+
+               fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+
+               fifo_size |= (last_fifo_depth << 16);
+
+               dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+                               dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+               dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
+                               fifo_size);
+
+               last_fifo_depth += (fifo_size & 0xffff);
+       }
+
+       return 0;
+}
+
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status)
 {
@@ -156,7 +314,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 }
 
 static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
-               struct dwc3_trb_hw *trb)
+               struct dwc3_trb *trb)
 {
        u32             offset = (char *) trb - (char *) dep->trb_pool;
 
@@ -305,9 +463,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                return ret;
 
        if (!(dep->flags & DWC3_EP_ENABLED)) {
-               struct dwc3_trb_hw      *trb_st_hw;
-               struct dwc3_trb_hw      *trb_link_hw;
-               struct dwc3_trb         trb_link;
+               struct dwc3_trb *trb_st_hw;
+               struct dwc3_trb *trb_link;
 
                ret = dwc3_gadget_set_xfer_resource(dwc, dep);
                if (ret)
@@ -327,15 +484,15 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 
                memset(&trb_link, 0, sizeof(trb_link));
 
-               /* Link TRB for ISOC. The HWO but is never reset */
+               /* Link TRB for ISOC. The HWO bit is never reset */
                trb_st_hw = &dep->trb_pool[0];
 
-               trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
-               trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
-               trb_link.hwo = true;
+               trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
 
-               trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
-               dwc3_trb_to_hw(&trb_link, trb_link_hw);
+               trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+               trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+               trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+               trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
        }
 
        return 0;
@@ -423,16 +580,16 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
 
        switch (usb_endpoint_type(desc)) {
        case USB_ENDPOINT_XFER_CONTROL:
-               strncat(dep->name, "-control", sizeof(dep->name));
+               strlcat(dep->name, "-control", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_ISOC:
-               strncat(dep->name, "-isoc", sizeof(dep->name));
+               strlcat(dep->name, "-isoc", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_BULK:
-               strncat(dep->name, "-bulk", sizeof(dep->name));
+               strlcat(dep->name, "-bulk", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_INT:
-               strncat(dep->name, "-int", sizeof(dep->name));
+               strlcat(dep->name, "-int", sizeof(dep->name));
                break;
        default:
                dev_err(dwc->dev, "invalid endpoint transfer type\n");
@@ -522,8 +679,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                unsigned length, unsigned last, unsigned chain)
 {
        struct dwc3             *dwc = dep->dwc;
-       struct dwc3_trb_hw      *trb_hw;
-       struct dwc3_trb         trb;
+       struct dwc3_trb         *trb;
 
        unsigned int            cur_slot;
 
@@ -532,7 +688,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                        length, last ? " last" : "",
                        chain ? " chain" : "");
 
-       trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+       trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
        cur_slot = dep->free_slot;
        dep->free_slot++;
 
@@ -541,40 +697,32 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                        usb_endpoint_xfer_isoc(dep->desc))
                return;
 
-       memset(&trb, 0, sizeof(trb));
        if (!req->trb) {
                dwc3_gadget_move_request_queued(req);
-               req->trb = trb_hw;
-               req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+               req->trb = trb;
+               req->trb_dma = dwc3_trb_dma_offset(dep, trb);
        }
 
-       if (usb_endpoint_xfer_isoc(dep->desc)) {
-               trb.isp_imi = true;
-               trb.csp = true;
-       } else {
-               trb.chn = chain;
-               trb.lst = last;
-       }
-
-       if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
-               trb.sid_sofn = req->request.stream_id;
+       trb->size = DWC3_TRB_SIZE_LENGTH(length);
+       trb->bpl = lower_32_bits(dma);
+       trb->bph = upper_32_bits(dma);
 
        switch (usb_endpoint_type(dep->desc)) {
        case USB_ENDPOINT_XFER_CONTROL:
-               trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+               trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
                break;
 
        case USB_ENDPOINT_XFER_ISOC:
-               trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+               trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
 
                /* IOC every DWC3_TRB_NUM / 4 so we can refill */
                if (!(cur_slot % (DWC3_TRB_NUM / 4)))
-                       trb.ioc = last;
+                       trb->ctrl |= DWC3_TRB_CTRL_IOC;
                break;
 
        case USB_ENDPOINT_XFER_BULK:
        case USB_ENDPOINT_XFER_INT:
-               trb.trbctl = DWC3_TRBCTL_NORMAL;
+               trb->ctrl = DWC3_TRBCTL_NORMAL;
                break;
        default:
                /*
@@ -584,11 +732,21 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                BUG();
        }
 
-       trb.length      = length;
-       trb.bplh        = dma;
-       trb.hwo         = true;
+       if (usb_endpoint_xfer_isoc(dep->desc)) {
+               trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+               trb->ctrl |= DWC3_TRB_CTRL_CSP;
+       } else {
+               if (chain)
+                       trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
+               if (last)
+                       trb->ctrl |= DWC3_TRB_CTRL_LST;
+       }
 
-       dwc3_trb_to_hw(&trb, trb_hw);
+       if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+               trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+       trb->ctrl |= DWC3_TRB_CTRL_HWO;
 }
 
 /*
@@ -596,14 +754,15 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
  * @dep: endpoint for which requests are being prepared
  * @starting: true if the endpoint is idle and no requests are queued.
  *
- * The functions goes through the requests list and setups TRBs for the
- * transfers. The functions returns once there are not more TRBs available or
- * it run out of requests.
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
  */
 static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 {
        struct dwc3_request     *req, *n;
        u32                     trbs_left;
+       u32                     max;
        unsigned int            last_one = 0;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -611,9 +770,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
        /* the first request must not be queued */
        trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
 
+       /* Can't wrap around on a non-isoc EP since there's no link TRB */
+       if (!usb_endpoint_xfer_isoc(dep->desc)) {
+               max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
+               if (trbs_left > max)
+                       trbs_left = max;
+       }
+
        /*
-        * if busy & slot are equal than it is either full or empty. If we are
-        * starting to proceed requests then we are empty. Otherwise we ar
+        * If busy & slot are equal than it is either full or empty. If we are
+        * starting to process requests then we are empty. Otherwise we are
         * full and don't do anything
         */
        if (!trbs_left) {
@@ -624,7 +790,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
                 * In case we start from scratch, we queue the ISOC requests
                 * starting from slot 1. This is done because we use ring
                 * buffer and have no LST bit to stop us. Instead, we place
-                * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+                * IOC bit every TRB_NUM/4. We try to avoid having an interrupt
                 * after the first request so we start at slot 1 and have
                 * 7 requests proceed before we hit the first IOC.
                 * Other transfer types don't use the ring buffer and are
@@ -660,8 +826,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
                                length = sg_dma_len(s);
                                dma = sg_dma_address(s);
 
-                               if (i == (request->num_mapped_sgs - 1)
-                                               || sg_is_last(s)) {
+                               if (i == (request->num_mapped_sgs - 1) ||
+                                               sg_is_last(s)) {
                                        last_one = true;
                                        chain = false;
                                }
@@ -729,8 +895,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                dwc3_prepare_trbs(dep, start_new);
 
                /*
-                * req points to the first request where HWO changed
-                * from 0 to 1
+                * req points to the first request where HWO changed from 0 to 1
                 */
                req = next_request(&dep->req_queued);
        }
@@ -756,7 +921,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                /*
                 * FIXME we need to iterate over the list of requests
                 * here and stop, unmap, free and del each of the linked
-                * requests instead of we do now.
+                * requests instead of what we do now.
                 */
                usb_gadget_unmap_request(&dwc->gadget, &req->request,
                                req->direction);
@@ -793,7 +958,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * particular token from the Host side.
         *
         * This will also avoid Host cancelling URBs due to too
-        * many NACKs.
+        * many NAKs.
         */
        ret = usb_gadget_map_request(&dwc->gadget, &req->request,
                        dep->direction);
@@ -819,11 +984,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                int start_trans;
 
                start_trans = 1;
-               if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                               dep->flags & DWC3_EP_BUSY)
+               if (usb_endpoint_xfer_isoc(dep->desc) &&
+                               (dep->flags & DWC3_EP_BUSY))
                        start_trans = 0;
 
-               ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+               ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
                if (ret && ret != -EBUSY) {
                        struct dwc3     *dwc = dep->dwc;
 
@@ -976,8 +1141,12 @@ out:
 static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 {
        struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+       unsigned long                   flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        dep->flags |= DWC3_EP_WEDGE;
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return dwc3_gadget_ep_set_halt(ep, 1);
 }
@@ -1067,26 +1236,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
                goto out;
        }
 
-       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-
-       /*
-        * Switch link state to Recovery. In HS/FS/LS this means
-        * RemoteWakeup Request
-        */
-       reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
-       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
-       /* wait for at least 2000us */
-       usleep_range(2000, 2500);
+       ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+       if (ret < 0) {
+               dev_err(dwc->dev, "failed to put link in Recovery\n");
+               goto out;
+       }
 
        /* write zeroes to Link Change Request */
        reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-       /* pool until Link State change to ON */
+       /* poll until Link State changes to ON */
        timeout = jiffies + msecs_to_jiffies(100);
 
-       while (!(time_after(jiffies, timeout))) {
+       while (!time_after(jiffies, timeout)) {
                reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
                /* in HS, means ON */
@@ -1109,8 +1272,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
                int is_selfpowered)
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        dwc->is_selfpowered = !!is_selfpowered;
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 }
@@ -1121,10 +1287,13 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
        u32                     timeout = 500;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-       if (is_on)
-               reg |= DWC3_DCTL_RUN_STOP;
-       else
+       if (is_on) {
+               reg &= ~DWC3_DCTL_TRGTULST_MASK;
+               reg |= (DWC3_DCTL_RUN_STOP
+                               | DWC3_DCTL_TRGTULST_RX_DET);
+       } else {
                reg &= ~DWC3_DCTL_RUN_STOP;
+       }
 
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
@@ -1331,7 +1500,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                const struct dwc3_event_depevt *event, int status)
 {
        struct dwc3_request     *req;
-       struct dwc3_trb         trb;
+       struct dwc3_trb         *trb;
        unsigned int            count;
        unsigned int            s_pkt = 0;
 
@@ -1342,20 +1511,20 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                        return 1;
                }
 
-               dwc3_trb_to_nat(req->trb, &trb);
+               trb = req->trb;
 
-               if (trb.hwo && status != -ESHUTDOWN)
+               if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
                        /*
                         * We continue despite the error. There is not much we
-                        * can do. If we don't clean in up we loop for ever. If
-                        * we skip the TRB than it gets overwritten reused after
-                        * a while since we use them in a ring buffer. a BUG()
-                        * would help. Lets hope that if this occures, someone
+                        * can do. If we don't clean it up we loop forever. If
+                        * we skip the TRB then it gets overwritten after a
+                        * while since we use them in a ring buffer. A BUG()
+                        * would help. Lets hope that if this occurs, someone
                         * fixes the root cause instead of looking away :)
                         */
                        dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
                                        dep->name, req->trb);
-               count = trb.length;
+               count = trb->size & DWC3_TRB_SIZE_MASK;
 
                if (dep->direction) {
                        if (count) {
@@ -1379,13 +1548,16 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                dwc3_gadget_giveback(dep, req, status);
                if (s_pkt)
                        break;
-               if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+               if ((event->status & DEPEVT_STATUS_LST) &&
+                               (trb->ctrl & DWC3_TRB_CTRL_LST))
                        break;
-               if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+               if ((event->status & DEPEVT_STATUS_IOC) &&
+                               (trb->ctrl & DWC3_TRB_CTRL_IOC))
                        break;
        } while (1);
 
-       if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+       if ((event->status & DEPEVT_STATUS_IOC) &&
+                       (trb->ctrl & DWC3_TRB_CTRL_IOC))
                return 0;
        return 1;
 }
@@ -1400,11 +1572,9 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
        if (event->status & DEPEVT_STATUS_BUSERR)
                status = -ECONNRESET;
 
-       clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
-       if (clean_busy) {
+       clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+       if (clean_busy)
                dep->flags &= ~DWC3_EP_BUSY;
-               dep->res_trans_idx = 0;
-       }
 
        /*
         * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@@ -1435,7 +1605,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
                struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
 {
-       u32 uf;
+       u32 uf, mask;
 
        if (list_empty(&dep->request_list)) {
                dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
@@ -1443,16 +1613,10 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
                return;
        }
 
-       if (event->parameters) {
-               u32 mask;
-
-               mask = ~(dep->interval - 1);
-               uf = event->parameters & mask;
-               /* 4 micro frames in the future */
-               uf += dep->interval * 4;
-       } else {
-               uf = 0;
-       }
+       mask = ~(dep->interval - 1);
+       uf = event->parameters & mask;
+       /* 4 micro frames in the future */
+       uf += dep->interval * 4;
 
        __dwc3_gadget_kick_transfer(dep, uf, 1);
 }
@@ -1464,8 +1628,8 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
        struct dwc3_event_depevt mod_ev = *event;
 
        /*
-        * We were asked to remove one requests. It is possible that this
-        * request and a few other were started together and have the same
+        * We were asked to remove one request. It is possible that this
+        * request and a few others were started together and have the same
         * transfer index. Since we stopped the complete endpoint we don't
         * know how many requests were already completed (and not yet)
         * reported and how could be done (later). We purge them all until
@@ -1474,7 +1638,7 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
        mod_ev.status = DEPEVT_STATUS_LST;
        dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
        dep->flags &= ~DWC3_EP_BUSY;
-       /* pending requets are ignored and are queued on XferNotReady */
+       /* pending requests are ignored and are queued on XferNotReady */
 }
 
 static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
@@ -1515,6 +1679,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
        switch (event->endpoint_event) {
        case DWC3_DEPEVT_XFERCOMPLETE:
+               dep->res_trans_idx = 0;
+
                if (usb_endpoint_xfer_isoc(dep->desc)) {
                        dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
                                        dep->name);
@@ -1539,7 +1705,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
                        int ret;
 
                        dev_vdbg(dwc->dev, "%s: reason %s\n",
-                                       dep->name, event->status
+                                       dep->name, event->status &
+                                       DEPEVT_STATUS_TRANSFER_ACTIVE
                                        ? "Transfer Active"
                                        : "Transfer Not Active");
 
@@ -1750,6 +1917,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+       dwc->test_mode = false;
 
        dwc3_stop_active_transfers(dwc);
        dwc3_clear_stall_all_ep(dwc);
@@ -2027,7 +2195,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
        while (left > 0) {
                union dwc3_event event;
 
-               memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+               event.raw = *(u32 *) (evt->buf + evt->lpos);
+
                dwc3_process_event_entry(dwc, &event);
                /*
                 * XXX we wrap around correctly to the next entry as almost all
@@ -2068,7 +2237,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 
 /**
  * dwc3_gadget_init - Initializes gadget related registers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
index 12f1e104977ff2a655eb02917f9fa2aea73656a3..a8600084348cf2013c07564740e364959876d0a2 100644 (file)
@@ -100,6 +100,9 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status);
 
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
index 7cfe211b6c37b546dafa8aa09900d8a8f3d99c7a..b108d18fd40d543a25915f8d72ee20cbd3a6fe6c 100644 (file)
@@ -53,7 +53,7 @@ int dwc3_host_init(struct dwc3 *dwc)
        struct platform_device  *xhci;
        int                     ret;
 
-       xhci = platform_device_alloc("xhci", -1);
+       xhci = platform_device_alloc("xhci-hcd", -1);
        if (!xhci) {
                dev_err(dwc->dev, "couldn't allocate xHCI device\n");
                ret = -ENOMEM;
diff --git a/include/linux/platform_data/dwc3-exynos.h b/include/linux/platform_data/dwc3-exynos.h
new file mode 100644 (file)
index 0000000..5eb7da9
--- /dev/null
@@ -0,0 +1,24 @@
+/**
+ * dwc3-exynos.h - Samsung EXYNOS DWC3 Specific Glue layer, header.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef _DWC3_EXYNOS_H_
+#define _DWC3_EXYNOS_H_
+
+struct dwc3_exynos_data {
+       int phy_type;
+       int (*phy_init)(struct platform_device *pdev, int type);
+       int (*phy_exit)(struct platform_device *pdev, int type);
+};
+
+#endif /* _DWC3_EXYNOS_H_ */