usb: dwc3: patches for v3.5 merge window

This pull request contains one workaround for a Silicon
 Issue found on all RTL releases prior to 2.20a, which
 would cause a metastability state on Run/Stop bit.
 
 We also have some patches implementing a few extra Standard
 requests introduced by USB3 spec (Set SEL and Set Isoch Delay),
 as well as one patch, which has been pending for a long time,
 implementing LPM support.
 
 Last, but not least, we are splitting the host address space
 out of the dwc3 core driver otherwise xHCI won't be able to
 request_mem_region() its own address space. This patch is
 only needed because we are (as we should) re-using the xHCI
 driver, which is a completely separate module.
 
 Together with these three big changes, come a few extra preparatory
 patches which most move code around, define macros and so on, as
 well as a fix for Isochronous transfers which hasn't been triggered
 before.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJPo7lXAAoJEIaOsuA1yqRESaIP/AgxZIfOAUbPx0GWLnhub3qr
 SxaUplweFc9q4KXRLn0kGdY9QArPR3bqW9g8KOTiRCBYRtjpACyMjibAUaAht81h
 +vLdPt87Slj2c14t1uguWFvgCUYQOCugkVvDIjRg9PCLIuTahm4cIBFqL3RJOHFf
 9WCd8JjH9ahr85ZtoCBk9B5bDNn71nS+Yh6/8+Ab90AE4vZ6t8Xx3+wLTHy2CBYQ
 UH1o61QZreAJ0J3OiUobjqrVbYwz6TM0dFYMjA6ko+OiPRhVOj8/C8aNl/U1whRm
 +7jjJiWO9aHp+Tu2OAQOBF6ydc3ZLBEiCl9RiE+O9MppmtOykzkTHFm1ZXatCEY7
 UUYOy43VXLNlHoz8nidNw6P25hAwwlSijzlyawpihKbIaE8le2MpE6I00AlciM2q
 BEo4LpluC8Rr6CUUr5W9dPZUexRlzxdAL5nQSJUnJgfEPphpP3x7dWTxUZBaWjq6
 akqjgGqVj1QKwMnqL4GILtRgdqWj6WYrw67fYVLHqj8QQla4cgXQ2sHp9/R0imvT
 nmjiL5ZiuIWWr965DgVHZwqIkdvMpSQb99a1xmptw8lFDGkVJDCssPDdEErbBMwy
 KmOSaqKeg/Yway05i+Pwo/NUKHQSZeiyuguzniMrF7iYFF1/2hVYRgfpH4V+95w/
 Xrnz4uH2YJGQGPddf87P
 =qgf/
 -----END PGP SIGNATURE-----

Merge tag 'dwc3-for-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

usb: dwc3: patches for v3.5 merge window

This pull request contains one workaround for a Silicon
Issue found on all RTL releases prior to 2.20a, which
would cause a metastability state on Run/Stop bit.

We also have some patches implementing a few extra Standard
requests introduced by USB3 spec (Set SEL and Set Isoch Delay),
as well as one patch, which has been pending for a long time,
implementing LPM support.

Last, but not least, we are splitting the host address space
out of the dwc3 core driver otherwise xHCI won't be able to
request_mem_region() its own address space. This patch is
only needed because we are (as we should) re-using the xHCI
driver, which is a completely separate module.

Together with these three big changes, come a few extra preparatory
patches which most move code around, define macros and so on, as
well as a fix for Isochronous transfers which hasn't been triggered
before.

[ resolved conflicts and build error in drivers/usb/dwc3/gadget.c - gregkh]
This commit is contained in:
Greg Kroah-Hartman 2012-05-07 10:09:55 -07:00
commit 23063b378d
9 changed files with 324 additions and 83 deletions

View File

