diff --git a/arch/arm/dts/am57xx-beagle-x15.dts b/arch/arm/dts/am57xx-beagle-x15.dts
index d6689106d2..8d9bdf10a7 100644
--- a/arch/arm/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/dts/am57xx-beagle-x15.dts
@@ -25,6 +25,11 @@
 	pinctrl-1 = <&mmc1_pins_hs>;
 
 	vmmc-supply = <&ldo1_reg>;
+	/delete-property/ sd-uhs-sdr104;
+	/delete-property/ sd-uhs-sdr50;
+	/delete-property/ sd-uhs-ddr50;
+	/delete-property/ sd-uhs-sdr25;
+	/delete-property/ sd-uhs-sdr12;
 };
 
 &mmc2 {
@@ -32,6 +37,7 @@
 	pinctrl-0 = <&mmc2_pins_default>;
 	pinctrl-1 = <&mmc2_pins_hs>;
 	pinctrl-2 = <&mmc2_pins_ddr_3_3v_rev11 &mmc2_iodelay_ddr_3_3v_rev11_conf>;
+	/delete-property/ mmc-hs200-1_8v;
 };
 
 /* errata i880 "Ethernet RGMII2 Limited to 10/100 Mbps" */
diff --git a/arch/arm/dts/am57xx-idk-common.dtsi b/arch/arm/dts/am57xx-idk-common.dtsi
index 97aa8e6a56..fa5a078b27 100644
--- a/arch/arm/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/dts/am57xx-idk-common.dtsi
@@ -413,6 +413,8 @@
 	bus-width = <8>;
 	ti,non-removable;
 	max-frequency = <96000000>;
+	no-1-8-v;
+	/delete-property/ mmc-hs200-1_8v;
 };
 
 &dcan1 {
diff --git a/arch/arm/dts/dra7.dtsi b/arch/arm/dts/dra7.dtsi
index 02a136a466..0f982d8b44 100644
--- a/arch/arm/dts/dra7.dtsi
+++ b/arch/arm/dts/dra7.dtsi
@@ -1056,7 +1056,7 @@
 		};
 
 		mmc1: mmc@4809c000 {
-			compatible = "ti,omap4-hsmmc";
+			compatible = "ti,dra7-hsmmc", "ti,omap4-hsmmc";
 			reg = <0x4809c000 0x400>;
 			interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
 			ti,hwmods = "mmc1";
@@ -1067,10 +1067,15 @@
 			status = "disabled";
 			pbias-supply = <&pbias_mmc_reg>;
 			max-frequency = <192000000>;
+			sd-uhs-sdr104;
+			sd-uhs-sdr50;
+			sd-uhs-ddr50;
+			sd-uhs-sdr25;
+			sd-uhs-sdr12;
 		};
 
 		mmc2: mmc@480b4000 {
-			compatible = "ti,omap4-hsmmc";
+			compatible = "ti,dra7-hsmmc", "ti,omap4-hsmmc";
 			reg = <0x480b4000 0x400>;
 			interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
 			ti,hwmods = "mmc2";
@@ -1079,10 +1084,14 @@
 			dma-names = "tx", "rx";
 			status = "disabled";
 			max-frequency = <192000000>;
+			sd-uhs-sdr25;
+			sd-uhs-sdr12;
+			mmc-hs200-1_8v;
+			mmc-ddr-1_8v;
 		};
 
 		mmc3: mmc@480ad000 {
-			compatible = "ti,omap4-hsmmc";
+			compatible = "ti,dra7-hsmmc", "ti,omap4-hsmmc";
 			reg = <0x480ad000 0x400>;
 			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
 			ti,hwmods = "mmc3";
@@ -1092,10 +1101,13 @@
 			status = "disabled";
 			/* Errata i887 limits max-frequency of MMC3 to 64 MHz */
 			max-frequency = <64000000>;
+			sd-uhs-sdr12;
+			sd-uhs-sdr25;
+			sd-uhs-sdr50;
 		};
 
 		mmc4: mmc@480d1000 {
-			compatible = "ti,omap4-hsmmc";
+			compatible = "ti,dra7-hsmmc", "ti,omap4-hsmmc";
 			reg = <0x480d1000 0x400>;
 			interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
 			ti,hwmods = "mmc4";
@@ -1104,6 +1116,8 @@
 			dma-names = "tx", "rx";
 			status = "disabled";
 			max-frequency = <192000000>;
+			sd-uhs-sdr12;
+			sd-uhs-sdr25;
 		};
 
 		mmu0_dsp1: mmu@40d01000 {
diff --git a/arch/arm/include/asm/arch-omap5/clock.h b/arch/arm/include/asm/arch-omap5/clock.h
index ee2e78b99b..3d718c02df 100644
--- a/arch/arm/include/asm/arch-omap5/clock.h
+++ b/arch/arm/include/asm/arch-omap5/clock.h
@@ -135,7 +135,7 @@
 
 /* CM_L3INIT_HSMMCn_CLKCTRL */
 #define HSMMC_CLKCTRL_CLKSEL_MASK		(1 << 24)
-#define HSMMC_CLKCTRL_CLKSEL_DIV_MASK		(1 << 25)
+#define HSMMC_CLKCTRL_CLKSEL_DIV_MASK		(3 << 25)
 
 /* CM_L3INIT_SATA_CLKCTRL */
 #define SATA_CLKCTRL_OPTFCLKEN_MASK		(1 << 8)
diff --git a/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h
index c997004039..a8780eeef8 100644
--- a/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h
+++ b/arch/arm/include/asm/arch-omap5/dra7xx_iodelay.h
@@ -83,6 +83,9 @@
 void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads,
 			   struct iodelay_cfg_entry const *iodelay,
 			   int niodelays);
+void late_recalibrate_iodelay(struct pad_conf_entry const *pad, int npads,
+			      struct iodelay_cfg_entry const *iodelay,
+			      int niodelays);
 int __recalibrate_iodelay_start(void);
 void __recalibrate_iodelay_end(int ret);
 
diff --git a/arch/arm/include/asm/arch-omap5/sys_proto.h b/arch/arm/include/asm/arch-omap5/sys_proto.h
index a6b3557b50..d43cd7f2e7 100644
--- a/arch/arm/include/asm/arch-omap5/sys_proto.h
+++ b/arch/arm/include/asm/arch-omap5/sys_proto.h
@@ -35,6 +35,12 @@ struct pad_conf_entry {
 	u32 val;
 };
 
+struct mmc_platform_fixups {
+	const char *hw_rev;
+	u32 unsupported_caps;
+	u32 max_freq;
+};
+
 struct omap_sysinfo {
 	char *board_string;
 };
@@ -71,6 +77,7 @@ void force_emif_self_refresh(void);
 void get_ioregs(const struct ctrl_ioregs **regs);
 void srcomp_enable(void);
 void setup_warmreset_time(void);
