summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Lin <shawn.lin@rock-chips.com>2026-03-09 11:29:03 +0800
committerUlf Hansson <ulf.hansson@linaro.org>2026-03-16 15:43:42 +0100
commitcc1060a18e0464a7b03c06fb64889935d27acee0 (patch)
treeba66260f2995bf1196570a700cd548e1e99e0733
parent8750929d971386c530ca1e131e50a56187fa5f73 (diff)
downloadlwn-cc1060a18e0464a7b03c06fb64889935d27acee0.tar.gz
lwn-cc1060a18e0464a7b03c06fb64889935d27acee0.zip
mmc: dw_mmc-rockchip: Add phase map support
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>
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 76995415bc4c..c6eece4ec3fd 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -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);
}
}