From e318d1fa2cc94c3e5afc23e35bf768e0ba524204 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Wed, 30 Apr 2014 17:37:18 -0700 Subject: scsi: ufs-msm: disable the sigdet before power collapsing PHY If UFS PHY power down is deasserted and power is restored to analog circuits, the rx_sigdet can glitch. If the glitch is wide enough, it can trigger the PHY digital logic to think it saw a DIF-N and cause it to exit Hibern8. Disabling the rx_sigdet during power-up will mask the glitch. Change-Id: I20d93d2f5b479bb9e1d9626cfb9939d280b172a5 Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufs-msm.c | 49 ++++++++++++++++++++++++++++++++++++---------- drivers/scsi/ufs/ufs-msm.h | 8 ++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/ufs/ufs-msm.c b/drivers/scsi/ufs/ufs-msm.c index cb6c9497cbc6..20b2e288a704 100644 --- a/drivers/scsi/ufs/ufs-msm.c +++ b/drivers/scsi/ufs/ufs-msm.c @@ -1855,13 +1855,6 @@ static int msm_ufs_phy_power_on(struct msm_ufs_phy *phy) if (err) goto out; - 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. - */ - mb(); - /* vdda_pll also enables ref clock LDOs so enable it first */ err = msm_ufs_phy_enable_vreg(phy, &phy->vdda_pll); if (err) @@ -1871,6 +1864,20 @@ static int msm_ufs_phy_power_on(struct msm_ufs_phy *phy) if (err) goto out_disable_pll; + 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. + */ + 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)); + /* make sure that SIGDET is enabled before proceeding further */ + mb(); + } + goto out; out_disable_pll: @@ -1883,7 +1890,17 @@ out: static int msm_ufs_phy_power_off(struct msm_ufs_phy *phy) { + 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)); + /* Ensure that SIGDET is disabled before PHY power collapse */ + mb(); + } writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + /* + * Ensure that PHY knows its PHY analog rail is going to be powered + * down. + */ mb(); msm_ufs_disable_phy_ref_clk(phy); @@ -2231,10 +2248,21 @@ static int msm_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) msm_ufs_save_phy_configuration(hba); msm_ufs_disable_phy_ref_clk(phy); + 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)); + /* + * Ensure that SIGDET is disabled before PHY power + * collapse + */ + mb(); + } writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); /* - * Ensure PHY knows that PHY analog rail is going to be powered - * down. + * Ensure that PHY knows its PHY analog rail is going to be + * powered down. */ mb(); msm_ufs_phy_disable_vreg(phy, &phy->vdda_phy); @@ -2558,7 +2586,8 @@ static void msm_ufs_advertise_quirks(struct ufs_hba *hba) | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP | UFSHCD_QUIRK_BROKEN_LCC); - phy->quirks = MSM_UFS_PHY_QUIRK_CFG_RESTORE; + phy->quirks = (MSM_UFS_PHY_QUIRK_CFG_RESTORE + | MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE); } } diff --git a/drivers/scsi/ufs/ufs-msm.h b/drivers/scsi/ufs/ufs-msm.h index b9afb1ddd8b0..89e575ed43ad 100644 --- a/drivers/scsi/ufs/ufs-msm.h +++ b/drivers/scsi/ufs/ufs-msm.h @@ -119,6 +119,14 @@ struct msm_ufs_phy { * 7. Wait for UFS_PHY_PCS_READY_STATUS[0] to be '1' */ #define MSM_UFS_PHY_QUIRK_CFG_RESTORE (1 << 0) + /* + * If UFS PHY power down is deasserted and power is restored to analog + * circuits, the rx_sigdet can glitch. If the glitch is wide enough, + * it can trigger the digital logic to think it saw a DIF-N and cause + * it to exit Hibern8. Disabling the rx_sigdet during power-up masks + * the glitch. + */ + #define MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE (1 << 1) }; struct msm_ufs_bus_vote { -- cgit v1.2.3