mmc: sdhci-pci-o2micro: Bug fix for SDR104 HW tuning failure
authorShirley Her <shirley.her@bayhubtech.com>
Sat, 6 Feb 2021 01:40:51 +0000 (17:40 -0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 15 Feb 2021 09:37:57 +0000 (10:37 +0100)
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>
drivers/mmc/host/sdhci-pci-o2micro.c

index fa76748d8929333ede3276d9ef13c1f656055ee8..94e3f72f6405d40f0445f068a6f864934340b5d3 100644 (file)
@@ -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);