mmc: sdhci-sprd: Add PHY DLL delay configuration
authorBaolin Wang <baolin.wang@linaro.org>
Tue, 4 Jun 2019 08:14:28 +0000 (16:14 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 10 Jun 2019 15:11:09 +0000 (17:11 +0200)
Set the PHY DLL delay for each timing mode, which is used to sample the clock
accurately and make the clock more stable.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-sprd.c

index e6eda13..024c3c5 100644 (file)
@@ -29,6 +29,8 @@
 #define  SDHCI_SPRD_DLL_INIT_COUNT     0xc00
 #define  SDHCI_SPRD_DLL_PHASE_INTERNAL 0x3
 
+#define SDHCI_SPRD_REG_32_DLL_DLY      0x204
+
 #define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET       0x208
 #define  SDHCIBSPRD_IT_WR_DLY_INV              BIT(5)
 #define  SDHCI_SPRD_BIT_CMD_DLY_INV            BIT(13)
@@ -72,6 +74,24 @@ struct sdhci_sprd_host {
        struct clk *clk_2x_enable;
        u32 base_rate;
        int flags; /* backup of host attribute */
+       u32 phy_delay[MMC_TIMING_MMC_HS400 + 2];
+};
+
+struct sdhci_sprd_phy_cfg {
+       const char *property;
+       u8 timing;
+};
+
+static const struct sdhci_sprd_phy_cfg sdhci_sprd_phy_cfgs[] = {
+       { "sprd,phy-delay-legacy", MMC_TIMING_LEGACY, },
+       { "sprd,phy-delay-sd-highspeed", MMC_TIMING_SD_HS, },
+       { "sprd,phy-delay-sd-uhs-sdr50", MMC_TIMING_UHS_SDR50, },
+       { "sprd,phy-delay-sd-uhs-sdr104", MMC_TIMING_UHS_SDR104, },
+       { "sprd,phy-delay-mmc-highspeed", MMC_TIMING_MMC_HS, },
+       { "sprd,phy-delay-mmc-ddr52", MMC_TIMING_MMC_DDR52, },
+       { "sprd,phy-delay-mmc-hs200", MMC_TIMING_MMC_HS200, },
+       { "sprd,phy-delay-mmc-hs400", MMC_TIMING_MMC_HS400, },
+       { "sprd,phy-delay-mmc-hs400es", MMC_TIMING_MMC_HS400 + 1, },
 };
 
 #define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))
@@ -276,6 +296,9 @@ static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
 static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
                                         unsigned int timing)
 {
+       struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+       struct mmc_host *mmc = host->mmc;
+       u32 *p = sprd_host->phy_delay;
        u16 ctrl_2;
 
        if (timing == host->timing)
@@ -314,6 +337,9 @@ static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
        }
 
        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+       if (!mmc->ios.enhanced_strobe)
+               sdhci_writel(host, p[timing], SDHCI_SPRD_REG_32_DLL_DLY);
 }
 
 static void sdhci_sprd_hw_reset(struct sdhci_host *host)
@@ -381,6 +407,8 @@ static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
                                             struct mmc_ios *ios)
 {
        struct sdhci_host *host = mmc_priv(mmc);
+       struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+       u32 *p = sprd_host->phy_delay;
        u16 ctrl_2;
 
        if (!ios->enhanced_strobe)
@@ -395,6 +423,28 @@ static void sdhci_sprd_hs400_enhanced_strobe(struct mmc_host *mmc,
        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
        sdhci_sprd_sd_clk_on(host);
+
+       /* Set the PHY DLL delay value for HS400 enhanced strobe mode */
+       sdhci_writel(host, p[MMC_TIMING_MMC_HS400 + 1],
+                    SDHCI_SPRD_REG_32_DLL_DLY);
+}
+
+static void sdhci_sprd_phy_param_parse(struct sdhci_sprd_host *sprd_host,
+                                      struct device_node *np)
+{
+       u32 *p = sprd_host->phy_delay;
+       int ret, i, index;
+       u32 val[4];
+
+       for (i = 0; i < ARRAY_SIZE(sdhci_sprd_phy_cfgs); i++) {
+               ret = of_property_read_u32_array(np,
+                               sdhci_sprd_phy_cfgs[i].property, val, 4);
+               if (ret)
+                       continue;
+
+               index = sdhci_sprd_phy_cfgs[i].timing;
+               p[index] = val[0] | (val[1] << 8) | (val[2] << 16) | (val[3] << 24);
+       }
 }
 
 static const struct sdhci_pltfm_data sdhci_sprd_pdata = {
@@ -428,6 +478,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev)
                goto pltfm_free;
 
        sprd_host = TO_SPRD_HOST(host);
+       sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node);
 
        clk = devm_clk_get(&pdev->dev, "sdio");
        if (IS_ERR(clk)) {