summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubhash Jadavani <subhashj@codeaurora.org>2014-07-18 11:39:16 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:57:04 -0700
commit6063aa8a3dcab6fb929a564698ccfc2402cde876 (patch)
tree0a6d5a6f4bd6e77cde3b6a2333a518a2f82690f2
parentf6ffbc88ef91064ee86f742a5bebc42d2ed8e6f8 (diff)
scsi: ufs-msm-phy-qmp-20nm: fix hibern8 exit failure
If UFS link is put into Hibern8 and if UFS PHY analog hardware is power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8 exit might fail even after powering on UFS PHY analog hardware. This change provides workaround to solve above issue by doing custom PHY settings just before PHY analog power collapse. Change-Id: I63d43329798c5475e07511248ac35450b8fe208d Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c46
-rw-r--r--drivers/scsi/ufs/ufs-msm-phy.h9
2 files changed, 35 insertions, 20 deletions
diff --git a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c
index 1e72dcc61ac9..88522f2a2a90 100644
--- a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c
+++ b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c
@@ -82,36 +82,41 @@ void ufs_msm_phy_qmp_20nm_power_control(struct ufs_msm_phy *phy, bool val)
writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
/*
* Before any transactions involving PHY, ensure PHY knows
- * that it's analog rail is powered ON. This also ensures
- * that PHY is out of power collapse before enabling the
- * SIGDET.
+ * that it's analog rail is powered ON.
*/
mb();
+
if (phy->quirks &
- MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
- writel_relaxed(0xC0,
- phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
- writel_relaxed(0xC0,
- phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
+ MSM_UFS_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE) {
+ /*
+ * Give atleast 1us delay after restoring PHY analog
+ * power.
+ */
+ usleep_range(1, 2);
+ writel_relaxed(0x0A, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ writel_relaxed(0x08, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
/*
- * make sure that SIGDET is enabled before proceeding
- * further.
+ * Make sure workaround is deactivated before proceeding
+ * with normal PHY operations.
*/
- mb();
+ mb();
}
} else {
- if (phy->quirks &
- MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
- writel_relaxed(0x0,
- phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
- writel_relaxed(0x0,
- phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
+ if (phy->quirks &
+ MSM_UFS_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE) {
+ writel_relaxed(0x0A, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ writel_relaxed(0x02, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
/*
- * Ensure that SIGDET is disabled before PHY power
- * collapse
+ * Make sure that above workaround is activated before
+ * PHY analog power collapse.
*/
mb();
}
+
writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
/*
* ensure that PHY knows its PHY analog rail is going
@@ -158,7 +163,8 @@ static void ufs_msm_phy_qmp_20nm_advertise_quirks(struct phy *generic_phy)
struct ufs_msm_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy);
struct ufs_msm_phy *phy_common = &(phy->common_cfg);
- phy_common->quirks = 0;
+ phy_common->quirks =
+ MSM_UFS_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
}
struct phy_ops ufs_msm_phy_qmp_20nm_phy_ops = {
diff --git a/drivers/scsi/ufs/ufs-msm-phy.h b/drivers/scsi/ufs/ufs-msm-phy.h
index 90eac935c161..e6f2b92539f6 100644
--- a/drivers/scsi/ufs/ufs-msm-phy.h
+++ b/drivers/scsi/ufs/ufs-msm-phy.h
@@ -108,6 +108,15 @@ struct ufs_msm_phy {
*/
#define MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE (1 << 1)
+ /*
+ * If UFS link is put into Hibern8 and if UFS PHY analog hardware is
+ * power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8
+ * exit might fail even after powering on UFS PHY analog hardware.
+ * Enabling this quirk will help to solve above issue by doing
+ * custom PHY settings just before PHY analog power collapse.
+ */
+ #define MSM_UFS_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE (1 << 2)
+
char name[UFS_MSM_PHY_NAME_LEN];
struct ufs_msm_phy_calibration *cached_regs;
int cached_regs_table_size;