#define HCI_MH_ALLOWABLE_TRAN_OF_VH            0x30C
 #define HCI_MH_IID_IN_TASK_TAG                 0X308
 
+#define PH_READY_TIMEOUT_MS                    (5 * MSEC_PER_SEC)
+
 enum {
        UNIPRO_L1_5 = 0,/* PHY Adapter */
        UNIPRO_L2,      /* Data Link */
        return 0;
 }
 
+static int exynosauto_ufs_vh_link_startup_notify(struct ufs_hba *hba,
+                                                enum ufs_notify_change_status status)
+{
+       if (status == POST_CHANGE) {
+               ufshcd_set_link_active(hba);
+               ufshcd_set_ufs_dev_active(hba);
+       }
+
+       return 0;
+}
+
+static int exynosauto_ufs_vh_wait_ph_ready(struct ufs_hba *hba)
+{
+       u32 mbox;
+       ktime_t start, stop;
+
+       start = ktime_get();
+       stop = ktime_add(start, ms_to_ktime(PH_READY_TIMEOUT_MS));
+
+       do {
+               mbox = ufshcd_readl(hba, PH2VH_MBOX);
+               /* TODO: Mailbox message protocols between the PH and VHs are
+                * not implemented yet. This will be supported later
+                */
+               if ((mbox & MH_MSG_MASK) == MH_MSG_PH_READY)
+                       return 0;
+
+               usleep_range(40, 50);
+       } while (ktime_before(ktime_get(), stop));
+
+       return -ETIME;
+}
+
+static int exynosauto_ufs_vh_init(struct ufs_hba *hba)
+{
+       struct device *dev = hba->dev;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct exynos_ufs *ufs;
+       int ret;
+
+       ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL);
+       if (!ufs)
+               return -ENOMEM;
+
+       /* exynos-specific hci */
+       ufs->reg_hci = devm_platform_ioremap_resource_byname(pdev, "vs_hci");
+       if (IS_ERR(ufs->reg_hci)) {
+               dev_err(dev, "cannot ioremap for hci vendor register\n");
+               return PTR_ERR(ufs->reg_hci);
+       }
+
+       ret = exynosauto_ufs_vh_wait_ph_ready(hba);
+       if (ret)
+               return ret;
+
+       ufs->drv_data = device_get_match_data(dev);
+       if (!ufs->drv_data)
+               return -ENODEV;
+
+       exynos_ufs_priv_init(hba, ufs);
+
+       return 0;
+}
+
 static struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
        .name                           = "exynos_ufs",
        .init                           = exynos_ufs_init,
        .resume                         = exynos_ufs_resume,
 };
 
+static struct ufs_hba_variant_ops ufs_hba_exynosauto_vh_ops = {
+       .name                           = "exynosauto_ufs_vh",
+       .init                           = exynosauto_ufs_vh_init,
+       .link_startup_notify            = exynosauto_ufs_vh_link_startup_notify,
+};
+
 static int exynos_ufs_probe(struct platform_device *pdev)
 {
        int err;
        .post_pwr_change        = exynosauto_ufs_post_pwr_change,
 };
 
+static struct exynos_ufs_drv_data exynosauto_ufs_vh_drvs = {
+       .vops                   = &ufs_hba_exynosauto_vh_ops,
+       .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
+                                 UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
+                                 UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
+                                 UFSHCI_QUIRK_BROKEN_HCE |
+                                 UFSHCD_QUIRK_BROKEN_UIC_CMD |
+                                 UFSHCD_QUIRK_SKIP_PH_CONFIGURATION |
+                                 UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
+       .opts                   = EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
+};
+
 static struct exynos_ufs_drv_data exynos_ufs_drvs = {
        .uic_attr               = &exynos7_uic_attr,
        .quirks                 = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
          .data       = &exynos_ufs_drvs },
        { .compatible = "samsung,exynosautov9-ufs",
          .data       = &exynosauto_ufs_drvs },
+       { .compatible = "samsung,exynosautov9-ufs-vh",
+         .data       = &exynosauto_ufs_vh_drvs },
        {},
 };