From 3d4dab853dfeeab9b1dfdb439406f63c9519cf6a Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Fri, 18 Jul 2014 11:39:16 -0700 Subject: [PATCH] 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 --- drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c | 50 ++++++++++++++----------- drivers/scsi/ufs/ufs-msm-phy.h | 9 +++++ 2 files changed, 37 insertions(+), 22 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) { /* - * make sure that SIGDET is enabled before proceeding - * further. + * Give atleast 1us delay after restoring PHY analog + * power. */ - 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)); + 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); /* - * Ensure that SIGDET is disabled before PHY power - * collapse + * Make sure workaround is deactivated before proceeding + * with normal PHY operations. */ mb(); } + } else { + 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); + /* + * 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;