mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 06:09:23 -04:00
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: Pratham Pratap <prathampratap@codeaurora.org>
This commit is contained in:
parent
28f1b2a9ba
commit
1837de6381
3 changed files with 54 additions and 12 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// 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 */
|
||||
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]);
|
||||
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]);
|
||||
|
||||
/* 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]);
|
||||
}
|
||||
|
||||
msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE);
|
||||
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]);
|
||||
/* 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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* 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; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue