usb: phy-msm-qusb-v2: Reset PLL only if not locked on resume
Driver currently unconditionally resets PLL while entering
suspend state. As per hardware databook PLL need not to be
reset across every suspend/resume. Driver should reset it
only if PLL fails to lock on resume which must be checked
using DEBUG_CTRL2 register.
Change-Id: I4cb544dd8ad94af9270746f67ad872ff1b77e2b0
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index 9b88356..c53367a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -141,7 +141,9 @@
0x198 /* PLL_BIAS_CONTROL_2 */
0x228 /* QUSB2PHY_SQ_CTRL1 */
0x22c /* QUSB2PHY_SQ_CTRL2 */
- 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+ 0x2a0>; /* QUSB2PHY_STAT5 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
@@ -431,7 +433,9 @@
0x198 /* PLL_BIAS_CONTROL_2 */
0x228 /* QUSB2PHY_SQ_CTRL1 */
0x22c /* QUSB2PHY_SQ_CTRL2 */
- 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+ 0x2a0>; /* QUSB2PHY_STAT5 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 6dfca9c..a17974c 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -76,6 +76,12 @@
/* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
#define BANDGAP_BYPASS BIT(0)
+/* DEBUG_CTRL2 register value to program VSTATUS MUX for PHY status */
+#define DEBUG_CTRL2_MUX_PLL_LOCK_STATUS 0x4
+
+/* STAT5 register bits */
+#define VSTATUS_PLL_LOCK_STATUS_MASK BIT(0)
+
enum qusb_phy_reg {
PORT_TUNE1,
PLL_COMMON_STATUS_ONE,
@@ -87,6 +93,8 @@
SQ_CTRL1,
SQ_CTRL2,
DEBUG_CTRL1,
+ DEBUG_CTRL2,
+ STAT5,
USB2_PHY_REG_MAX,
};
@@ -470,6 +478,18 @@
__func__);
}
+static bool qusb_phy_pll_locked(struct qusb_phy *qphy)
+{
+ u32 val;
+
+ writel_relaxed(DEBUG_CTRL2_MUX_PLL_LOCK_STATUS,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL2]);
+
+ val = readl_relaxed(qphy->base + qphy->phy_reg[STAT5]);
+
+ return (val & VSTATUS_PLL_LOCK_STATUS_MASK);
+}
+
static void qusb_phy_host_init(struct usb_phy *phy)
{
u8 reg;
@@ -748,18 +768,12 @@
writel_relaxed(intr_mask,
qphy->base + qphy->phy_reg[INTR_CTRL]);
- /* hold core PLL into reset */
- writel_relaxed(CORE_PLL_EN_FROM_RESET |
- CORE_RESET | CORE_RESET_MUX,
- qphy->base +
- qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
-
if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
/* enable phy auto-resume */
writel_relaxed(0x91,
qphy->base + qphy->phy_reg[TEST1]);
- /* flush the previous write before next write */
- wmb();
+ /* Delay recommended between TEST1 writes */
+ usleep_range(10, 20);
writel_relaxed(0x90,
qphy->base + qphy->phy_reg[TEST1]);
}
@@ -788,12 +802,26 @@
writel_relaxed(0x00,
qphy->base + qphy->phy_reg[INTR_CTRL]);
- /* bring core PLL out of reset */
- writel_relaxed(CORE_PLL_EN_FROM_RESET, qphy->base +
- qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+ /* Reset PLL if needed */
+ if (!qusb_phy_pll_locked(qphy)) {
+ dev_dbg(phy->dev, "%s: reset PLL\n", __func__);
+ /* hold core PLL into reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET |
+ CORE_RESET | CORE_RESET_MUX,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
- /* Makes sure that above write goes through */
- wmb();
+ /* Wait for PLL to get reset */
+ usleep_range(10, 20);
+
+ /* bring core PLL out of reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+
+ /* Makes sure that above write goes through */
+ wmb();
+ }
} else { /* Cable connect case */
qusb_phy_enable_clocks(qphy, true);
}