Hi Greg, Here are the latest updates to DWC3 driver. With them I have USB30CV passing all except LPM-related tests. Driver is now a lot more stable and works fine in FS/HS/SS modes. Consolidated changes are appended below and patches were sent to linux-usb a while ago for reference. The following changes since commit 0ae52d5458ddb14d5da63054f1d8269a13fe9054: usb: musb: Enable DMA mode1 RX for transfers without short packets (2011-09-09 13:08:17 +0300) are available in the git repository at: gitorious.org:usb/usb.git for-next Felipe Balbi (9): usb: dwc3: ep0: Make USB30CV happy with SetAddress usb: dwc3: ep0: ignore direction on 2-stage transfer usb: dwc3: ep0: fix debug message usb: dwc3: gadget: add support for Bursts usb: dwc3: gadget: implement streams support usb: dwc3: add struct dwc3_hwparams usb: dwc3: core: cache GHWPARAMS* registers usb: dwc3: gadget: allow clock gating to work usb: dwc3: convert structures into bitshifts Paul Zimmerman (4): usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs usb: dwc3: gadget: driver should not wait for RxFIFO to drain usb: dwc3: gadget: make DWC3_EP_WEDGE do the right thing usb: dwc3: gadget: fix DMA offset calculation Sebastian Andrzej Siewior (3): usb: dwc3: ep0: remove second giveback in error case usb: dwc3: ep0: fix debug output usb: dwc: remove "All rights reserved" statement. Documentation/usb/dwc3.txt | 8 --- drivers/usb/dwc3/core.c | 18 +++++- drivers/usb/dwc3/core.h | 41 ++++++++++++- drivers/usb/dwc3/debug.h | 1 - drivers/usb/dwc3/debugfs.c | 1 - drivers/usb/dwc3/dwc3-omap.c | 1 - drivers/usb/dwc3/dwc3-pci.c | 1 - drivers/usb/dwc3/ep0.c | 58 ++++++----------- drivers/usb/dwc3/gadget.c | 115 +++++++++++++++++++++------------- drivers/usb/dwc3/gadget.h | 140 ++++++++---------------------------------- drivers/usb/dwc3/io.h | 1 - 11 files changed, 175 insertions(+), 210 deletions(-) diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt index 2f65853..7b590ed 100644 --- a/Documentation/usb/dwc3.txt +++ b/Documentation/usb/dwc3.txt @@ -3,14 +3,6 @@ ~~~~~~ Please pick something while reading :) -- Implement streaming support for BULK endpoints - Tatyana's patch "usb: Add streams support to the gadget framework" - introduces streaming support for the gadget driver. - Every usb_request has new field called stream_id which holds its id. - Every usb_ep has a field num_supported_strms which describes the max - number of streams supported (for this ep). - UAS is AFAIK the only gadget with streaming support. - - Convert interrupt handler to per-ep-thread-irq As it turns out some DWC3-commands ~1ms to complete. Currently we spin diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 64ba097..d35f905 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2,7 +2,6 @@ * core.c - DesignWare USB3 DRD Controller Core file * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> @@ -230,6 +229,21 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) } } +static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc) +{ + struct dwc3_hwparams *parms = &dwc->hwparams; + + parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); + parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); + parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); + parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); + parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); + parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); + parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); + parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); + parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -284,6 +298,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) goto err1; } + dwc3_cache_hwparams(dwc); + return 0; err1: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 07d2018..29a8e16 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -2,7 +2,6 @@ * core.h - DesignWare USB3 DRD Core Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> @@ -162,6 +161,7 @@ #define DWC3_GCTL_CORESOFTRESET (1 << 11) #define DWC3_GCTL_SCALEDOWN(n) (n << 4) #define DWC3_GCTL_DISSCRAMBLE (1 << 3) +#define DWC3_GCTL_DSBLCLKGTNG (1 << 0) /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) @@ -171,6 +171,11 @@ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) +/* Global HWPARAMS1 Register */ +#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24) +#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 +#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -330,6 +335,7 @@ struct dwc3_event_buffer { * @interval: the intervall on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk * @direction: true for TX, false for RX + * @stream_capable: true when streams are enabled */ struct dwc3_ep { struct usb_ep endpoint; @@ -363,6 +369,7 @@ struct dwc3_ep { char name[20]; unsigned direction:1; + unsigned stream_capable:1; }; enum dwc3_phy { @@ -506,6 +513,30 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) } /** + * dwc3_hwparams - copy of HWPARAMS registers + * @hwparams0 - GHWPARAMS0 + * @hwparams1 - GHWPARAMS1 + * @hwparams2 - GHWPARAMS2 + * @hwparams3 - GHWPARAMS3 + * @hwparams4 - GHWPARAMS4 + * @hwparams5 - GHWPARAMS5 + * @hwparams6 - GHWPARAMS6 + * @hwparams7 - GHWPARAMS7 + * @hwparams8 - GHWPARAMS8 + */ +struct dwc3_hwparams { + u32 hwparams0; + u32 hwparams1; + u32 hwparams2; + u32 hwparams3; + u32 hwparams4; + u32 hwparams5; + u32 hwparams6; + u32 hwparams7; + u32 hwparams8; +}; + +/** * struct dwc3 - representation of our controller * @ctrl_req: usb control request which is used for ep0 * @ep0_trb: trb which is used for the ctrl_req @@ -530,11 +561,13 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) * @ep0_status_pending: ep0 status response without a req is pending * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer + * @start_config_issued: true when StartConfig command has been issued * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state * @speed: device speed (super, high, full, low) * @mem: points to start of memory which is used for this struct. + * @hwparams: copy of hwparams registers * @root: debugfs root folder pointer */ struct dwc3 { @@ -577,6 +610,7 @@ struct dwc3 { unsigned ep0_status_pending:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; + unsigned start_config_issued:1; enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; @@ -586,6 +620,7 @@ struct dwc3 { u8 speed; void *mem; + struct dwc3_hwparams hwparams; struct dentry *root; }; @@ -649,6 +684,10 @@ struct dwc3_event_depevt { #define DEPEVT_STATUS_IOC (1 << 2) #define DEPEVT_STATUS_LST (1 << 3) +/* Stream event only */ +#define DEPEVT_STREAMEVT_FOUND 1 +#define DEPEVT_STREAMEVT_NOTFOUND 2 + /* Control-only Status */ #define DEPEVT_STATUS_CONTROL_SETUP 0 #define DEPEVT_STATUS_CONTROL_DATA 1 diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index ee3ba73..5894ee8 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -2,7 +2,6 @@ * debug.h - DesignWare USB3 DRD Controller Debug Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 20d329f..da1ad77 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -2,7 +2,6 @@ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 72cc92b..64ce3fc 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -2,7 +2,6 @@ * dwc3-omap.c - OMAP Specific Glue layer * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index e3b77d2..f77c000 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -2,7 +2,6 @@ * dwc3-pci.c - PCI Specific glue layer * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index b66d969..69a4e43 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -2,7 +2,6 @@ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> @@ -104,10 +103,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, dwc3_trb_to_hw(&trb, trb_hw); memset(¶ms, 0, sizeof(params)); - params.param0.depstrtxfer.transfer_desc_addr_high = - upper_32_bits(dwc->ep0_trb_addr); - params.param1.depstrtxfer.transfer_desc_addr_low = - lower_32_bits(dwc->ep0_trb_addr); + params.param0 = upper_32_bits(dwc->ep0_trb_addr); + params.param1 = lower_32_bits(dwc->ep0_trb_addr); ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_STARTTRANSFER, ¶ms); @@ -421,7 +418,6 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { - int ret = 0; u32 addr; u32 reg; @@ -429,29 +425,17 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) if (addr > 127) return -EINVAL; - switch (dwc->dev_state) { - case DWC3_DEFAULT_STATE: - case DWC3_ADDRESS_STATE: - /* - * Not sure if we should program DevAddr now or later - */ - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_DEVADDR_MASK); - reg |= DWC3_DCFG_DEVADDR(addr); - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - - if (addr) - dwc->dev_state = DWC3_ADDRESS_STATE; - else - dwc->dev_state = DWC3_DEFAULT_STATE; - break; + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg &= ~(DWC3_DCFG_DEVADDR_MASK); + reg |= DWC3_DCFG_DEVADDR(addr); + dwc3_writel(dwc->regs, DWC3_DCFG, reg); - case DWC3_CONFIGURED_STATE: - ret = -EINVAL; - break; - } + if (addr) + dwc->dev_state = DWC3_ADDRESS_STATE; + else + dwc->dev_state = DWC3_DEFAULT_STATE; - return ret; + return 0; } static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -469,6 +453,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) u32 cfg; int ret; + dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); switch (dwc->dev_state) { @@ -538,15 +523,15 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, len = le16_to_cpu(ctrl->wLength); if (!len) { - dwc->three_stage_setup = 0; + dwc->three_stage_setup = false; + dwc->ep0_expect_in = false; dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; } else { - dwc->three_stage_setup = 1; + dwc->three_stage_setup = true; + dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; } - dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) ret = dwc3_ep0_std_request(dwc, ctrl); else @@ -600,7 +585,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, /* for some reason we did not get everything out */ dwc3_ep0_stall_and_restart(dwc); - dwc3_gadget_giveback(dep, r, -ECONNRESET); } else { /* * handle the case where we have to send a zero packet. This @@ -753,8 +737,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) { dev_vdbg(dwc->dev, "Expected %d got %d\n", - DEPEVT_STATUS_CONTROL_DATA, - event->status); + dwc->ep0_next_event, + DWC3_EP0_NRDY_DATA); dwc3_ep0_stall_and_restart(dwc); return; @@ -782,8 +766,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) { dev_vdbg(dwc->dev, "Expected %d got %d\n", - DEPEVT_STATUS_CONTROL_STATUS, - event->status); + dwc->ep0_next_event, + DWC3_EP0_NRDY_STATUS); dwc3_ep0_stall_and_restart(dwc); return; @@ -799,7 +783,7 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc, dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n", dwc3_ep_event_string(event->endpoint_event), - epnum, (epnum & 1) ? "in" : "out", + epnum >> 1, (epnum & 1) ? "in" : "out", dwc3_ep0_state_string(dwc->ep0state)); switch (event->endpoint_event) { diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 859257a..fa824cf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2,7 +2,6 @@ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> @@ -159,12 +158,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", dep->name, - dwc3_gadget_ep_cmd_string(cmd), params->param0.raw, - params->param1.raw, params->param2.raw); + dwc3_gadget_ep_cmd_string(cmd), params->param0, + params->param1, params->param2); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0.raw); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1.raw); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2.raw); + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT); do { @@ -190,7 +189,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) { - u32 offset = trb - dep->trb_pool; + u32 offset = (char *) trb - (char *) dep->trb_pool; return dep->trb_pool_dma + offset; } @@ -238,8 +237,12 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) if (dep->number != 1) { cmd = DWC3_DEPCMD_DEPSTARTCFG; /* XferRscIdx == 0 for ep0 and 2 for the remaining */ - if (dep->number > 1) + if (dep->number > 1) { + if (dwc->start_config_issued) + return 0; + dwc->start_config_issued = true; cmd |= DWC3_DEPCMD_PARAM(2); + } return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); } @@ -254,14 +257,21 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, memset(¶ms, 0x00, sizeof(params)); - params.param0.depcfg.ep_type = usb_endpoint_type(desc); - params.param0.depcfg.max_packet_size = usb_endpoint_maxp(desc); + params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) + | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) + | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst); + + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN + | DWC3_DEPCFG_XFER_NOT_READY_EN; - params.param1.depcfg.xfer_complete_enable = true; - params.param1.depcfg.xfer_not_ready_enable = true; + if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) { + params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE + | DWC3_DEPCFG_STREAM_EVENT_EN; + dep->stream_capable = true; + } if (usb_endpoint_xfer_isoc(desc)) - params.param1.depcfg.xfer_in_progress_enable = true; + params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN; /* * We are doing 1:1 mapping for endpoints, meaning @@ -269,17 +279,17 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, * so on. We consider the direction bit as part of the physical * endpoint number. So USB endpoint 0x81 is 0x03. */ - params.param1.depcfg.ep_number = dep->number; + params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number); /* * We must use the lower 16 TX FIFOs even though * HW might have more */ if (dep->direction) - params.param0.depcfg.fifo_number = dep->number >> 1; + params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1); if (desc->bInterval) { - params.param1.depcfg.binterval_m1 = desc->bInterval - 1; + params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1); dep->interval = 1 << (desc->bInterval - 1); } @@ -293,7 +303,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) memset(¶ms, 0x00, sizeof(params)); - params.param0.depxfercfg.number_xfer_resources = 1; + params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); return dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_SETTRANSFRESOURCE, ¶ms); @@ -387,15 +397,16 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) struct dwc3 *dwc = dep->dwc; u32 reg; - dep->flags &= ~DWC3_EP_ENABLED; dwc3_remove_requests(dwc, dep); reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + dep->stream_capable = false; dep->desc = NULL; dep->type = 0; + dep->flags = 0; return 0; } @@ -629,6 +640,9 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep, trb.lst = last_one; } + if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) + trb.sid_sofn = req->request.stream_id; + switch (usb_endpoint_type(dep->desc)) { case USB_ENDPOINT_XFER_CONTROL: trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP; @@ -705,10 +719,8 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, } memset(¶ms, 0, sizeof(params)); - params.param0.depstrtxfer.transfer_desc_addr_high = - upper_32_bits(req->trb_dma); - params.param1.depstrtxfer.transfer_desc_addr_low = - lower_32_bits(req->trb_dma); + params.param0 = upper_32_bits(req->trb_dma); + params.param1 = lower_32_bits(req->trb_dma); if (start_new) cmd = DWC3_DEPCMD_STARTTRANSFER; @@ -891,6 +903,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) else dep->flags |= DWC3_EP_STALL; } else { + if (dep->flags & DWC3_EP_WEDGE) + return 0; + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_CLEARSTALL, ¶ms); if (ret) @@ -900,6 +915,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) else dep->flags &= ~DWC3_EP_STALL; } + return ret; } @@ -933,7 +949,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) dep->flags |= DWC3_EP_WEDGE; - return usb_ep_set_halt(ep); + return dwc3_gadget_ep_set_halt(ep, 1); } /* -------------------------------------------------------------------------- */ @@ -1146,6 +1162,14 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg &= ~DWC3_GCTL_DISSCRAMBLE; reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); + switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) { + case DWC3_GHWPARAMS1_EN_PWROPT_CLK: + reg &= ~DWC3_GCTL_DSBLCLKGTNG; + break; + default: + dev_dbg(dwc->dev, "No power optimization available\n"); + } + /* * WORKAROUND: DWC3 revisions <1.90a have a bug * when The device fails to connect at SuperSpeed @@ -1162,6 +1186,8 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg |= DWC3_DCFG_SUPERSPEED; dwc3_writel(dwc->regs, DWC3_DCFG, reg); + dwc->start_config_issued = false; + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); @@ -1495,12 +1521,28 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, } break; + case DWC3_DEPEVT_STREAMEVT: + if (!usb_endpoint_xfer_bulk(dep->desc)) { + dev_err(dwc->dev, "Stream event for non-Bulk %s\n", + dep->name); + return; + } + + switch (event->status) { + case DEPEVT_STREAMEVT_FOUND: + dev_vdbg(dwc->dev, "Stream %d found and started\n", + event->parameters); + + break; + case DEPEVT_STREAMEVT_NOTFOUND: + /* FALLTHROUGH */ + default: + dev_dbg(dwc->dev, "Couldn't find suitable stream\n"); + } + break; case DWC3_DEPEVT_RXTXFIFOEVT: dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name); break; - case DWC3_DEPEVT_STREAMEVT: - dev_dbg(dwc->dev, "%s Stream Event\n", dep->name); - break; case DWC3_DEPEVT_EPCMDCMPLT: dwc3_ep_cmd_compl(dep, event); break; @@ -1593,6 +1635,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc3_stop_active_transfers(dwc); dwc3_disconnect_gadget(dwc); + dwc->start_config_issued = false; dwc->gadget.speed = USB_SPEED_UNKNOWN; } @@ -1644,30 +1687,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); + dwc->start_config_issued = false; /* Reset device address to zero */ reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_DEVADDR_MASK); dwc3_writel(dwc->regs, DWC3_DCFG, reg); - - /* - * Wait for RxFifo to drain - * - * REVISIT probably shouldn't wait forever. - * In case Hardware ends up in a screwed up - * case, we error out, notify the user and, - * maybe, WARN() or BUG() but leave the rest - * of the kernel working fine. - * - * REVISIT the below is rather CPU intensive, - * maybe we should read and if it doesn't work - * sleep (not busy wait) for a few useconds. - * - * REVISIT why wait until the RXFIFO is empty anyway? - */ - while (!(dwc3_readl(dwc->regs, DWC3_DSTS) - & DWC3_DSTS_RXFIFOEMPTY)) - cpu_relax(); } static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 4809ac8..71145a4 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -2,7 +2,6 @@ * gadget.h - DesignWare USB3 DRD Gadget Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> @@ -48,120 +47,35 @@ struct dwc3; #define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint)) #define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget)) -/** - * struct dwc3_gadget_ep_depcfg_param1 - DEPCMDPAR0 for DEPCFG command - * @interrupt_number: self-explanatory - * @reserved7_5: set to zero - * @xfer_complete_enable: event generated when transfer completed - * @xfer_in_progress_enable: event generated when transfer in progress - * @xfer_not_ready_enable: event generated when transfer not read - * @fifo_error_enable: generates events when FIFO Underrun (IN eps) - * or FIFO Overrun (OUT) eps - * @reserved_12: set to zero - * @stream_event_enable: event generated on stream - * @reserved14_15: set to zero - * @binterval_m1: bInterval minus 1 - * @stream_capable: this EP is capable of handling streams - * @ep_number: self-explanatory - * @bulk_based: Set to ‘1’ if this isochronous endpoint represents a bulk - * data stream that ignores the relationship of bus time to the - * intervals programmed in TRBs. - * @fifo_based: Set to ‘1’ if this isochronous endpoint represents a - * FIFO-based data stream where TRBs have fixed values and are never - * written back by the core. - */ -struct dwc3_gadget_ep_depcfg_param1 { - u32 interrupt_number:5; - u32 reserved7_5:3; /* set to zero */ - u32 xfer_complete_enable:1; - u32 xfer_in_progress_enable:1; - u32 xfer_not_ready_enable:1; - u32 fifo_error_enable:1; /* IN-underrun, OUT-overrun */ - u32 reserved12:1; /* set to zero */ - u32 stream_event_enable:1; - u32 reserved14_15:2; - u32 binterval_m1:8; /* bInterval minus 1 */ - u32 stream_capable:1; - u32 ep_number:5; - u32 bulk_based:1; - u32 fifo_based:1; -} __packed; - -/** - * struct dwc3_gadget_ep_depcfg_param0 - Parameter 0 for DEPCFG - * @reserved0: set to zero - * @ep_type: Endpoint Type (control, bulk, iso, interrupt) - * @max_packet_size: max packet size in bytes - * @reserved16_14: set to zero - * @fifo_number: self-explanatory - * @burst_size: burst size minus 1 - * @data_sequence_number: Must be 0 when an endpoint is initially configured - * May be non-zero when an endpoint is configured after a power transition - * that requires a save/restore. - * @ignore_sequence_number: Set to ‘1’ to avoid resetting the sequence - * number. This setting is used by software to modify the DEPEVTEN - * event enable bits without modifying other endpoint settings. - */ -struct dwc3_gadget_ep_depcfg_param0 { - u32 reserved0:1; - u32 ep_type:2; - u32 max_packet_size:11; - u32 reserved16_14:3; - u32 fifo_number:5; - u32 burst_size:4; - u32 data_sequence_number:5; - u32 ignore_sequence_number:1; -} __packed; - -/** - * struct dwc3_gadget_ep_depxfercfg_param0 - Parameter 0 of DEPXFERCFG - * @number_xfer_resources: Defines the number of Transfer Resources allocated - * to this endpoint. This field must be set to 1. - * @reserved16_31: set to zero; - */ -struct dwc3_gadget_ep_depxfercfg_param0 { - u32 number_xfer_resources:16; - u32 reserved16_31:16; -} __packed; - -/** - * struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER - * @transfer_desc_addr_low: Indicates the lower 32 bits of the external - * memory's start address for the transfer descriptor. Because TRBs - * must be aligned to a 16-byte boundary, the lower 4 bits of this - * address must be 0. - */ -struct dwc3_gadget_ep_depstrtxfer_param1 { - u32 transfer_desc_addr_low; -} __packed; - -/** - * struct dwc3_gadget_ep_depstrtxfer_param1 - Parameter 1 of DEPSTRTXFER - * @transfer_desc_addr_high: Indicates the higher 32 bits of the external - * memory’s start address for the transfer descriptor. - */ -struct dwc3_gadget_ep_depstrtxfer_param0 { - u32 transfer_desc_addr_high; -} __packed; +/* DEPCFG parameter 1 */ +#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0) +#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8) +#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9) +#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10) +#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11) +#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13) +#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16) +#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24) +#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25) +#define DWC3_DEPCFG_BULK_BASED (1 << 30) +#define DWC3_DEPCFG_FIFO_BASED (1 << 31) + +/* DEPCFG parameter 0 */ +#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1) +#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3) +#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17) +#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22) +#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26) +#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31) + +/* DEPXFERCFG parameter 0 */ +#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff) struct dwc3_gadget_ep_cmd_params { - union { - u32 raw; - } param2; - - union { - u32 raw; - struct dwc3_gadget_ep_depcfg_param1 depcfg; - struct dwc3_gadget_ep_depstrtxfer_param1 depstrtxfer; - } param1; - - union { - u32 raw; - struct dwc3_gadget_ep_depcfg_param0 depcfg; - struct dwc3_gadget_ep_depxfercfg_param0 depxfercfg; - struct dwc3_gadget_ep_depstrtxfer_param0 depstrtxfer; - } param0; -} __packed; + u32 param2; + u32 param1; + u32 param0; +}; /* -------------------------------------------------------------------------- */ diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 0c4e2a9..bc957db 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -2,7 +2,6 @@ * io.h - DesignWare USB3 DRD IO Header * * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * All rights reserved. * * Authors: Felipe Balbi <balbi@xxxxxx>, * Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html