]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/mmc/host/sdhci-msm.c
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112...
[mirror_ubuntu-artful-kernel.git] / drivers / mmc / host / sdhci-msm.c
index 5a37c294b17a6a8514db35177d100e1ff313fc10..10cdc84d51136694d8e95413b754d5f6d26ace48 100644 (file)
@@ -69,6 +69,7 @@
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
 #define CORE_VENDOR_SPEC       0x10c
+#define CORE_VENDOR_SPEC_POR_VAL       0xa1c
 #define CORE_CLK_PWRSAVE       BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
 
 #define CORE_DDR_200_CFG               0x184
 #define CORE_CDC_T4_DLY_SEL            BIT(0)
+#define CORE_CMDIN_RCLK_EN             BIT(1)
 #define CORE_START_CDC_TRAFFIC         BIT(6)
 #define CORE_VENDOR_SPEC3      0x1b0
 #define CORE_PWRSAVE_DLL       BIT(3)
@@ -150,7 +152,8 @@ static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
         */
        if (ios.timing == MMC_TIMING_UHS_DDR50 ||
            ios.timing == MMC_TIMING_MMC_DDR52 ||
-           ios.timing == MMC_TIMING_MMC_HS400)
+           ios.timing == MMC_TIMING_MMC_HS400 ||
+           host->flags & SDHCI_HS400_TUNING)
                clock *= 2;
        return clock;
 }
@@ -545,6 +548,7 @@ static void msm_hc_select_hs400(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct mmc_ios ios = host->mmc->ios;
        u32 config, dll_lock;
        int rc;
 
@@ -558,7 +562,8 @@ static void msm_hc_select_hs400(struct sdhci_host *host)
         * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
         * register
         */
-       if (msm_host->tuning_done && !msm_host->calibration_done) {
+       if ((msm_host->tuning_done || ios.enhanced_strobe) &&
+           !msm_host->calibration_done) {
                config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
                config |= CORE_HC_SELECT_IN_HS400;
                config |= CORE_HC_SELECT_IN_EN;
@@ -610,7 +615,8 @@ void sdhci_msm_hc_select_mode(struct sdhci_host *host)
 {
        struct mmc_ios ios = host->mmc->ios;
 
-       if (ios.timing == MMC_TIMING_MMC_HS400)
+       if (ios.timing == MMC_TIMING_MMC_HS400 ||
+           host->flags & SDHCI_HS400_TUNING)
                msm_hc_select_hs400(host);
        else
                msm_hc_select_default(host);
@@ -658,19 +664,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
        config &= ~CORE_START_CDC_TRAFFIC;
        writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
 
-       /*
-        * Perform CDC Register Initialization Sequence
-        *
-        * CORE_CSR_CDC_CTLR_CFG0       0x11800EC
-        * CORE_CSR_CDC_CTLR_CFG1       0x3011111
-        * CORE_CSR_CDC_CAL_TIMER_CFG0  0x1201000
-        * CORE_CSR_CDC_CAL_TIMER_CFG1  0x4
-        * CORE_CSR_CDC_REFCOUNT_CFG    0xCB732020
-        * CORE_CSR_CDC_COARSE_CAL_CFG  0xB19
-        * CORE_CSR_CDC_DELAY_CFG       0x3AC
-        * CORE_CDC_OFFSET_CFG          0x0
-        * CORE_CDC_SLAVE_DDA_CFG       0x16334
-        */
+       /* Perform CDC Register Initialization Sequence */
 
        writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
        writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
@@ -678,7 +672,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
        writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
        writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
        writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
-       writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
+       writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
        writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
        writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
 
@@ -731,6 +725,7 @@ out:
 
 static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
 {
+       struct mmc_host *mmc = host->mmc;
        u32 dll_status, config;
        int ret;
 
@@ -745,6 +740,12 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
         */
        writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);
 
+       if (mmc->ios.enhanced_strobe) {
+               config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG);
+               config |= CORE_CMDIN_RCLK_EN;
+               writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
+       }
+
        config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
        config |= CORE_DDR_CAL_EN;
        writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2);
@@ -779,6 +780,7 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct mmc_host *mmc = host->mmc;
        int ret;
        u32 config;
 
@@ -792,14 +794,17 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
        if (ret)
                goto out;
 
-       /* Set the selected phase in delay line hw block */
-       ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
-       if (ret)
-               goto out;
+       if (!mmc->ios.enhanced_strobe) {
+               /* Set the selected phase in delay line hw block */
+               ret = msm_config_cm_dll_phase(host,
+                                             msm_host->saved_tuning_phase);
+               if (ret)
+                       goto out;
+               config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+               config |= CORE_CMD_DAT_TRACK_SEL;
+               writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+       }
 
-       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
-       config |= CORE_CMD_DAT_TRACK_SEL;
-       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
        if (msm_host->use_cdclp533)
                ret = sdhci_msm_cdclp533_calibration(host);
        else
@@ -810,12 +815,12 @@ out:
        return ret;
 }
 
-static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        int tuning_seq_cnt = 3;
        u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
        int rc;
-       struct mmc_host *mmc = host->mmc;
        struct mmc_ios ios = host->mmc->ios;
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
@@ -830,6 +835,17 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
            ios.timing == MMC_TIMING_UHS_SDR104))
                return 0;
 
