return val;
 }
 
+#ifdef CONFIG_IODELAY_RECALIBRATION
+void __weak recalibrate_iodelay(void)
+{
+}
+#endif
+
 /*
  * Setup the voltages for the main SoC core power domains.
  * We start with the maximum voltages allowed here, as set in the corresponding
 
        debug("cor: %d\n", vcores->core.value);
        do_scale_vcore(vcores->core.addr, vcores->core.value, vcores->core.pmic);
+       /*
+        * IO delay recalibration should be done immediately after
+        * adjusting AVS voltages for VDD_CORE_L.
+        * Respective boards should call __recalibrate_iodelay()
+        * with proper mux, virtual and manual mode configurations.
+        */
+#ifdef CONFIG_IODELAY_RECALIBRATION
+       recalibrate_iodelay();
+#endif
+
        debug("mpu: %d\n", vcores->mpu.value);
        do_scale_vcore(vcores->mpu.addr, vcores->mpu.value, vcores->mpu.pmic);
        /* Configure MPU ABB LDO after scale */
        val = optimize_vcore_voltage(&vcores->core);
        do_scale_vcore(vcores->core.addr, val, vcores->core.pmic);
 
+       /*
+        * IO delay recalibration should be done immediately after
+        * adjusting AVS voltages for VDD_CORE_L.
+        * Respective boards should call __recalibrate_iodelay()
+        * with proper mux, virtual and manual mode configurations.
+        */
+#ifdef CONFIG_IODELAY_RECALIBRATION
+       recalibrate_iodelay();
+#endif
+
        val = optimize_vcore_voltage(&vcores->mpu);
        do_scale_vcore(vcores->mpu.addr, val, vcores->mpu.pmic);
 
 
 obj-y  += prcm-regs.o
 obj-y  += hw_data.o
 obj-y  += abb.o
+obj-$(CONFIG_IODELAY_RECALIBRATION) += dra7xx_iodelay.o
 
