Merge tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB merge for 3.4-rc1 from Greg KH: "Here's the big USB merge for the 3.4-rc1 merge window. Lots of gadget driver reworks here, driver updates, xhci changes, some new drivers added, usb-serial core reworking to fix some bugs, and other various minor things. There are some patches touching arch code, but they have all been acked by the various arch maintainers." * tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (302 commits) net: qmi_wwan: add support for ZTE MF820D USB: option: add ZTE MF820D usb: gadget: f_fs: Remove lock is held before freeing checks USB: option: make interface blacklist work again usb/ub: deprecate & schedule for removal the "Low Performance USB Block" driver USB: ohci-pxa27x: add clk_prepare/clk_unprepare calls USB: use generic platform driver on ath79 USB: EHCI: Add a generic platform device driver USB: OHCI: Add a generic platform device driver USB: ftdi_sio: new PID: LUMEL PD12 USB: ftdi_sio: add support for FT-X series devices USB: serial: mos7840: Fixed MCS7820 device attach problem usb: Don't make USB_ARCH_HAS_{XHCI,OHCI,EHCI} depend on USB_SUPPORT. usb gadget: fix a section mismatch when compiling g_ffs with CONFIG_USB_FUNCTIONFS_ETH USB: ohci-nxp: Remove i2c_write(), use smbus USB: ohci-nxp: Support for LPC32xx USB: ohci-nxp: Rename symbols from pnx4008 to nxp USB: OHCI-HCD: Rename ohci-pnx4008 to ohci-nxp usb: gadget: Kconfig: fix typo for 'different' usb: dwc3: pci: fix another failure path in dwc3_pci_probe() ...
This commit is contained in:
@@ -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
|
||||
|
@@ -48,10 +48,10 @@
|
||||
#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:
|
||||
err1:
|
||||
dwc3_core_exit(dwc);
|
||||
|
||||
err3:
|
||||
iounmap(regs);
|
||||
|
||||
err2:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
err1:
|
||||
kfree(dwc->mem);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -605,19 +597,9 @@ static struct platform_driver dwc3_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dwc3_driver);
|
||||
|
||||
MODULE_ALIAS("platform:dwc3");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
|
||||
|
||||
static int __devinit dwc3_init(void)
|
||||
{
|
||||
return platform_driver_register(&dwc3_driver);
|
||||
}
|
||||
module_init(dwc3_init);
|
||||
|
||||
static void __exit dwc3_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dwc3_driver);
|
||||
}
|
||||
module_exit(dwc3_exit);
|
||||
|
@@ -145,22 +145,23 @@
|
||||
/* 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)
|
||||
|
||||
@@ -172,8 +173,12 @@
|
||||
#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
|
||||
|
||||
@@ -198,6 +203,15 @@
|
||||
|
||||
#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)
|
||||
@@ -260,10 +274,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)
|
||||
@@ -288,7 +302,7 @@
|
||||
|
||||
/* 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;
|
||||
/* 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))
|
||||
|
||||
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;
|
||||
};
|
||||
#define DWC3_TRBSTS_OK 0
|
||||
#define DWC3_TRBSTS_MISSED_ISOC 1
|
||||
#define DWC3_TRBSTS_SETUP_PENDING 2
|
||||
|
||||
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 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;
|
||||
@@ -572,7 +538,6 @@ struct dwc3_request {
|
||||
* @ctrl_req_addr: dma address of ctrl_req
|
||||
* @ep0_trb: dma address of ep0_trb
|
||||
* @ep0_usb_req: dummy req used while handling STD USB requests
|
||||
* @setup_buf_addr: dma address of setup_buf
|
||||
* @ep0_bounce_addr: dma address of ep0_bounce
|
||||
* @lock: for synchronizing
|
||||
* @dev: pointer to our struct device
|
||||
@@ -594,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
|
||||
@@ -604,12 +571,11 @@ 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;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t setup_buf_addr;
|
||||
dma_addr_t ep0_bounce_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
/* device lock */
|
||||
@@ -651,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;
|
||||
@@ -662,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 {
|
||||
@@ -719,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 */
|
||||
@@ -807,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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
151
drivers/usb/dwc3/dwc3-exynos.c
Normal file
151
drivers/usb/dwc3/dwc3-exynos.c
Normal file
@@ -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");
|
@@ -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:
|
||||
err2:
|
||||
platform_device_put(dwc3);
|
||||
|
||||
err3:
|
||||
err1:
|
||||
dwc3_put_device_id(devid);
|
||||
|
||||
err2:
|
||||
iounmap(base);
|
||||
|
||||
err1:
|
||||
kfree(omap);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@@ -61,32 +61,36 @@ 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");
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
|
||||
@@ -102,41 +106,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:
|
||||
err2:
|
||||
dwc3_put_device_id(devid);
|
||||
|
||||
err2:
|
||||
err1:
|
||||
pci_disable_device(pci);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,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) = {
|
||||
|
@@ -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(¶ms, 0, sizeof(params));
|
||||
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
||||
@@ -302,7 +299,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
||||
dep = dwc->eps[0];
|
||||
dwc->ep0_usb_req.dep = dep;
|
||||
dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
|
||||
dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
|
||||
dwc->ep0_usb_req.request.buf = dwc->setup_buf;
|
||||
dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
|
||||
|
||||
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
|
||||
@@ -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) {
|
||||
@@ -679,7 +673,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else if ((req->request.length % dep->endpoint.maxpacket)
|
||||
&& (event->endpoint_number == 0)) {
|
||||
dwc3_map_buffer_to_dma(req);
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
event->endpoint_number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(req->request.length > dep->endpoint.maxpacket);
|
||||
|
||||
@@ -694,7 +693,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
} else {
|
||||
dwc3_map_buffer_to_dma(req);
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
event->endpoint_number);
|
||||
if (ret) {
|
||||
dev_dbg(dwc->dev, "failed to map request\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
|
||||
req->request.dma, req->request.length,
|
||||
@@ -720,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));
|
||||
}
|
||||
|
||||
|
@@ -54,68 +54,162 @@
|
||||
#include "gadget.h"
|
||||
#include "io.h"
|
||||
|
||||
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
|
||||
|
||||
void dwc3_map_buffer_to_dma(struct dwc3_request *req)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct dwc3 *dwc = req->dep->dwc;
|
||||
u32 reg;
|
||||
|
||||
if (req->request.length == 0) {
|
||||
/* req->request.dma = dwc->setup_buf_addr; */
|
||||
return;
|
||||
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;
|
||||
}
|
||||
|
||||
if (req->request.num_sgs) {
|
||||
int mapped;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
mapped = dma_map_sg(dwc->dev, req->request.sg,
|
||||
req->request.num_sgs,
|
||||
req->direction ? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
if (mapped < 0) {
|
||||
dev_err(dwc->dev, "failed to map SGs\n");
|
||||
return;
|
||||
}
|
||||
|
||||
req->request.num_mapped_sgs = mapped;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->request.dma == DMA_ADDR_INVALID) {
|
||||
req->request.dma = dma_map_single(dwc->dev, req->request.buf,
|
||||
req->request.length, req->direction
|
||||
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct dwc3 *dwc = req->dep->dwc;
|
||||
int retries = 10000;
|
||||
u32 reg;
|
||||
|
||||
if (req->request.length == 0) {
|
||||
req->request.dma = DMA_ADDR_INVALID;
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
||||
if (req->request.num_mapped_sgs) {
|
||||
req->request.dma = DMA_ADDR_INVALID;
|
||||
dma_unmap_sg(dwc->dev, req->request.sg,
|
||||
req->request.num_mapped_sgs,
|
||||
req->direction ? DMA_TO_DEVICE
|
||||
: DMA_FROM_DEVICE);
|
||||
dev_vdbg(dwc->dev, "link state change request timed out\n");
|
||||
|
||||
req->request.num_mapped_sgs = 0;
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
||||
if (req->mapped) {
|
||||
dma_unmap_single(dwc->dev, req->request.dma,
|
||||
req->request.length, req->direction
|
||||
? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
req->mapped = 0;
|
||||
req->request.dma = DMA_ADDR_INVALID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
@@ -144,14 +238,15 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
if (req->request.status == -EINPROGRESS)
|
||||
req->request.status = status;
|
||||
|
||||
dwc3_unmap_buffer_from_dma(req);
|
||||
usb_gadget_unmap_request(&dwc->gadget, &req->request,
|
||||
req->direction);
|
||||
|
||||
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
|
||||
req, dep->name, req->request.actual,
|
||||
req->request.length, status);
|
||||
|
||||
spin_unlock(&dwc->lock);
|
||||
req->request.complete(&req->dep->endpoint, &req->request);
|
||||
req->request.complete(&dep->endpoint, &req->request);
|
||||
spin_lock(&dwc->lock);
|
||||
}
|
||||
|
||||
@@ -219,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;
|
||||
|
||||
@@ -368,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)
|
||||
@@ -390,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;
|
||||
@@ -440,6 +534,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
|
||||
dep->stream_capable = false;
|
||||
dep->desc = NULL;
|
||||
dep->endpoint.desc = NULL;
|
||||
dep->comp_desc = NULL;
|
||||
dep->type = 0;
|
||||
dep->flags = 0;
|
||||
@@ -485,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");
|
||||
@@ -562,7 +657,6 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
|
||||
|
||||
req->epnum = dep->number;
|
||||
req->dep = dep;
|
||||
req->request.dma = DMA_ADDR_INVALID;
|
||||
|
||||
return &req->request;
|
||||
}
|
||||
@@ -585,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;
|
||||
|
||||
@@ -595,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++;
|
||||
|
||||
@@ -604,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:
|
||||
/*
|
||||
@@ -647,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;
|
||||
|
||||
dwc3_trb_to_hw(&trb, trb_hw);
|
||||
if (last)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_LST;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -659,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);
|
||||
@@ -674,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) {
|
||||
@@ -687,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
|
||||
@@ -723,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;
|
||||
}
|
||||
@@ -792,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);
|
||||
}
|
||||
@@ -819,9 +921,10 @@ 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.
|
||||
*/
|
||||
dwc3_unmap_buffer_from_dma(req);
|
||||
usb_gadget_unmap_request(&dwc->gadget, &req->request,
|
||||
req->direction);
|
||||
list_del(&req->list);
|
||||
return ret;
|
||||
}
|
||||
@@ -837,6 +940,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
||||
|
||||
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int ret;
|
||||
|
||||
req->request.actual = 0;
|
||||
req->request.status = -EINPROGRESS;
|
||||
req->direction = dep->direction;
|
||||
@@ -852,9 +958,13 @@ 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.
|
||||
*/
|
||||
dwc3_map_buffer_to_dma(req);
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
dep->direction);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
|
||||
/*
|
||||
@@ -874,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;
|
||||
|
||||
@@ -1031,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);
|
||||
}
|
||||
@@ -1122,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 */
|
||||
@@ -1164,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;
|
||||
}
|
||||
@@ -1176,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);
|
||||
|
||||
@@ -1386,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;
|
||||
|
||||
@@ -1397,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) {
|
||||
@@ -1434,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;
|
||||
}
|
||||
@@ -1455,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.
|
||||
@@ -1490,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",
|
||||
@@ -1498,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);
|
||||
}
|
||||
@@ -1519,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
|
||||
@@ -1529,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,
|
||||
@@ -1570,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);
|
||||
@@ -1594,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");
|
||||
|
||||
@@ -1805,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);
|
||||
@@ -2082,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
|
||||
@@ -2123,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.
|
||||
*/
|
||||
@@ -2149,9 +2263,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dwc->setup_buf = dma_alloc_coherent(dwc->dev,
|
||||
sizeof(*dwc->setup_buf) * 2,
|
||||
&dwc->setup_buf_addr, GFP_KERNEL);
|
||||
dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
|
||||
GFP_KERNEL);
|
||||
if (!dwc->setup_buf) {
|
||||
dev_err(dwc->dev, "failed to allocate setup buffer\n");
|
||||
ret = -ENOMEM;
|
||||
@@ -2242,8 +2355,7 @@ err4:
|
||||
dwc->ep0_bounce_addr);
|
||||
|
||||
err3:
|
||||
dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
|
||||
dwc->setup_buf, dwc->setup_buf_addr);
|
||||
kfree(dwc->setup_buf);
|
||||
|
||||
err2:
|
||||
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
|
||||
@@ -2272,8 +2384,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
|
||||
dwc->ep0_bounce_addr);
|
||||
|
||||
dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
|
||||
dwc->setup_buf, dwc->setup_buf_addr);
|
||||
kfree(dwc->setup_buf);
|
||||
|
||||
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
|
||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||
|
@@ -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);
|
||||
@@ -108,8 +111,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
|
||||
void dwc3_map_buffer_to_dma(struct dwc3_request *req);
|
||||
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
|
||||
|
||||
/**
|
||||
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user