diff mbox

[U-Boot,4/5] rockchip: video: rk3399: add HDMI TX support on the RK3399

Message ID 1493394792-20743-5-git-send-email-philipp.tomsich@theobroma-systems.com
State Superseded
Headers show

Commit Message

Philipp Tomsich April 28, 2017, 3:53 p.m. UTC
This commit enables the RK3399 HDMI TX, which is very similar to the
one found on the RK3288. The differences between the two SoCs (mainly
the input VOP selection) is abstracted away through the driverdata.

Note that the I2C communication for reading the EDID works well with
the default settings, but does not with the alternate settings used on
the RK3288... so this configuration aspect also is part of the
driverdata.

Having some sort of DTS-based configuration for the regulator
dependencies would be nice for the future, but for now we simply use
lists of regulator names (also via driverdata) that we probe.

Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
---

 arch/arm/include/asm/arch-rockchip/grf_rk3399.h |   5 +
 drivers/video/rockchip/rk_hdmi.c                | 165 +++++++++++++++++++-----
 2 files changed, 135 insertions(+), 35 deletions(-)

Comments

Jernej Škrabec April 28, 2017, 4:07 p.m. UTC | #1
Hi Philipp,

Dne petek, 28. april 2017 ob 17:53:11 CEST je Philipp Tomsich napisal(a):
> This commit enables the RK3399 HDMI TX, which is very similar to the
> one found on the RK3288. The differences between the two SoCs (mainly
> the input VOP selection) is abstracted away through the driverdata.
> 
> Note that the I2C communication for reading the EDID works well with
> the default settings, but does not with the alternate settings used on
> the RK3288... so this configuration aspect also is part of the
> driverdata.
> 
> Having some sort of DTS-based configuration for the regulator
> dependencies would be nice for the future, but for now we simply use
> lists of regulator names (also via driverdata) that we probe.
> 
> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> ---
> 
>  arch/arm/include/asm/arch-rockchip/grf_rk3399.h |   5 +
>  drivers/video/rockchip/rk_hdmi.c                | 165
> +++++++++++++++++++----- 2 files changed, 135 insertions(+), 35
> deletions(-)
> 
> diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h index 22d8d97..ddd558e
> 100644
> --- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
> @@ -462,6 +462,11 @@ enum {
>  	GRF_UART_DBG_SEL_MASK	= 3 << GRF_UART_DBG_SEL_SHIFT,
>  	GRF_UART_DBG_SEL_C	= 2,
> 
> +	/* GRF_SOC_CON20 */
> +	GRF_RK3399_HDMI_VOP_SEL_MASK = 1 << 6,
> +	GRF_RK3399_HDMI_VOP_SEL_B = 0 << 6,
> +	GRF_RK3399_HDMI_VOP_SEL_L = 1 << 6,
> +
>  	/*  PMUGRF_GPIO0A_IOMUX */
>  	PMUGRF_GPIO0A6_SEL_SHIFT        = 12,
>  	PMUGRF_GPIO0A6_SEL_MASK = 3 << PMUGRF_GPIO0A6_SEL_SHIFT,
> diff --git a/drivers/video/rockchip/rk_hdmi.c
> b/drivers/video/rockchip/rk_hdmi.c index db07588..ea92551 100644
> --- a/drivers/video/rockchip/rk_hdmi.c
> +++ b/drivers/video/rockchip/rk_hdmi.c
> @@ -1,10 +1,13 @@
>  /*
> + * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
>   * Copyright (c) 2015 Google, Inc
>   * Copyright 2014 Rockchip Inc.
>   *
>   * SPDX-License-Identifier:	GPL-2.0+
>   */
> 
> +#define DEBUG
> +

That shouldn't be in final version.

>  #include <common.h>
>  #include <clk.h>
>  #include <display.h>
> @@ -16,12 +19,25 @@
>  #include <asm/gpio.h>
>  #include <asm/io.h>
>  #include <asm/arch/clock.h>
> +#include <asm/arch/hardware.h>
>  #include <asm/arch/grf_rk3288.h>
> +#include <asm/arch/grf_rk3399.h>
>  #include <power/regulator.h>
> 
>  struct rk_hdmi_priv {
>  	struct dw_hdmi hdmi;
> -	struct rk3288_grf *grf;
> +	void *grf;
> +};
> +
> +struct rkhdmi_driverdata {
> +	/* configuration */
> +	u8 i2c_clk_high;
> +	u8 i2c_clk_low;
> +	const char * const *regulator_names;
> +	u32 regulator_names_cnt;
> +	/* setters/getters */
> +	int (*set_input_vop)(struct udevice *dev);
> +	int (*clk_config)(struct udevice *dev);
>  };
> 
>  static const struct hdmi_phy_config rockchip_phy_config[] = {
> @@ -65,6 +81,60 @@ static const struct hdmi_mpll_config rockchip_mpll_cfg[]
> = { }
>  };
> 
> +static int rk3288_set_input_vop(struct udevice *dev)
> +{
> +	struct rk_hdmi_priv *priv = dev_get_priv(dev);
> +	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
> +	int vop_id = uc_plat->source_id;
> +	struct rk3288_grf *grf = priv->grf;
> +
> +	/* hdmi source select hdmi controller */
> +	rk_setreg(&grf->soc_con6, 1 << 15);
> +
> +	/* hdmi data from vop id */
> +	rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
> +
> +	return 0;
> +}
> +
> +static int rk3399_set_input_vop(struct udevice *dev)
> +{
> +	struct rk_hdmi_priv *priv = dev_get_priv(dev);
> +	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
> +	int vop_id = uc_plat->source_id;
> +	struct rk3399_grf_regs *grf = priv->grf;
> +
> +	/* hdmi data from vop id */
> +	rk_clrsetreg(&grf->soc_con20, GRF_RK3399_HDMI_VOP_SEL_MASK,
> +		     (vop_id == 1) ? GRF_RK3399_HDMI_VOP_SEL_L : 0);
> +
> +	return 0;
> +}
> +
> +static int rk3288_clk_config(struct udevice *dev)
> +{
> +	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
> +	struct clk clk;
> +	int ret;
> +
> +	/*
> +	 * Configure the maximum clock to permit whatever resolution the
> +	 * monitor wants
> +	 */
> +	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
> +	if (ret >= 0) {
> +		ret = clk_set_rate(&clk, 384000000);
> +		clk_free(&clk);
> +	}
> +	if (ret < 0) {
> +		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
> +		      __func__, uc_plat->src_dev->name, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
>  {
>  	struct rk_hdmi_priv *priv = dev_get_priv(dev);
> @@ -83,20 +153,16 @@ static int rk_hdmi_enable(struct udevice *dev, int
> panel_bpp, static int rk_hdmi_ofdata_to_platdata(struct udevice *dev)
>  {
>  	struct rk_hdmi_priv *priv = dev_get_priv(dev);
> +	struct rkhdmi_driverdata *data =
> +		(struct rkhdmi_driverdata *)dev_get_driver_data(dev);
>  	struct dw_hdmi *hdmi = &priv->hdmi;
> 
>  	hdmi->ioaddr = (ulong)dev_get_addr(dev);
>  	hdmi->mpll_cfg = rockchip_mpll_cfg;
>  	hdmi->phy_cfg = rockchip_phy_config;
> -	hdmi->i2c_clk_high = 0x7a;
> -	hdmi->i2c_clk_low = 0x8d;
> +	hdmi->i2c_clk_high = data->i2c_clk_high;
> +	hdmi->i2c_clk_low = data->i2c_clk_low;
> 
> -	/*
> -	 * TODO(sjg@chromium.org): The above values don't work - these ones
> -	 * work better, but generate lots of errors in the data.
> -	 */
> -	hdmi->i2c_clk_high = 0x0d;
> -	hdmi->i2c_clk_low = 0x0d;
>  	hdmi->reg_io_width = 4;
>  	hdmi->phy_set = dw_hdmi_phy_cfg;
> 
> @@ -107,13 +173,15 @@ static int rk_hdmi_ofdata_to_platdata(struct udevice
> *dev)
> 
>  static int rk_hdmi_probe(struct udevice *dev)
>  {
> -	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
> +	struct rkhdmi_driverdata *data =
> +		(struct rkhdmi_driverdata *)dev_get_driver_data(dev);
>  	struct rk_hdmi_priv *priv = dev_get_priv(dev);
>  	struct dw_hdmi *hdmi = &priv->hdmi;
>  	struct udevice *reg;
>  	struct clk clk;
> +	const char *regulator_name;
>  	int ret;
> -	int vop_id = uc_plat->source_id;
> +	int i;
> 
>  	ret = clk_get_by_index(dev, 0, &clk);
>  	if (ret >= 0) {
> @@ -125,33 +193,27 @@ static int rk_hdmi_probe(struct udevice *dev)
>  		return ret;
>  	}
> 
> -	/*
> -	 * Configure the maximum clock to permit whatever resolution the
> -	 * monitor wants
> -	 */
> -	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
> -	if (ret >= 0) {
> -		ret = clk_set_rate(&clk, 384000000);
> -		clk_free(&clk);
> -	}
> -	if (ret < 0) {
> -		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
> -		      __func__, uc_plat->src_dev->name, ret);
> -		return ret;
> +	if (data->clk_config) {
> +		ret = data->clk_config(dev);
> +		if (ret < 0)
> +			return ret;
>  	}
> 
> -	ret = regulator_get_by_platname("vcc50_hdmi", &reg);
> -	if (!ret)
> -		ret = regulator_set_enable(reg, true);
> -	if (ret)
> -		debug("%s: Cannot set regulator vcc50_hdmi\n", __func__);
> +	for (i = 0; i < data->regulator_names_cnt; ++i) {
> +		regulator_name = data->regulator_names[i];
> +		debug("%s: probing regulator '%s'\n", __func__, regulator_name);
> 
> -	/* hdmi source select hdmi controller */
> -	rk_setreg(&priv->grf->soc_con6, 1 << 15);
> +		ret = regulator_autoset_by_name(regulator_name, &reg);
> +		if (!ret)
> +			ret = regulator_set_enable(reg, true);
> +	}
> 
> -	/* hdmi data from vop id */
> -	rk_clrsetreg(&priv->grf->soc_con6, 1 << 4,
> -		     (vop_id == 1) ? (1 << 4) : 0);
> +	if (!data->set_input_vop) {
> +		debug("%s: data->set_input_vop not set\n", __func__);
> +		return -1;
> +	}
> +
> +	data->set_input_vop(dev);
> 
>  	ret = dw_hdmi_phy_wait_for_hpd(hdmi);
>  	if (ret < 0) {
> @@ -170,8 +232,41 @@ static const struct dm_display_ops rk_hdmi_ops = {
>  	.enable = rk_hdmi_enable,
>  };
> 
> +static const char * const rk3288_regulator_names[] = {
> +	"vcc50_hdmi",
> +};
> +
> +static const struct rkhdmi_driverdata rk3288_driverdata = {
> +	/*
> +	 * TODO(sjg@chromium.org): The above values don't work - these ones
> +	 * work better, but generate lots of errors in the data.
> +	 */

Maybe you should rephrase the comment. In this form it doesn't make sense 
anymore.

Regards,
Jernej

> +	.i2c_clk_high = 0x0d,
> +	.i2c_clk_low = 0x0d,
> +	.regulator_names = rk3288_regulator_names,
> +	.regulator_names_cnt = ARRAY_SIZE(rk3288_regulator_names),
> +	.set_input_vop = rk3288_set_input_vop,
> +	.clk_config = rk3288_clk_config,
> +};
> +
> +static const char * const rk3399_regulator_names[] = {
> +	"vcc1v8_hdmi",
> +	"vcc0v9_hdmi"
> +};
> +
> +static const struct rkhdmi_driverdata rk3399_driverdata = {
> +	.i2c_clk_high = 0x7a,
> +	.i2c_clk_low = 0x8d,
> +	.regulator_names = rk3399_regulator_names,
> +	.regulator_names_cnt = ARRAY_SIZE(rk3399_regulator_names),
> +	.set_input_vop = rk3399_set_input_vop,
> +};
> +
>  static const struct udevice_id rk_hdmi_ids[] = {
> -	{ .compatible = "rockchip,rk3288-dw-hdmi" },
> +	{ .compatible = "rockchip,rk3288-dw-hdmi",
> +	  .data = (ulong)&rk3288_driverdata },
> +	{ .compatible = "rockchip,rk3399-dw-hdmi",
> +	  .data = (ulong)&rk3399_driverdata },
>  	{ }
>  };
> 
> --
> 1.9.1
Simon Glass April 30, 2017, 3:49 a.m. UTC | #2
Hi Philipp,

On 28 April 2017 at 09:53, Philipp Tomsich
<philipp.tomsich@theobroma-systems.com> wrote:
> This commit enables the RK3399 HDMI TX, which is very similar to the
> one found on the RK3288. The differences between the two SoCs (mainly
> the input VOP selection) is abstracted away through the driverdata.
>
> Note that the I2C communication for reading the EDID works well with
> the default settings, but does not with the alternate settings used on
> the RK3288... so this configuration aspect also is part of the
> driverdata.
>
> Having some sort of DTS-based configuration for the regulator
> dependencies would be nice for the future, but for now we simply use
> lists of regulator names (also via driverdata) that we probe.
>
> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> ---
>
>  arch/arm/include/asm/arch-rockchip/grf_rk3399.h |   5 +
>  drivers/video/rockchip/rk_hdmi.c                | 165 +++++++++++++++++++-----
>  2 files changed, 135 insertions(+), 35 deletions(-)

Similar comment to the previous patch.

- Simon
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
index 22d8d97..ddd558e 100644
--- a/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
+++ b/arch/arm/include/asm/arch-rockchip/grf_rk3399.h
@@ -462,6 +462,11 @@  enum {
 	GRF_UART_DBG_SEL_MASK	= 3 << GRF_UART_DBG_SEL_SHIFT,
 	GRF_UART_DBG_SEL_C	= 2,
 
+	/* GRF_SOC_CON20 */
+	GRF_RK3399_HDMI_VOP_SEL_MASK = 1 << 6,
+	GRF_RK3399_HDMI_VOP_SEL_B = 0 << 6,
+	GRF_RK3399_HDMI_VOP_SEL_L = 1 << 6,
+
 	/*  PMUGRF_GPIO0A_IOMUX */
 	PMUGRF_GPIO0A6_SEL_SHIFT        = 12,
 	PMUGRF_GPIO0A6_SEL_MASK = 3 << PMUGRF_GPIO0A6_SEL_SHIFT,
diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c
index db07588..ea92551 100644
--- a/drivers/video/rockchip/rk_hdmi.c
+++ b/drivers/video/rockchip/rk_hdmi.c
@@ -1,10 +1,13 @@ 
 /*
+ * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
  * Copyright (c) 2015 Google, Inc
  * Copyright 2014 Rockchip Inc.
  *
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#define DEBUG
+
 #include <common.h>
 #include <clk.h>
 #include <display.h>
@@ -16,12 +19,25 @@ 
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
+#include <asm/arch/hardware.h>
 #include <asm/arch/grf_rk3288.h>
+#include <asm/arch/grf_rk3399.h>
 #include <power/regulator.h>
 
 struct rk_hdmi_priv {
 	struct dw_hdmi hdmi;
-	struct rk3288_grf *grf;
+	void *grf;
+};
+
+struct rkhdmi_driverdata {
+	/* configuration */
+	u8 i2c_clk_high;
+	u8 i2c_clk_low;
+	const char * const *regulator_names;
+	u32 regulator_names_cnt;
+	/* setters/getters */
+	int (*set_input_vop)(struct udevice *dev);
+	int (*clk_config)(struct udevice *dev);
 };
 
 static const struct hdmi_phy_config rockchip_phy_config[] = {
@@ -65,6 +81,60 @@  static const struct hdmi_mpll_config rockchip_mpll_cfg[] = {
 	}
 };
 
+static int rk3288_set_input_vop(struct udevice *dev)
+{
+	struct rk_hdmi_priv *priv = dev_get_priv(dev);
+	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
+	int vop_id = uc_plat->source_id;
+	struct rk3288_grf *grf = priv->grf;
+
+	/* hdmi source select hdmi controller */
+	rk_setreg(&grf->soc_con6, 1 << 15);
+
+	/* hdmi data from vop id */
+	rk_clrsetreg(&grf->soc_con6, 1 << 4, (vop_id == 1) ? (1 << 4) : 0);
+
+	return 0;
+}
+
+static int rk3399_set_input_vop(struct udevice *dev)
+{
+	struct rk_hdmi_priv *priv = dev_get_priv(dev);
+	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
+	int vop_id = uc_plat->source_id;
+	struct rk3399_grf_regs *grf = priv->grf;
+
+	/* hdmi data from vop id */
+	rk_clrsetreg(&grf->soc_con20, GRF_RK3399_HDMI_VOP_SEL_MASK,
+		     (vop_id == 1) ? GRF_RK3399_HDMI_VOP_SEL_L : 0);
+
+	return 0;
+}
+
+static int rk3288_clk_config(struct udevice *dev)
+{
+	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
+	struct clk clk;
+	int ret;
+
+	/*
+	 * Configure the maximum clock to permit whatever resolution the
+	 * monitor wants
+	 */
+	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
+	if (ret >= 0) {
+		ret = clk_set_rate(&clk, 384000000);
+		clk_free(&clk);
+	}
+	if (ret < 0) {
+		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
+		      __func__, uc_plat->src_dev->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
 {
 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
@@ -83,20 +153,16 @@  static int rk_hdmi_enable(struct udevice *dev, int panel_bpp,
 static int rk_hdmi_ofdata_to_platdata(struct udevice *dev)
 {
 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
+	struct rkhdmi_driverdata *data =
+		(struct rkhdmi_driverdata *)dev_get_driver_data(dev);
 	struct dw_hdmi *hdmi = &priv->hdmi;
 
 	hdmi->ioaddr = (ulong)dev_get_addr(dev);
 	hdmi->mpll_cfg = rockchip_mpll_cfg;
 	hdmi->phy_cfg = rockchip_phy_config;
-	hdmi->i2c_clk_high = 0x7a;
-	hdmi->i2c_clk_low = 0x8d;
+	hdmi->i2c_clk_high = data->i2c_clk_high;
+	hdmi->i2c_clk_low = data->i2c_clk_low;
 
-	/*
-	 * TODO(sjg@chromium.org): The above values don't work - these ones
-	 * work better, but generate lots of errors in the data.
-	 */
-	hdmi->i2c_clk_high = 0x0d;
-	hdmi->i2c_clk_low = 0x0d;
 	hdmi->reg_io_width = 4;
 	hdmi->phy_set = dw_hdmi_phy_cfg;
 
@@ -107,13 +173,15 @@  static int rk_hdmi_ofdata_to_platdata(struct udevice *dev)
 
 static int rk_hdmi_probe(struct udevice *dev)
 {
-	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
+	struct rkhdmi_driverdata *data =
+		(struct rkhdmi_driverdata *)dev_get_driver_data(dev);
 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
 	struct dw_hdmi *hdmi = &priv->hdmi;
 	struct udevice *reg;
 	struct clk clk;
+	const char *regulator_name;
 	int ret;
-	int vop_id = uc_plat->source_id;
+	int i;
 
 	ret = clk_get_by_index(dev, 0, &clk);
 	if (ret >= 0) {
@@ -125,33 +193,27 @@  static int rk_hdmi_probe(struct udevice *dev)
 		return ret;
 	}
 
-	/*
-	 * Configure the maximum clock to permit whatever resolution the
-	 * monitor wants
-	 */
-	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
-	if (ret >= 0) {
-		ret = clk_set_rate(&clk, 384000000);
-		clk_free(&clk);
-	}
-	if (ret < 0) {
-		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
-		      __func__, uc_plat->src_dev->name, ret);
-		return ret;
+	if (data->clk_config) {
+		ret = data->clk_config(dev);
+		if (ret < 0)
+			return ret;
 	}
 
-	ret = regulator_get_by_platname("vcc50_hdmi", &reg);
-	if (!ret)
-		ret = regulator_set_enable(reg, true);
-	if (ret)
-		debug("%s: Cannot set regulator vcc50_hdmi\n", __func__);
+	for (i = 0; i < data->regulator_names_cnt; ++i) {
+		regulator_name = data->regulator_names[i];
+		debug("%s: probing regulator '%s'\n", __func__, regulator_name);
 
-	/* hdmi source select hdmi controller */
-	rk_setreg(&priv->grf->soc_con6, 1 << 15);
+		ret = regulator_autoset_by_name(regulator_name, &reg);
+		if (!ret)
+			ret = regulator_set_enable(reg, true);
+	}
 
-	/* hdmi data from vop id */
-	rk_clrsetreg(&priv->grf->soc_con6, 1 << 4,
-		     (vop_id == 1) ? (1 << 4) : 0);
+	if (!data->set_input_vop) {
+		debug("%s: data->set_input_vop not set\n", __func__);
+		return -1;
+	}
+
+	data->set_input_vop(dev);
 
 	ret = dw_hdmi_phy_wait_for_hpd(hdmi);
 	if (ret < 0) {
@@ -170,8 +232,41 @@  static const struct dm_display_ops rk_hdmi_ops = {
 	.enable = rk_hdmi_enable,
 };
 
+static const char * const rk3288_regulator_names[] = {
+	"vcc50_hdmi",
+};
+
+static const struct rkhdmi_driverdata rk3288_driverdata = {
+	/*
+	 * TODO(sjg@chromium.org): The above values don't work - these ones
+	 * work better, but generate lots of errors in the data.
+	 */
+	.i2c_clk_high = 0x0d,
+	.i2c_clk_low = 0x0d,
+	.regulator_names = rk3288_regulator_names,
+	.regulator_names_cnt = ARRAY_SIZE(rk3288_regulator_names),
+	.set_input_vop = rk3288_set_input_vop,
+	.clk_config = rk3288_clk_config,
+};
+
+static const char * const rk3399_regulator_names[] = {
+	"vcc1v8_hdmi",
+	"vcc0v9_hdmi"
+};
+
+static const struct rkhdmi_driverdata rk3399_driverdata = {
+	.i2c_clk_high = 0x7a,
+	.i2c_clk_low = 0x8d,
+	.regulator_names = rk3399_regulator_names,
+	.regulator_names_cnt = ARRAY_SIZE(rk3399_regulator_names),
+	.set_input_vop = rk3399_set_input_vop,
+};
+
 static const struct udevice_id rk_hdmi_ids[] = {
-	{ .compatible = "rockchip,rk3288-dw-hdmi" },
+	{ .compatible = "rockchip,rk3288-dw-hdmi",
+	  .data = (ulong)&rk3288_driverdata },
+	{ .compatible = "rockchip,rk3399-dw-hdmi",
+	  .data = (ulong)&rk3399_driverdata },
 	{ }
 };