summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c123
-rw-r--r--drivers/usb/dwc3/core.h35
-rw-r--r--drivers/usb/dwc3/debug.h2
-rw-r--r--drivers/usb/dwc3/dwc3-of-simple.c47
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c15
-rw-r--r--drivers/usb/dwc3/gadget.c329
-rw-r--r--drivers/usb/dwc3/ulpi.c10
8 files changed, 327 insertions, 236 deletions
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index a64ce1c94d6d..b97cde76914d 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,7 +1,7 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && HAS_DMA
- select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
+ select USB_XHCI_PLATFORM if USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 946643157b78..7287a763cd0c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -49,6 +49,57 @@
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
+/**
+ * dwc3_get_dr_mode - Validates and sets dr_mode
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_get_dr_mode(struct dwc3 *dwc)
+{
+ enum usb_dr_mode mode;
+ struct device *dev = dwc->dev;
+ unsigned int hw_mode;
+
+ if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+ dwc->dr_mode = USB_DR_MODE_OTG;
+
+ mode = dwc->dr_mode;
+ hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
+ switch (hw_mode) {
+ case DWC3_GHWPARAMS0_MODE_GADGET:
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
+ dev_err(dev,
+ "Controller does not support host mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_PERIPHERAL;
+ break;
+ case DWC3_GHWPARAMS0_MODE_HOST:
+ if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+ dev_err(dev,
+ "Controller does not support device mode.\n");
+ return -EINVAL;
+ }
+ mode = USB_DR_MODE_HOST;
+ break;
+ default:
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+ mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+ mode = USB_DR_MODE_PERIPHERAL;
+ }
+
+ if (mode != dwc->dr_mode) {
+ dev_warn(dev,
+ "Configuration mismatch. dr_mode forced to %s\n",
+ mode == USB_DR_MODE_HOST ? "host" : "gadget");
+
+ dwc->dr_mode = mode;
+ }
+
+ return 0;
+}
+
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
u32 reg;
@@ -448,6 +499,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_u3_susphy_quirk)
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+ if (dwc->dis_del_phy_power_chg_quirk)
+ reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -485,6 +539,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
break;
}
+ switch (dwc->hsphy_mode) {
+ case USBPHY_INTERFACE_MODE_UTMI:
+ reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+ DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+ reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
+ DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
+ break;
+ case USBPHY_INTERFACE_MODE_UTMIW:
+ reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+ DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+ reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
+ DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+ break;
+ default:
+ break;
+ }
+
/*
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
* '0' during coreConsultant configuration. So default value will
@@ -500,6 +571,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
+ if (dwc->dis_u2_freeclk_exists_quirk)
+ reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
return 0;
@@ -666,6 +740,32 @@ static int dwc3_core_init(struct dwc3 *dwc)
goto err4;
}
+ switch (dwc->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ break;
+ case USB_DR_MODE_HOST:
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+ break;
+ case USB_DR_MODE_OTG:
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ break;
+ default:
+ dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
+ break;
+ }
+
+ /*
+ * ENDXFER polling is available on version 3.10a and later of
+ * the DWC_usb3 controller. It is NOT available in the
+ * DWC_usb31 controller.
+ */
+ if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
+ reg |= DWC3_GUCTL2_RST_ACTBITLATER;
+ dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
+ }
+
return 0;
err4:
@@ -763,7 +863,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -772,7 +871,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_HOST:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -781,7 +879,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_OTG:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -888,6 +985,7 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->maximum_speed = usb_get_maximum_speed(dev);
dwc->dr_mode = usb_get_dr_mode(dev);
+ dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
dwc->has_lpm_erratum = device_property_read_bool(dev,
"snps,has-lpm-erratum");
@@ -924,6 +1022,10 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,dis_enblslpm_quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
+ dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+ "snps,dis-u2-freeclk-exists-quirk");
+ dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+ "snps,dis-del-phy-power-chg-quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
@@ -972,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2;
}
- if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
- (dwc->dr_mode == USB_DR_MODE_OTG ||
- dwc->dr_mode == USB_DR_MODE_UNKNOWN))
- dwc->dr_mode = USB_DR_MODE_HOST;
- else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
- (dwc->dr_mode == USB_DR_MODE_OTG ||
- dwc->dr_mode == USB_DR_MODE_UNKNOWN))
- dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
-
- if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
- dwc->dr_mode = USB_DR_MODE_OTG;
+ ret = dwc3_get_dr_mode(dwc);
+ if (ret)
+ goto err3;
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
@@ -1192,6 +1286,7 @@ static int dwc3_runtime_resume(struct device *dev)
}
pm_runtime_mark_last_busy(dev);
+ pm_runtime_put(dev);
return 0;
}
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 45d6de5107c7..6b60e42626a2 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -109,6 +109,7 @@
#define DWC3_GPRTBIMAP_HS1 0xc184
#define DWC3_GPRTBIMAP_FS0 0xc188
#define DWC3_GPRTBIMAP_FS1 0xc18c
+#define DWC3_GUCTL2 0xc19c
#define DWC3_VER_NUMBER 0xc1a0
#define DWC3_VER_TYPE 0xc1a4
@@ -199,9 +200,18 @@
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT 9
+#define USBTRDTIM_UTMI_16_BIT 5
+#define UTMI_PHYIF_16_BIT 1
+#define UTMI_PHYIF_8_BIT 0
/* Global USB2 PHY Vendor Control Register */
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
@@ -235,7 +245,10 @@
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
/* Global HWPARAMS0 Register */
-#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE(n) ((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE_GADGET 0
+#define DWC3_GHWPARAMS0_MODE_HOST 1
+#define DWC3_GHWPARAMS0_MODE_DRD 2
#define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7)
#define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3)
#define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff)
@@ -279,6 +292,9 @@
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
+/* Global User Control Register 2 */
+#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14)
+
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -685,6 +701,8 @@ struct dwc3_hwparams {
* @request: struct usb_request to be transferred
* @list: a list_head used for request queueing
* @dep: struct dwc3_ep owning this request
+ * @sg: pointer to first incomplete sg
+ * @num_pending_sgs: counter to pending sgs
* @first_trb_index: index to first trb used by this request
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
@@ -697,7 +715,9 @@ struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
+ struct scatterlist *sg;
+ unsigned num_pending_sgs;
u8 first_trb_index;
u8 epnum;
struct dwc3_trb *trb;
@@ -743,6 +763,9 @@ struct dwc3_scratchpad_array {
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @dr_mode: requested mode of operation
+ * @hsphy_mode: UTMI phy mode, one of following:
+ * - USBPHY_INTERFACE_MODE_UTMI
+ * - USBPHY_INTERFACE_MODE_UTMIW
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
@@ -799,6 +822,11 @@ struct dwc3_scratchpad_array {
* @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
* @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
* disabling the suspend signal to the PHY.
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ * in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ * provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ * change quirk.
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis
@@ -845,6 +873,7 @@ struct dwc3 {
size_t regs_size;
enum usb_dr_mode dr_mode;
+ enum usb_phy_interface hsphy_mode;
u32 fladj;
u32 irq_gadget;
@@ -880,6 +909,8 @@ struct dwc3 {
#define DWC3_REVISION_260A 0x5533260a
#define DWC3_REVISION_270A 0x5533270a
#define DWC3_REVISION_280A 0x5533280a
+#define DWC3_REVISION_300A 0x5533300a
+#define DWC3_REVISION_310A 0x5533310a
/*
* NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
@@ -942,6 +973,8 @@ struct dwc3 {
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
+ unsigned dis_u2_freeclk_exists_quirk:1;
+ unsigned dis_del_phy_power_chg_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 22dfc3dd6a13..33ab2a203c1b 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -192,7 +192,7 @@ dwc3_ep_event_string(const struct dwc3_event_depevt *event)
int ret;
ret = sprintf(str, "ep%d%s: ", epnum >> 1,
- (epnum & 1) ? "in" : "in");
+ (epnum & 1) ? "in" : "out");
if (ret < 0)
return "UNKNOWN";
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index 974335377d9f..fe414e7a9c78 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -36,35 +36,25 @@ struct dwc3_of_simple {
int num_clocks;
};
-static int dwc3_of_simple_probe(struct platform_device *pdev)
+static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
{
- struct dwc3_of_simple *simple;
- struct device *dev = &pdev->dev;
+ struct device *dev = simple->dev;
struct device_node *np = dev->of_node;
-
- unsigned int count;
- int ret;
int i;
- simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
- if (!simple)
- return -ENOMEM;
+ simple->num_clocks = count;
- count = of_clk_get_parent_count(np);
if (!count)
- return -ENOENT;
-
- simple->num_clocks = count;
+ return 0;
simple->clks = devm_kcalloc(dev, simple->num_clocks,
sizeof(struct clk *), GFP_KERNEL);
if (!simple->clks)
return -ENOMEM;
- simple->dev = dev;
-
for (i = 0; i < simple->num_clocks; i++) {
struct clk *clk;
+ int ret;
clk = of_clk_get(np, i);
if (IS_ERR(clk)) {
@@ -87,6 +77,29 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
simple->clks[i] = clk;
}
+ return 0;
+}
+
+static int dwc3_of_simple_probe(struct platform_device *pdev)
+{
+ struct dwc3_of_simple *simple;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ int ret;
+ int i;
+
+ simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL);
+ if (!simple)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, simple);
+ simple->dev = dev;
+
+ ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np));
+ if (ret)
+ return ret;
+
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) {
for (i = 0; i < simple->num_clocks; i++) {
@@ -111,7 +124,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
int i;
for (i = 0; i < simple->num_clocks; i++) {
- clk_unprepare(simple->clks[i]);
+ clk_disable_unprepare(simple->clks[i]);
clk_put(simple->clks[i]);
}
@@ -161,7 +174,9 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
static const struct of_device_id of_dwc3_simple_match[] = {
{ .compatible = "qcom,dwc3" },
+ { .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "xlnx,zynqmp-dwc3" },
+ { .compatible = "cavium,octeon-7130-usb-uctl" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 45f5a232d9fb..6df0f5dad9a4 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -37,6 +37,7 @@
#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa
#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa
#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
+#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@@ -227,6 +228,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */
};
@@ -241,6 +243,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev)
return -EBUSY;
}
+static int dwc3_pci_runtime_resume(struct device *dev)
+{
+ struct platform_device *dwc3 = dev_get_drvdata(dev);
+
+ return pm_runtime_get(&dwc3->dev);
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
static int dwc3_pci_pm_dummy(struct device *dev)
{
/*
@@ -253,11 +264,11 @@ static int dwc3_pci_pm_dummy(struct device *dev)
*/
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_pm_dummy, dwc3_pci_pm_dummy)
- SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_pm_dummy,
+ SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,
NULL)
};
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8f8c2157910e..07cc8929f271 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -174,15 +174,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status)
{
struct dwc3 *dwc = dep->dwc;
- int i;
- if (req->started) {
- i = 0;
- do {
- dwc3_ep_inc_deq(dep);
- } while(++i < req->request.num_mapped_sgs);
- req->started = false;
- }
+ req->started = false;
list_del(&req->list);
req->trb = NULL;
@@ -348,7 +341,8 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
* IN transfers due to a mishandled error condition. Synopsys
* STAR 9000614252.
*/
- if (dep->direction && (dwc->revision >= DWC3_REVISION_260A))
+ if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) &&
+ (dwc->gadget.speed >= USB_SPEED_SUPER))
cmd |= DWC3_DEPCMD_CLEARPENDIN;
memset(&params, 0, sizeof(params));
@@ -490,7 +484,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
params.param0 |= DWC3_DEPCFG_ACTION_INIT;
}
- params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
+ if (usb_endpoint_xfer_control(desc))
+ params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
@@ -764,6 +759,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
kfree(req);
}
+static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep);
+
/**
* dwc3_prepare_one_trb - setup one TRB from one request
* @dep: endpoint for which this request is prepared
@@ -771,15 +768,13 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
*/
static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
- unsigned length, unsigned last, unsigned chain, unsigned node)
+ unsigned length, unsigned chain, unsigned node)
{
struct dwc3_trb *trb;
- dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
+ dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s",
dep->name, req, (unsigned long long) dma,
- length, last ? " last" : "",
- chain ? " chain" : "");
-
+ length, chain ? " chain" : "");
trb = &dep->trb_pool[dep->trb_enqueue];
@@ -826,12 +821,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
/* always enable Continue on Short Packet */
trb->ctrl |= DWC3_TRB_CTRL_CSP;
- if (!req->request.no_interrupt && !chain)
+ if ((!req->request.no_interrupt && !chain) ||
+ (dwc3_calc_trbs_left(dep) == 0))
trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
- if (last)
- trb->ctrl |= DWC3_TRB_CTRL_LST;
-
if (chain)
trb->ctrl |= DWC3_TRB_CTRL_CHN;
@@ -856,12 +849,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
*/
static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)
{
- if (!index)
- index = DWC3_TRB_NUM - 2;
- else
- index = dep->trb_enqueue - 1;
+ u8 tmp = index;
+
+ if (!tmp)
+ tmp = DWC3_TRB_NUM - 1;
- return &dep->trb_pool[index];
+ return &dep->trb_pool[tmp - 1];
}
static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
@@ -894,65 +887,42 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
}
static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
- struct dwc3_request *req, unsigned int trbs_left,
- unsigned int more_coming)
+ struct dwc3_request *req)
{
- struct usb_request *request = &req->request;
- struct scatterlist *sg = request->sg;
+ struct scatterlist *sg = req->sg;
struct scatterlist *s;
- unsigned int last = false;
unsigned int length;
dma_addr_t dma;
int i;
- for_each_sg(sg, s, request->num_mapped_sgs, i) {
+ for_each_sg(sg, s, req->num_pending_sgs, i) {
unsigned chain = true;
length = sg_dma_len(s);
dma = sg_dma_address(s);
- if (sg_is_last(s)) {
- if (usb_endpoint_xfer_int(dep->endpoint.desc) ||
- !more_coming)
- last = true;
-
- chain = false;
- }
-
- if (!trbs_left--)
- last = true;
-
- if (last)
+ if (sg_is_last(s))
chain = false;
dwc3_prepare_one_trb(dep, req, dma, length,
- last, chain, i);
+ chain, i);
- if (last)
+ if (!dwc3_calc_trbs_left(dep))
break;
}
}
static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
- struct dwc3_request *req, unsigned int trbs_left,
- unsigned int more_coming)
+ struct dwc3_request *req)
{
- unsigned int last = false;
unsigned int length;
dma_addr_t dma;
dma = req->request.dma;
length = req->request.length;
- if (!trbs_left)
- last = true;
-
- /* Is this the last request? */
- if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming)
- last = true;
-
dwc3_prepare_one_trb(dep, req, dma, length,
- last, false, 0);
+ false, 0);
}
/*
@@ -966,26 +936,19 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
static void dwc3_prepare_trbs(struct dwc3_ep *dep)
{
struct dwc3_request *req, *n;
- unsigned int more_coming;
- u32 trbs_left;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
- trbs_left = dwc3_calc_trbs_left(dep);
- if (!trbs_left)
+ if (!dwc3_calc_trbs_left(dep))
return;
- more_coming = dep->allocated_requests - dep->queued_requests;
-
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
- if (req->request.num_mapped_sgs > 0)
- dwc3_prepare_one_trb_sg(dep, req, trbs_left--,
- more_coming);
+ if (req->num_pending_sgs > 0)
+ dwc3_prepare_one_trb_sg(dep, req);
else
- dwc3_prepare_one_trb_linear(dep, req, trbs_left--,
- more_coming);
+ dwc3_prepare_one_trb_linear(dep, req);
- if (!trbs_left)
+ if (!dwc3_calc_trbs_left(dep))
return;
}
}
@@ -1101,93 +1064,29 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
trace_dwc3_ep_queue(req);
- /*
- * We only add to our list of requests now and
- * start consuming the list once we get XferNotReady
- * IRQ.
- *
- * That way, we avoid doing anything that we don't need
- * to do now and defer it until the point we receive a
- * particular token from the Host side.
- *
- * This will also avoid Host cancelling URBs due to too
- * many NAKs.
- */
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->direction);
if (ret)
return ret;
- list_add_tail(&req->list, &dep->pending_list);
+ req->sg = req->request.sg;
+ req->num_pending_sgs = req->request.num_mapped_sgs;
- /*
- * If there are no pending requests and the endpoint isn't already
- * busy, we will just start the request straight away.
- *
- * This will save one IRQ (XFER_NOT_READY) and possibly make it a
- * little bit faster.
- */
- if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
- !usb_endpoint_xfer_int(dep->endpoint.desc)) {
- ret = __dwc3_gadget_kick_transfer(dep, 0);
- goto out;
- }
-
- /*
- * There are a few special cases:
- *
- * 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.
- *
- */
- if (dep->flags & DWC3_EP_PENDING_REQUEST) {
- /*
- * If xfernotready is already elapsed and it is a case
- * of isoc transfer, then issue END TRANSFER, so that
- * you can receive xfernotready again and can have
- * notion of current microframe.
- */
- if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- if (list_empty(&dep->started_list)) {
- dwc3_stop_active_transfer(dwc, dep->number, true);
- dep->flags = DWC3_EP_ENABLED;
- }
- return 0;
- }
-
- ret = __dwc3_gadget_kick_transfer(dep, 0);
- if (!ret)
- dep->flags &= ~DWC3_EP_PENDING_REQUEST;
-
- goto out;
- }
+ list_add_tail(&req->list, &dep->pending_list);
- /*
- * 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 (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
- (dep->flags & DWC3_EP_BUSY) &&
- !(dep->flags & DWC3_EP_MISSED_ISOC)) {
- WARN_ON_ONCE(!dep->resource_index);
- ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index);
- goto out;
+ dep->flags & DWC3_EP_PENDING_REQUEST) {
+ if (list_empty(&dep->started_list)) {
+ dwc3_stop_active_transfer(dwc, dep->number, true);
+ dep->flags = DWC3_EP_ENABLED;
+ }
+ return 0;
}
- /*
- * 4. Stream Capable Bulk Endpoints. We need to start the transfer
- * right away, otherwise host will not know we have streams to be
- * handled.
- */
- if (dep->stream_capable)
- ret = __dwc3_gadget_kick_transfer(dep, 0);
+ if (!dwc3_calc_trbs_left(dep))
+ return 0;
-out:
+ ret = __dwc3_gadget_kick_transfer(dep, 0);
if (ret && ret != -EBUSY)
dwc3_trace(trace_dwc3_gadget,
"%s: failed to kick transfers",
@@ -1433,7 +1332,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
{
- unsigned long timeout;
+ int retries;
int ret;
u32 reg;
@@ -1484,9 +1383,9 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
}
/* poll until Link State changes to ON */
- timeout = jiffies + msecs_to_jiffies(100);
+ retries = 20000;
- while (!time_after(jiffies, timeout)) {
+ while (retries--) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
@@ -1955,27 +1854,35 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
struct dwc3_request *req, struct dwc3_trb *trb,
- const struct dwc3_event_depevt *event, int status)
+ const struct dwc3_event_depevt *event, int status,
+ int chain)
{
unsigned int count;
unsigned int s_pkt = 0;
unsigned int trb_status;
dep->queued_requests--;
+ dwc3_ep_inc_deq(dep);
trace_dwc3_complete_trb(dep, trb);
+ /*
+ * If we're in the middle of series of chained TRBs and we
+ * receive a short transfer along the way, DWC3 will skip
+ * through all TRBs including the last TRB in the chain (the
+ * where CHN bit is zero. DWC3 will also avoid clearing HWO
+ * bit and SW has to do it manually.
+ *
+ * We're going to do that here to avoid problems of HW trying
+ * to use bogus TRBs for transfers.
+ */
+ if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
+ trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+
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 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, trb);
+ return 1;
+
count = trb->size & DWC3_TRB_SIZE_MASK;
+ req->request.actual += count;
if (dep->direction) {
if (count) {
@@ -2013,59 +1920,76 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
s_pkt = 1;
}
- /*
- * We assume here we will always receive the entire data block
- * which we should receive. Meaning, if we program RX to
- * receive 4K but we receive only 2K, we assume that's all we
- * should receive and we simply bounce the request back to the
- * gadget driver for further processing.
- */
- req->request.actual += req->request.length - count;
- if (s_pkt)
- return 1;
- if ((event->status & DEPEVT_STATUS_LST) &&
- (trb->ctrl & (DWC3_TRB_CTRL_LST |
- DWC3_TRB_CTRL_HWO)))
+ if (s_pkt && !chain)
return 1;
+
if ((event->status & DEPEVT_STATUS_IOC) &&
(trb->ctrl & DWC3_TRB_CTRL_IOC))
return 1;
+
return 0;
}
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_request *req, *n;
struct dwc3_trb *trb;
- unsigned int slot;
- unsigned int i;
+ bool ioc = false;
int ret;
- do {
- req = next_request(&dep->started_list);
- if (WARN_ON_ONCE(!req))
- return 1;
+ list_for_each_entry_safe(req, n, &dep->started_list, list) {
+ unsigned length;
+ unsigned actual;
+ int chain;
+
+ length = req->request.length;
+ chain = req->num_pending_sgs > 0;
+ if (chain) {
+ struct scatterlist *sg = req->sg;
+ struct scatterlist *s;
+ unsigned int pending = req->num_pending_sgs;
+ unsigned int i;
+
+ for_each_sg(sg, s, pending, i) {
+ trb = &dep->trb_pool[dep->trb_dequeue];
+
+ req->sg = sg_next(s);
+ req->num_pending_sgs--;
+
+ ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+ event, status, chain);
+ if (ret)
+ break;
+ }
+ } else {
+ trb = &dep->trb_pool[dep->trb_dequeue];
+ ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+ event, status, chain);
+ }
- i = 0;
- do {
- slot = req->first_trb_index + i;
- if (slot == DWC3_TRB_NUM - 1)
- slot++;
- slot %= DWC3_TRB_NUM;
- trb = &dep->trb_pool[slot];
+ /*
+ * We assume here we will always receive the entire data block
+ * which we should receive. Meaning, if we program RX to
+ * receive 4K but we receive only 2K, we assume that's all we
+ * should receive and we simply bounce the request back to the
+ * gadget driver for further processing.
+ */
+ actual = length - req->request.actual;
+ req->request.actual = actual;
- ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
- event, status);
- if (ret)
- break;
- } while (++i < req->request.num_mapped_sgs);
+ if (ret && chain && (actual < length) && req->num_pending_sgs)
+ return __dwc3_gadget_kick_transfer(dep, 0);
dwc3_gadget_giveback(dep, req, status);
- if (ret)
+ if (ret) {
+ if ((event->status & DEPEVT_STATUS_IOC) &&
+ (trb->ctrl & DWC3_TRB_CTRL_IOC))
+ ioc = true;
break;
- } while (1);
+ }
+ }
/*
* Our endpoint might get disabled by another thread during
@@ -2092,10 +2016,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
return 1;
}
- if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
- if ((event->status & DEPEVT_STATUS_IOC) &&
- (trb->ctrl & DWC3_TRB_CTRL_IOC))
- return 0;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && ioc)
+ return 0;
+
return 1;
}
@@ -2311,6 +2234,18 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
*
* - Issue EndTransfer WITH CMDIOC bit set
* - Wait 100us
+ *
+ * As of IP version 3.10a of the DWC_usb3 IP, the controller
+ * supports a mode to work around the above limitation. The
+ * software can poll the CMDACT bit in the DEPCMD register
+ * after issuing a EndTransfer command. This mode is enabled
+ * by writing GUCTL2[14]. This polling is already done in the
+ * dwc3_send_gadget_ep_cmd() function so if the mode is
+ * enabled, the EndTransfer command will have completed upon
+ * returning from this function and we don't need to delay for
+ * 100us.
+ *
+ * This mode is NOT available on the DWC_usb31 IP.
*/
cmd = DWC3_DEPCMD_ENDTRANSFER;
@@ -2322,7 +2257,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
WARN_ON_ONCE(ret);
dep->resource_index = 0;
dep->flags &= ~DWC3_EP_BUSY;
- udelay(100);
+
+ if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
+ udelay(100);
}
static void dwc3_stop_active_transfers(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c
index ec004c6d76f2..bd86f84f3790 100644
--- a/drivers/usb/dwc3/ulpi.c
+++ b/drivers/usb/dwc3/ulpi.c
@@ -35,9 +35,9 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
return -ETIMEDOUT;
}
-static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
+static int dwc3_ulpi_read(struct device *dev, u8 addr)
{
- struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
u32 reg;
int ret;
@@ -53,9 +53,9 @@ static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
return DWC3_GUSB2PHYACC_DATA(reg);
}
-static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
+static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
{
- struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+ struct dwc3 *dwc = dev_get_drvdata(dev);
u32 reg;
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
@@ -65,7 +65,7 @@ static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
return dwc3_ulpi_busyloop(dwc);
}
-static struct ulpi_ops dwc3_ulpi_ops = {
+static const struct ulpi_ops dwc3_ulpi_ops = {
.read = dwc3_ulpi_read,
.write = dwc3_ulpi_write,
};