+const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr);
 
 static inline u32 div_round_up(u32 num, u32 den)
 {
diff --git a/arch/arm/include/asm/omap_mmc.h b/arch/arm/include/asm/omap_mmc.h
index bf9de9b211..3d70148882 100644
--- a/arch/arm/include/asm/omap_mmc.h
+++ b/arch/arm/include/asm/omap_mmc.h
@@ -39,7 +39,9 @@ struct hsmmc {
 	unsigned int sysstatus;		/* 0x14 */
 	unsigned char res2[0x14];
 	unsigned int con;		/* 0x2C */
-	unsigned char res3[0xD4];
+	unsigned int pwcnt;		/* 0x30 */
+	unsigned int dll;		/* 0x34 */
+	unsigned char res3[0xcc];
 	unsigned int blk;		/* 0x104 */
 	unsigned int arg;		/* 0x108 */
 	unsigned int cmd;		/* 0x10C */
@@ -53,9 +55,11 @@ struct hsmmc {
 	unsigned int sysctl;		/* 0x12C */
 	unsigned int stat;		/* 0x130 */
 	unsigned int ie;		/* 0x134 */
-	unsigned char res4[0x8];
+	unsigned char res4[0x4];
+	unsigned int ac12;		/* 0x13C */
 	unsigned int capa;		/* 0x140 */
-	unsigned char res5[0x10];
+	unsigned int capa2;		/* 0x144 */
+	unsigned char res5[0xc];
 	unsigned int admaes;		/* 0x154 */
 	unsigned int admasal;		/* 0x158 */
 };
@@ -65,6 +69,8 @@ struct omap_hsmmc_plat {
 	struct hsmmc *base_addr;
 	struct mmc mmc;
 	bool cd_inverted;
+	u32 controller_flags;
+	const char *hw_rev;
 };
 
 /*
@@ -87,6 +93,7 @@ struct omap_hsmmc_plat {
 #define WPP_ACTIVEHIGH			(0x0 << 8)
 #define RESERVED_MASK			(0x3 << 9)
 #define CTPL_MMC_SD			(0x0 << 11)
+#define DDR				(0x1 << 19)
 #define DMA_MASTER			(0x1 << 20)
 #define BLEN_512BYTESLEN		(0x200 << 0)
 #define NBLK_STPCNT			(0x0 << 16)
@@ -124,8 +131,10 @@ struct omap_hsmmc_plat {
 #define DTW_8_BITMODE                   (0x1 << 5) /* CON[DW8]*/
 #define SDBP_PWROFF			(0x0 << 8)
 #define SDBP_PWRON			(0x1 << 8)
+#define SDVS_MASK			(0x7 << 9)
 #define SDVS_1V8			(0x5 << 9)
 #define SDVS_3V0			(0x6 << 9)
+#define SDVS_3V3			(0x7 << 9)
 #define DMA_SELECT			(0x2 << 3)
 #define ICE_MASK			(0x1 << 0)
 #define ICE_STOP			(0x0 << 0)
@@ -159,8 +168,20 @@ struct omap_hsmmc_plat {
 #define IE_CERR				(0x01 << 28)
 #define IE_BADA				(0x01 << 29)
 
-#define VS30_3V0SUP			(1 << 25)
-#define VS18_1V8SUP			(1 << 26)
+#define VS33_3V3SUP			BIT(24)
+#define VS30_3V0SUP			BIT(25)
+#define VS18_1V8SUP			BIT(26)
+
+#define AC12_ET				BIT(22)
+#define AC12_V1V8_SIGEN			BIT(19)
+#define AC12_SCLK_SEL			BIT(23)
+#define AC12_UHSMC_MASK			(7 << 16)
+#define AC12_UHSMC_DDR50		(4 << 16)
+#define AC12_UHSMC_SDR104		(3 << 16)
+#define AC12_UHSMC_SDR50		(2 << 16)
+#define AC12_UHSMC_SDR25		(1 << 16)
+#define AC12_UHSMC_SDR12		(0 << 16)
+#define AC12_UHSMC_RES			(0x7 << 16)
 
 /* Driver definitions */
 #define MMCSD_SECTOR_SIZE		512
@@ -172,15 +193,43 @@ struct omap_hsmmc_plat {
 #define CLK_400KHZ			1
 #define CLK_MISC			2
 
+#define CLKD_MAX			0x3FF	/* max clock divisor: 1023 */
+
 #define RSP_TYPE_NONE	(RSP_TYPE_NORSP   | CCCE_NOCHECK | CICE_NOCHECK)
 #define MMC_CMD0	(INDEX(0)  | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
 
 /* Clock Configurations and Macros */
+#ifdef CONFIG_OMAP54XX
+#define MMC_CLOCK_REFERENCE	192 /* MHz */
+#else
 #define MMC_CLOCK_REFERENCE	96 /* MHz */
+#endif
+
+/* DLL */
+#define DLL_SWT			BIT(20)
+#define DLL_FORCE_SR_C_SHIFT	13
+#define DLL_FORCE_SR_C_MASK	0x7f
+#define DLL_FORCE_VALUE		BIT(12)
+#define DLL_CALIB		BIT(1)
+
+#define MAX_PHASE_DELAY		0x7c
+
+/* CAPA2 */
+#define CAPA2_TSDR50		BIT(13)
 
 #define mmc_reg_out(addr, mask, val)\
 	writel((readl(addr) & (~(mask))) | ((val) & (mask)), (addr))
 
+#define INT_EN_MASK (IE_BADA | IE_CERR | IE_DEB | IE_DCRC |\
+		IE_DTO | IE_CIE | IE_CEB | IE_CCRC | IE_ADMAE | IE_CTO |\
+		IE_BRR | IE_BWR | IE_TC | IE_CC)
+
+#define CON_CLKEXTFREE		BIT(16)
+#define CON_PADEN		BIT(15)
+#define PSTATE_CLEV		BIT(24)
+#define PSTATE_DLEV		(0xF << 20)
+#define PSTATE_DLEV_DAT0	(0x1 << 20)
+
 int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 		int wp_gpio);
 
diff --git a/arch/arm/mach-omap2/omap5/dra7xx_iodelay.c b/arch/arm/mach-omap2/omap5/dra7xx_iodelay.c
index 87987308ac..a9a9f75e6e 100644
--- a/arch/arm/mach-omap2/omap5/dra7xx_iodelay.c
+++ b/arch/arm/mach-omap2/omap5/dra7xx_iodelay.c
@@ -272,3 +272,33 @@ err:
 	__recalibrate_iodelay_end(ret);
 
 }
+
+void late_recalibrate_iodelay(struct pad_conf_entry const *pad, int npads,
+			      struct iodelay_cfg_entry const *iodelay,
+			      int niodelays)
+{
+	int ret = 0;
+
+	/* unlock IODELAY CONFIG registers */
+	writel(CFG_IODELAY_UNLOCK_KEY, (*ctrl)->iodelay_config_base +
+	       CFG_REG_8_OFFSET);
+
+	ret = calibrate_iodelay((*ctrl)->iodelay_config_base);
+	if (ret)
+		goto err;
+
+	ret = update_delay_mechanism((*ctrl)->iodelay_config_base);
+
+	/* Configure Mux settings */
+	do_set_mux32((*ctrl)->control_padconf_core_base, pad, npads);
+
+	/* Configure Manual IO timing modes */
+	ret = do_set_iodelay((*ctrl)->iodelay_config_base, iodelay, niodelays);
+	if (ret)
+		goto err;
+
+err:
+	/* lock IODELAY CONFIG registers */
+	writel(CFG_IODELAY_LOCK_KEY, (*ctrl)->iodelay_config_base +
+	       CFG_REG_8_OFFSET);
+}
diff --git a/arch/arm/mach-omap2/omap5/hw_data.c b/arch/arm/mach-omap2/omap5/hw_data.c
index bb05e1920b..7fc38368c9 100644
--- a/arch/arm/mach-omap2/omap5/hw_data.c
+++ b/arch/arm/mach-omap2/omap5/hw_data.c
@@ -438,17 +438,17 @@ void enable_basic_clocks(void)
 	setbits_le32((*prcm)->cm_l4per_gpio4_clkctrl,
 			GPIO4_CLKCTRL_OPTFCLKEN_MASK);
 
-	/* Enable 96 MHz clock for MMC1 & MMC2 */
+	/* Enable 192 MHz clock for MMC1 & MMC2 */
 	setbits_le32((*prcm)->cm_l3init_hsmmc1_clkctrl,
 			HSMMC_CLKCTRL_CLKSEL_MASK);
 	setbits_le32((*prcm)->cm_l3init_hsmmc2_clkctrl,
 			HSMMC_CLKCTRL_CLKSEL_MASK);
 
 	/* Set the correct clock dividers for mmc */
-	setbits_le32((*prcm)->cm_l3init_hsmmc1_clkctrl,
-			HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
-	setbits_le32((*prcm)->cm_l3init_hsmmc2_clkctrl,
-			HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
+	clrbits_le32((*prcm)->cm_l3init_hsmmc1_clkctrl,
+		     HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
+	clrbits_le32((*prcm)->cm_l3init_hsmmc2_clkctrl,
+		     HSMMC_CLKCTRL_CLKSEL_DIV_MASK);
 
 	/* Select 32KHz clock as the source of GPTIMER1 */
 	setbits_le32((*prcm)->cm_wkup_gptimer1_clkctrl,
diff --git a/board/ti/am57xx/board.c b/board/ti/am57xx/board.c
index c3f60f60c8..5bd8778563 100644
--- a/board/ti/am57xx/board.c
+++ b/board/ti/am57xx/board.c
@@ -30,6 +30,7 @@
 #include <dwc3-uboot.h>
 #include <dwc3-omap-uboot.h>
 #include <ti-usb-phy-uboot.h>
+#include <mmc.h>
 
 #include "../common/board_detect.h"
 #include "mux_data.h"
@@ -815,6 +816,35 @@ int board_mmc_init(bd_t *bis)
 	omap_mmc_init(1, 0, 0, -1, -1);
 	return 0;
 }
+
+static const struct mmc_platform_fixups am57x_es1_1_mmc1_fixups = {
+	.hw_rev = "rev11",
+	.unsupported_caps = MMC_CAP(MMC_HS_200) |
+			    MMC_CAP(UHS_SDR104),
+	.max_freq = 96000000,
+};
+
+static const struct mmc_platform_fixups am57x_es1_1_mmc23_fixups = {
+	.hw_rev = "rev11",
+	.unsupported_caps = MMC_CAP(MMC_HS_200) |
+			    MMC_CAP(UHS_SDR104) |
+			    MMC_CAP(UHS_SDR50),
+	.max_freq = 48000000,
+};
+
+const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr)
+{
+	switch (omap_revision()) {
+	case DRA752_ES1_0:
+	case DRA752_ES1_1:
+		if (addr == OMAP_HSMMC1_BASE)
+			return &am57x_es1_1_mmc1_fixups;
+		else
+			return &am57x_es1_1_mmc23_fixups;
+	default:
+		return NULL;
+	}
+}
 #endif
 
 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_OS_BOOT)
diff --git a/board/ti/dra7xx/evm.c b/board/ti/dra7xx/evm.c
index 519475e01f..06f061c92c 100644
--- a/board/ti/dra7xx/evm.c
+++ b/board/ti/dra7xx/evm.c
@@ -866,6 +866,35 @@ void board_mmc_poweron_ldo(uint voltage)
 		palmas_mmc1_poweron_ldo(LDO1_VOLTAGE, LDO1_CTRL, voltage);
 	}
 }
