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:
Linus Torvalds
2012-03-20 11:26:30 -07:00
269 changed files with 9685 additions and 5603 deletions

View 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

View File

@@ -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);

View File

@@ -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);

View 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;
}

View 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");

View 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:
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;
}

View File

@@ -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) = {

View 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);
@@ -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));
}

View File

@@ -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);

View 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);
@@ -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

View 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;