--- /dev/null
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/utils.h>
+#include <asm/arch/dra7xx_iodelay.h>
+#include <asm/arch/omap.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clock.h>
+#include <asm/omap_common.h>
+
+static int isolate_io(u32 isolate)
+{
+       if (isolate) {
+               clrsetbits_le32((*ctrl)->control_pbias, SDCARD_PWRDNZ,
+                               SDCARD_PWRDNZ);
+               clrsetbits_le32((*ctrl)->control_pbias, SDCARD_BIAS_PWRDNZ,
+                               SDCARD_BIAS_PWRDNZ);
+       }
+
+       /* Override control on ISOCLKIN signal to IO pad ring. */
+       clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
+                       PMCTRL_ISOCLK_OVERRIDE_CTRL);
+       if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK, PMCTRL_ISOCLK_STATUS_MASK,
+                          (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
+               return ERR_DEISOLATE_IO << isolate;
+
+       /* Isolate/Deisolate IO */
+       clrsetbits_le32((*ctrl)->ctrl_core_sma_sw_0, CTRL_ISOLATE_MASK,
+                       isolate << CTRL_ISOLATE_SHIFT);
+       /* Dummy read to add delay t > 10ns */
+       readl((*ctrl)->ctrl_core_sma_sw_0);
+
+       /* Return control on ISOCLKIN to hardware */
+       clrsetbits_le32((*prcm)->prm_io_pmctrl, PMCTRL_ISOCLK_OVERRIDE_MASK,
+                       PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL);
+       if (!wait_on_value(PMCTRL_ISOCLK_STATUS_MASK,
+                          0 << PMCTRL_ISOCLK_STATUS_SHIFT,
+                          (u32 *)(*prcm)->prm_io_pmctrl, LDELAY))
+               return ERR_DEISOLATE_IO << isolate;
+
+       return 0;
+}
+
+static int calibrate_iodelay(u32 base)
+{
+       u32 reg;
+
+       /* Configure REFCLK period */
+       reg = readl(base + CFG_REG_2_OFFSET);
+       reg &= ~CFG_REG_REFCLK_PERIOD_MASK;
+       reg |= CFG_REG_REFCLK_PERIOD;
+       writel(reg, base + CFG_REG_2_OFFSET);
+
+       /* Initiate Calibration */
+       clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_CALIB_STRT_MASK,
+                       CFG_REG_CALIB_STRT << CFG_REG_CALIB_STRT_SHIFT);
+       if (!wait_on_value(CFG_REG_CALIB_STRT_MASK, CFG_REG_CALIB_END,
+                          (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
+               return ERR_CALIBRATE_IODELAY;
+
+       return 0;
+}
+
+static int update_delay_mechanism(u32 base)
+{
+       /* Initiate the reload of calibrated values. */
+       clrsetbits_le32(base + CFG_REG_0_OFFSET, CFG_REG_ROM_READ_MASK,
+                       CFG_REG_ROM_READ_START);
+       if (!wait_on_value(CFG_REG_ROM_READ_MASK, CFG_REG_ROM_READ_END,
+                          (u32 *)(base + CFG_REG_0_OFFSET), LDELAY))
+               return ERR_UPDATE_DELAY;
+
+       return 0;
+}
+
+void __recalibrate_iodelay(struct pad_conf_entry const *pad, int npads)
+{
+       int ret = 0;
+
+       /* IO recalibration should be done only from SRAM */
+       if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context()) {
+               puts("IODELAY recalibration called from invalid context - use only from SPL in SRAM\n");
+               return;
+       }
+
+       /* 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 = isolate_io(ISOLATE_IO);
+       if (ret)
+               goto err;
+
+       ret = update_delay_mechanism((*ctrl)->iodelay_config_base);
+       if (ret)
+               goto err;
+
+       /* Configure Mux settings */
+       do_set_mux32((*ctrl)->control_padconf_core_base, pad, npads);
+
+       ret = isolate_io(DEISOLATE_IO);
+
+err:
+       /* lock IODELAY CONFIG registers */
+       writel(CFG_IODELAY_LOCK_KEY, (*ctrl)->iodelay_config_base +
+              CFG_REG_8_OFFSET);
+       /*
+        * UART cannot be used during IO recalibration sequence as IOs are in
+        * isolation. So error handling and debug prints are done after
+        * complete IO delay recalibration sequence
+        */
+       switch (ret) {
+       case ERR_CALIBRATE_IODELAY:
+               puts("IODELAY: IO delay calibration sequence failed\n");
+               break;
+       case ERR_ISOLATE_IO:
+               puts("IODELAY: Isolation of Device IOs failed\n");
+               break;
+       case ERR_UPDATE_DELAY:
+               puts("IODELAY: Delay mechanism update with new calibrated values failed\n");
+               break;
+       case ERR_DEISOLATE_IO:
+               puts("IODELAY: De-isolation of Device IOs failed\n");
+               break;
+       default:
+               debug("IODELAY: IO delay recalibration successfully completed\n");
+       }
+}
 
        .control_status                         = 0x4A002134,
        .control_phy_power_usb                  = 0x4A002370,
        .control_phy_power_sata                 = 0x4A002374,
+       .ctrl_core_sma_sw_0                     = 0x4A0023FC,
        .control_core_mac_id_0_lo               = 0x4A002514,
        .control_core_mac_id_0_hi               = 0x4A002518,
        .control_core_mac_id_1_lo               = 0x4A00251C,
        .control_efuse_3                        = 0x4AE0C5D0,
        .control_efuse_4                        = 0x4AE0C5D4,
        .control_efuse_13                       = 0x4AE0C5F0,
+       .iodelay_config_base                    = 0x4844A000,
 };
 
 struct prcm_regs const omap5_es2_prcm = {
        .prm_rstctrl                            = 0x4ae07d00,
        .prm_rstst                              = 0x4ae07d04,
        .prm_rsttime                            = 0x4ae07d08,
+       .prm_io_pmctrl                          = 0x4ae07d20,
        .prm_vc_val_bypass                      = 0x4ae07da0,
        .prm_vc_cfg_i2c_mode                    = 0x4ae07db4,
        .prm_vc_cfg_i2c_clk                     = 0x4ae07db8,
 
--- /dev/null
+/*
+ * (C) Copyright 2015
+ * Texas Instruments Incorporated
+ *
+ * Lokesh Vutla <lokeshvutla@ti.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _DRA7_IODELAY_H_
+#define _DRA7_IODELAY_H_
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+
+/* CONFIG_REG_0 */
+#define CFG_REG_0_OFFSET               0xC
+#define CFG_REG_ROM_READ_SHIFT         1
+#define CFG_REG_ROM_READ_MASK          (1 << 1)
+#define CFG_REG_CALIB_STRT_SHIFT       0
+#define CFG_REG_CALIB_STRT_MASK                (1 << 0)
+#define CFG_REG_CALIB_STRT             1
+#define CFG_REG_CALIB_END              0
+#define CFG_REG_ROM_READ_START         (1 << 1)
+#define CFG_REG_ROM_READ_END           (0 << 1)
+
+/* CONFIG_REG_2 */
+#define CFG_REG_2_OFFSET               0x14
+#define CFG_REG_REFCLK_PERIOD_SHIFT    0
+#define CFG_REG_REFCLK_PERIOD_MASK     (0xFFFF << 0)
+#define CFG_REG_REFCLK_PERIOD          0x2EF
+
+/* CONFIG_REG_8 */
+#define CFG_REG_8_OFFSET               0x2C
+#define CFG_IODELAY_UNLOCK_KEY         0x0000AAAA
+#define CFG_IODELAY_LOCK_KEY           0x0000AAAB
+
+/* CTRL_CORE_SMA_SW_0 */
+#define CTRL_ISOLATE_SHIFT             2
+#define CTRL_ISOLATE_MASK              (1 << 2)
+#define ISOLATE_IO                     1
+#define DEISOLATE_IO                   0
+
+/* PRM_IO_PMCTRL */
+#define PMCTRL_ISOCLK_OVERRIDE_SHIFT   0
+#define PMCTRL_ISOCLK_OVERRIDE_MASK    (1 << 0)
+#define PMCTRL_ISOCLK_STATUS_SHIFT     1
+#define PMCTRL_ISOCLK_STATUS_MASK      (1 << 1)
+#define PMCTRL_ISOCLK_OVERRIDE_CTRL    1
+#define PMCTRL_ISOCLK_NOT_OVERRIDE_CTRL        0
+
+#define ERR_CALIBRATE_IODELAY          0x1
+#define ERR_DEISOLATE_IO               0x2
+#define ERR_ISOLATE_IO                 0x4
+#define ERR_UPDATE_DELAY               0x8
+
+void __recalibrate_iodelay(struct pad_conf_entry const *array, int npads);
+#endif
 
        u32 prm_rstctrl;
        u32 prm_rstst;
        u32 prm_rsttime;
+       u32 prm_io_pmctrl;
        u32 prm_vc_val_bypass;
        u32 prm_vc_cfg_i2c_mode;
        u32 prm_vc_cfg_i2c_clk;
        u32 control_efuse_12;
        u32 control_efuse_13;
        u32 control_padconf_wkup_base;
+       u32 iodelay_config_base;
+       u32 ctrl_core_sma_sw_0;
 };
 
 struct dpll_params {
 
 void usb_fake_mac_from_die_id(u32 *id);
 void usb_set_serial_num_from_die_id(u32 *id);
+void recalibrate_iodelay(void);
 
 void omap_smc1(u32 service, u32 val);