ipq806x: dwc3: Fix power_on and power_off sequence
authorPavel Kubelun <be.dissent@gmail.com>
Thu, 15 Jun 2017 08:48:17 +0000 (11:48 +0300)
committerFelix Fietkau <nbd@nbd.name>
Wed, 17 Jan 2018 10:02:06 +0000 (11:02 +0100)
Picking commit from QSDK
https://source.codeaurora.org/quic/qsdk/oss/kernel/linux-msm/commit/drivers/phy/phy-qcom-dwc3.c?h=eggplant&id=d316437c9cdb70023a760342678f32e27241725a

The commit fixes:
- dwc3 phy module unloading
- possibly fixes FS#177 when some devices were improperly enumerated as HS while being SS thus stucking the driver during boot.

Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
target/linux/ipq806x/patches-4.9/0032-phy-add-qcom-dwc3-phy.patch

index 230afd2..bd77785 100644 (file)
@@ -7,8 +7,8 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 ---
  drivers/phy/Kconfig         |  12 +
  drivers/phy/Makefile        |   1 +
- drivers/phy/phy-qcom-dwc3.c | 546 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 559 insertions(+)
+ drivers/phy/phy-qcom-dwc3.c | 575 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 588 insertions(+)
  create mode 100644 drivers/phy/phy-qcom-dwc3.c
 
 --- a/drivers/phy/Kconfig
@@ -39,7 +39,7 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +obj-$(CONFIG_PHY_QCOM_DWC3)           += phy-qcom-dwc3.o
 --- /dev/null
 +++ b/drivers/phy/phy-qcom-dwc3.c
-@@ -0,0 +1,546 @@
+@@ -0,0 +1,575 @@
 +/* Copyright (c) 2014-2015, Code Aurora Forum. All rights reserved.
 + *
 + * This program is free software; you can redistribute it and/or modify
@@ -299,36 +299,21 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +      return ret;
 +}
 +
-+static int qcom_dwc3_phy_power_on(struct phy *phy)
++static int qcom_dwc3_hs_phy_init(struct phy *phy)
 +{
-+      int ret;
 +      struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++      int ret;
++      u32 val;
 +
 +      ret = clk_prepare_enable(phy_dwc3->xo_clk);
 +      if (ret)
 +              return ret;
 +
 +      ret = clk_prepare_enable(phy_dwc3->ref_clk);
-+      if (ret)
++      if (ret) {
 +              clk_disable_unprepare(phy_dwc3->xo_clk);
-+
-+      return ret;
-+}
-+
-+static int qcom_dwc3_phy_power_off(struct phy *phy)
-+{
-+      struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
-+
-+      clk_disable_unprepare(phy_dwc3->ref_clk);
-+      clk_disable_unprepare(phy_dwc3->xo_clk);
-+
-+      return 0;
-+}
-+
-+static int qcom_dwc3_hs_phy_init(struct phy *phy)
-+{
-+      struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
-+      u32 val;
++              return ret;
++      }
 +
 +      /*
 +       * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
@@ -353,12 +338,32 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +      return 0;
 +}
 +
++static int qcom_dwc3_hs_phy_exit(struct phy *phy)
++{
++      struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++
++      clk_disable_unprepare(phy_dwc3->ref_clk);
++      clk_disable_unprepare(phy_dwc3->xo_clk);
++
++      return 0;
++}
++
 +static int qcom_dwc3_ss_phy_init(struct phy *phy)
 +{
 +      struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
 +      int ret;
 +      u32 data = 0;
 +
++      ret = clk_prepare_enable(phy_dwc3->xo_clk);
++      if (ret)
++              return ret;
++
++      ret = clk_prepare_enable(phy_dwc3->ref_clk);
++      if (ret) {
++              clk_disable_unprepare(phy_dwc3->xo_clk);
++              return ret;
++      }
++
 +      /* reset phy */
 +      data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 +      writel(data | SSUSB_CTRL_SS_PHY_RESET,
@@ -381,6 +386,30 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +      writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
 +
 +      /*
++       * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
++       * in HS mode instead of SS mode. Workaround it by asserting
++       * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
++       */
++      ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x102D, &data);
++      if (ret)
++              goto err_phy_trans;
++
++      data |= (1 << 7);
++      ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x102D, data);
++      if (ret)
++              goto err_phy_trans;
++
++      ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x1010, &data);
++      if (ret)
++              goto err_phy_trans;
++
++      data &= ~0xff0;
++      data |= 0x20;
++      ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x1010, data);
++      if (ret)
++              goto err_phy_trans;
++
++      /*
 +       * Fix RX Equalization setting as follows
 +       * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
 +       * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
@@ -462,7 +491,10 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +      qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
 +              SSUSB_CTRL_REF_USE_PAD, 0x0);
 +      qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
-+              0x0, SSUSB_CTRL_TEST_POWERDOWN);
++              SSUSB_CTRL_TEST_POWERDOWN, 0x0);
++
++      clk_disable_unprepare(phy_dwc3->ref_clk);
++      clk_disable_unprepare(phy_dwc3->xo_clk);
 +
 +      return 0;
 +}
@@ -470,8 +502,7 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +static const struct qcom_dwc3_phy_drvdata qcom_dwc3_hs_drvdata = {
 +      .ops = {
 +              .init           = qcom_dwc3_hs_phy_init,
-+              .power_on       = qcom_dwc3_phy_power_on,
-+              .power_off      = qcom_dwc3_phy_power_off,
++              .exit           = qcom_dwc3_hs_phy_exit,
 +              .owner          = THIS_MODULE,
 +      },
 +      .clk_rate = 60000000,
@@ -481,8 +512,6 @@ Signed-off-by: Andy Gross <agross@codeaurora.org>
 +      .ops = {
 +              .init           = qcom_dwc3_ss_phy_init,
 +              .exit           = qcom_dwc3_ss_phy_exit,
-+              .power_on       = qcom_dwc3_phy_power_on,
-+              .power_off      = qcom_dwc3_phy_power_off,
 +              .owner          = THIS_MODULE,
 +      },
 +      .clk_rate = 125000000,