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

Commit 7322af4c authored by Azhar Shaikh's avatar Azhar Shaikh
Browse files

usb: phy: Add snapshot of changes from msm-3.10



Squash and apply the following usb phy driver changes taken
from the msm-3.10 kernel branch as of msm-3.10 commit
71fd06e8b45d	("Merge defconfig: msm8976: Enable gladiator error
		  reporting")

924fa1186aa5	usb: phy: qmp: Turn off usb30_pipe3_clk upon bus suspend
726fa4fb6c87	usb: phy: Assert usb3_phy_vls_clamp_en as part of enabling
		autonomous mode
6760e3ec2363	usb: qmp: phy: Clear LFPS RXTERM irq upon bus suspend
67280fc1602f	usb: qmp: phy: Add misc configuration for QMP PHY rev1
2a0584b52f2c	usb: phy: qmp: Fix unbalanced regulator disable when
		charger connected
921369edd700	usb: phy: qmp: Update QMP PHY parameters for
		msmzirc and 8994
887cc75c602c	usb: phy: qusb: Bring phy to non-driving mode upon
		disconnect
e499073d28ed	USB: Add support for emulator platforms

Change-Id: Ie3294f0a4e81604fda2fff58ca1be0acadb48736
Signed-off-by: default avatarAzhar Shaikh <azhars@codeaurora.org>
parent a5f9d251
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -99,6 +99,8 @@ Required properties:
   Required regs are:
   "qmp_phy_base" : QMP PHY Base register set.
   "qmp_ahb2phy_base" : SS AHB2PHY CSR register set.
 - "vls_clamp_reg" : top-level CSR register to be written to enable phy vls
   clamp which allows phy to detect autonomous mode.
 - <supply-name>-supply: phandle to the regulator device tree node
   Required "supply-name" examples are:
	"vdd" : vdd supply for SSPHY digital circuit operation
@@ -113,14 +115,17 @@ Optional properties:
   order to manually relay the notification to the SSPHY.
 - qcom,no-pipe-clk-switch: If present, indicates that the pipe_clk does not need
   to switch sources between the XO and the PHY PIPE clock output.
 - qcom,emulation: Indicates that we are running on emulation platform.

Example:
	ssphy0: ssphy@f9b38000 {
		compatible = "qcom,usb-ssphy-qmp";
		reg = <0xf9b38000 0x16c>,
			<0xf9b3e000 0x3ff>;
			<0xf9b3e000 0x3ff>,
			<0x01947244 0x4>;
		reg-names = "qmp_phy_base",
			"qmp_ahb2phy_base";
			"qmp_ahb2phy_base",
			"vls_clamp_reg";
		vdd-supply = <&pmd9635_l4>;
		vdda18-supply = <&pmd9635_l8>;
		qcom,vdd-voltage-level = <0 900000 1050000>;
@@ -156,12 +161,10 @@ Optional properties:
   allows us to manipulate QUSB PHY bits eg. to enable D+ pull-up using s/w
   control in device mode. The reg-names property is required if the
   reg property is specified.
 - qcom,qusb-tune: Used to pass QUSB PHY tuning parameters. The 4 tuning parameters
   are passed in as 4 bytes packed into a single 32-bit value. The parameters control
   On-chip Rout Term, TX Output Level, RX Sensitivity and TX Pre-emphasis respectively.
 - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair.
 - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register
 - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble
 - qcom,emulation: Indicates that we are running on emulation platform.

Example:
	qusb_phy: qusb@f9b39000 {
+4 −2
Original line number Diff line number Diff line
@@ -2132,9 +2132,11 @@
	ssphy: ssphy@7410000 {
		compatible = "qcom,usb-ssphy-qmp-v2";
		reg = <0x7410000 0x45C>,
		      <0x7416000 0x400>;
		      <0x7416000 0x400>,
		      <0x007AB244 0x4>;
		reg-names = "qmp_phy_base",
			    "qmp_ahb2phy_base";
			    "qmp_ahb2phy_base",
			    "vls_clamp_reg";
		vdd-supply = <&pm8994_l28>;
		vdda18-supply = <&pm8994_l12>;
		qcom,vdd-voltage-level = <0 925000 925000>;
+93 −47
Original line number Diff line number Diff line
@@ -29,7 +29,16 @@
#define CLAMP_N_EN			BIT(5)
#define FREEZIO_N			BIT(1)
#define POWER_DOWN			BIT(0)

#define QUSB2PHY_PORT_UTMI_CTRL1	0xC0
#define TERM_SELECT			BIT(4)
#define XCVR_SELECT_FS			BIT(2)
#define OP_MODE_NON_DRIVE		BIT(0)

#define QUSB2PHY_PORT_UTMI_CTRL2	0xC4
#define UTMI_ULPI_SEL			BIT(7)
#define UTMI_TEST_MUX_SEL		BIT(6)

#define QUSB2PHY_PORT_TUNE1             0x80
#define QUSB2PHY_PORT_TUNE2             0x84
#define QUSB2PHY_PORT_TUNE3             0x88
@@ -41,6 +50,14 @@

/* Get TUNE2's high nibble value read from efuse */
#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask)	((val >> pos) & mask)
#define QRBTC_USB2_PLL			0x404
#define QRBTC_USB2_PLLCTRL2		0x414
#define QRBTC_USB2_PLLCTRL1		0x410
#define QRBTC_USB2_PLLCTRL3		0x418
#define QRBTC_USB2_PLLTEST1		0x408
#define RUMI_RESET_ADDRESS		0x6500
#define RUMI_RESET_VALUE_1		0x80000000
#define RUMI_RESET_VALUE_2		0x000201e0

#define QUSB2PHY_PORT_INTR_CTRL         0xBC
#define CHG_DET_INTR_EN                 BIT(4)
@@ -80,7 +97,6 @@ struct qusb_phy {
	struct regulator	*vdda33;
	struct regulator	*vdda18;
	int			vdd_levels[3]; /* none, low, high */
	u32			qusb_tune;
	int			init_seq_len;
	int			*qusb_phy_init_seq;

@@ -93,6 +109,7 @@ struct qusb_phy {
	bool			cable_connected;
	bool			suspended;
	bool			ulpi_mode;
	bool			emulation;
};

static int qusb_phy_reset(struct usb_phy *phy)
@@ -284,7 +301,6 @@ static int qusb_phy_init(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
	int ret, *seq = NULL, i;
	u32 t1, t2, t3, t4;

	dev_dbg(phy->dev, "%s\n", __func__);

@@ -298,6 +314,33 @@ static int qusb_phy_init(struct usb_phy *phy)
		qphy->clocks_enabled = true;
	}

	if (qphy->emulation) {
		/* Configure QUSB2 PLLs for RUMI */
		writel_relaxed(0x19, qphy->base + QRBTC_USB2_PLL);
		writel_relaxed(0x20, qphy->base + QRBTC_USB2_PLLCTRL2);
		writel_relaxed(0x79, qphy->base + QRBTC_USB2_PLLCTRL1);
		writel_relaxed(0x00, qphy->base + QRBTC_USB2_PLLCTRL3);
		writel_relaxed(0x99, qphy->base + QRBTC_USB2_PLL);
		writel_relaxed(0x04, qphy->base + QRBTC_USB2_PLLTEST1);
		writel_relaxed(0xD9, qphy->base + QRBTC_USB2_PLL);

		/* Wait for 5ms as per QUSB2 RUMI sequence from VI */
		usleep_range(5000, 7000);

		/* Perform the RUMI PLL Reset */
		writel_relaxed((int)RUMI_RESET_VALUE_1,
					qphy->base + RUMI_RESET_ADDRESS);
		/* Wait for 10ms as per QUSB2 RUMI sequence from VI */
		usleep_range(10000, 12000);
		writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS);
		/* Wait for 10ms as per QUSB2 RUMI sequence from VI */
		usleep_range(10000, 12000);
		writel_relaxed((int)RUMI_RESET_VALUE_2,
					qphy->base + RUMI_RESET_ADDRESS);
		/* Wait for 10ms as per QUSB2 RUMI sequence from VI */
		usleep_range(10000, 12000);
		writel_relaxed(0x0, qphy->base + RUMI_RESET_ADDRESS);
	} else {
		/* Disable the PHY */
		writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
				qphy->base + QUSB2PHY_PORT_POWERDOWN);
@@ -307,20 +350,6 @@ static int qusb_phy_init(struct usb_phy *phy)
			writel_relaxed(0x0,
				qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);

	/* Program tuning parameters for PHY */
	if (qphy->qusb_tune) {
		t1 = qphy->qusb_tune >> 24;
		t2 = (qphy->qusb_tune) >> 16 & 0xFF;
		t3 = (qphy->qusb_tune) >> 8 & 0xFF;
		t4 = (qphy->qusb_tune) & 0xFF;

		/* Program tuning parameters for PHY */
		writel_relaxed(t1, qphy->base + QUSB2PHY_PORT_TUNE1);
		writel_relaxed(t2, qphy->base + QUSB2PHY_PORT_TUNE2);
		writel_relaxed(t3, qphy->base + QUSB2PHY_PORT_TUNE3);
		writel_relaxed(t4, qphy->base + QUSB2PHY_PORT_TUNE4);
	}

		if (qphy->qusb_phy_init_seq) {
			seq = qphy->qusb_phy_init_seq;
			dev_dbg(phy->dev, "count:%d\n", qphy->init_seq_len);
@@ -351,7 +380,7 @@ static int qusb_phy_init(struct usb_phy *phy)
		/* Enable the PHY */
		writel_relaxed(CLAMP_N_EN | FREEZIO_N,
			qphy->base + QUSB2PHY_PORT_POWERDOWN);

	}
	return 0;
}

@@ -433,6 +462,21 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
			clk_disable_unprepare(qphy->cfg_ahb_clk);
			clk_disable_unprepare(qphy->ref_clk);
		} else { /* Disconnect case */
			/* Disable all interrupts */
			writel_relaxed(0x00,
				qphy->base + QUSB2PHY_PORT_INTR_CTRL);
			/*
			 * Phy in non-driving mode leaves Dp and Dm lines in
			 * high-Z state. Controller power collapse is not
			 * switching phy to non-driving mode causing charger
			 * detection failure. Bring phy to non-driving mode by
			 * overriding controller output via UTMI interface.
			 */
			writel_relaxed(TERM_SELECT | XCVR_SELECT_FS |
				OP_MODE_NON_DRIVE,
				qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
			writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL,
				qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
			clk_disable_unprepare(qphy->cfg_ahb_clk);
			clk_disable_unprepare(qphy->ref_clk);
			qusb_phy_enable_power(qphy, false);
@@ -581,7 +625,9 @@ static int qusb_phy_probe(struct platform_device *pdev)
	if (IS_ERR(qphy->phy_reset))
		return PTR_ERR(qphy->phy_reset);

	of_property_read_u32(dev->of_node, "qcom,qusb-tune", &qphy->qusb_tune);
	qphy->emulation = of_property_read_bool(dev->of_node,
					"qcom,emulation");

	of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size);
	if (size) {
		qphy->qusb_phy_init_seq = devm_kzalloc(dev,
+74 −31
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#define PCIE_USB3_PHY_SW_RESET			0x600
#define PCIE_USB3_PHY_POWER_DOWN_CONTROL	0x604
#define PCIE_USB3_PHY_START			0x608
#define PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL	0x6BC
#define PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR	0x6C0

#define PHYSTATUS				BIT(6)

@@ -152,12 +154,12 @@ static const struct qmp_reg_val qmp_settings_rev1[] = {
	{0x100, 0xD5}, /* QSERDES_COM_DIV_FRAC_START1 */
	{0x104, 0xAA}, /* QSERDES_COM_DIV_FRAC_START2 */
	{0x108, 0x4D}, /* QSERDES_COM_DIV_FRAC_START3 */
	{0x9C, 0x01}, /* QSERDES_COM_PLLLOCK_CMP_EN */
	{0x9C, 0x11}, /* QSERDES_COM_PLLLOCK_CMP_EN */
	{0x90, 0x2B}, /* QSERDES_COM_PLLLOCK_CMP1 */
	{0x94, 0x68}, /* QSERDES_COM_PLLLOCK_CMP2 */
	{0x114, 0x7C}, /* QSERDES_COM_PLL_CRCTRL */
	{0x34, 0x07}, /* QSERDES_COM_PLL_CP_SETI */
	{0x38, 0x1F}, /* QSERDES_COM_PLL_IP_SETP */
	{0x34, 0x1F}, /* QSERDES_COM_PLL_CP_SETI */
	{0x38, 0x12}, /* QSERDES_COM_PLL_IP_SETP */
	{0x3C, 0x0F}, /* QSERDES_COM_PLL_CP_SETP */
	{0x24, 0x01}, /* QSERDES_COM_PLL_IP_SETI */
	{0x0C, 0x0F}, /* QSERDES_COM_IE_TRIM */
@@ -172,7 +174,7 @@ static const struct qmp_reg_val qmp_settings_rev1[] = {
	{0x50, 0x07}, /* QSERDES_COM_RESETSM_CNTRL2 */
	{0x04, 0xE1}, /* QSERDES_COM_PLL_VCOTAIL_EN */

	{0xE0, 0x20}, /* QSERDES_COM_RES_CODE_START_SEG1 */
	{0xE0, 0x24}, /* QSERDES_COM_RES_CODE_START_SEG1 */
	{0xE8, 0x77}, /* QSERDES_COM_RES_CODE_CAL_CSR */
	{0xF0, 0x15}, /* QSERDES_COM_RES_TRIM_CONTROL */
	{0x268, 0x02}, /* QSERDES_TX_RCV_DETECT_LVL */
@@ -319,10 +321,19 @@ static const struct qmp_reg_val qmp_override_sysclk[] = {
	{-1, -1} /* terminating entry */
};

/* Vbg related settings */
static const struct qmp_reg_val qmp_settings_rev1_misc[] = {
	{0x0C, 0x03}, /* QSERDES_COM_IE_TRIM */
	{0x10, 0x00}, /* QSERDES_COM_IP_TRIM */
	{0xA0, 0xFF}, /* QSERDES_COM_BGTC */
	{-1, -1} /* terminating entry */
};

struct msm_ssphy_qmp {
	struct usb_phy		phy;
	void __iomem		*base;
	void __iomem		*ahb2phy;
	void __iomem		*vls_clamp_reg;
	struct regulator	*vdd;
	struct regulator	*vdda18;
	int			vdd_levels[3]; /* none, low, high */
@@ -361,28 +372,40 @@ static inline char *get_cable_status_str(struct msm_ssphy_qmp *phy)
	return phy->cable_connected ? "connected" : "disconnected";
}

static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy)
static void msm_ssusb_qmp_clr_lfps_rxterm_int(struct msm_ssphy_qmp *phy)
{
	writeb_relaxed(1, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR);
	/* flush the previous write before next write */
	wmb();
	writeb_relaxed(0, phy->base + PCIE_USB3_PHY_LFPS_RXTERM_IRQ_CLEAR);
}

static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy,
		int enable)
{
	u8 val;

	dev_dbg(phy->phy.dev, "enabling QMP autonomous mode with cable %s\n",
			get_cable_status_str(phy));
	val = readb_relaxed(phy->base +
			phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]);

	if (enable) {
		msm_ssusb_qmp_clr_lfps_rxterm_int(phy);
		val =
		readb_relaxed(phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL);
		val |= ARCVR_DTCT_EN;
	if (phy->cable_connected) {
		val |= ALFPS_DTCT_EN;
		/* Detect detach */
		val &= ~ARCVR_DTCT_EVENT_SEL;
		writeb_relaxed(val,
				phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL);

		 /* clamp phy level shifter to perform autonomous detection */
		writel_relaxed(0x1, phy->vls_clamp_reg);
	} else {
		val &= ~ALFPS_DTCT_EN;
		/* Detect attach */
		val |= ARCVR_DTCT_EVENT_SEL;
		writel_relaxed(0x0, phy->vls_clamp_reg);
		writeb_relaxed(0,
				phy->base + PCIE_USB3_PHY_AUTONOMOUS_MODE_CTRL);
		msm_ssusb_qmp_clr_lfps_rxterm_int(phy);
	}

	writeb_relaxed(val, phy->base +
			phy->phy_reg[USB3_PHY_AUTONOMOUS_MODE_CTRL]);
}


@@ -521,6 +544,7 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy)
		break;
	case 0x10000001:
		reg = qmp_settings_rev1;
		misc = qmp_settings_rev1_misc;
		break;
	case 0x20000000:
	case 0x20000001:
@@ -688,14 +712,13 @@ deassert_phy_com_reset:
static int msm_ssphy_power_enable(struct msm_ssphy_qmp *phy, bool on)
{
	bool host = phy->phy.flags & PHY_HOST_MODE;
	bool chg_connected = phy->phy.flags & PHY_CHARGER_CONNECTED;
	int ret = 0;

	/*
	 * Turn off the phy's LDOs when cable is disconnected for device mode
	 * with external vbus_id indication.
	 */
	if (!host && !chg_connected && !phy->cable_connected) {
	if (!host && !phy->cable_connected) {
		if (on) {
			ret = regulator_enable(phy->vdd);
			if (ret)
@@ -748,29 +771,33 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend)
	}

	if (suspend) {
		msm_ssusb_qmp_enable_autonomous(phy);
		if (!phy->cable_connected) {
			clk_disable_unprepare(phy->pipe_clk);
		if (!phy->cable_connected)
			writel_relaxed(0x00,
				phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL);
		}
		else
			msm_ssusb_qmp_enable_autonomous(phy, 1);

		clk_disable_unprepare(phy->cfg_ahb_clk);
		clk_disable_unprepare(phy->aux_clk);
		clk_disable_unprepare(phy->pipe_clk);
		phy->clk_enabled = false;
		phy->in_suspend = true;
		msm_ssphy_power_enable(phy, 0);
		dev_dbg(uphy->dev, "QMP PHY is suspend\n");
	} else {
		msm_ssphy_power_enable(phy, 1);
		clk_prepare_enable(phy->pipe_clk);
		if (!phy->clk_enabled) {
			clk_prepare_enable(phy->aux_clk);
			clk_prepare_enable(phy->cfg_ahb_clk);
			clk_prepare_enable(phy->pipe_clk);
			phy->clk_enabled = true;
		}
		if (!phy->cable_connected) {
			writel_relaxed(0x01,
				phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL);
		msm_ssusb_qmp_enable_autonomous(phy);
		} else  {
			msm_ssusb_qmp_enable_autonomous(phy, 0);
		}
		phy->in_suspend = false;
		dev_dbg(uphy->dev, "QMP PHY is resumed\n");
	}
@@ -798,7 +825,6 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy,

	dev_dbg(uphy->dev, "QMP phy disconnect notification\n");
	dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected);
	msm_ssusb_qmp_enable_autonomous(phy);
	phy->cable_connected = false;
	return 0;
}
@@ -899,19 +925,36 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						"qmp_phy_base");
	if (!res) {
		dev_err(dev, "failed getting qmp_phy_base\n");
		return -ENODEV;
	}
	phy->base = devm_ioremap_resource(dev, res);
	if (IS_ERR(phy->base)) {
		ret = PTR_ERR(phy->base);
		goto err;
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
			"vls_clamp_reg");
	if (!res) {
		dev_err(dev, "failed getting vls_clamp_reg\n");
		return -ENODEV;
	}
	phy->vls_clamp_reg = devm_ioremap_resource(dev, res);
	if (IS_ERR(phy->vls_clamp_reg)) {
		dev_err(dev, "couldn't find vls_clamp_reg address.\n");
		return PTR_ERR(phy->vls_clamp_reg);
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
						"qmp_ahb2phy_base");
	if (res) {
		phy->ahb2phy = devm_ioremap_resource(dev, res);
		if (IS_ERR(phy->ahb2phy)) {
		dev_err(dev, "couldn't find qmp_ahb2phy_base address.\n");
		ret = PTR_ERR(phy->ahb2phy);
		goto err;
			dev_err(dev, "couldn't find qmp_ahb2phy_base addr.\n");
			phy->ahb2phy = NULL;
		}
	}

	phy->emulation = of_property_read_bool(dev->of_node,