const char *name;
        unsigned int gen;
        bool has_svsret;
+       int (*configure)(struct dw_hdmi *hdmi,
+                        const struct dw_hdmi_plat_data *pdata,
+                        unsigned long mpixelclock);
 };
 
 struct dw_hdmi {
        return true;
 }
 
-static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
-                                unsigned char addr)
+void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+                          unsigned char addr)
 {
        hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
        hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
                    HDMI_PHY_I2CM_OPERATION_ADDR);
        hdmi_phy_wait_i2c_done(hdmi, 1000);
 }
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
 
 static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
 {
        return 0;
 }
 
-static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+/*
+ * PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available
+ * information the DWC MHL PHY has the same register layout and is thus also
+ * supported by this function.
+ */
+static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
+               const struct dw_hdmi_plat_data *pdata,
+               unsigned long mpixelclock)
 {
-       const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
-       const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
        const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
        const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
        const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
 
        /* PLL/MPLL Cfg - always match on final entry */
        for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   mpll_config->mpixelclock)
+               if (mpixelclock <= mpll_config->mpixelclock)
                        break;
 
        for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   curr_ctrl->mpixelclock)
+               if (mpixelclock <= curr_ctrl->mpixelclock)
                        break;
 
        for (; phy_config->mpixelclock != ~0UL; phy_config++)
-               if (hdmi->hdmi_data.video_mode.mpixelclock <=
-                   phy_config->mpixelclock)
+               if (mpixelclock <= phy_config->mpixelclock)
                        break;
 
        if (mpll_config->mpixelclock == ~0UL ||
            curr_ctrl->mpixelclock == ~0UL ||
-           phy_config->mpixelclock == ~0UL) {
-               dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
-                       hdmi->hdmi_data.video_mode.mpixelclock);
+           phy_config->mpixelclock == ~0UL)
                return -EINVAL;
-       }
+
+       dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
+                             HDMI_3D_TX_PHY_CPCE_CTRL);
+       dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
+                             HDMI_3D_TX_PHY_GMPCTRL);
+       dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
+                             HDMI_3D_TX_PHY_CURRCTRL);
+
+       dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
+       dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
+                             HDMI_3D_TX_PHY_MSM_CTRL);
+
+       dw_hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
+       dw_hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+                             HDMI_3D_TX_PHY_CKSYMTXCTRL);
+       dw_hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+                             HDMI_3D_TX_PHY_VLEVCTRL);
+
+       /* Override and disable clock termination. */
+       dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
+                             HDMI_3D_TX_PHY_CKCALCTRL);
+
+       return 0;
+}
+
+static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+{
+       const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
+       const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
+       unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+       int ret;
 
        dw_hdmi_phy_power_off(hdmi);
 
                    HDMI_PHY_I2CM_SLAVE_ADDR);
        hdmi_phy_test_clear(hdmi, 0);
 
-       hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
-                          HDMI_3D_TX_PHY_CPCE_CTRL);
-       hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
-                          HDMI_3D_TX_PHY_GMPCTRL);
-       hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
-                          HDMI_3D_TX_PHY_CURRCTRL);
-
-       hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
-       hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
-                          HDMI_3D_TX_PHY_MSM_CTRL);
-
-       hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
-       hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
-                          HDMI_3D_TX_PHY_CKSYMTXCTRL);
-       hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
-                          HDMI_3D_TX_PHY_VLEVCTRL);
-
-       /* Override and disable clock termination. */
-       hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
-                          HDMI_3D_TX_PHY_CKCALCTRL);
+       /* Write to the PHY as configured by the platform */
+       if (pdata->configure_phy)
+               ret = pdata->configure_phy(hdmi, pdata, mpixelclock);
+       else
+               ret = phy->configure(hdmi, pdata, mpixelclock);
+       if (ret) {
+               dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
+                       mpixelclock);
+               return ret;
+       }
 
        return dw_hdmi_phy_power_on(hdmi);
 }
                .name = "DWC MHL PHY + HEAC PHY",
                .gen = 2,
                .has_svsret = true,
+               .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
        }, {
                .type = DW_HDMI_PHY_DWC_MHL_PHY,
                .name = "DWC MHL PHY",
                .gen = 2,
                .has_svsret = true,
+               .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
        }, {
                .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
                .name = "DWC HDMI 3D TX PHY + HEAC PHY",
                .gen = 2,
+               .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
        }, {
                .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
                .name = "DWC HDMI 3D TX PHY",
                .gen = 2,
+               .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
        }, {
                .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
                .name = "DWC HDMI 2.0 TX PHY",
                .gen = 2,
                .has_svsret = true,
+       }, {
+               .type = DW_HDMI_PHY_VENDOR_PHY,
+               .name = "Vendor PHY",
        }
 };
 
                        hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops;
                        hdmi->phy.name = dw_hdmi_phys[i].name;
                        hdmi->phy.data = (void *)&dw_hdmi_phys[i];
+
+                       if (!dw_hdmi_phys[i].configure &&
+                           !hdmi->plat_data->configure_phy) {
+                               dev_err(hdmi->dev, "%s requires platform support\n",
+                                       hdmi->phy.name);
+                               return -ENODEV;
+                       }
+
                        return 0;
                }
        }