@ -410,7 +410,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
int irq;
void __iomem *regs;
void *mem;
@ -425,15 +424,28 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing resource\n");
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
dwc->xhci_resources[1] = *res;
dwc->res = res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
return -ENODEV;
}
dwc->xhci_resources[0] = *res;
dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
DWC3_XHCI_REGS_END;
res = devm_request_mem_region(dev, res->start, resource_size(res),
/*
* Request memory region but exclude xHCI regs,
* since it will be requested by the xhci-plat driver.
*/
res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
resource_size(res) - DWC3_GLOBALS_REGS_START,
dev_name(dev));
if (!res) {
dev_err(dev, "can't request mem region\n");
@ -446,19 +458,12 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
return -ENOMEM;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;

View File

@ -51,7 +51,9 @@
#include <linux/usb/gadget.h>
/* Global constants */
#define DWC3_EP0_BOUNCE_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
#define DWC3_XHCI_RESOURCES_NUM 2
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
#define DWC3_EVENT_TYPE_MASK 0xfe
@ -75,6 +77,16 @@
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
/* DWC3 registers memory space boundries */
#define DWC3_XHCI_REGS_START 0x0
#define DWC3_XHCI_REGS_END 0x7fff
#define DWC3_GLOBALS_REGS_START 0xc100
#define DWC3_GLOBALS_REGS_END 0xc6ff
#define DWC3_DEVICE_REGS_START 0xc700
#define DWC3_DEVICE_REGS_END 0xcbff
#define DWC3_OTG_REGS_START 0xcc00
#define DWC3_OTG_REGS_END 0xccff
/* Global Registers */
#define DWC3_GSBUSCFG0 0xc100
#define DWC3_GSBUSCFG1 0xc104
@ -183,6 +195,7 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
/* Device Configuration Register */
#define DWC3_DCFG_LPM_CAP (1 << 22)
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@ -272,12 +285,14 @@
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1)
#define DWC3_DGCMD_CMDACT (1 << 10)
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8)
@ -560,6 +575,11 @@ struct dwc3_request {
* @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.
* @isoch_delay: wValue from Set Isochronous Delay request;
* @u2sel: parameter from Set SEL request.
* @u2pel: parameter from Set SEL request.
* @u1sel: parameter from Set SEL request.
* @u1pel: parameter from Set SEL request.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@ -582,7 +602,7 @@ struct dwc3 {
struct device *dev;
struct platform_device *xhci;
struct resource *res;
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
@ -593,8 +613,6 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
int irq;
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@ -608,6 +626,10 @@ struct dwc3 {
#define DWC3_REVISION_185A 0x5533185a
#define DWC3_REVISION_188A 0x5533188a
#define DWC3_REVISION_190A 0x5533190a
#define DWC3_REVISION_200A 0x5533200a
#define DWC3_REVISION_202A 0x5533202a
#define DWC3_REVISION_210A 0x5533210a
#define DWC3_REVISION_220A 0x5533220a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@ -624,7 +646,14 @@ struct dwc3 {
enum dwc3_link_state link_state;
enum dwc3_device_state dev_state;
u16 isoch_delay;
u16 u2sel;
u16 u2pel;
u8 u1sel;
u8 u1pel;
u8 speed;
void *mem;
struct dwc3_hwparams hwparams;

View File

@ -49,7 +49,6 @@
#include <linux/of.h>
#include "core.h"
#include "io.h"
/*
* All these registers belong to OMAP's Wrapper around the
@ -143,6 +142,17 @@ struct dwc3_omap {
u32 dma_status:1;
};
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
return readl(base + offset);
}
static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
{
writel(value, base + offset);
}
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
@ -150,7 +160,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
spin_lock(&omap->lock);
reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@ -184,10 +194,10 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
spin_unlock(&omap->lock);
@ -270,7 +280,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
omap->base = base;
omap->dwc3 = dwc3;
reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
@ -293,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
}
}
dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
@ -306,7 +316,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
@ -318,7 +328,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
@ -330,7 +340,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);

View File

@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
{
struct dwc3_ep *dep;
u32 recip;
u32 reg;
u16 usb_status = 0;
__le16 *response_pkt;
@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
/*
* We are self-powered. U1/U2/LTM will be set later
* once we handle this states. RemoteWakeup is 0 on SS
* LTM will be set once we know how to set this in HW.
*/
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU1ENA)
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
if (reg & DWC3_DCTL_INITU2ENA)
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
}
break;
case USB_RECIP_INTERFACE:
@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip;
u32 wValue;
u32 wIndex;
u32 reg;
int ret;
wValue = le16_to_cpu(ctrl->wValue);
@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
/*
* 9.4.1 says only only for SS, in AddressState only for
* default control pipe
*/
switch (wValue) {
case USB_DEVICE_U1_ENABLE:
case USB_DEVICE_U2_ENABLE:
case USB_DEVICE_LTM_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
}
/* XXX add U[12] & LTM */
switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
case USB_DEVICE_U1_ENABLE:
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU1ENA;
else
reg &= ~DWC3_DCTL_INITU1ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
case USB_DEVICE_U2_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU2ENA;
else
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
case USB_DEVICE_LTM_ENABLE:
return -EINVAL;
break;
case USB_DEVICE_TEST_MODE:
@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return ret;
}
static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
u32 param = 0;
u32 reg;
struct timing {
u8 u1sel;
u8 u1pel;
u16 u2sel;
u16 u2pel;
} __packed timing;
int ret;
memcpy(&timing, req->buf, sizeof(timing));
dwc->u1sel = timing.u1sel;
dwc->u1pel = timing.u1pel;
dwc->u2sel = timing.u2sel;
dwc->u2pel = timing.u2pel;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU2ENA)
param = dwc->u2pel;
if (reg & DWC3_DCTL_INITU1ENA)
param = dwc->u1pel;
/*
* According to Synopsys Databook, if parameter is
* greater than 125, a value of zero should be
* programmed in the register.
*/
if (param > 125)
param = 0;
/* now that we have the time, issue DGCMD Set Sel */
ret = dwc3_send_gadget_generic_command(dwc,
DWC3_DGCMD_SET_PERIODIC_PAR, param);
WARN_ON(ret < 0);
}
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
struct dwc3_ep *dep;
u16 wLength;
u16 wValue;
if (dwc->dev_state == DWC3_DEFAULT_STATE)
return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);
wLength = le16_to_cpu(ctrl->wLength);
if (wLength != 6) {
dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
wLength);
return -EINVAL;
}
/*
* To handle Set SEL we need to receive 6 bytes from Host. So let's
* queue a usb_request for 6 bytes.
*
* Remember, though, this controller can't handle non-wMaxPacketSize
* aligned transfers on the OUT direction, so we queue a request for
* wMaxPacketSize instead.
*/
dep = dwc->eps[0];
dwc->ep0_usb_req.dep = dep;
dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
dwc->ep0_usb_req.request.buf = dwc->setup_buf;
dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
}
static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
u16 wLength;
u16 wValue;
u16 wIndex;
wValue = le16_to_cpu(ctrl->wValue);
wLength = le16_to_cpu(ctrl->wLength);
wIndex = le16_to_cpu(ctrl->wIndex);
if (wIndex || wLength)
return -EINVAL;
/*
* REVISIT It's unclear from Databook what to do with this
* value. For now, just cache it.
*/
dwc->isoch_delay = wValue;
return 0;
}
static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
int ret;
@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
ret = dwc3_ep0_set_config(dwc, ctrl);
break;
case USB_REQ_SET_SEL:
dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
ret = dwc3_ep0_set_sel(dwc, ctrl);
break;
case USB_REQ_SET_ISOCH_DELAY:
dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
break;
default:
dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
ret = dwc3_ep0_delegate_req(dwc, ctrl);

