summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorVijayavardhan Vennapusa <vvreddy@codeaurora.org>2014-05-08 13:47:50 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:06:31 -0700
commit567c83ebc7e73ea9dde355fa52e03be13e45d43f (patch)
treed0231b11e2da0b9028a4af3437a8ab154c0bc4f5 /drivers/usb
parent01edad63c9152c1ac3aae8edbf8d373f18dbcd07 (diff)
USB: dwc3: Add support for fixing superspeed enumeration issue
Setting SSPHY SUSP bit (bit 17) in GUSB3PIPECTL(0) register might cause device enumerating at high speed mode instead of superspeed mode on some platforms. Hence add workaround by clearing the SSPHY SUSP bit during disconnect and setting it after it is configured to fix this enumeration issue on those platforms. Also add support for disabling U1 and U2 low power modes which could also affect this enumeration issue. CRs-Fixed: 637902 Change-Id: I8668ced09a88b77f37265ab15e89fa9e964bfbe9 Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org> [jackp@codeaurora.org: only add u1/u2 disable bits] Signed-off-by: Jack Pham <jackp@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/core.h2
-rw-r--r--drivers/usb/dwc3/ep0.c29
3 files changed, 26 insertions, 7 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index aa78f38220d2..6ae3202ae9e6 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -997,6 +997,8 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->nominal_elastic_buffer = device_property_read_bool(dev,
"snps,nominal-elastic-buffer");
+ dwc->usb3_u1u2_disable = device_property_read_bool(dev,
+ "snps,usb3-u1u2-disable");
if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 60d5f8515f14..bc7129185554 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -797,6 +797,7 @@ struct dwc3_scratchpad_array {
* 2 - No de-emphasis
* 3 - Reserved
* @err_evt_seen: previous event in queue was erratic error
+ * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
* @in_lpm: indicates if controller is in low power mode (no clocks)
*/
struct dwc3 {
@@ -945,6 +946,7 @@ struct dwc3 {
unsigned nominal_elastic_buffer:1;
unsigned err_evt_seen:1;
+ unsigned usb3_u1u2_disable:1;
struct dwc3_gadget_events dbg_gadget_events;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 55191ea9d6e2..e6bcbf11b872 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -36,6 +37,11 @@
#include "io.h"
#include "debug.h"
+
+static bool enable_dwc3_u1u2;
+module_param(enable_dwc3_u1u2, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes");
+
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req);
@@ -431,6 +437,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
+ if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2)
+ return -EINVAL;
+
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU1ENA;
@@ -445,6 +454,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
+ if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2)
+ return -EINVAL;
+
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU2ENA;
@@ -579,13 +591,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
usb_gadget_set_state(&dwc->gadget,
USB_STATE_CONFIGURED);
- /*
- * Enable transition to U1/U2 state when
- * nothing is pending from application.
- */
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ if (!dwc->usb3_u1u2_disable || enable_dwc3_u1u2) {
+ /*
+ * Enable transition to U1/U2 state when
+ * nothing is pending from application.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg |= (DWC3_DCTL_ACCEPTU1ENA |
+ DWC3_DCTL_ACCEPTU2ENA);
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ }
dwc->resize_fifos = true;
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");