diff mbox series

[v3,06/20] mmc: am654_sdhci: Add support for input tap delay

Message ID 20210121124052.3454-7-a-govindraju@ti.com
State Changes Requested
Delegated to: Lokesh Vutla
Headers show
Series Add support for MMC higher speed modes for TI's am65x, j721e and j7200 platforms | expand

Commit Message

Aswath Govindraju Jan. 21, 2021, 12:40 p.m. UTC
From: Faiz Abbas <faiz_abbas@ti.com>

DLL need only be enabled for speed modes and clock frequencies at or
above 50 MHz. For speed modes that don't enable the DLL, we need to
configure a static input delay value. This involves reading an optional
itap-del-sel-* value from the device tree and configuring it for the
appropriate speed mode.

Therefore, move all dll configurations to their own functions and gate it
with 50 MHz speed and a minimum mode. If both these conditions are not
satisfied then configure delay chain modes.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
---
 drivers/mmc/am654_sdhci.c | 241 +++++++++++++++++++++++++-------------
 1 file changed, 161 insertions(+), 80 deletions(-)

Comments

Jaehoon Chung Jan. 25, 2021, 10:21 p.m. UTC | #1
On 1/21/21 9:40 PM, Aswath Govindraju wrote:
> From: Faiz Abbas <faiz_abbas@ti.com>
> 
> DLL need only be enabled for speed modes and clock frequencies at or
> above 50 MHz. For speed modes that don't enable the DLL, we need to
> configure a static input delay value. This involves reading an optional
> itap-del-sel-* value from the device tree and configuring it for the
> appropriate speed mode.
> 
> Therefore, move all dll configurations to their own functions and gate it
> with 50 MHz speed and a minimum mode. If both these conditions are not
> satisfied then configure delay chain modes.
> 
> Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>

Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>

Best Regards,
Jaehoon Chung