+
+static const struct mmc_platform_fixups dra7x_es1_1_mmc1_fixups = {
+	.hw_rev = "rev11",
+	.unsupported_caps = MMC_CAP(MMC_HS_200) |
+			    MMC_CAP(UHS_SDR104),
+	.max_freq = 96000000,
+};
+
+static const struct mmc_platform_fixups dra7x_es1_1_mmc23_fixups = {
+	.hw_rev = "rev11",
+	.unsupported_caps = MMC_CAP(MMC_HS_200) |
+			    MMC_CAP(UHS_SDR104) |
+			    MMC_CAP(UHS_SDR50),
+	.max_freq = 48000000,
+};
+
+const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr)
+{
+	switch (omap_revision()) {
+	case DRA752_ES1_0:
+	case DRA752_ES1_1:
+		if (addr == OMAP_HSMMC1_BASE)
+			return &dra7x_es1_1_mmc1_fixups;
+		else
+			return &dra7x_es1_1_mmc23_fixups;
+	default:
+		return NULL;
+	}
+}
 #endif
 
 #ifdef CONFIG_USB_DWC3
diff --git a/configs/dra7xx_evm_defconfig b/configs/dra7xx_evm_defconfig
index b13a27e365..e79e6d6737 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -49,6 +49,9 @@ CONFIG_DM_GPIO=y
 CONFIG_PCF8575_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_HS200_SUPPORT=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig
index 7ccb4f0bce..bc15fd8f3a 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -51,6 +51,9 @@ CONFIG_DM_GPIO=y
 CONFIG_PCF8575_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_DM_MMC=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_HS200_SUPPORT=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH=y
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 255310a8e6..fb303dc21e 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -213,8 +213,8 @@ static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
 	mmc->selected_mode = mode;
 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
-	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
-	      mmc->tran_speed / 1000000);
+	pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
+		 mmc->tran_speed / 1000000);
 	return 0;
 }
 
@@ -457,7 +457,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
 	}
 
 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
-		debug("%s: Failed to set blocklen\n", __func__);
+		pr_debug("%s: Failed to set blocklen\n", __func__);
 		return 0;
 	}
 
@@ -465,7 +465,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
 		cur = (blocks_todo > mmc->cfg->b_max) ?
 			mmc->cfg->b_max : blocks_todo;
 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
-			debug("%s: Failed to read blocks\n", __func__);
+			pr_debug("%s: Failed to read blocks\n", __func__);
 			return 0;
 		}
 		blocks_todo -= cur;
@@ -900,11 +900,11 @@ static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
 		forbidden = MMC_CAP(MMC_HS_200);
 
 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
-		debug("selected mode (%s) is forbidden for part %d\n",
-		      mmc_mode_name(mmc->selected_mode), part_num);
+		pr_debug("selected mode (%s) is forbidden for part %d\n",
+			 mmc_mode_name(mmc->selected_mode), part_num);
 		change = true;
 	} else if (mmc->selected_mode != mmc->best_mode) {
-		debug("selected mode is not optimal\n");
+		pr_debug("selected mode is not optimal\n");
 		change = true;
 	}
 
@@ -1333,7 +1333,7 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
 	if (err)
 		return err;
 
-	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
+	if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed)
 		return -ENOTSUPP;
 
 	return 0;
@@ -1427,7 +1427,7 @@ retry_ssr:
 			mmc->ssr.erase_offset = eo * 1000;
 		}
 	} else {
-		debug("Invalid Allocation Unit Size.\n");
+		pr_debug("Invalid Allocation Unit Size.\n");
 	}
 
 	return 0;
@@ -1532,18 +1532,18 @@ void mmc_dump_capabilities(const char *text, uint caps)
 {
 	enum bus_mode mode;
 
-	printf("%s: widths [", text);
+	pr_debug("%s: widths [", text);
 	if (caps & MMC_MODE_8BIT)
-		printf("8, ");
+		pr_debug("8, ");
 	if (caps & MMC_MODE_4BIT)
-		printf("4, ");
+		pr_debug("4, ");
 	if (caps & MMC_MODE_1BIT)
-		printf("1, ");
-	printf("\b\b] modes [");
+		pr_debug("1, ");
+	pr_debug("\b\b] modes [");
 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
 		if (MMC_CAP(mode) & caps)
-			printf("%s, ", mmc_mode_name(mode));
-	printf("\b\b]\n");
+			pr_debug("%s, ", mmc_mode_name(mode));
+	pr_debug("\b\b]\n");
 }
 #endif
 
@@ -1577,7 +1577,7 @@ static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
 	mmc->signal_voltage = signal_voltage;
 	err = mmc_set_ios(mmc);
 	if (err)
-		debug("unable to set voltage (err %d)\n", err);
+		pr_debug("unable to set voltage (err %d)\n", err);
 
 	return err;
 }
@@ -1660,10 +1660,10 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
 
 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
 			if (*w & caps & mwt->widths) {
-				debug("trying mode %s width %d (at %d MHz)\n",
-				      mmc_mode_name(mwt->mode),
-				      bus_width(*w),
-				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
+				pr_debug("trying mode %s width %d (at %d MHz)\n",
+					 mmc_mode_name(mwt->mode),
+					 bus_width(*w),
+					 mmc_mode2freq(mmc, mwt->mode) / 1000000);
 
 				/* configure the bus width (card + host) */
 				err = sd_select_bus_width(mmc, bus_width(*w));
@@ -1686,7 +1686,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
 					err = mmc_execute_tuning(mmc,
 								 mwt->tuning);
 					if (err) {
-						debug("tuning failed\n");
+						pr_debug("tuning failed\n");
 						goto error;
 					}
 				}
@@ -1708,7 +1708,7 @@ error:
 		}
 	}
 
-	printf("unable to select a mode\n");
+	pr_err("unable to select a mode\n");
 	return -ENOTSUPP;
 }
 
@@ -1860,7 +1860,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 		return 0;
 
 	if (!mmc->ext_csd) {
-		debug("No ext_csd found!\n"); /* this should enver happen */
+		pr_debug("No ext_csd found!\n"); /* this should enver happen */
 		return -ENOTSUPP;
 	}
 
