]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mmc: dw_mmc-rockchip: Add phase map support
authorShawn Lin <shawn.lin@rock-chips.com>
Mon, 9 Mar 2026 03:29:03 +0000 (11:29 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 16 Mar 2026 14:43:42 +0000 (15:43 +0100)
Multiple boards require different phase settings, rendering the default
phase policy unscalable. Therefore, we introduce phase map to address this
limitation. To preserve backward compatibility, the default_sample_phase
and original drv phase for different modes are retained, with phase map
values taking precedence when available.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/dw_mmc-rockchip.c

index 76995415bc4c336794101931c14cabe3710f4ee5..c6eece4ec3fda980dca726505be0f372d7cb4367 100644 (file)
@@ -179,7 +179,8 @@ static int rockchip_mmc_set_phase(struct dw_mci *host, bool sample, int degrees)
 static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 {
        struct dw_mci_rockchip_priv_data *priv = host->priv;
-       int ret;
+       struct mmc_clk_phase phase = host->phase_map.phase[ios->timing];
+       int ret, sample_phase, drv_phase;
        unsigned int cclkin;
        u32 bus_hz;
 
@@ -213,8 +214,15 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
        }
 
        /* Make sure we use phases which we can enumerate with */
-       if (!IS_ERR(priv->sample_clk) && ios->timing <= MMC_TIMING_SD_HS)
-               rockchip_mmc_set_phase(host, true, priv->default_sample_phase);
+       if (!IS_ERR(priv->sample_clk)) {
+               /* Keep backward compatibility */
+               if (ios->timing <= MMC_TIMING_SD_HS) {
+                       sample_phase = phase.valid ? phase.in_deg : priv->default_sample_phase;
+                       rockchip_mmc_set_phase(host, true, sample_phase);
+               } else if (phase.valid) {
+                       rockchip_mmc_set_phase(host, true, phase.in_deg);
+               }
+       }
 
        /*
         * Set the drive phase offset based on speed mode to achieve hold times.
@@ -243,15 +251,13 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
         * same results, for instance).
         */
        if (!IS_ERR(priv->drv_clk)) {
-               int phase;
-
                /*
                 * In almost all cases a 90 degree phase offset will provide
                 * sufficient hold times across all valid input clock rates
                 * assuming delay_o is not absurd for a given SoC.  We'll use
                 * that as a default.
                 */
-               phase = 90;
+               drv_phase = 90;
 
                switch (ios->timing) {
                case MMC_TIMING_MMC_DDR52:
@@ -261,7 +267,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
                         * to get the same timings.
                         */
                        if (ios->bus_width == MMC_BUS_WIDTH_8)
-                               phase = 180;
+                               drv_phase = 180;
                        break;
                case MMC_TIMING_UHS_SDR104:
                case MMC_TIMING_MMC_HS200:
@@ -273,11 +279,14 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
                         * SoCs measured this seems to be OK, but it doesn't
                         * hurt to give margin here, so we use 180.
                         */
-                       phase = 180;
+                       drv_phase = 180;
                        break;
                }
 
-               rockchip_mmc_set_phase(host, false, phase);
+               /* Use out phase from phase map first */
+               if (phase.valid)
+                       drv_phase = phase.out_deg;
+               rockchip_mmc_set_phase(host, false, drv_phase);
        }
 }