> ---
>  drivers/mmc/am654_sdhci.c | 241 +++++++++++++++++++++++++-------------
>  1 file changed, 161 insertions(+), 80 deletions(-)
> 
> diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
> index 5790fa3d0dbf..b82558254ebb 100644
> --- a/drivers/mmc/am654_sdhci.c
> +++ b/drivers/mmc/am654_sdhci.c
> @@ -62,6 +62,16 @@
>  #define CALDONE_MASK		BIT(CALDONE_SHIFT)
>  #define RETRIM_SHIFT		17
>  #define RETRIM_MASK		BIT(RETRIM_SHIFT)
> +#define SELDLYTXCLK_SHIFT	17
> +#define SELDLYTXCLK_MASK	BIT(SELDLYTXCLK_SHIFT)
> +#define SELDLYRXCLK_SHIFT	16
> +#define SELDLYRXCLK_MASK	BIT(SELDLYRXCLK_SHIFT)
> +#define ITAPDLYSEL_SHIFT	0
> +#define ITAPDLYSEL_MASK		GENMASK(4, 0)
> +#define ITAPDLYENA_SHIFT	8
> +#define ITAPDLYENA_MASK		BIT(ITAPDLYENA_SHIFT)
> +#define ITAPCHGWIN_SHIFT	9
> +#define ITAPCHGWIN_MASK		BIT(ITAPCHGWIN_SHIFT)
>  
>  #define DRIVER_STRENGTH_50_OHM	0x0
>  #define DRIVER_STRENGTH_33_OHM	0x1
> @@ -70,6 +80,7 @@
>  #define DRIVER_STRENGTH_40_OHM	0x4
>  
>  #define AM654_SDHCI_MIN_FREQ	400000
> +#define CLOCK_TOO_SLOW_HZ	50000000
>  
>  struct am654_sdhci_plat {
>  	struct mmc_config cfg;
> @@ -77,6 +88,7 @@ struct am654_sdhci_plat {
>  	struct regmap *base;
>  	bool non_removable;
>  	u32 otap_del_sel[MMC_MODES_END];
> +	u32 itap_del_sel[MMC_MODES_END];
>  	u32 trm_icp;
>  	u32 drv_strength;
>  	u32 strb_sel;
> @@ -89,22 +101,45 @@ struct am654_sdhci_plat {
>  };
>  
>  struct timing_data {
> -	const char *binding;
> +	const char *otap_binding;
> +	const char *itap_binding;
>  	u32 capability;
>  };
>  
>  static const struct timing_data td[] = {
> -	[MMC_LEGACY] = {"ti,otap-del-sel-legacy", 0},
> -	[MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP(MMC_HS)},
> -	[SD_HS]  = {"ti,otap-del-sel-sd-hs", MMC_CAP(SD_HS)},
> -	[UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP(UHS_SDR12)},
> -	[UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP(UHS_SDR25)},
> -	[UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP(UHS_SDR50)},
> -	[UHS_SDR104] = {"ti,otap-del-sel-sdr104", MMC_CAP(UHS_SDR104)},
> -	[UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP(UHS_DDR50)},
> -	[MMC_DDR_52] = {"ti,otap-del-sel-ddr52", MMC_CAP(MMC_DDR_52)},
> -	[MMC_HS_200] = {"ti,otap-del-sel-hs200", MMC_CAP(MMC_HS_200)},
> -	[MMC_HS_400] = {"ti,otap-del-sel-hs400", MMC_CAP(MMC_HS_400)},
> +	[MMC_LEGACY]	= {"ti,otap-del-sel-legacy",
> +			   "ti,itap-del-sel-legacy",
> +			   0},
> +	[MMC_HS]	= {"ti,otap-del-sel-mmc-hs",
> +			   "ti,itap-del-sel-mms-hs",
> +			   MMC_CAP(MMC_HS)},
> +	[SD_HS]		= {"ti,otap-del-sel-sd-hs",
> +			   "ti,itap-del-sel-sd-hs",
> +			   MMC_CAP(SD_HS)},
> +	[UHS_SDR12]	= {"ti,otap-del-sel-sdr12",
> +			   "ti,itap-del-sel-sdr12",
> +			   MMC_CAP(UHS_SDR12)},
> +	[UHS_SDR25]	= {"ti,otap-del-sel-sdr25",
> +			   "ti,itap-del-sel-sdr25",
> +			   MMC_CAP(UHS_SDR25)},
> +	[UHS_SDR50]	= {"ti,otap-del-sel-sdr50",
> +			   NULL,
> +			   MMC_CAP(UHS_SDR50)},
> +	[UHS_SDR104]	= {"ti,otap-del-sel-sdr104",
> +			   NULL,
> +			   MMC_CAP(UHS_SDR104)},
> +	[UHS_DDR50]	= {"ti,otap-del-sel-ddr50",
> +			   NULL,
> +			   MMC_CAP(UHS_DDR50)},
> +	[MMC_DDR_52]	= {"ti,otap-del-sel-ddr52",
> +			   "ti,itap-del-sel-ddr52",
> +			   MMC_CAP(MMC_DDR_52)},
> +	[MMC_HS_200]	= {"ti,otap-del-sel-hs200",
> +			   NULL,
> +			   MMC_CAP(MMC_HS_200)},
> +	[MMC_HS_400]	= {"ti,otap-del-sel-hs400",
> +			   NULL,
> +			   MMC_CAP(MMC_HS_400)},
>  };
>  
>  struct am654_driver_data {
> @@ -127,12 +162,99 @@ static void am654_sdhci_set_control_reg(struct sdhci_host *host)
>  	sdhci_set_uhs_timing(host);
>  }
>  
> +static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat,
> +				 unsigned int speed)
> +{
> +	int sel50, sel100, freqsel;
> +	u32 mask, val;
> +	int ret;
> +
> +	/* Disable delay chain mode */
> +	regmap_update_bits(plat->base, PHY_CTRL5,
> +			   SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0);
> +
> +	if (plat->flags & FREQSEL_2_BIT) {
> +		switch (speed) {
> +		case 200000000:
> +			sel50 = 0;
> +			sel100 = 0;
> +			break;
> +		case 100000000:
> +			sel50 = 0;
> +			sel100 = 1;
> +			break;
> +		default:
> +			sel50 = 1;
> +			sel100 = 0;
> +		}
> +
> +		/* Configure PHY DLL frequency */
> +		mask = SEL50_MASK | SEL100_MASK;
> +		val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
> +		regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
> +	} else {
> +		switch (speed) {
> +		case 200000000:
> +			freqsel = 0x0;
> +			break;
> +		default:
> +			freqsel = 0x4;
> +		}
> +		regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
> +				   freqsel << FREQSEL_SHIFT);
> +	}
> +
> +	/* Configure DLL TRIM */
> +	mask = DLL_TRIM_ICP_MASK;
> +	val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
> +
> +	/* Configure DLL driver strength */
> +	mask |= DR_TY_MASK;
> +	val |= plat->drv_strength << DR_TY_SHIFT;
> +	regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
> +
> +	/* Enable DLL */
> +	regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
> +			   0x1 << ENDLL_SHIFT);
> +	/*
> +	 * Poll for DLL ready. Use a one second timeout.
> +	 * Works in all experiments done so far
> +	 */
> +	ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
> +				       val & DLLRDY_MASK, 1000, 1000000);
> +
> +	return ret;
> +}
> +
> +static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat,
> +				      u32 itapdly)
> +{
> +	/* Set ITAPCHGWIN before writing to ITAPDLY */
> +	regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
> +			   1 << ITAPCHGWIN_SHIFT);
> +	regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYSEL_MASK,
> +			   itapdly << ITAPDLYSEL_SHIFT);
> +	regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
> +}
> +
> +static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat,
> +					  int mode)
> +{
> +	u32 mask, val;
> +
> +	val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT;
> +	mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
> +	regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
> +
> +	am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode]);
> +}
> +
>  static int am654_sdhci_set_ios_post(struct sdhci_host *host)
>  {
>  	struct udevice *dev = host->mmc->dev;
>  	struct am654_sdhci_plat *plat = dev_get_plat(dev);
>  	unsigned int speed = host->mmc->clock;
> -	int sel50, sel100, freqsel;
> +	int mode = host->mmc->selected_mode;
>  	u32 otap_del_sel;
>  	u32 mask, val;
>  	int ret;
> @@ -148,75 +270,29 @@ static int am654_sdhci_set_ios_post(struct sdhci_host *host)
>  	sdhci_set_clock(host->mmc, speed);
>  
>  	/* switch phy back on */
> -	if (speed > AM654_SDHCI_MIN_FREQ) {
> -		otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode];
> -		mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
> -		val = (1 << OTAPDLYENA_SHIFT) |
> -		      (otap_del_sel << OTAPDLYSEL_SHIFT);
> -
> -		/* Write to STRBSEL for HS400 speed mode */
> -		if (host->mmc->selected_mode == MMC_HS_400) {
> -			if (plat->flags & STRBSEL_4_BIT)
> -				mask |= STRBSEL_4BIT_MASK;
> -			else
> -				mask |= STRBSEL_8BIT_MASK;
> -
> -			val |= plat->strb_sel << STRBSEL_SHIFT;
> -		}
> +	otap_del_sel = plat->otap_del_sel[mode];
> +	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
> +	val = (1 << OTAPDLYENA_SHIFT) |
> +	      (otap_del_sel << OTAPDLYSEL_SHIFT);
>  
> -		regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
> -
> -		if (plat->flags & FREQSEL_2_BIT) {
> -			switch (speed) {
> -			case 200000000:
> -				sel50 = 0;
> -				sel100 = 0;
> -				break;
> -			case 100000000:
> -				sel50 = 0;
> -				sel100 = 1;
> -				break;
> -			default:
> -				sel50 = 1;
> -				sel100 = 0;
> -			}
> -
> -			/* Configure PHY DLL frequency */
> -			mask = SEL50_MASK | SEL100_MASK;
> -			val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
> -			regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
> -		} else {
> -			switch (speed) {
> -			case 200000000:
> -				freqsel = 0x0;
> -				break;
> -			default:
> -				freqsel = 0x4;
> -			}
> -			regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
> -					   freqsel << FREQSEL_SHIFT);
> -		}
> +	/* Write to STRBSEL for HS400 speed mode */
> +	if (host->mmc->selected_mode == MMC_HS_400) {
> +		if (plat->flags & STRBSEL_4_BIT)
> +			mask |= STRBSEL_4BIT_MASK;
> +		else
> +			mask |= STRBSEL_8BIT_MASK;
>  
> -		/* Configure DLL TRIM */
> -		mask = DLL_TRIM_ICP_MASK;
> -		val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
> -
> -		/* Configure DLL driver strength */
> -		mask |= DR_TY_MASK;
> -		val |= plat->drv_strength << DR_TY_SHIFT;
> -		regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
> -
> -		/* Enable DLL */
> -		regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
> -				   0x1 << ENDLL_SHIFT);
> -		/*
> -		 * Poll for DLL ready. Use a one second timeout.
> -		 * Works in all experiments done so far
> -		 */
> -		ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
> -					 val & DLLRDY_MASK, 1000, 1000000);
> +		val |= plat->strb_sel << STRBSEL_SHIFT;
> +	}
> +
> +	regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
> +
> +	if (mode > UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) {
> +		ret = am654_sdhci_setup_dll(plat, speed);
>  		if (ret)
>  			return ret;
> +	} else {
> +		am654_sdhci_setup_delay_chain(plat, mode);
>  	}
>  
>  	return 0;
> @@ -354,15 +430,20 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev,
>  	 * value is not found
>  	 */
>  	for (i = MMC_HS; i <= MMC_HS_400; i++) {
> -		ret = dev_read_u32(dev, td[i].binding, &plat->otap_del_sel[i]);
> +		ret = dev_read_u32(dev, td[i].otap_binding,
> +				   &plat->otap_del_sel[i]);
>  		if (ret) {
> -			dev_dbg(dev, "Couldn't find %s\n", td[i].binding);
> +			dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding);
>  			/*
>  			 * Remove the corresponding capability
>  			 * if an otap-del-sel value is not found
>  			 */
>  			cfg->host_caps &= ~td[i].capability;
>  		}
> +
> +		if (td[i].itap_binding)
> +			dev_read_u32(dev, td[i].itap_binding,
> +				     &plat->itap_del_sel[i]);
>  	}
>  
>  	return 0;
>
diff mbox series