@@ -1870,10 +1870,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 		for_each_supported_width(card_caps & mwt->widths,
 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
 			enum mmc_voltage old_voltage;
-			debug("trying mode %s width %d (at %d MHz)\n",
-			      mmc_mode_name(mwt->mode),
-			      bus_width(ecbw->cap),
-			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
+			pr_debug("trying mode %s width %d (at %d MHz)\n",
+				 mmc_mode_name(mwt->mode),
+				 bus_width(ecbw->cap),
+				 mmc_mode2freq(mmc, mwt->mode) / 1000000);
 			old_voltage = mmc->signal_voltage;
 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
 						     MMC_ALL_SIGNAL_VOLTAGE);
@@ -1914,7 +1914,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
 			if (mwt->tuning) {
 				err = mmc_execute_tuning(mmc, mwt->tuning);
 				if (err) {
-					debug("tuning failed\n");
+					pr_debug("tuning failed\n");
 					goto error;
 				}
 			}
@@ -1950,6 +1950,7 @@ static int mmc_startup_v4(struct mmc *mmc)
 		MMC_VERSION_4_1,
 		MMC_VERSION_4_2,
 		MMC_VERSION_4_3,
+		MMC_VERSION_4_4,
 		MMC_VERSION_4_41,
 		MMC_VERSION_4_5,
 		MMC_VERSION_5_0,
@@ -2396,12 +2397,12 @@ static int mmc_power_init(struct mmc *mmc)
 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
 					  &mmc->vmmc_supply);
 	if (ret)
-		debug("%s: No vmmc supply\n", mmc->dev->name);
+		pr_debug("%s: No vmmc supply\n", mmc->dev->name);
 
 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
 					  &mmc->vqmmc_supply);
 	if (ret)
-		debug("%s: No vqmmc supply\n", mmc->dev->name);
+		pr_debug("%s: No vqmmc supply\n", mmc->dev->name);
 #endif
 #else /* !CONFIG_DM_MMC */
 	/*
@@ -2457,7 +2458,7 @@ static int mmc_power_off(struct mmc *mmc)
 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
 
 		if (ret) {
-			debug("Error disabling VMMC supply\n");
+			pr_debug("Error disabling VMMC supply\n");
 			return ret;
 		}
 	}
@@ -2505,7 +2506,7 @@ int mmc_start_init(struct mmc *mmc)
 	if (no_card) {
 		mmc->has_init = 0;
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-		printf("MMC: no card present\n");
+		pr_err("MMC: no card present\n");
 #endif
 		return -ENOMEDIUM;
 	}
@@ -2532,7 +2533,7 @@ int mmc_start_init(struct mmc *mmc)
 		 * to use the UHS modes, because we wouldn't be able to
 		 * recover from an error during the UHS initialization.
 		 */
-		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
+		pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
 		uhs_en = false;
 		mmc->host_caps &= ~UHS_CAPS;
 		err = mmc_power_on(mmc);
@@ -2629,7 +2630,7 @@ int mmc_init(struct mmc *mmc)
 	if (!err)
 		err = mmc_complete_init(mmc);
 	if (err)
-		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
+		pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
 
 	return err;
 }
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index b12d6d9102..02970f29b2 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -34,6 +34,10 @@
 #endif
 #include <asm/io.h>
 #include <asm/arch/mmc_host_def.h>
+#ifdef CONFIG_OMAP54XX
+#include <asm/arch/mux_dra7xx.h>
+#include <asm/arch/dra7xx_iodelay.h>
+#endif
 #if !defined(CONFIG_SOC_KEYSTONE)
 #include <asm/gpio.h>
 #include <asm/arch/sys_proto.h>
@@ -42,6 +46,7 @@
 #include <asm/arch/mux.h>
 #endif
 #include <dm.h>
+#include <power/regulator.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -57,11 +62,23 @@ DECLARE_GLOBAL_DATA_PTR;
 #define SYSCTL_SRC	(1 << 25)
 #define SYSCTL_SRD	(1 << 26)
 
+#ifdef CONFIG_IODELAY_RECALIBRATION
+struct omap_hsmmc_pinctrl_state {
+	struct pad_conf_entry *padconf;
+	int npads;
+	struct iodelay_cfg_entry *iodelay;
+	int niodelays;
+};
+#endif
+
 struct omap_hsmmc_data {
 	struct hsmmc *base_addr;
 #if !CONFIG_IS_ENABLED(DM_MMC)
 	struct mmc_config cfg;
 #endif
+	uint bus_width;
+	uint clock;
+	ushort last_cmd;
 #ifdef OMAP_HSMMC_USE_GPIO
 #if CONFIG_IS_ENABLED(DM_MMC)
 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
@@ -71,12 +88,33 @@ struct omap_hsmmc_data {
 	int cd_gpio;
 	int wp_gpio;
 #endif
+#endif
+#if CONFIG_IS_ENABLED(DM_MMC)
+	enum bus_mode mode;
 #endif
 	u8 controller_flags;
 #ifndef CONFIG_OMAP34XX
 	struct omap_hsmmc_adma_desc *adma_desc_table;
 	uint desc_slot;
 #endif
+	const char *hw_rev;
+	struct udevice *pbias_supply;
+	uint signal_voltage;
+#ifdef CONFIG_IODELAY_RECALIBRATION
+	struct omap_hsmmc_pinctrl_state *default_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *hs_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *hs200_1_8v_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *ddr_1_8v_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *sdr12_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *sdr25_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *ddr50_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *sdr50_pinctrl_state;
+	struct omap_hsmmc_pinctrl_state *sdr104_pinctrl_state;
+#endif
+};
+
+struct omap_mmc_of_data {
+	u8 controller_flags;
 };
 
 #ifndef CONFIG_OMAP34XX
@@ -102,6 +140,7 @@ struct omap_hsmmc_adma_desc {
 
 /* If we fail after 1 second wait, something is really bad */
 #define MAX_RETRY_MS	1000
+#define MMC_TIMEOUT_MS	20
 
 /* DMA transfers can take a long time if a lot a data is transferred.
  * The timeout must take in account the amount of data. Let's assume
@@ -109,11 +148,17 @@ struct omap_hsmmc_adma_desc {
  * that the bandwidth is always above 3MB/s).
  */
 #define DMA_TIMEOUT_PER_MB	333
+#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT		BIT(0)
+#define OMAP_HSMMC_NO_1_8_V			BIT(1)
 #define OMAP_HSMMC_USE_ADMA			BIT(2)
+#define OMAP_HSMMC_REQUIRE_IODELAY		BIT(3)
 
 static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
 static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
 			unsigned int siz);
+static void omap_hsmmc_start_clock(struct hsmmc *mmc_base);
+static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base);
+static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit);
 
 static inline struct omap_hsmmc_data *omap_hsmmc_get_data(struct mmc *mmc)
 {
@@ -211,7 +256,8 @@ static unsigned char mmc_board_init(struct mmc *mmc)
 		&prcm_base->iclken1_core);
 #endif
 
-#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
+#if (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) &&\
+	!CONFIG_IS_ENABLED(DM_REGULATOR)
 	/* PBIAS config needed for MMC1 only */
 	if (mmc_get_blk_desc(mmc)->devnum == 0)
 		vmmc_pbias_config(LDO_VOLT_3V0);
@@ -248,6 +294,424 @@ void mmc_init_stream(struct hsmmc *mmc_base)
 	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
 }
 