View File

@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
}
}
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
{
u32 timeout = 500;
u32 reg;
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
DWC3_DGCMD_STATUS(reg));
return 0;
}
/*
* We can't sleep here, because it's also called from
* interrupt context.
*/
timeout--;
if (!timeout)
return -ETIMEDOUT;
udelay(1);
} while (1);
}
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
@ -929,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
}
dep->flags |= DWC3_EP_BUSY;
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
dep->number);
WARN_ON_ONCE(!dep->res_trans_idx);
if (start_new) {
dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
dep->number);
WARN_ON_ONCE(!dep->res_trans_idx);
}
return 0;
}
@ -966,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
list_add_tail(&req->list, &dep->request_list);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
dep->flags |= DWC3_EP_PENDING_REQUEST;
/*
* There is one special case: XferNotReady with
* empty list of requests. We need to kick the
* transfer here in that situation, otherwise
* we will be NAKing forever.
* There are two special cases:
*
* If we get XferNotReady before gadget driver
* has a chance to queue a request, we will ACK
* the IRQ but won't be able to receive the data
* until the next request is queued. The following
* code is handling exactly that.
* 1. XferNotReady with empty list of requests. We need to kick the
* transfer here in that situation, otherwise we will be NAKing
* forever. If we get XferNotReady before gadget driver has a
* chance to queue a request, we will ACK the IRQ but won't be
* able to receive the data until the next request is queued.
* The following code is handling exactly that.
*
* 2. XferInProgress on Isoc EP with an active transfer. We need to
* kick the transfer here after queuing a request, otherwise the
* core may not see the modified TRB(s).
*/
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
int ret;
int start_trans;
int ret;
int start_trans = 1;
u8 trans_idx = dep->res_trans_idx;
start_trans = 1;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(dep->flags & DWC3_EP_BUSY))
(dep->flags & DWC3_EP_BUSY)) {
start_trans = 0;
WARN_ON_ONCE(!trans_idx);
} else {
trans_idx = 0;
}
ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
@ -1355,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g,
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
reg |= dwc->maximum_speed;
/**
* WORKAROUND: DWC3 revision < 2.20a have an issue
* which would cause metastability state on Run/Stop
* bit if we try to force the IP to USB2-only mode.
*
* Because of that, we cannot configure the IP to any
* speed other than the SuperSpeed
*
* Refers to:
*
* STAR#9000525659: Clock Domain Crossing on DCTL in
* USB 2.0 Mode
*/
if (dwc->revision < DWC3_REVISION_220A)
reg |= DWC3_DCFG_SUPERSPEED;
else
reg |= dwc->maximum_speed;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc->start_config_issued = false;
@ -1915,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->test_mode = false;
@ -2262,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err1;
}
dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
GFP_KERNEL);
dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
@ -2271,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
512, &dwc->ep0_bounce_addr, GFP_KERNEL);
DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
@ -2312,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err5;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN |
@ -2350,8 +2414,8 @@ err5:
dwc3_gadget_free_endpoints(dwc);
err4:
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);
dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
dwc->ep0_bounce, dwc->ep0_bounce_addr);
err3:
kfree(dwc->setup_buf);
@ -2380,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc3_gadget_free_endpoints(dwc);
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);
dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
dwc->ep0_bounce, dwc->ep0_bounce_addr);
kfree(dwc->setup_buf);

View File

@ -111,6 +111,7 @@ 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);
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW

View File

@ -39,15 +39,6 @@
#include "core.h"
static struct resource generic_resources[] = {
{
.flags = IORESOURCE_IRQ,
},
{
.flags = IORESOURCE_MEM,
},
};
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
@ -68,14 +59,8 @@ int dwc3_host_init(struct dwc3 *dwc)
dwc->xhci = xhci;
/* setup resources */
generic_resources[0].start = dwc->irq;
generic_resources[1].start = dwc->res->start;
generic_resources[1].end = dwc->res->start + 0x7fff;
ret = platform_device_add_resources(xhci, generic_resources,
ARRAY_SIZE(generic_resources));
ret = platform_device_add_resources(xhci, dwc->xhci_resources,
DWC3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;

View File

@ -41,14 +41,26 @@
#include <linux/io.h>
#include "core.h"
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
return readl(base + offset);
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
return readl(base + (offset - DWC3_GLOBALS_REGS_START));
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
writel(value, base + offset);
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */

View File

@ -88,6 +88,8 @@
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_SEL 0x30
#define USB_REQ_SET_ISOCH_DELAY 0x31
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E