summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index f219c82e9619..dfa1b5fe48dc 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1479,6 +1479,26 @@ static int dwc3_core_init(struct dwc3 *dwc)
}
}
+ /*
+ * STAR 9001346572: This issue affects DWC_usb31 versions 1.80a and
+ * prior. When an active endpoint not currently cached in the host
+ * controller is chosen to be cached to the same index as an endpoint
+ * receiving NAKs, the endpoint receiving NAKs enters continuous
+ * retry mode. This prevents it from being evicted from the host
+ * controller cache, blocking the new endpoint from being cached and
+ * serviced.
+ *
+ * To resolve this, for controller versions 1.70a and 1.80a, set the
+ * GUCTL3 bit[16] (USB2.0 Internal Retry Disable) to 1. This bit
+ * disables the USB2.0 internal retry feature. The GUCTL3[16] register
+ * function is available only from version 1.70a.
+ */
+ if (DWC3_VER_IS_WITHIN(DWC31, 170A, 180A)) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
+ reg |= DWC3_GUCTL3_USB20_RETRY_DISABLE;
+ dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
+ }
+
return 0;
err_power_off_phy:
@@ -1664,8 +1684,6 @@ static void dwc3_get_properties(struct dwc3 *dwc)
u8 tx_thr_num_pkt_prd = 0;
u8 tx_max_burst_prd = 0;
u8 tx_fifo_resize_max_num;
- const char *usb_psy_name;
- int ret;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xf;
@@ -1700,13 +1718,6 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->sys_wakeup = device_may_wakeup(dwc->sysdev);
- ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name);
- if (ret >= 0) {
- dwc->usb_psy = power_supply_get_by_name(usb_psy_name);
- if (!dwc->usb_psy)
- dev_err(dev, "couldn't get usb power supply\n");
- }
-
dwc->has_lpm_erratum = device_property_read_bool(dev,
"snps,has-lpm-erratum");
device_property_read_u8(dev, "snps,lpm-nyet-threshold",
@@ -2109,6 +2120,23 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
return 0;
}
+static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
+{
+ struct power_supply *usb_psy;
+ const char *usb_psy_name;
+ int ret;
+
+ ret = device_property_read_string(dwc->dev, "usb-psy-name", &usb_psy_name);
+ if (ret < 0)
+ return NULL;
+
+ usb_psy = power_supply_get_by_name(usb_psy_name);
+ if (!usb_psy)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return usb_psy;
+}
+
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2165,6 +2193,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_software_properties(dwc);
+ dwc->usb_psy = dwc3_get_usb_power_supply(dwc);
+ if (IS_ERR(dwc->usb_psy))
+ return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n");
+
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
if (IS_ERR(dwc->reset)) {
ret = PTR_ERR(dwc->reset);
@@ -2589,12 +2621,15 @@ static int dwc3_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ goto out;
ret = dwc3_resume_common(dwc, PMSG_RESUME);
if (ret)
pm_runtime_set_suspended(dev);
+out:
pm_runtime_enable(dev);
return ret;