+#if CONFIG_IS_ENABLED(DM_MMC)
+#ifdef CONFIG_IODELAY_RECALIBRATION
+static void omap_hsmmc_io_recalibrate(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct omap_hsmmc_pinctrl_state *pinctrl_state;
+
+	switch (priv->mode) {
+	case MMC_HS_200:
+		pinctrl_state = priv->hs200_1_8v_pinctrl_state;
+		break;
+	case UHS_SDR104:
+		pinctrl_state = priv->sdr104_pinctrl_state;
+		break;
+	case UHS_SDR50:
+		pinctrl_state = priv->sdr50_pinctrl_state;
+		break;
+	case UHS_DDR50:
+		pinctrl_state = priv->ddr50_pinctrl_state;
+		break;
+	case UHS_SDR25:
+		pinctrl_state = priv->sdr25_pinctrl_state;
+		break;
+	case UHS_SDR12:
+		pinctrl_state = priv->sdr12_pinctrl_state;
+		break;
+	case SD_HS:
+	case MMC_HS:
+	case MMC_HS_52:
+		pinctrl_state = priv->hs_pinctrl_state;
+		break;
+	case MMC_DDR_52:
+		pinctrl_state = priv->ddr_1_8v_pinctrl_state;
+	default:
+		pinctrl_state = priv->default_pinctrl_state;
+		break;
+	}
+
+	if (!pinctrl_state)
+		pinctrl_state = priv->default_pinctrl_state;
+
+	if (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY) {
+		if (pinctrl_state->iodelay)
+			late_recalibrate_iodelay(pinctrl_state->padconf,
+						 pinctrl_state->npads,
+						 pinctrl_state->iodelay,
+						 pinctrl_state->niodelays);
+		else
+			do_set_mux32((*ctrl)->control_padconf_core_base,
+				     pinctrl_state->padconf,
+				     pinctrl_state->npads);
+	}
+}
+#endif
+static void omap_hsmmc_set_timing(struct mmc *mmc)
+{
+	u32 val;
+	struct hsmmc *mmc_base;
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+
+	mmc_base = priv->base_addr;
+
+	omap_hsmmc_stop_clock(mmc_base);
+	val = readl(&mmc_base->ac12);
+	val &= ~AC12_UHSMC_MASK;
+	priv->mode = mmc->selected_mode;
+
+	if (mmc_is_mode_ddr(priv->mode))
+		writel(readl(&mmc_base->con) | DDR, &mmc_base->con);
+	else
+		writel(readl(&mmc_base->con) & ~DDR, &mmc_base->con);
+
+	switch (priv->mode) {
+	case MMC_HS_200:
+	case UHS_SDR104:
+		val |= AC12_UHSMC_SDR104;
+		break;
+	case UHS_SDR50:
+		val |= AC12_UHSMC_SDR50;
+		break;
+	case MMC_DDR_52:
+	case UHS_DDR50:
+		val |= AC12_UHSMC_DDR50;
+		break;
+	case SD_HS:
+	case MMC_HS_52:
+	case UHS_SDR25:
+		val |= AC12_UHSMC_SDR25;
+		break;
+	case MMC_LEGACY:
+	case MMC_HS:
+	case SD_LEGACY:
+	case UHS_SDR12:
+		val |= AC12_UHSMC_SDR12;
+		break;
+	default:
+		val |= AC12_UHSMC_RES;
+		break;
+	}
+	writel(val, &mmc_base->ac12);
+
+#ifdef CONFIG_IODELAY_RECALIBRATION
+	omap_hsmmc_io_recalibrate(mmc);
+#endif
+	omap_hsmmc_start_clock(mmc_base);
+}
+
+static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage)
+{
+	struct hsmmc *mmc_base;
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	u32 hctl, ac12;
+
+	mmc_base = priv->base_addr;
+
+	hctl = readl(&mmc_base->hctl) & ~SDVS_MASK;
+	ac12 = readl(&mmc_base->ac12) & ~AC12_V1V8_SIGEN;
+
+	switch (signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
+		hctl |= SDVS_3V0;
+		break;
+	case MMC_SIGNAL_VOLTAGE_180:
+		hctl |= SDVS_1V8;
+		ac12 |= AC12_V1V8_SIGEN;
+		break;
+	}
+
+	writel(hctl, &mmc_base->hctl);
+	writel(ac12, &mmc_base->ac12);
+}
+
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout)
+{
+	int ret = -ETIMEDOUT;
+	u32 con;
+	bool dat0_high;
+	bool target_dat0_high = !!state;
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
+	struct hsmmc *mmc_base = priv->base_addr;
+
+	con = readl(&mmc_base->con);
+	writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con);
+
+	timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */
+	while (timeout--)	{
+		dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0);
+		if (dat0_high == target_dat0_high) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	}
+	writel(con, &mmc_base->con);
+
+	return ret;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+static int omap_hsmmc_set_io_regulator(struct mmc *mmc, int mV)
+{
+	int ret = 0;
+	int uV = mV * 1000;
+
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+
+	if (!mmc->vqmmc_supply)
+		return 0;
+
+	/* Disable PBIAS */
+	ret = regulator_set_enable(priv->pbias_supply, false);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	/* Turn off IO voltage */
+	ret = regulator_set_enable(mmc->vqmmc_supply, false);
+	if (ret && ret != -ENOSYS)
+		return ret;
+	/* Program a new IO voltage value */
+	ret = regulator_set_value(mmc->vqmmc_supply, uV);
+	if (ret)
+		return ret;
+	/* Turn on IO voltage */
+	ret = regulator_set_enable(mmc->vqmmc_supply, true);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	/* Program PBIAS voltage*/
+	ret = regulator_set_value(priv->pbias_supply, uV);
+	if (ret && ret != -ENOSYS)
+		return ret;
+	/* Enable PBIAS */
+	ret = regulator_set_enable(priv->pbias_supply, true);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	return 0;
+}
+#endif
+
+static int omap_hsmmc_set_signal_voltage(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct hsmmc *mmc_base = priv->base_addr;
+	int mv = mmc_voltage_to_mv(mmc->signal_voltage);
+	u32 capa_mask;
+	__maybe_unused u8 palmas_ldo_volt;
+	u32 val;
+
+	if (mv < 0)
+		return -EINVAL;
+
+	if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		/* Use 3.0V rather than 3.3V */
+		mv = 3000;
+		capa_mask = VS30_3V0SUP;
+		palmas_ldo_volt = LDO_VOLT_3V0;
+	} else if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		capa_mask = VS18_1V8SUP;
+		palmas_ldo_volt = LDO_VOLT_1V8;
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	val = readl(&mmc_base->capa);
+	if (!(val & capa_mask))
+		return -EOPNOTSUPP;
+
+	priv->signal_voltage = mmc->signal_voltage;
+
+	omap_hsmmc_conf_bus_power(mmc, mmc->signal_voltage);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	return omap_hsmmc_set_io_regulator(mmc, mv);
+#elif (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) && \
+	defined(CONFIG_PALMAS_POWER)
+	if (mmc_get_blk_desc(mmc)->devnum == 0)
+		vmmc_pbias_config(palmas_ldo_volt);
+	return 0;
+#else
+	return 0;
+#endif
+}
+#endif
+
+static uint32_t omap_hsmmc_set_capabilities(struct mmc *mmc)
+{
+	struct hsmmc *mmc_base;
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	u32 val;
+
+	mmc_base = priv->base_addr;
+	val = readl(&mmc_base->capa);
+
+	if (priv->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
+		val |= (VS30_3V0SUP | VS18_1V8SUP);
+	} else if (priv->controller_flags & OMAP_HSMMC_NO_1_8_V) {
+		val |= VS30_3V0SUP;
+		val &= ~VS18_1V8SUP;
+	} else {
+		val |= VS18_1V8SUP;
+		val &= ~VS30_3V0SUP;
+	}
+
+	writel(val, &mmc_base->capa);
+
+	return val;
+}
+
+#ifdef MMC_SUPPORTS_TUNING
+static void omap_hsmmc_disable_tuning(struct mmc *mmc)
+{
+	struct hsmmc *mmc_base;
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	u32 val;
+
+	mmc_base = priv->base_addr;
+	val = readl(&mmc_base->ac12);
+	val &= ~(AC12_SCLK_SEL);
+	writel(val, &mmc_base->ac12);
+
+	val = readl(&mmc_base->dll);
+	val &= ~(DLL_FORCE_VALUE | DLL_SWT);
+	writel(val, &mmc_base->dll);
+}
+
+static void omap_hsmmc_set_dll(struct mmc *mmc, int count)
+{
+	int i;
+	struct hsmmc *mmc_base;
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	u32 val;
+
+	mmc_base = priv->base_addr;
+	val = readl(&mmc_base->dll);
+	val |= DLL_FORCE_VALUE;
+	val &= ~(DLL_FORCE_SR_C_MASK << DLL_FORCE_SR_C_SHIFT);
+	val |= (count << DLL_FORCE_SR_C_SHIFT);
+	writel(val, &mmc_base->dll);
+
+	val |= DLL_CALIB;
+	writel(val, &mmc_base->dll);
+	for (i = 0; i < 1000; i++) {
+		if (readl(&mmc_base->dll) & DLL_CALIB)
+			break;
+	}
+	val &= ~DLL_CALIB;
+	writel(val, &mmc_base->dll);
+}
+
+static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode)
+{
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct mmc *mmc = upriv->mmc;
+	struct hsmmc *mmc_base;
+	u32 val;
+	u8 cur_match, prev_match = 0;
+	int ret;
+	u32 phase_delay = 0;
+	u32 start_window = 0, max_window = 0;
+	u32 length = 0, max_len = 0;
+
+	mmc_base = priv->base_addr;
+	val = readl(&mmc_base->capa2);
+
+	/* clock tuning is not needed for upto 52MHz */
+	if (!((mmc->selected_mode == MMC_HS_200) ||
+	      (mmc->selected_mode == UHS_SDR104) ||
+	      ((mmc->selected_mode == UHS_SDR50) && (val & CAPA2_TSDR50))))
+		return 0;
+
+	val = readl(&mmc_base->dll);
+	val |= DLL_SWT;
+	writel(val, &mmc_base->dll);
+	while (phase_delay <= MAX_PHASE_DELAY) {
+		omap_hsmmc_set_dll(mmc, phase_delay);
+
+		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+
+		if (cur_match) {
+			if (prev_match) {
+				length++;
+			} else {
+				start_window = phase_delay;
+				length = 1;
+			}
+		}
+
+		if (length > max_len) {
+			max_window = start_window;
+			max_len = length;
+		}
+
+		prev_match = cur_match;
+		phase_delay += 4;
+	}
+
+	if (!max_len) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	val = readl(&mmc_base->ac12);
+	if (!(val & AC12_SCLK_SEL)) {
+		ret = -EIO;
+		goto tuning_error;
+	}
+
+	phase_delay = max_window + 4 * ((3 * max_len) >> 2);
+	omap_hsmmc_set_dll(mmc, phase_delay);
+
+	mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
+	mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
+
+	return 0;
+
+tuning_error:
+
+	omap_hsmmc_disable_tuning(mmc);
+	mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
+	mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
+
+	return ret;
+}
+#endif
+
+static void omap_hsmmc_send_init_stream(struct udevice *dev)
+{
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
+	struct hsmmc *mmc_base = priv->base_addr;
+
+	mmc_init_stream(mmc_base);
+}
+#endif
+
+static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct hsmmc *mmc_base = priv->base_addr;
+	u32 irq_mask = INT_EN_MASK;
+
+	/*
+	 * TODO: Errata i802 indicates only DCRC interrupts can occur during
+	 * tuning procedure and DCRC should be disabled. But see occurences
+	 * of DEB, CIE, CEB, CCRC interupts during tuning procedure. These
+	 * interrupts occur along with BRR, so the data is actually in the
+	 * buffer. It has to be debugged why these interrutps occur
+	 */
+	if (cmd && mmc_is_tuning_cmd(cmd->cmdidx))
+		irq_mask &= ~(IE_DEB | IE_DCRC | IE_CIE | IE_CEB | IE_CCRC);
+
+	writel(irq_mask, &mmc_base->ie);
+}
+
 static int omap_hsmmc_init_setup(struct mmc *mmc)
 {
 	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
@@ -282,9 +746,16 @@ static int omap_hsmmc_init_setup(struct mmc *mmc)
 	if (reg_val & MADMA_EN)
 		priv->controller_flags |= OMAP_HSMMC_USE_ADMA;
 #endif
+
+#if CONFIG_IS_ENABLED(DM_MMC)
+	reg_val = omap_hsmmc_set_capabilities(mmc);
+	omap_hsmmc_conf_bus_power(mmc, (reg_val & VS30_3V0SUP) ?
+			  MMC_SIGNAL_VOLTAGE_330 : MMC_SIGNAL_VOLTAGE_180);
+#else
 	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
 	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
 		&mmc_base->capa);
