Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba9d3bf3 authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa
Browse files

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: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
parent 3fc0e794
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ Optional properties:
 - snps,core-reset-after-phy-init: If present, PHY reset and initialization is
   performed before core reset.
 - snps,hsphy-auto-suspend-disable: If present, auto suspend feature is not enabled with hsusb phy.
 - snps,ssphy-clear-auto-suspend-on-disconnect: If present, clear auto suspend feaure with ssusb phy
   during cable disconnect.
 - snps,usb3-u1u2-disable: If present, disable u1u2 low power modes for DWC3 core controller in SS mode.

This is usually a subnode to DWC3 glue to which it is connected.

@@ -30,4 +33,6 @@ dwc3@4a030000 {
	usb-phy = <&usb2_phy>, <&usb3,phy>;
	tx-fifo-resize;
	snps,hsphy-auto-suspend-disable;
	snps,ssphy-clear-auto-suspend-on-disconnect;
	snps,usb3-u1u2-disable;
};
+10 −3
Original line number Diff line number Diff line
@@ -101,9 +101,11 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
		}
	}

	if (!dwc->ssphy_clear_auto_suspend_on_disconnect) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
	}
	if (!dwc->hsphy_auto_suspend_disable) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
@@ -598,6 +600,11 @@ static int dwc3_probe(struct platform_device *pdev)
	host_only_mode = of_property_read_bool(node, "snps,host-only-mode");
	dwc->hsphy_auto_suspend_disable = of_property_read_bool(node,
						"snps,hsphy-auto-suspend-disable");
	dwc->ssphy_clear_auto_suspend_on_disconnect =
						of_property_read_bool(node,
						"snps,ssphy-clear-auto-suspend-on-disconnect");
	dwc->usb3_u1u2_disable = of_property_read_bool(node,
						"snps,usb3-u1u2-disable");
	dwc->maximum_speed = of_usb_get_maximum_speed(node);

	if (node) {
+5 −0
Original line number Diff line number Diff line
@@ -759,6 +759,9 @@ struct dwc3_scratchpad_array {
 * @root: debugfs root folder pointer
 * @tx_fifo_size: Available RAM size for TX fifo allocation
 * @err_evt_seen: previous event in queue was erratic error
 * @ssphy_clear_auto_suspend_on_disconnect: if true, clear ssphy autosuspend bit
 *	during disconnect and set it after device is configured.
 * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
 */
struct dwc3 {
	struct usb_ctrlrequest	*ctrl_req;
@@ -866,6 +869,8 @@ struct dwc3 {
	bool			core_reset_after_phy_init;
	bool			err_evt_seen;
	bool			hsphy_auto_suspend_disable;
	bool			ssphy_clear_auto_suspend_on_disconnect;
	bool			usb3_u1u2_disable;
	bool			enable_suspend_event;
	struct dwc3_gadget_events	dbg_gadget_events;
};
+19 −0
Original line number Diff line number Diff line
@@ -91,6 +91,22 @@ static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}

static void dwc3_otg_set_ssphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
{
	struct dwc3 *dwc = dotg->dwc;
	u32 reg;

	if (!dwc->ssphy_clear_auto_suspend_on_disconnect)
		return;

	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
	if (susp)
		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
	else
		reg &= ~(DWC3_GUSB3PIPECTL_SUSPHY);
	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}

/**
 * dwc3_otg_set_host_power - Enable port power control for host operation
 *
@@ -202,6 +218,7 @@ static int dwc3_otg_start_host(struct usb_otg *otg, int on)
		 * anymore.
		 */
		dwc3_otg_set_hsphy_auto_suspend(dotg, true);
		dwc3_otg_set_ssphy_auto_suspend(dotg, true);
		dwc3_otg_set_host_regs(dotg);
		/*
		 * FIXME If micro A cable is disconnected during system suspend,
@@ -251,6 +268,7 @@ static int dwc3_otg_start_host(struct usb_otg *otg, int on)
			ext_xceiv->ext_block_reset(ext_xceiv, true);

		dwc3_otg_set_hsphy_auto_suspend(dotg, false);
		dwc3_otg_set_ssphy_auto_suspend(dotg, false);
		dwc3_otg_set_peripheral_regs(dotg);

		/* re-init core and OTG registers as block reset clears these */
@@ -332,6 +350,7 @@ static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
		usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH);
		usb_phy_notify_disconnect(dotg->dwc->usb3_phy, USB_SPEED_SUPER);
		dwc3_otg_set_hsphy_auto_suspend(dotg, false);
		dwc3_otg_set_ssphy_auto_suspend(dotg, false);
	}

	return 0;
+30 −7
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -55,6 +56,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);
@@ -422,6 +428,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;
@@ -436,6 +445,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;
@@ -563,13 +575,24 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
			usb_gadget_set_state(&dwc->gadget,
					USB_STATE_CONFIGURED);

			if (dwc->ssphy_clear_auto_suspend_on_disconnect) {
				reg = dwc3_readl(dwc->regs,
							DWC3_GUSB3PIPECTL(0));
				reg |= DWC3_GUSB3PIPECTL_SUSPHY;
				dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0),
									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);
				reg |= (DWC3_DCTL_ACCEPTU1ENA |
							DWC3_DCTL_ACCEPTU2ENA);
				dwc3_writel(dwc->regs, DWC3_DCTL, reg);
			}

			dwc->resize_fifos = true;
			dev_dbg(dwc->dev, "resize fifos flag SET\n");
Loading