+       /*
+        * For HS400 tuning in HS200 timing requires:
+        * - select MCLK/2 in VENDOR_SPEC
+        * - program MCLK to 400MHz (or nearest supported) in GCC
+        */
+       if (host->flags & SDHCI_HS400_TUNING) {
+               sdhci_msm_hc_select_mode(host);
+               msm_set_clock_rate_for_bus_mode(host, ios.clock);
+               host->flags &= ~SDHCI_HS400_TUNING;
+       }
+
 retry:
        /* First of all reset the tuning block */
        rc = msm_init_cm_dll(host);
@@ -886,6 +902,7 @@ retry:
 
 /*
  * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation.
+ * This needs to be done for both tuning and enhanced_strobe mode.
  * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz
  * fixed feedback clock is used.
  */
@@ -896,7 +913,8 @@ static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios)
        int ret;
 
        if (host->clock > CORE_FREQ_100MHZ &&
-           msm_host->tuning_done && !msm_host->calibration_done) {
+           (msm_host->tuning_done || ios->enhanced_strobe) &&
+           !msm_host->calibration_done) {
                ret = sdhci_msm_hs400_dll_calibration(host);
                if (!ret)
                        msm_host->calibration_done = true;
@@ -1090,7 +1108,6 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
 static const struct sdhci_ops sdhci_msm_ops = {
-       .platform_execute_tuning = sdhci_msm_execute_tuning,
        .reset = sdhci_reset,
        .set_clock = sdhci_msm_set_clock,
        .get_min_clock = sdhci_msm_get_min_clock,
@@ -1197,17 +1214,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
-       config = readl_relaxed(msm_host->core_mem + CORE_POWER);
-       config |= CORE_SW_RST;
-       writel_relaxed(config, msm_host->core_mem + CORE_POWER);
-
-       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
-       usleep_range(1000, 5000);
-       if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
-               dev_err(&pdev->dev, "Stuck in reset\n");
-               ret = -ETIMEDOUT;
-               goto clk_disable;
-       }
+       /* Reset the vendor spec register to power on reset state */
+       writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
+                      host->ioaddr + CORE_VENDOR_SPEC);
 
        /* Set HC_MODE_EN bit in HC_MODE register */
        writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
@@ -1273,6 +1282,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                                         MSM_MMC_AUTOSUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(&pdev->dev);
 
+       host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
        ret = sdhci_add_host(host);
        if (ret)
                goto pm_runtime_disable;