+#endif
 
 	reg_val = readl(&mmc_base->con) & RESERVED_MASK;
 
@@ -308,11 +779,11 @@ static int omap_hsmmc_init_setup(struct mmc *mmc)
 
 	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
 
-	writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
-		IE_CEB | IE_CCRC | IE_ADMAE | IE_CTO | IE_BRR | IE_BWR | IE_TC |
-		IE_CC, &mmc_base->ie);
+	mmc_enable_irq(mmc, NULL);
 
+#if !CONFIG_IS_ENABLED(DM_MMC)
 	mmc_init_stream(mmc_base);
+#endif
 
 	return 0;
 }
@@ -348,7 +819,7 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
 	if (!(readl(&mmc_base->sysctl) & bit)) {
 		start = get_timer(0);
 		while (!(readl(&mmc_base->sysctl) & bit)) {
-			if (get_timer(0) - start > MAX_RETRY_MS)
+			if (get_timer(0) - start > MMC_TIMEOUT_MS)
 				return;
 		}
 	}
@@ -484,14 +955,13 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 			struct mmc_data *data)
 {
 	struct omap_hsmmc_data *priv = dev_get_priv(dev);
-#ifndef CONFIG_OMAP34XX
 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 	struct mmc *mmc = upriv->mmc;
-#endif
 #endif
 	struct hsmmc *mmc_base;
 	unsigned int flags, mmc_stat;
 	ulong start;
+	priv->last_cmd = cmd->cmdidx;
 
 	mmc_base = priv->base_addr;
 
@@ -576,6 +1046,8 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 #endif
 	}
 
+	mmc_enable_irq(mmc, cmd);
+
 	writel(cmd->cmdarg, &mmc_base->arg);
 	udelay(20);		/* To fix "No status update" error on eMMC */
 	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
@@ -764,21 +1236,59 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
 	return 0;
 }
 
-#if !CONFIG_IS_ENABLED(DM_MMC)
-static int omap_hsmmc_set_ios(struct mmc *mmc)
+static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base)
+{
+	writel(readl(&mmc_base->sysctl) & ~CEN_ENABLE, &mmc_base->sysctl);
+}
+
+static void omap_hsmmc_start_clock(struct hsmmc *mmc_base)
+{
+	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+}
+
+static void omap_hsmmc_set_clock(struct mmc *mmc)
 {
 	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
-#else
-static int omap_hsmmc_set_ios(struct udevice *dev)
-{
-	struct omap_hsmmc_data *priv = dev_get_priv(dev);
-	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
-	struct mmc *mmc = upriv->mmc;
-#endif
 	struct hsmmc *mmc_base;
 	unsigned int dsor = 0;
 	ulong start;
 
+	mmc_base = priv->base_addr;
+	omap_hsmmc_stop_clock(mmc_base);
+
+	/* TODO: Is setting DTO required here? */
+	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK),
+		    (ICE_STOP | DTO_15THDTO));
+
+	if (mmc->clock != 0) {
+		dsor = DIV_ROUND_UP(MMC_CLOCK_REFERENCE * 1000000, mmc->clock);
+		if (dsor > CLKD_MAX)
+			dsor = CLKD_MAX;
+	} else {
+		dsor = CLKD_MAX;
+	}
+
+	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+		    (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for ics!\n", __func__);
+			return;
+		}
+	}
+
+	priv->clock = MMC_CLOCK_REFERENCE * 1000000 / dsor;
+	mmc->clock = priv->clock;
+	omap_hsmmc_start_clock(mmc_base);
+}
+
+static void omap_hsmmc_set_bus_width(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct hsmmc *mmc_base;
+
 	mmc_base = priv->base_addr;
 	/* configue bus width */
 	switch (mmc->bus_width) {
@@ -803,30 +1313,44 @@ static int omap_hsmmc_set_ios(struct udevice *dev)
 		break;
 	}
 
-	/* configure clock with 96Mhz system clock.
-	 */
-	if (mmc->clock != 0) {
-		dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock);
-		if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock)
-			dsor++;
-	}
+	priv->bus_width = mmc->bus_width;
+}
 
-	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
-				(ICE_STOP | DTO_15THDTO));
+#if !CONFIG_IS_ENABLED(DM_MMC)
+static int omap_hsmmc_set_ios(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+#else
+static int omap_hsmmc_set_ios(struct udevice *dev)
+{
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct mmc *mmc = upriv->mmc;
+#endif
+	struct hsmmc *mmc_base = priv->base_addr;
+	int ret = 0;
 
-	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
-				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+	if (priv->bus_width != mmc->bus_width)
+		omap_hsmmc_set_bus_width(mmc);
 
-	start = get_timer(0);
-	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
-		if (get_timer(0) - start > MAX_RETRY_MS) {
-			printf("%s: timedout waiting for ics!\n", __func__);
-			return -ETIMEDOUT;
-		}
-	}
-	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+	if (priv->clock != mmc->clock)
+		omap_hsmmc_set_clock(mmc);
 
-	return 0;
+	if (mmc->clk_disable)
+		omap_hsmmc_stop_clock(mmc_base);
+	else
+		omap_hsmmc_start_clock(mmc_base);
+
+#if CONFIG_IS_ENABLED(DM_MMC)
+	if (priv->mode != mmc->selected_mode)
+		omap_hsmmc_set_timing(mmc);
+
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
+	if (priv->signal_voltage != mmc->signal_voltage)
+		ret = omap_hsmmc_set_signal_voltage(mmc);
+#endif
+#endif
+	return ret;
 }
 
 #ifdef OMAP_HSMMC_USE_GPIO