Patch

diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
index 5790fa3d0dbf..b82558254ebb 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -62,6 +62,16 @@ 
 #define CALDONE_MASK		BIT(CALDONE_SHIFT)
 #define RETRIM_SHIFT		17
 #define RETRIM_MASK		BIT(RETRIM_SHIFT)
+#define SELDLYTXCLK_SHIFT	17
+#define SELDLYTXCLK_MASK	BIT(SELDLYTXCLK_SHIFT)
+#define SELDLYRXCLK_SHIFT	16
+#define SELDLYRXCLK_MASK	BIT(SELDLYRXCLK_SHIFT)
+#define ITAPDLYSEL_SHIFT	0
+#define ITAPDLYSEL_MASK		GENMASK(4, 0)
+#define ITAPDLYENA_SHIFT	8
+#define ITAPDLYENA_MASK		BIT(ITAPDLYENA_SHIFT)
+#define ITAPCHGWIN_SHIFT	9
+#define ITAPCHGWIN_MASK		BIT(ITAPCHGWIN_SHIFT)
 
 #define DRIVER_STRENGTH_50_OHM	0x0
 #define DRIVER_STRENGTH_33_OHM	0x1
@@ -70,6 +80,7 @@ 
 #define DRIVER_STRENGTH_40_OHM	0x4
 
 #define AM654_SDHCI_MIN_FREQ	400000
