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

Commit 8aec0d07 authored by Pratham Pratap's avatar Pratham Pratap Committed by Jack Pham
Browse files

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



When USB3 controller stops responding to stop endpoint
command driver performs global phy reset to recover from
error state. During this USB host mode recovery is performed
and global phy reset is done 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 4f875855
Loading
Loading
Loading
Loading
+89 −8
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/phy.h>
#include <linux/usb/phy.h>
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/extcon.h>
#include <linux/reset.h>
#include <linux/reset.h>
#include <linux/hrtimer.h>
#include <linux/hrtimer.h>


@@ -128,6 +129,8 @@ struct msm_ssphy_qmp {
	struct reset_control	*phy_reset;
	struct reset_control	*phy_reset;
	struct reset_control	*phy_phy_reset;
	struct reset_control	*phy_phy_reset;
	struct reset_control	*global_phy_reset;
	struct reset_control	*global_phy_reset;
	struct extcon_dev	*extcon_dp;
	struct notifier_block	dp_nb;
	bool			power_enabled;
	bool			power_enabled;
	bool			clk_enabled;
	bool			clk_enabled;
	bool			cable_connected;
	bool			cable_connected;
@@ -366,9 +369,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
	switch (phy->phy.type) {
	switch (phy->phy.type) {
	case USB_PHY_TYPE_USB3_AND_DP:
	case USB_PHY_TYPE_USB3_AND_DP:
		/* override hardware control for reset of 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 |
			writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
				SW_USB3PHY_RESET_MUX | SW_USB3PHY_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 */
		/* update port select */
		if (val > 0) {
		if (val > 0) {
@@ -378,11 +383,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
				phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]);
				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);
			msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE);


		/* bring both QMP USB and QMP DP PHYs PCS block out of reset */
			/* bring both USB and DP PHYs PCS block out of reset */
		writel_relaxed(0x00,
			writel_relaxed(0x00, phy->base +
			phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
				phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
		}
		break;
		break;
	case  USB_PHY_TYPE_USB3_OR_DP:
	case  USB_PHY_TYPE_USB3_OR_DP:
		if (val > 0) {
		if (val > 0) {
@@ -470,7 +477,8 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy)
	}
	}


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


@@ -508,6 +516,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy)
					phy);
					phy);
	int ret = 0;
	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");
	dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n");
	/* Assert global PHY reset */
	/* Assert global PHY reset */
	ret = reset_control_assert(phy->global_phy_reset);
	ret = reset_control_assert(phy->global_phy_reset);
@@ -774,6 +801,56 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy,
	return 0;
	return 0;
}
}


static int msm_ssphy_qmp_vbus_notifier(struct notifier_block *nb,
		unsigned long event, void *ptr)
{
	return 0;
}

static int msm_ssphy_qmp_dp_notifier(struct notifier_block *nb,
		unsigned long dp_lane, void *ptr)
{
	struct msm_ssphy_qmp *phy = container_of(nb,
			struct msm_ssphy_qmp, dp_nb);

	if (dp_lane == 2 || dp_lane == 4)
		phy->phy.flags |= PHY_USB_DP_CONCURRENT_MODE;
	else
		phy->phy.flags &= ~PHY_USB_DP_CONCURRENT_MODE;

	return 0;

}

static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy,
				struct device *dev)
{
	struct device_node *node = dev->of_node;
	struct extcon_dev *edev;
	int ret = 0;

	if (!of_property_read_bool(node, "extcon"))
		return 0;

	edev = extcon_get_edev_by_phandle(dev, 0);
	if (IS_ERR(edev)) {
		dev_err(dev, "failed to get phandle for msm_ssphy_qmp\n");
		return PTR_ERR(edev);
	}

	phy->extcon_dp = edev;
	phy->phy.vbus_nb.notifier_call = msm_ssphy_qmp_vbus_notifier;
	phy->dp_nb.notifier_call = msm_ssphy_qmp_dp_notifier;
	ret = extcon_register_blocking_notifier(edev, EXTCON_DISP_DP,
								&phy->dp_nb);
	if (ret < 0) {
		dev_err(dev, "failed to register blocking notifier\n");
		return ret;
	}

	return 0;
}

static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev)
static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev)
{
{
	int ret = 0;
	int ret = 0;
@@ -1085,6 +1162,10 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)
	else
	else
		phy->phy.reset		= msm_ssphy_qmp_reset;
		phy->phy.reset		= msm_ssphy_qmp_reset;


	ret = msm_ssphy_qmp_extcon_register(phy, dev);
	if (ret)
		goto err;

	ret = usb_add_phy_dev(&phy->phy);
	ret = usb_add_phy_dev(&phy->phy);


err:
err:
+1 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
#define PHY_LANE_B		BIT(7)
#define PHY_LANE_B		BIT(7)
#define PHY_HSFS_MODE		BIT(8)
#define PHY_HSFS_MODE		BIT(8)
#define PHY_LS_MODE		BIT(9)
#define PHY_LS_MODE		BIT(9)
#define PHY_USB_DP_CONCURRENT_MODE	BIT(10)


enum usb_phy_interface {
enum usb_phy_interface {
	USBPHY_INTERFACE_MODE_UNKNOWN,
	USBPHY_INTERFACE_MODE_UNKNOWN,