summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorShirley Her <shirley.her@bayhubtech.com>2021-02-06 04:40:51 +0300
committerUlf Hansson <ulf.hansson@linaro.org>2021-02-15 12:37:57 +0300
commit1ad9f88014ae1d5abccb6fe930bc4c5c311bdc05 (patch)
tree05755c36e18120ddbce811d40660719d9cd2f966 /drivers/mmc
parent3f957dec6dc219a8a1bf6d7994ee95ed7004f701 (diff)
downloadlinux-1ad9f88014ae1d5abccb6fe930bc4c5c311bdc05.tar.xz
mmc: sdhci-pci-o2micro: Bug fix for SDR104 HW tuning failure
Force chip enter L0 power state during SDR104 HW tuning to avoid tuning failure Signed-off-by: Shirley Her <shirley.her@bayhubtech.com> Link: https://lore.kernel.org/r/20210206014051.3418-1-shirley.her@bayhubtech.com Fixes: 7b7d897e8898 ("mmc: sdhci-pci-o2micro: Add HW tuning for SDR104 mode") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index fa76748d8929..94e3f72f6405 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -33,6 +33,8 @@
#define O2_SD_ADMA2 0xE7
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
+#define O2_SD_MISC_CTRL 0x1C0
+#define O2_SD_PWR_FORCE_L0 0x0002
#define O2_SD_TUNING_CTRL 0x300
#define O2_SD_PLL_SETTING 0x304
#define O2_SD_MISC_SETTING 0x308
@@ -300,6 +302,8 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
int current_bus_width = 0;
+ u32 scratch32 = 0;
+ u16 scratch = 0;
/*
* This handler only implements the eMMC tuning that is specific to
@@ -312,6 +316,17 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
(opcode != MMC_SEND_TUNING_BLOCK)))
return -EINVAL;
+
+ /* Force power mode enter L0 */
+ scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
+ scratch |= O2_SD_PWR_FORCE_L0;
+ sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
+
+ /* wait DLL lock, timeout value 5ms */
+ if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
+ scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000))
+ pr_warn("%s: DLL can't lock in 5ms after force L0 during tuning.\n",
+ mmc_hostname(host->mmc));
/*
* Judge the tuning reason, whether caused by dll shift
* If cause by dll shift, should call sdhci_o2_dll_recovery
@@ -344,6 +359,11 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_set_bus_width(host, current_bus_width);
}
+ /* Cancel force power mode enter L0 */
+ scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
+ scratch &= ~(O2_SD_PWR_FORCE_L0);
+ sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
+
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);