@@ -896,6 +1420,13 @@ static const struct dm_mmc_ops omap_hsmmc_ops = {
 	.get_cd		= omap_hsmmc_getcd,
 	.get_wp		= omap_hsmmc_getwp,
 #endif
+#ifdef MMC_SUPPORTS_TUNING
+	.execute_tuning = omap_hsmmc_execute_tuning,
+#endif
+	.send_init_stream	= omap_hsmmc_send_init_stream,
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+	.wait_dat0	= omap_hsmmc_wait_dat0,
+#endif
 };
 #else
 static const struct mmc_ops omap_hsmmc_ops = {
@@ -918,7 +1449,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 	struct mmc_config *cfg;
 	uint host_caps_val;
 
-	priv = malloc(sizeof(*priv));
+	priv = calloc(1, sizeof(*priv));
 	if (priv == NULL)
 		return -1;
 
@@ -990,6 +1521,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 	if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
 		cfg->b_max = 1;
 #endif
+
 	mmc = mmc_create(cfg, priv);
 	if (mmc == NULL)
 		return -1;
@@ -997,41 +1529,321 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 	return 0;
 }
 #else
+
+#ifdef CONFIG_IODELAY_RECALIBRATION
+static struct pad_conf_entry *
+omap_hsmmc_get_pad_conf_entry(const fdt32_t *pinctrl, int count)
+{
+	int index = 0;
+	struct pad_conf_entry *padconf;
+
+	padconf = (struct pad_conf_entry *)malloc(sizeof(*padconf) * count);
+	if (!padconf) {
+		debug("failed to allocate memory\n");
+		return 0;
+	}
+
+	while (index < count) {
+		padconf[index].offset = fdt32_to_cpu(pinctrl[2 * index]);
+		padconf[index].val = fdt32_to_cpu(pinctrl[2 * index + 1]);
+		index++;
+	}
+
+	return padconf;
+}
+
+static struct iodelay_cfg_entry *
+omap_hsmmc_get_iodelay_cfg_entry(const fdt32_t *pinctrl, int count)
+{
+	int index = 0;
+	struct iodelay_cfg_entry *iodelay;
+
+	iodelay = (struct iodelay_cfg_entry *)malloc(sizeof(*iodelay) * count);
+	if (!iodelay) {
+		debug("failed to allocate memory\n");
+		return 0;
+	}
+
+	while (index < count) {
+		iodelay[index].offset = fdt32_to_cpu(pinctrl[3 * index]);
+		iodelay[index].a_delay = fdt32_to_cpu(pinctrl[3 * index + 1]);
+		iodelay[index].g_delay = fdt32_to_cpu(pinctrl[3 * index + 2]);
+		index++;
+	}
+
+	return iodelay;
+}
+
+static const fdt32_t *omap_hsmmc_get_pinctrl_entry(u32  phandle,
+						   const char *name, int *len)
+{
+	const void *fdt = gd->fdt_blob;
+	int offset;
+	const fdt32_t *pinctrl;
+
+	offset = fdt_node_offset_by_phandle(fdt, phandle);
+	if (offset < 0) {
+		debug("failed to get pinctrl node %s.\n",
+		      fdt_strerror(offset));
+		return 0;
+	}
+
+	pinctrl = fdt_getprop(fdt, offset, name, len);
+	if (!pinctrl) {
+		debug("failed to get property %s\n", name);
+		return 0;
+	}
+
+	return pinctrl;
+}
+
+static uint32_t omap_hsmmc_get_pad_conf_phandle(struct mmc *mmc,
+						char *prop_name)
+{
+	const void *fdt = gd->fdt_blob;
+	const __be32 *phandle;
+	int node = dev_of_offset(mmc->dev);
+
+	phandle = fdt_getprop(fdt, node, prop_name, NULL);
+	if (!phandle) {
+		debug("failed to get property %s\n", prop_name);
+		return 0;
+	}
+
+	return fdt32_to_cpu(*phandle);
+}
+
+static uint32_t omap_hsmmc_get_iodelay_phandle(struct mmc *mmc,
+					       char *prop_name)
+{
+	const void *fdt = gd->fdt_blob;
+	const __be32 *phandle;
+	int len;
+	int count;
+	int node = dev_of_offset(mmc->dev);
+
+	phandle = fdt_getprop(fdt, node, prop_name, &len);
+	if (!phandle) {
+		debug("failed to get property %s\n", prop_name);
+		return 0;
+	}
+
+	/* No manual mode iodelay values if count < 2 */
+	count = len / sizeof(*phandle);
+	if (count < 2)
+		return 0;
+
+	return fdt32_to_cpu(*(phandle + 1));
+}
+
+static struct pad_conf_entry *
+omap_hsmmc_get_pad_conf(struct mmc *mmc, char *prop_name, int *npads)
+{
+	int len;
+	int count;
+	struct pad_conf_entry *padconf;
+	u32 phandle;
+	const fdt32_t *pinctrl;
+
+	phandle = omap_hsmmc_get_pad_conf_phandle(mmc, prop_name);
+	if (!phandle)
+		return ERR_PTR(-EINVAL);
+
+	pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-single,pins",
+					       &len);
+	if (!pinctrl)
+		return ERR_PTR(-EINVAL);
+
+	count = (len / sizeof(*pinctrl)) / 2;
+	padconf = omap_hsmmc_get_pad_conf_entry(pinctrl, count);
+	if (!padconf)
+		return ERR_PTR(-EINVAL);
+
+	*npads = count;
+
+	return padconf;
+}
+
+static struct iodelay_cfg_entry *
+omap_hsmmc_get_iodelay(struct mmc *mmc, char *prop_name, int *niodelay)
+{
+	int len;
+	int count;
+	struct iodelay_cfg_entry *iodelay;
+	u32 phandle;
+	const fdt32_t *pinctrl;
+
+	phandle = omap_hsmmc_get_iodelay_phandle(mmc, prop_name);
+	/* Not all modes have manual mode iodelay values. So its not fatal */
+	if (!phandle)
+		return 0;
+
+	pinctrl = omap_hsmmc_get_pinctrl_entry(phandle, "pinctrl-pin-array",
+					       &len);
+	if (!pinctrl)
+		return ERR_PTR(-EINVAL);
+
+	count = (len / sizeof(*pinctrl)) / 3;
+	iodelay = omap_hsmmc_get_iodelay_cfg_entry(pinctrl, count);
+	if (!iodelay)
+		return ERR_PTR(-EINVAL);
+
+	*niodelay = count;
+
+	return iodelay;
+}
+
+static struct omap_hsmmc_pinctrl_state *
+omap_hsmmc_get_pinctrl_by_mode(struct mmc *mmc, char *mode)
+{
+	int index;
+	int npads = 0;
+	int niodelays = 0;
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(mmc->dev);
+	char prop_name[11];
+	struct omap_hsmmc_pinctrl_state *pinctrl_state;
+
+	pinctrl_state = (struct omap_hsmmc_pinctrl_state *)
+			 malloc(sizeof(*pinctrl_state));
+	if (!pinctrl_state) {
+		debug("failed to allocate memory\n");
+		return 0;
+	}
+
+	index = fdt_stringlist_search(fdt, node, "pinctrl-names", mode);
+	if (index < 0) {
+		debug("fail to find %s mode %s\n", mode, fdt_strerror(index));
+		goto err_pinctrl_state;
+	}
+
+	sprintf(prop_name, "pinctrl-%d", index);
+
+	pinctrl_state->padconf = omap_hsmmc_get_pad_conf(mmc, prop_name,
+							 &npads);
+	if (IS_ERR(pinctrl_state->padconf))
+		goto err_pinctrl_state;
+	pinctrl_state->npads = npads;
+
+	pinctrl_state->iodelay = omap_hsmmc_get_iodelay(mmc, prop_name,
+							&niodelays);
+	if (IS_ERR(pinctrl_state->iodelay))
+		goto err_padconf;
+	pinctrl_state->niodelays = niodelays;
+
+	return pinctrl_state;
+
+err_padconf:
+	kfree(pinctrl_state->padconf);
+
+err_pinctrl_state:
+	kfree(pinctrl_state);
+	return 0;
+}
+
+#define OMAP_HSMMC_SETUP_PINCTRL(capmask, mode, optional)		\
+	do {								\
+		struct omap_hsmmc_pinctrl_state *s = NULL;		\
+		char str[20];						\
+		if (!(cfg->host_caps & capmask))			\
+			break;						\
+									\
+		if (priv->hw_rev) {					\
+			sprintf(str, "%s-%s", #mode, priv->hw_rev);	\
+			s = omap_hsmmc_get_pinctrl_by_mode(mmc, str);	\
+		}							\
+									\
+		if (!s)							\
+			s = omap_hsmmc_get_pinctrl_by_mode(mmc, #mode);	\
+									\
+		if (!s && !optional) {					\
+			debug("%s: no pinctrl for %s\n",		\
+			      mmc->dev->name, #mode);			\
+			cfg->host_caps &= ~(capmask);			\
+		} else {						\
+			priv->mode##_pinctrl_state = s;			\
+		}							\
+	} while (0)
+
+static int omap_hsmmc_get_pinctrl_state(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct mmc_config *cfg = omap_hsmmc_get_cfg(mmc);
+	struct omap_hsmmc_pinctrl_state *default_pinctrl;
+
+	if (!(priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY))
+		return 0;
+
+	default_pinctrl = omap_hsmmc_get_pinctrl_by_mode(mmc, "default");
+	if (!default_pinctrl) {
+		printf("no pinctrl state for default mode\n");
+		return -EINVAL;
+	}
+
+	priv->default_pinctrl_state = default_pinctrl;
+
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR104), sdr104, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR50), sdr50, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_DDR50), ddr50, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR25), sdr25, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(UHS_SDR12), sdr12, false);
+
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_HS_200), hs200_1_8v, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_CAP(MMC_DDR_52), ddr_1_8v, false);
+	OMAP_HSMMC_SETUP_PINCTRL(MMC_MODE_HS, hs, true);
+
+	return 0;
+}
+#endif
+
 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+#ifdef CONFIG_OMAP54XX
