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

Commit 1837de63 authored by Pratham Pratap's avatar Pratham Pratap Committed by Gerrit - the friendly Code Review server
Browse files

usb: phy-msm-ssusb-qmp: Perform USB only reset in USB+DP mode



Consider a case where USB thumb drive and DP is connected to a
multiport adaptor(MPA) and PIPO is performed. If USB3 controller
stops responding to stop endpoint command during MPA disconnect
driver will treat it as HC died and move into error path. Now
let's say, while the driver was handling this next connect came
due to which HC was not able to handle setup packets, which leads
the driver to powercycle the port.This performs global phy reset
of the USB_DP combo phy but DP driver is not notified of this
reset which results in unclocked access of DP link registers.

Fix this by replacing phy global reset with USB
only reset to not affect DP PHY when USB is reset in DP+USB
concurrent mode.

Change-Id: I2acde04c99b84293644fdefdceee4bd00a964e7f
Signed-off-by: default avatarPratham Pratap <prathampratap@codeaurora.org>
parent 28f1b2a9
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -4423,7 +4423,7 @@ static void dwc3_start_stop_device(struct dwc3_msm *mdwc, bool start)
		dbg_log_string("stop_device_mode completed");
}

int dwc3_msm_release_ss_lane(struct device *dev)
int dwc3_msm_release_ss_lane(struct device *dev, bool usb_dp_concurrent_mode)
{
	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
	struct dwc3 *dwc = NULL;
@@ -4439,6 +4439,16 @@ int dwc3_msm_release_ss_lane(struct device *dev)
		return -EAGAIN;
	}

	/*
	 * If the MPA connected is multi_func capable set the flag assuming
	 * that USB and DP is operating in concurrent mode and bail out early.
	 */
	if (usb_dp_concurrent_mode) {
		mdwc->ss_phy->flags |= PHY_USB_DP_CONCURRENT_MODE;
		dbg_event(0xFF, "USB_DP_CONCURRENT_MODE", 1);
		return 0;
	}

	dbg_event(0xFF, "ss_lane_release", 0);
	/* flush any pending work */
	flush_work(&mdwc->resume_work);
@@ -5244,6 +5254,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
					USB_SPEED_SUPER);
			usb_phy_notify_disconnect(mdwc->ss_phy,
					USB_SPEED_SUPER);
			mdwc->ss_phy->flags &= ~PHY_USB_DP_CONCURRENT_MODE;
		}
		redriver_notify_disconnect(mdwc->ss_redriver_node);

@@ -5365,6 +5376,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
		usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
		usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);
		redriver_notify_disconnect(mdwc->ss_redriver_node);
		mdwc->ss_phy->flags &= ~PHY_USB_DP_CONCURRENT_MODE;
		dwc3_override_vbus_status(mdwc, false);
		dwc3_msm_write_reg_field(mdwc->base, DWC3_GUSB3PIPECTL(0),
				DWC3_GUSB3PIPECTL_SUSPHY, 0);
+37 −8
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/module.h>
@@ -405,9 +405,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
		}

		/* override hardware control for reset of qmp phy */
		if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE))
			writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
				SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET,
			phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
				phy->base +
				phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);

		/* update port select */
		if (val > 0) {
@@ -417,11 +419,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
				phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]);
		}

		if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) {
			msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE);

			/* bring both USB and DP PHYs PCS block out of reset */
			writel_relaxed(0x00, phy->base +
				phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
		}
		break;
	case  USB3_OR_DP:
		if (val > 0) {
@@ -513,6 +517,12 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy)
		goto fail;
	}

	/* perform software reset of PHY common logic */
	if (phy->phy_type == USB3_AND_DP &&
				!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE))
		writel_relaxed(0x00,
			phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]);

	/* perform software reset of PCS/Serdes */
	writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_PHY_SW_RESET]);
	/* start PCS/Serdes to operation mode */
@@ -556,6 +566,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy)
					phy);
	int ret = 0;

	if (phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE) {
		dev_dbg(uphy->dev, "Resetting USB part of QMP phy\n");

		/* Assert USB3 PHY CSR reset */
		ret = reset_control_assert(phy->phy_reset);
		if (ret) {
			dev_err(uphy->dev, "phy_reset assert failed\n");
			goto exit;
		}

		/* Deassert USB3 PHY CSR reset */
		ret = reset_control_deassert(phy->phy_reset);
		if (ret) {
			dev_err(uphy->dev, "phy_reset deassert failed\n");
			goto exit;
		}
		return 0;
	}

	dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n");
	/* Assert global PHY reset */
	ret = reset_control_assert(phy->global_phy_reset);
+4 −3
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
 */

#ifndef __LINUX_USB_DWC3_MSM_H
@@ -19,6 +19,7 @@
#define EUD_SPOOF_DISCONNECT		BIT(6)
#define EUD_SPOOF_CONNECT		BIT(7)
#define PHY_SUS_OVERRIDE		BIT(8)
#define PHY_USB_DP_CONCURRENT_MODE	BIT(9)

/*
 * The following are bit fields describing the USB BAM options.
@@ -135,7 +136,7 @@ int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size,
	u8 dst_pipe_idx);
bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget);
int msm_dwc3_reset_dbm_ep(struct usb_ep *ep);
int dwc3_msm_release_ss_lane(struct device *dev);
int dwc3_msm_release_ss_lane(struct device *dev, bool usb_dp_concurrent_mode);
bool usb_get_remote_wakeup_status(struct usb_gadget *gadget);
#else
static inline struct usb_ep *usb_ep_autoconfig_by_name(
@@ -162,7 +163,7 @@ static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget)
{ return false; }
static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep)
{ return -ENODEV; }
static inline int dwc3_msm_release_ss_lane(struct device *dev)
static inline int dwc3_msm_release_ss_lane(struct device *dev, bool usb_dp_concurrent_mode)
{ return -ENODEV; }
static bool __maybe_unused usb_get_remote_wakeup_status(struct usb_gadget *gadget)
{ return false; }