+#define CLOCK_TOO_SLOW_HZ	50000000
 
 struct am654_sdhci_plat {
 	struct mmc_config cfg;
@@ -77,6 +88,7 @@  struct am654_sdhci_plat {
 	struct regmap *base;
 	bool non_removable;
 	u32 otap_del_sel[MMC_MODES_END];
+	u32 itap_del_sel[MMC_MODES_END];
 	u32 trm_icp;
 	u32 drv_strength;
 	u32 strb_sel;
@@ -89,22 +101,45 @@  struct am654_sdhci_plat {
 };
 
 struct timing_data {
-	const char *binding;
+	const char *otap_binding;
+	const char *itap_binding;
 	u32 capability;
 };
 
 static const struct timing_data td[] = {
-	[MMC_LEGACY] = {"ti,otap-del-sel-legacy", 0},
-	[MMC_HS] = {"ti,otap-del-sel-mmc-hs", MMC_CAP(MMC_HS)},
-	[SD_HS]  = {"ti,otap-del-sel-sd-hs", MMC_CAP(SD_HS)},
-	[UHS_SDR12] = {"ti,otap-del-sel-sdr12", MMC_CAP(UHS_SDR12)},
-	[UHS_SDR25] = {"ti,otap-del-sel-sdr25", MMC_CAP(UHS_SDR25)},
-	[UHS_SDR50] = {"ti,otap-del-sel-sdr50", MMC_CAP(UHS_SDR50)},
-	[UHS_SDR104] = {"ti,otap-del-sel-sdr104", MMC_CAP(UHS_SDR104)},
-	[UHS_DDR50] = {"ti,otap-del-sel-ddr50", MMC_CAP(UHS_DDR50)},
-	[MMC_DDR_52] = {"ti,otap-del-sel-ddr52", MMC_CAP(MMC_DDR_52)},
-	[MMC_HS_200] = {"ti,otap-del-sel-hs200", MMC_CAP(MMC_HS_200)},
-	[MMC_HS_400] = {"ti,otap-del-sel-hs400", MMC_CAP(MMC_HS_400)},
+	[MMC_LEGACY]	= {"ti,otap-del-sel-legacy",
+			   "ti,itap-del-sel-legacy",
+			   0},
+	[MMC_HS]	= {"ti,otap-del-sel-mmc-hs",
+			   "ti,itap-del-sel-mms-hs",
+			   MMC_CAP(MMC_HS)},
+	[SD_HS]		= {"ti,otap-del-sel-sd-hs",
+			   "ti,itap-del-sel-sd-hs",
+			   MMC_CAP(SD_HS)},
+	[UHS_SDR12]	= {"ti,otap-del-sel-sdr12",
+			   "ti,itap-del-sel-sdr12",
+			   MMC_CAP(UHS_SDR12)},
+	[UHS_SDR25]	= {"ti,otap-del-sel-sdr25",
+			   "ti,itap-del-sel-sdr25",
+			   MMC_CAP(UHS_SDR25)},
+	[UHS_SDR50]	= {"ti,otap-del-sel-sdr50",
+			   NULL,
+			   MMC_CAP(UHS_SDR50)},
+	[UHS_SDR104]	= {"ti,otap-del-sel-sdr104",
+			   NULL,
+			   MMC_CAP(UHS_SDR104)},
+	[UHS_DDR50]	= {"ti,otap-del-sel-ddr50",
+			   NULL,
+			   MMC_CAP(UHS_DDR50)},
+	[MMC_DDR_52]	= {"ti,otap-del-sel-ddr52",
+			   "ti,itap-del-sel-ddr52",
+			   MMC_CAP(MMC_DDR_52)},
+	[MMC_HS_200]	= {"ti,otap-del-sel-hs200",
+			   NULL,
+			   MMC_CAP(MMC_HS_200)},
+	[MMC_HS_400]	= {"ti,otap-del-sel-hs400",
+			   NULL,
+			   MMC_CAP(MMC_HS_400)},
 };
 
 struct am654_driver_data {
@@ -127,12 +162,99 @@  static void am654_sdhci_set_control_reg(struct sdhci_host *host)
 	sdhci_set_uhs_timing(host);
 }
 
+static int am654_sdhci_setup_dll(struct am654_sdhci_plat *plat,
+				 unsigned int speed)
+{
+	int sel50, sel100, freqsel;
+	u32 mask, val;
+	int ret;
+
+	/* Disable delay chain mode */
+	regmap_update_bits(plat->base, PHY_CTRL5,
+			   SELDLYTXCLK_MASK | SELDLYRXCLK_MASK, 0);
+
+	if (plat->flags & FREQSEL_2_BIT) {
+		switch (speed) {
+		case 200000000:
+			sel50 = 0;
+			sel100 = 0;
+			break;
+		case 100000000:
+			sel50 = 0;
+			sel100 = 1;
+			break;
+		default:
+			sel50 = 1;
+			sel100 = 0;
+		}
+
+		/* Configure PHY DLL frequency */
+		mask = SEL50_MASK | SEL100_MASK;
+		val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+		regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
+	} else {
+		switch (speed) {
+		case 200000000:
+			freqsel = 0x0;
+			break;
+		default:
+			freqsel = 0x4;
+		}
+		regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
+				   freqsel << FREQSEL_SHIFT);
+	}
+
+	/* Configure DLL TRIM */
+	mask = DLL_TRIM_ICP_MASK;
+	val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
+
+	/* Configure DLL driver strength */
+	mask |= DR_TY_MASK;
+	val |= plat->drv_strength << DR_TY_SHIFT;
+	regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
+
+	/* Enable DLL */
+	regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
+			   0x1 << ENDLL_SHIFT);
+	/*
+	 * Poll for DLL ready. Use a one second timeout.
+	 * Works in all experiments done so far
+	 */
+	ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
+				       val & DLLRDY_MASK, 1000, 1000000);
+
+	return ret;
+}
+
+static void am654_sdhci_write_itapdly(struct am654_sdhci_plat *plat,
+				      u32 itapdly)
+{
+	/* Set ITAPCHGWIN before writing to ITAPDLY */
+	regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK,
+			   1 << ITAPCHGWIN_SHIFT);
+	regmap_update_bits(plat->base, PHY_CTRL4, ITAPDLYSEL_MASK,
+			   itapdly << ITAPDLYSEL_SHIFT);
+	regmap_update_bits(plat->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
+}
+
+static void am654_sdhci_setup_delay_chain(struct am654_sdhci_plat *plat,
+					  int mode)
+{
+	u32 mask, val;
+
+	val = 1 << SELDLYTXCLK_SHIFT | 1 << SELDLYRXCLK_SHIFT;
+	mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
+	regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
+
+	am654_sdhci_write_itapdly(plat, plat->itap_del_sel[mode]);
+}
+
 static int am654_sdhci_set_ios_post(struct sdhci_host *host)
 {
 	struct udevice *dev = host->mmc->dev;
 	struct am654_sdhci_plat *plat = dev_get_plat(dev);
 	unsigned int speed = host->mmc->clock;
-	int sel50, sel100, freqsel;
+	int mode = host->mmc->selected_mode;
 	u32 otap_del_sel;
 	u32 mask, val;
 	int ret;
@@ -148,75 +270,29 @@  static int am654_sdhci_set_ios_post(struct sdhci_host *host)
 	sdhci_set_clock(host->mmc, speed);
 
 	/* switch phy back on */
-	if (speed > AM654_SDHCI_MIN_FREQ) {
-		otap_del_sel = plat->otap_del_sel[host->mmc->selected_mode];
-		mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
-		val = (1 << OTAPDLYENA_SHIFT) |
-		      (otap_del_sel << OTAPDLYSEL_SHIFT);
-
-		/* Write to STRBSEL for HS400 speed mode */
-		if (host->mmc->selected_mode == MMC_HS_400) {
-			if (plat->flags & STRBSEL_4_BIT)
-				mask |= STRBSEL_4BIT_MASK;
-			else
-				mask |= STRBSEL_8BIT_MASK;
-
-			val |= plat->strb_sel << STRBSEL_SHIFT;
-		}
+	otap_del_sel = plat->otap_del_sel[mode];
+	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+	val = (1 << OTAPDLYENA_SHIFT) |
+	      (otap_del_sel << OTAPDLYSEL_SHIFT);
 
-		regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
-
-		if (plat->flags & FREQSEL_2_BIT) {
-			switch (speed) {
-			case 200000000:
-				sel50 = 0;
-				sel100 = 0;
-				break;
-			case 100000000:
-				sel50 = 0;
-				sel100 = 1;
-				break;
-			default:
-				sel50 = 1;
-				sel100 = 0;
-			}
-
-			/* Configure PHY DLL frequency */
-			mask = SEL50_MASK | SEL100_MASK;
-			val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
-			regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
-		} else {
-			switch (speed) {
-			case 200000000:
-				freqsel = 0x0;
-				break;
-			default:
-				freqsel = 0x4;
-			}
-			regmap_update_bits(plat->base, PHY_CTRL5, FREQSEL_MASK,
-					   freqsel << FREQSEL_SHIFT);
-		}
+	/* Write to STRBSEL for HS400 speed mode */
+	if (host->mmc->selected_mode == MMC_HS_400) {
+		if (plat->flags & STRBSEL_4_BIT)
+			mask |= STRBSEL_4BIT_MASK;
+		else
+			mask |= STRBSEL_8BIT_MASK;
 
-		/* Configure DLL TRIM */
-		mask = DLL_TRIM_ICP_MASK;
-		val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
-
-		/* Configure DLL driver strength */
-		mask |= DR_TY_MASK;
-		val |= plat->drv_strength << DR_TY_SHIFT;
-		regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
-
-		/* Enable DLL */
-		regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
-				   0x1 << ENDLL_SHIFT);
-		/*
-		 * Poll for DLL ready. Use a one second timeout.
-		 * Works in all experiments done so far
-		 */
-		ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
-					 val & DLLRDY_MASK, 1000, 1000000);
+		val |= plat->strb_sel << STRBSEL_SHIFT;
+	}
+
+	regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
+
+	if (mode > UHS_SDR25 && speed >= CLOCK_TOO_SLOW_HZ) {
+		ret = am654_sdhci_setup_dll(plat, speed);
 		if (ret)
 			return ret;
+	} else {
+		am654_sdhci_setup_delay_chain(plat, mode);
 	}
 
 	return 0;
@@ -354,15 +430,20 @@  static int sdhci_am654_get_otap_delay(struct udevice *dev,
 	 * value is not found
 	 */
 	for (i = MMC_HS; i <= MMC_HS_400; i++) {
-		ret = dev_read_u32(dev, td[i].binding, &plat->otap_del_sel[i]);
+		ret = dev_read_u32(dev, td[i].otap_binding,
+				   &plat->otap_del_sel[i]);
 		if (ret) {
-			dev_dbg(dev, "Couldn't find %s\n", td[i].binding);
+			dev_dbg(dev, "Couldn't find %s\n", td[i].otap_binding);
 			/*
 			 * Remove the corresponding capability
 			 * if an otap-del-sel value is not found
 			 */
 			cfg->host_caps &= ~td[i].capability;
 		}
+
+		if (td[i].itap_binding)
+			dev_read_u32(dev, td[i].itap_binding,
+				     &plat->itap_del_sel[i]);
 	}
 
 	return 0;