+__weak const struct mmc_platform_fixups *platform_fixups_mmc(uint32_t addr)
+{
+	return NULL;
+}
+#endif
+
 static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
 {
 	struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
+	struct omap_mmc_of_data *of_data = (void *)dev_get_driver_data(dev);
+
 	struct mmc_config *cfg = &plat->cfg;
+#ifdef CONFIG_OMAP54XX
+	const struct mmc_platform_fixups *fixups;
+#endif
 	const void *fdt = gd->fdt_blob;
 	int node = dev_of_offset(dev);
-	int val;
+	int ret;
 
 	plat->base_addr = map_physmem(devfdt_get_addr(dev),
 				      sizeof(struct hsmmc *),
 				      MAP_NOCACHE);
 
-	cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
-	val = fdtdec_get_int(fdt, node, "bus-width", -1);
-	if (val < 0) {
-		printf("error: bus-width property missing\n");
-		return -ENOENT;
-	}
-
-	switch (val) {
-	case 0x8:
-		cfg->host_caps |= MMC_MODE_8BIT;
-	case 0x4:
-		cfg->host_caps |= MMC_MODE_4BIT;
-		break;
-	default:
-		printf("error: invalid bus-width property\n");
-		return -ENOENT;
-	}
+	ret = mmc_of_parse(dev, cfg);
+	if (ret < 0)
+		return ret;
 
+	cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
 	cfg->f_min = 400000;
-	cfg->f_max = fdtdec_get_int(fdt, node, "max-frequency", 52000000);
 	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
 	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+	if (fdtdec_get_bool(fdt, node, "ti,dual-volt"))
+		plat->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
+	if (fdtdec_get_bool(fdt, node, "no-1-8-v"))
+		plat->controller_flags |= OMAP_HSMMC_NO_1_8_V;
+	if (of_data)
+		plat->controller_flags |= of_data->controller_flags;
+
+#ifdef CONFIG_OMAP54XX
+	fixups = platform_fixups_mmc(devfdt_get_addr(dev));
+	if (fixups) {
+		plat->hw_rev = fixups->hw_rev;
+		cfg->host_caps &= ~fixups->unsupported_caps;
+		cfg->f_max = fixups->max_freq;
+	}
+#endif
 
 #ifdef OMAP_HSMMC_USE_GPIO
 	plat->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
@@ -1057,9 +1869,14 @@ static int omap_hsmmc_probe(struct udevice *dev)
 	struct omap_hsmmc_data *priv = dev_get_priv(dev);
 	struct mmc_config *cfg = &plat->cfg;
 	struct mmc *mmc;
+#ifdef CONFIG_IODELAY_RECALIBRATION
+	int ret;
+#endif
 
 	cfg->name = "OMAP SD/MMC";
 	priv->base_addr = plat->base_addr;
+	priv->controller_flags = plat->controller_flags;
+	priv->hw_rev = plat->hw_rev;
 #ifdef OMAP_HSMMC_USE_GPIO
 	priv->cd_inverted = plat->cd_inverted;
 #endif
@@ -1071,7 +1888,10 @@ static int omap_hsmmc_probe(struct udevice *dev)
 	if (mmc == NULL)
 		return -1;
 #endif
-
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	device_get_supply_regulator(dev, "pbias-supply",
+				    &priv->pbias_supply);
+#endif
 #if defined(OMAP_HSMMC_USE_GPIO) && CONFIG_IS_ENABLED(OF_CONTROL)
 	gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
 	gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
@@ -1080,14 +1900,34 @@ static int omap_hsmmc_probe(struct udevice *dev)
 	mmc->dev = dev;
 	upriv->mmc = mmc;
 
+#ifdef CONFIG_IODELAY_RECALIBRATION
+	ret = omap_hsmmc_get_pinctrl_state(mmc);
+	/*
+	 * disable high speed modes for the platforms that require IO delay
+	 * and for which we don't have this information
+	 */
+	if ((ret < 0) &&
+	    (priv->controller_flags & OMAP_HSMMC_REQUIRE_IODELAY)) {
+		priv->controller_flags &= ~OMAP_HSMMC_REQUIRE_IODELAY;
+		cfg->host_caps &= ~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_DDR_52) |
+				    UHS_CAPS);
+	}
+#endif
+
 	return omap_hsmmc_init_setup(mmc);
 }
 
 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+
+static const struct omap_mmc_of_data dra7_mmc_of_data = {
+	.controller_flags = OMAP_HSMMC_REQUIRE_IODELAY,
+};
+
 static const struct udevice_id omap_hsmmc_ids[] = {
 	{ .compatible = "ti,omap3-hsmmc" },
 	{ .compatible = "ti,omap4-hsmmc" },
 	{ .compatible = "ti,am33xx-hsmmc" },
+	{ .compatible = "ti,dra7-hsmmc", .data = (ulong)&dra7_mmc_of_data },
 	{ }
 };
 #endif
diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h
index 7546b3f9d0..65465d1f79 100644
--- a/include/configs/am57xx_evm.h
+++ b/include/configs/am57xx_evm.h
@@ -15,9 +15,7 @@
 #include <environment/ti/dfu.h>
 #include <linux/sizes.h>
 
-#ifdef CONFIG_SPL_BUILD
 #define CONFIG_IODELAY_RECALIBRATION
-#endif
 
 #define CONFIG_NR_DRAM_BANKS		2
 
diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h
index ff90b6df72..975e6fdf58 100644
--- a/include/configs/dra7xx_evm.h
+++ b/include/configs/dra7xx_evm.h
@@ -14,9 +14,7 @@
 
 #include <environment/ti/dfu.h>
 
-#ifdef CONFIG_SPL_BUILD
 #define CONFIG_IODELAY_RECALIBRATION
-#endif
 
 #define CONFIG_VERY_BIG_RAM
 #define CONFIG_NR_DRAM_BANKS		2
diff --git a/include/mmc.h b/include/mmc.h
index a46eaed746..86f885b504 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -54,6 +54,7 @@
 #define MMC_VERSION_4_1		MAKE_MMC_VERSION(4, 1, 0)
 #define MMC_VERSION_4_2		MAKE_MMC_VERSION(4, 2, 0)
 #define MMC_VERSION_4_3		MAKE_MMC_VERSION(4, 3, 0)
+#define MMC_VERSION_4_4		MAKE_MMC_VERSION(4, 4, 0)
 #define MMC_VERSION_4_41	MAKE_MMC_VERSION(4, 4, 1)
 #define MMC_VERSION_4_5		MAKE_MMC_VERSION(4, 5, 0)
 #define MMC_VERSION_5_0		MAKE_MMC_VERSION(5, 0, 0)