diff mbox

[1/2] drm/exynos: hdmi: Add support for Exynos7 HDMI

Message ID 1424964285-27480-1-git-send-email-ajaykumar.rs@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ajay Kumar Feb. 26, 2015, 3:24 p.m. UTC
Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
* Add phy configs for Exynos7.
* Exynos7 has a different clock structure for HDMI,
  so introduce the new clocks.
* Add sysreg support to enable HDMI SYSREG on Exynos7.
* Exynos7 based boards need a DCDC_EN and LS_EN pins
  for powering up HDMI. Add support for that too.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
---
 .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
 drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
 drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
 3 files changed, 231 insertions(+), 46 deletions(-)

Comments

Andrzej Hajda Feb. 27, 2015, 10:48 a.m. UTC | #1
Hi Ajay,

Thanks for the patch.

On 02/26/2015 04:24 PM, Ajay Kumar wrote:
> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
> * Add phy configs for Exynos7.
> * Exynos7 has a different clock structure for HDMI,
>   so introduce the new clocks.
> * Add sysreg support to enable HDMI SYSREG on Exynos7.
> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>   for powering up HDMI. Add support for that too.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> ---
>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>  3 files changed, 231 insertions(+), 46 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
> index 1fd8cf9..bb22a60 100644
> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
> @@ -6,6 +6,7 @@ Required properties:
>  	2) "samsung,exynos4210-hdmi"
>  	3) "samsung,exynos4212-hdmi"
>  	4) "samsung,exynos5420-hdmi"
> +	5) "samsung,exynos7-hdmi"

Why not "samsung,exynos7420-hdmi" ?
What compatible will you use for Exynos7430 or higher chip number?

>  - reg: physical base address of the hdmi and length of memory mapped
>  	region.
>  - interrupts: interrupt number to the cpu.
> @@ -15,21 +16,33 @@ Required properties:
>  	c) optional flags and pull up/down.
>  - clocks: list of clock IDs from SoC clock driver.
>  	a) hdmi: Gate of HDMI IP bus clock.
> -	b) sclk_hdmi: Gate of HDMI special clock.
> -	c) sclk_pixel: Pixel special clock, one of the two possible inputs of
> +	HDMI clocks necessary for non exynos7:
> +	 b) sclk_hdmi: Gate of HDMI special clock.
> +	 c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>  		HDMI clock mux.
> -	d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
> +	 d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>  		HDMI clock mux.
> -	e) mout_hdmi: It is required by the driver to switch between the 2
> +	 e) mout_hdmi: It is required by the driver to switch between the 2
>  		parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>  		after configuration, parent is set to sclk_hdmiphy else
>  		sclk_pixel.
> +	HDMI clocks necessary for Exynos7:
> +	 b) pclk_hdmiphy: Gate to HDMIPHY clock.

According to specs there is also pclk_hdmi, why do you specify only this
one?

> +	 c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
> +	 d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.

According to specs these clocks should be named i_pixel_clk and
i_tmds_clk, shouldn't they?

>  - clock-names: aliases as per driver requirements for above clock IDs:
>  	"hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>  - ddc: phandle to the hdmi ddc node
>  - phy: phandle to the hdmi phy node
>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>  
> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
> +
> +Optional properties:
> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.

What is purpose of these gpios?

> +
>  Example:
>  
>  	hdmi {
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index 229b361..1b579ea 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -67,6 +67,7 @@
>  enum hdmi_type {
>  	HDMI_TYPE13,
>  	HDMI_TYPE14,
> +	HDMI_TYPE14_7,
>  };
>  
>  struct hdmi_driver_data {
> @@ -82,6 +83,9 @@ struct hdmi_resources {
>  	struct clk			*sclk_pixel;
>  	struct clk			*sclk_hdmiphy;
>  	struct clk			*mout_hdmi;
> +	struct clk			*hdmi_pixel;
> +	struct clk			*pclk_hdmiphy;
> +	struct clk			*hdmi_tmds;
>  	struct regulator_bulk_data	*regul_bulk;
>  	struct regulator		*reg_hdmi_en;
>  	int				regul_count;
> @@ -210,6 +214,7 @@ struct hdmi_context {
>  	unsigned int			phy_conf_count;
>  
>  	struct regmap			*pmureg;
> +	struct regmap			*sysreg;
>  	enum hdmi_type			type;
>  };
>  
> @@ -584,6 +589,61 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
>  	},
>  };
>  
> +static const struct hdmiphy_config hdmiphy_7_configs[] = {
> +	{
> +		.pixel_clock = 27000000,
> +		.conf = {
> +			0x01, 0xD2, 0x87, 0xB0, 0x01, 0x00, 0x88, 0x02,
> +			0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
> +			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0B, 0x00, 0x10,
> +			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
> +		},
> +	},
> +	{
> +		.pixel_clock = 27027000,
> +		.conf = {
> +			0x01, 0xD1, 0x5A, 0xFA, 0xE4, 0x12, 0x88, 0x43,
> +			0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
> +			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0F, 0x00, 0x10,
> +			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
> +		},
> +	},
> +	{
> +		.pixel_clock = 74176000,
> +		.conf = {
> +			0x01, 0xD1, 0x3E, 0x35, 0xDB, 0xA2, 0x88, 0x42,
> +			0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
> +			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
> +			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
> +		},
> +	},
> +	{
> +		.pixel_clock = 74250000,
> +		.conf = {
> +			0x01, 0xD1, 0x3E, 0x35, 0xC0, 0x90, 0x88, 0x42,
> +			0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
> +			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
> +			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
> +		},
> +	},
> +	{
> +		.pixel_clock = 148500000,
> +		.conf = {
> +			0x01, 0xD1, 0x3E, 0x15, 0xC0, 0x90, 0x88, 0x42,
> +			0x4F, 0x30, 0x33, 0x65, 0x20, 0xA6, 0x24, 0x80,
> +			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x01, 0x00, 0x10,
> +			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
> +		},
> +	},
> +};
> +
> +static struct hdmi_driver_data exynos7_hdmi_driver_data = {
> +	.type		= HDMI_TYPE14_7,
> +	.phy_confs	= hdmiphy_7_configs,
> +	.phy_conf_count	= ARRAY_SIZE(hdmiphy_7_configs),
> +	.is_apb_phy	= 1,
> +};
> +
>  static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
>  	.type		= HDMI_TYPE14,
>  	.phy_confs	= hdmiphy_5420_configs,
> @@ -1355,6 +1415,9 @@ static void hdmi_start(struct hdmi_context *hdata, bool start)
>  		val |= HDMI_FIELD_EN;
>  
>  	hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
> +	if (hdata->type == HDMI_TYPE14_7)
> +		hdmi_reg_writemask(hdata, HDMI_CON_0, HDMI_ENCODING_RETAIN,
> +							HDMI_ENCODING_RETAIN);
>  	hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
>  }
>  
> @@ -1489,9 +1552,11 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
>  		hdmi_regs_dump(hdata, "timing apply");
>  	}
>  
> -	clk_disable_unprepare(hdata->res.sclk_hdmi);
> -	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
> -	clk_prepare_enable(hdata->res.sclk_hdmi);
> +	if (hdata->type != HDMI_TYPE14_7) {
> +		clk_disable_unprepare(hdata->res.sclk_hdmi);
> +		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
> +		clk_prepare_enable(hdata->res.sclk_hdmi);
> +	}

If is not neccessary, hdmi_v13_mode_apply is called only for HDMI_TYPE13.

>  
>  	/* enable HDMI and timing generator */
>  	hdmi_start(hdata, true);
> @@ -1651,9 +1716,11 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
>  		hdmi_regs_dump(hdata, "timing apply");
>  	}
>  
> -	clk_disable_unprepare(hdata->res.sclk_hdmi);
> -	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
> -	clk_prepare_enable(hdata->res.sclk_hdmi);
> +	if (hdata->type != HDMI_TYPE14_7) {
> +		clk_disable_unprepare(hdata->res.sclk_hdmi);
> +		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
> +		clk_prepare_enable(hdata->res.sclk_hdmi);
> +	}
>  
>  	/* enable HDMI and timing generator */
>  	hdmi_start(hdata, true);
> @@ -1671,9 +1738,11 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>  {
>  	u32 reg;
>  
> -	clk_disable_unprepare(hdata->res.sclk_hdmi);
> -	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
> -	clk_prepare_enable(hdata->res.sclk_hdmi);
> +	if (hdata->type != HDMI_TYPE14_7) {
> +		clk_disable_unprepare(hdata->res.sclk_hdmi);
> +		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
> +		clk_prepare_enable(hdata->res.sclk_hdmi);
> +	}
>  
>  	/* operation mode */
>  	hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
> @@ -1693,7 +1762,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>  
>  static void hdmiphy_poweron(struct hdmi_context *hdata)
>  {
> -	if (hdata->type != HDMI_TYPE14)
> +	if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))
>  		return;
>  
>  	DRM_DEBUG_KMS("\n");
> @@ -1713,7 +1782,7 @@ static void hdmiphy_poweron(struct hdmi_context *hdata)
>  
>  static void hdmiphy_poweroff(struct hdmi_context *hdata)
>  {
> -	if (hdata->type != HDMI_TYPE14)
> +	if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))

It could be replaced with if (hdata->type == HDMI_TYPE13)

>  		return;
>  
>  	DRM_DEBUG_KMS("\n");
> @@ -2042,6 +2111,10 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>  		return;
>  	}
>  
> +	if (hdata->type == HDMI_TYPE14_7)
> +		regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
> +					SYSREG_HDMI_REFCLK_SEL, 1);
> +
>  	hdata->powered = true;
>  
>  	mutex_unlock(&hdata->hdmi_mutex);
> @@ -2056,7 +2129,19 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>  			PMU_HDMI_PHY_ENABLE_BIT, 1);
>  
>  	clk_prepare_enable(res->hdmi);
> -	clk_prepare_enable(res->sclk_hdmi);
> +	if (hdata->type != HDMI_TYPE14_7)
> +		clk_prepare_enable(res->sclk_hdmi);
> +	else
> +		clk_prepare_enable(res->pclk_hdmiphy);
> +
> +	if (hdata->type == HDMI_TYPE14_7)
> +		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
> +					HDMI_PHY_POWER_OFF_EN);
> +
> +	if (hdata->type == HDMI_TYPE14_7) {
> +		clk_prepare_enable(res->hdmi_pixel);
> +		clk_prepare_enable(res->hdmi_tmds);
> +	}


All ifs can be squashed.

>  
>  	hdmiphy_poweron(hdata);
>  	hdmi_commit(&hdata->display);
> @@ -2074,13 +2159,29 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
>  	/* HDMI System Disable */
>  	hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
>  
> +	if (hdata->type == HDMI_TYPE14_7) {
> +		clk_disable_unprepare(res->hdmi_pixel);
> +		clk_disable_unprepare(res->hdmi_tmds);
> +	}
> +
> +	if (hdata->type == HDMI_TYPE14_7)
> +		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
> +					HDMI_PHY_POWER_OFF_EN);

Ditto

> +
>  	hdmiphy_poweroff(hdata);
>  
>  	cancel_delayed_work(&hdata->hotplug_work);
>  
> -	clk_disable_unprepare(res->sclk_hdmi);
> +	if (hdata->type != HDMI_TYPE14_7)
> +		clk_disable_unprepare(res->sclk_hdmi);
> +	else
> +		clk_disable_unprepare(res->pclk_hdmiphy);
>  	clk_disable_unprepare(res->hdmi);
>  
> +	if (hdata->type == HDMI_TYPE14_7)
> +		regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
> +					SYSREG_HDMI_REFCLK_SEL, 0);
> +
>  	/* reset pmu hdmiphy control bit to disable hdmiphy */
>  	regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
>  			PMU_HDMI_PHY_ENABLE_BIT, 0);
> @@ -2121,10 +2222,12 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
>  		 * Below codes will try to disable Mixer and VP(if used)
>  		 * prior to disabling HDMI.
>  		 */
> -		if (crtc)
> -			funcs = crtc->helper_private;
> -		if (funcs && funcs->dpms)
> -			(*funcs->dpms)(crtc, mode);
> +		if (hdata->type != HDMI_TYPE14_7) {
> +			if (crtc)
> +				funcs = crtc->helper_private;
> +			if (funcs && funcs->dpms)
> +				(*funcs->dpms)(crtc, mode);
> +		}
>  
>  		hdmi_poweroff(hdata);
>  		break;
> @@ -2166,6 +2269,31 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
>  	return IRQ_HANDLED;
>  }
>  
> +static int hdmi_configure_gpios(struct hdmi_context *hdata)
> +{
> +	struct gpio_desc *dcdc_gpio, *lsen_gpio;
> +	int err;
> +
> +	dcdc_gpio = devm_gpiod_get_optional(hdata->dev, "dcdc", GPIOD_OUT_LOW);
> +	if (IS_ERR(dcdc_gpio)) {
> +		err = PTR_ERR(dcdc_gpio);
> +		dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
> +		return err;
> +	}
> +
> +	lsen_gpio = devm_gpiod_get_optional(hdata->dev, "lsen", GPIOD_OUT_LOW);
> +	if (IS_ERR(lsen_gpio)) {
> +		err = PTR_ERR(lsen_gpio);
> +		dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
> +		return err;
> +	}
> +
> +	gpiod_set_value(dcdc_gpio, 1);
> +	gpiod_set_value(lsen_gpio, 1);
> +
> +	return 0;
> +}
> +
>  static int hdmi_resources_init(struct hdmi_context *hdata)
>  {
>  	struct device *dev = hdata->dev;
> @@ -2179,6 +2307,10 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
>  
>  	DRM_DEBUG_KMS("HDMI resource init\n");
>  
> +	ret = hdmi_configure_gpios(hdata);
> +	if (ret)
> +		goto fail;
> +
>  	/* get clocks, power */
>  	res->hdmi = devm_clk_get(dev, "hdmi");
>  	if (IS_ERR(res->hdmi)) {
> @@ -2186,32 +2318,55 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
>  		ret = PTR_ERR(res->hdmi);
>  		goto fail;
>  	}
> -	res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
> -	if (IS_ERR(res->sclk_hdmi)) {
> -		DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
> -		ret = PTR_ERR(res->sclk_hdmi);
> -		goto fail;
> -	}
> -	res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
> -	if (IS_ERR(res->sclk_pixel)) {
> -		DRM_ERROR("failed to get clock 'sclk_pixel'\n");
> -		ret = PTR_ERR(res->sclk_pixel);
> -		goto fail;
> -	}
> -	res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
> -	if (IS_ERR(res->sclk_hdmiphy)) {
> -		DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
> -		ret = PTR_ERR(res->sclk_hdmiphy);
> -		goto fail;
> -	}
> -	res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
> -	if (IS_ERR(res->mout_hdmi)) {
> -		DRM_ERROR("failed to get clock 'mout_hdmi'\n");
> -		ret = PTR_ERR(res->mout_hdmi);
> -		goto fail;
> -	}
>  
> -	clk_set_parent(res->mout_hdmi, res->sclk_pixel);
> +	if (hdata->type != HDMI_TYPE14_7) {
> +		res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
> +		if (IS_ERR(res->sclk_hdmi)) {
> +			DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
> +			ret = PTR_ERR(res->sclk_hdmi);
> +			goto fail;
> +		}
> +		res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
> +		if (IS_ERR(res->sclk_pixel)) {
> +			DRM_ERROR("failed to get clock 'sclk_pixel'\n");
> +			ret = PTR_ERR(res->sclk_pixel);
> +			goto fail;
> +		}
> +		res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
> +		if (IS_ERR(res->sclk_hdmiphy)) {
> +			DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
> +			ret = PTR_ERR(res->sclk_hdmiphy);
> +			goto fail;
> +		}
> +		res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
> +		if (IS_ERR(res->mout_hdmi)) {
> +			DRM_ERROR("failed to get clock 'mout_hdmi'\n");
> +			ret = PTR_ERR(res->mout_hdmi);
> +			goto fail;
> +		}
> +
> +		clk_set_parent(res->mout_hdmi, res->sclk_pixel);
> +	} else {
> +
> +		res->pclk_hdmiphy = clk_get(dev, "pclk_hdmiphy");
> +		if (IS_ERR_OR_NULL(res->pclk_hdmiphy)) {

NULL clock is valid so IS_ERR_OR_NULL should be replaced with IS_ERR.

By the way, it would be nice to replace this redundant clock get code
with some helpers.


> +			DRM_ERROR("failed to get clock 'pclk_hdmiphy'\n");
> +			ret = PTR_ERR(res->pclk_hdmiphy);
> +			goto fail;
> +		}
> +		res->hdmi_pixel = clk_get(dev, "hdmi_pixel");
> +		if (IS_ERR_OR_NULL(res->hdmi_pixel)) {

ditto

> +			DRM_ERROR("failed to get clock 'hdmi_pixel'\n");
> +			ret = PTR_ERR(res->hdmi_pixel);
> +			goto fail;
> +		}
> +		res->hdmi_tmds = clk_get(dev, "hdmi_tmds");
> +		if (IS_ERR_OR_NULL(res->hdmi_tmds)) {

ditto

> +			DRM_ERROR("failed to get clock 'hdmi_tmds'\n");
> +			ret = PTR_ERR(res->hdmi_tmds);
> +			goto fail;
> +		}
> +	}
>  
>  	res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
>  		sizeof(res->regul_bulk[0]), GFP_KERNEL);
> @@ -2288,6 +2443,9 @@ static struct of_device_id hdmi_match_types[] = {
>  		.compatible = "samsung,exynos5420-hdmi",
>  		.data = &exynos5420_hdmi_driver_data,
>  	}, {
> +		.compatible = "samsung,exynos7-hdmi",
> +		.data = &exynos7_hdmi_driver_data,
> +	}, {
>  		/* end node */
>  	}
>  };
> @@ -2474,6 +2632,16 @@ out_get_phy_port:
>  		goto err_hdmiphy;
>  	}
>  
> +	if (hdata->type == HDMI_TYPE14_7) {
> +		hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
> +			"samsung,sysreg-phandle");
> +		if (IS_ERR(hdata->sysreg)) {
> +			DRM_ERROR("sysreg regmap lookup failed.\n");
> +			ret = -EPROBE_DEFER;
> +			goto err_hdmiphy;
> +		}
> +	}
> +
>  	pm_runtime_enable(dev);
>  
>  	ret = component_add(&pdev->dev, &hdmi_component_ops);
> diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
> index 3f35ac6..d6c84e0 100644
> --- a/drivers/gpu/drm/exynos/regs-hdmi.h
> +++ b/drivers/gpu/drm/exynos/regs-hdmi.h
> @@ -133,6 +133,7 @@
>  
>  /* HDMI_CON_0 */
>  #define HDMI_BLUE_SCR_EN		(1 << 5)
> +#define HDMI_ENCODING_RETAIN		(1 << 4)
>  #define HDMI_ASP_EN			(1 << 2)
>  #define HDMI_ASP_DIS			(0 << 2)
>  #define HDMI_ASP_MASK			(1 << 2)
> @@ -594,4 +595,7 @@
>  #define PMU_HDMI_PHY_CONTROL		0x700
>  #define PMU_HDMI_PHY_ENABLE_BIT		BIT(0)
>  
> +#define SYSREG_DISP_HDMI_PHY		0x838
> +#define SYSREG_HDMI_REFCLK_SEL		BIT(0)
> +
>  #endif /* SAMSUNG_REGS_HDMI_H */
>
Ajay kumar March 2, 2015, 8:40 a.m. UTC | #2
Hi Andrej,

On Fri, Feb 27, 2015 at 4:18 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> Hi Ajay,
>
> Thanks for the patch.
Thanks for reviewing the patch.

> On 02/26/2015 04:24 PM, Ajay Kumar wrote:
>> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
>> * Add phy configs for Exynos7.
>> * Exynos7 has a different clock structure for HDMI,
>>   so introduce the new clocks.
>> * Add sysreg support to enable HDMI SYSREG on Exynos7.
>> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>>   for powering up HDMI. Add support for that too.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>> ---
>>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>>  3 files changed, 231 insertions(+), 46 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>> index 1fd8cf9..bb22a60 100644
>> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>> @@ -6,6 +6,7 @@ Required properties:
>>       2) "samsung,exynos4210-hdmi"
>>       3) "samsung,exynos4212-hdmi"
>>       4) "samsung,exynos5420-hdmi"
>> +     5) "samsung,exynos7-hdmi"
>
> Why not "samsung,exynos7420-hdmi" ?
> What compatible will you use for Exynos7430 or higher chip number?
I will leave this decision to Inki Dae or Kukjin.

>>  - reg: physical base address of the hdmi and length of memory mapped
>>       region.
>>  - interrupts: interrupt number to the cpu.
>> @@ -15,21 +16,33 @@ Required properties:
>>       c) optional flags and pull up/down.
>>  - clocks: list of clock IDs from SoC clock driver.
>>       a) hdmi: Gate of HDMI IP bus clock.
>> -     b) sclk_hdmi: Gate of HDMI special clock.
>> -     c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>> +     HDMI clocks necessary for non exynos7:
>> +      b) sclk_hdmi: Gate of HDMI special clock.
>> +      c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>               HDMI clock mux.
>> -     d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>> +      d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>               HDMI clock mux.
>> -     e) mout_hdmi: It is required by the driver to switch between the 2
>> +      e) mout_hdmi: It is required by the driver to switch between the 2
>>               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>>               after configuration, parent is set to sclk_hdmiphy else
>>               sclk_pixel.
>> +     HDMI clocks necessary for Exynos7:
>> +      b) pclk_hdmiphy: Gate to HDMIPHY clock.
>
> According to specs there is also pclk_hdmi, why do you specify only this
> one?
Right, I have reused "hdmi" gating clock for pclk_hdmi. That is why I have
left "hdmi" clock as common for exynos7 and non-exynos7.

>> +      c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
>> +      d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
>
> According to specs these clocks should be named i_pixel_clk and
> i_tmds_clk, shouldn't they?
I actually took these changes from an "internal" code(non-DRM).
The original author used these names, and I just carried the same names. :)

>>  - clock-names: aliases as per driver requirements for above clock IDs:
>>       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>>  - ddc: phandle to the hdmi ddc node
>>  - phy: phandle to the hdmi phy node
>>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>>
>> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
>> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
>> +
>> +Optional properties:
>> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
>> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
>
> What is purpose of these gpios?
These 2 GPIOs need to be enabled to powerup HDMI on exynos7-espresso board.
Other boards need not provide the GPIO.

>> +
>>  Example:
>>
>>       hdmi {
>> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
>> index 229b361..1b579ea 100644
>> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
>> @@ -67,6 +67,7 @@
>>  enum hdmi_type {
>>       HDMI_TYPE13,
>>       HDMI_TYPE14,
>> +     HDMI_TYPE14_7,
>>  };
>>
>>  struct hdmi_driver_data {
>> @@ -82,6 +83,9 @@ struct hdmi_resources {
>>       struct clk                      *sclk_pixel;
>>       struct clk                      *sclk_hdmiphy;
>>       struct clk                      *mout_hdmi;
>> +     struct clk                      *hdmi_pixel;
>> +     struct clk                      *pclk_hdmiphy;
>> +     struct clk                      *hdmi_tmds;
>>       struct regulator_bulk_data      *regul_bulk;
>>       struct regulator                *reg_hdmi_en;
>>       int                             regul_count;
>> @@ -210,6 +214,7 @@ struct hdmi_context {
>>       unsigned int                    phy_conf_count;
>>
>>       struct regmap                   *pmureg;
>> +     struct regmap                   *sysreg;
>>       enum hdmi_type                  type;
>>  };
>>
>> @@ -584,6 +589,61 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = {
>>       },
>>  };
>>
>> +static const struct hdmiphy_config hdmiphy_7_configs[] = {
>> +     {
>> +             .pixel_clock = 27000000,
>> +             .conf = {
>> +                     0x01, 0xD2, 0x87, 0xB0, 0x01, 0x00, 0x88, 0x02,
>> +                     0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
>> +                     0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0B, 0x00, 0x10,
>> +                     0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
>> +             },
>> +     },
>> +     {
>> +             .pixel_clock = 27027000,
>> +             .conf = {
>> +                     0x01, 0xD1, 0x5A, 0xFA, 0xE4, 0x12, 0x88, 0x43,
>> +                     0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
>> +                     0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0F, 0x00, 0x10,
>> +                     0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
>> +             },
>> +     },
>> +     {
>> +             .pixel_clock = 74176000,
>> +             .conf = {
>> +                     0x01, 0xD1, 0x3E, 0x35, 0xDB, 0xA2, 0x88, 0x42,
>> +                     0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
>> +                     0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
>> +                     0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
>> +             },
>> +     },
>> +     {
>> +             .pixel_clock = 74250000,
>> +             .conf = {
>> +                     0x01, 0xD1, 0x3E, 0x35, 0xC0, 0x90, 0x88, 0x42,
>> +                     0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
>> +                     0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
>> +                     0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
>> +             },
>> +     },
>> +     {
>> +             .pixel_clock = 148500000,
>> +             .conf = {
>> +                     0x01, 0xD1, 0x3E, 0x15, 0xC0, 0x90, 0x88, 0x42,
>> +                     0x4F, 0x30, 0x33, 0x65, 0x20, 0xA6, 0x24, 0x80,
>> +                     0x6C, 0xF2, 0x67, 0x00, 0x10, 0x01, 0x00, 0x10,
>> +                     0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
>> +             },
>> +     },
>> +};
>> +
>> +static struct hdmi_driver_data exynos7_hdmi_driver_data = {
>> +     .type           = HDMI_TYPE14_7,
>> +     .phy_confs      = hdmiphy_7_configs,
>> +     .phy_conf_count = ARRAY_SIZE(hdmiphy_7_configs),
>> +     .is_apb_phy     = 1,
>> +};
>> +
>>  static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
>>       .type           = HDMI_TYPE14,
>>       .phy_confs      = hdmiphy_5420_configs,
>> @@ -1355,6 +1415,9 @@ static void hdmi_start(struct hdmi_context *hdata, bool start)
>>               val |= HDMI_FIELD_EN;
>>
>>       hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
>> +     if (hdata->type == HDMI_TYPE14_7)
>> +             hdmi_reg_writemask(hdata, HDMI_CON_0, HDMI_ENCODING_RETAIN,
>> +                                                     HDMI_ENCODING_RETAIN);
>>       hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
>>  }
>>
>> @@ -1489,9 +1552,11 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
>>               hdmi_regs_dump(hdata, "timing apply");
>>       }
>>
>> -     clk_disable_unprepare(hdata->res.sclk_hdmi);
>> -     clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
>> -     clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     if (hdata->type != HDMI_TYPE14_7) {
>> +             clk_disable_unprepare(hdata->res.sclk_hdmi);
>> +             clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
>> +             clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     }
>
> If is not neccessary, hdmi_v13_mode_apply is called only for HDMI_TYPE13.
Ahh, That's a nice catch. I will remove it.

>>
>>       /* enable HDMI and timing generator */
>>       hdmi_start(hdata, true);
>> @@ -1651,9 +1716,11 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
>>               hdmi_regs_dump(hdata, "timing apply");
>>       }
>>
>> -     clk_disable_unprepare(hdata->res.sclk_hdmi);
>> -     clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
>> -     clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     if (hdata->type != HDMI_TYPE14_7) {
>> +             clk_disable_unprepare(hdata->res.sclk_hdmi);
>> +             clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
>> +             clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     }
>>
>>       /* enable HDMI and timing generator */
>>       hdmi_start(hdata, true);
>> @@ -1671,9 +1738,11 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>>  {
>>       u32 reg;
>>
>> -     clk_disable_unprepare(hdata->res.sclk_hdmi);
>> -     clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
>> -     clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     if (hdata->type != HDMI_TYPE14_7) {
>> +             clk_disable_unprepare(hdata->res.sclk_hdmi);
>> +             clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
>> +             clk_prepare_enable(hdata->res.sclk_hdmi);
>> +     }
>>
>>       /* operation mode */
>>       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
>> @@ -1693,7 +1762,7 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>>
>>  static void hdmiphy_poweron(struct hdmi_context *hdata)
>>  {
>> -     if (hdata->type != HDMI_TYPE14)
>> +     if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))
>>               return;
>>
>>       DRM_DEBUG_KMS("\n");
>> @@ -1713,7 +1782,7 @@ static void hdmiphy_poweron(struct hdmi_context *hdata)
>>
>>  static void hdmiphy_poweroff(struct hdmi_context *hdata)
>>  {
>> -     if (hdata->type != HDMI_TYPE14)
>> +     if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))
>
> It could be replaced with if (hdata->type == HDMI_TYPE13)
Ok, I will change it.

>>               return;
>>
>>       DRM_DEBUG_KMS("\n");
>> @@ -2042,6 +2111,10 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>>               return;
>>       }
>>
>> +     if (hdata->type == HDMI_TYPE14_7)
>> +             regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
>> +                                     SYSREG_HDMI_REFCLK_SEL, 1);
>> +
>>       hdata->powered = true;
>>
>>       mutex_unlock(&hdata->hdmi_mutex);
>> @@ -2056,7 +2129,19 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>>                       PMU_HDMI_PHY_ENABLE_BIT, 1);
>>
>>       clk_prepare_enable(res->hdmi);
>> -     clk_prepare_enable(res->sclk_hdmi);
>> +     if (hdata->type != HDMI_TYPE14_7)
>> +             clk_prepare_enable(res->sclk_hdmi);
>> +     else
>> +             clk_prepare_enable(res->pclk_hdmiphy);
>> +
>> +     if (hdata->type == HDMI_TYPE14_7)
>> +             hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
>> +                                     HDMI_PHY_POWER_OFF_EN);
>> +
>> +     if (hdata->type == HDMI_TYPE14_7) {
>> +             clk_prepare_enable(res->hdmi_pixel);
>> +             clk_prepare_enable(res->hdmi_tmds);
>> +     }
>
>
> All ifs can be squashed.
Right, this big chunk can easily go inside a single if.

>>
>>       hdmiphy_poweron(hdata);
>>       hdmi_commit(&hdata->display);
>> @@ -2074,13 +2159,29 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
>>       /* HDMI System Disable */
>>       hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
>>
>> +     if (hdata->type == HDMI_TYPE14_7) {
>> +             clk_disable_unprepare(res->hdmi_pixel);
>> +             clk_disable_unprepare(res->hdmi_tmds);
>> +     }
>> +
>> +     if (hdata->type == HDMI_TYPE14_7)
>> +             hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
>> +                                     HDMI_PHY_POWER_OFF_EN);
>
> Ditto
Ok, one if can be removed.

>> +
>>       hdmiphy_poweroff(hdata);
>>
>>       cancel_delayed_work(&hdata->hotplug_work);
>>
>> -     clk_disable_unprepare(res->sclk_hdmi);
>> +     if (hdata->type != HDMI_TYPE14_7)
>> +             clk_disable_unprepare(res->sclk_hdmi);
>> +     else
>> +             clk_disable_unprepare(res->pclk_hdmiphy);
>>       clk_disable_unprepare(res->hdmi);
>>
>> +     if (hdata->type == HDMI_TYPE14_7)
>> +             regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
>> +                                     SYSREG_HDMI_REFCLK_SEL, 0);
>> +
>>       /* reset pmu hdmiphy control bit to disable hdmiphy */
>>       regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
>>                       PMU_HDMI_PHY_ENABLE_BIT, 0);
>> @@ -2121,10 +2222,12 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
>>                * Below codes will try to disable Mixer and VP(if used)
>>                * prior to disabling HDMI.
>>                */
>> -             if (crtc)
>> -                     funcs = crtc->helper_private;
>> -             if (funcs && funcs->dpms)
>> -                     (*funcs->dpms)(crtc, mode);
>> +             if (hdata->type != HDMI_TYPE14_7) {
>> +                     if (crtc)
>> +                             funcs = crtc->helper_private;
>> +                     if (funcs && funcs->dpms)
>> +                             (*funcs->dpms)(crtc, mode);
>> +             }
>>
>>               hdmi_poweroff(hdata);
>>               break;
>> @@ -2166,6 +2269,31 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
>>       return IRQ_HANDLED;
>>  }
>>
>> +static int hdmi_configure_gpios(struct hdmi_context *hdata)
>> +{
>> +     struct gpio_desc *dcdc_gpio, *lsen_gpio;
>> +     int err;
>> +
>> +     dcdc_gpio = devm_gpiod_get_optional(hdata->dev, "dcdc", GPIOD_OUT_LOW);
>> +     if (IS_ERR(dcdc_gpio)) {
>> +             err = PTR_ERR(dcdc_gpio);
>> +             dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
>> +             return err;
>> +     }
>> +
>> +     lsen_gpio = devm_gpiod_get_optional(hdata->dev, "lsen", GPIOD_OUT_LOW);
>> +     if (IS_ERR(lsen_gpio)) {
>> +             err = PTR_ERR(lsen_gpio);
>> +             dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
>> +             return err;
>> +     }
>> +
>> +     gpiod_set_value(dcdc_gpio, 1);
>> +     gpiod_set_value(lsen_gpio, 1);
>> +
>> +     return 0;
>> +}
>> +
>>  static int hdmi_resources_init(struct hdmi_context *hdata)
>>  {
>>       struct device *dev = hdata->dev;
>> @@ -2179,6 +2307,10 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
>>
>>       DRM_DEBUG_KMS("HDMI resource init\n");
>>
>> +     ret = hdmi_configure_gpios(hdata);
>> +     if (ret)
>> +             goto fail;
>> +
>>       /* get clocks, power */
>>       res->hdmi = devm_clk_get(dev, "hdmi");
>>       if (IS_ERR(res->hdmi)) {
>> @@ -2186,32 +2318,55 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
>>               ret = PTR_ERR(res->hdmi);
>>               goto fail;
>>       }
>> -     res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
>> -     if (IS_ERR(res->sclk_hdmi)) {
>> -             DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
>> -             ret = PTR_ERR(res->sclk_hdmi);
>> -             goto fail;
>> -     }
>> -     res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
>> -     if (IS_ERR(res->sclk_pixel)) {
>> -             DRM_ERROR("failed to get clock 'sclk_pixel'\n");
>> -             ret = PTR_ERR(res->sclk_pixel);
>> -             goto fail;
>> -     }
>> -     res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
>> -     if (IS_ERR(res->sclk_hdmiphy)) {
>> -             DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
>> -             ret = PTR_ERR(res->sclk_hdmiphy);
>> -             goto fail;
>> -     }
>> -     res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
>> -     if (IS_ERR(res->mout_hdmi)) {
>> -             DRM_ERROR("failed to get clock 'mout_hdmi'\n");
>> -             ret = PTR_ERR(res->mout_hdmi);
>> -             goto fail;
>> -     }
>>
>> -     clk_set_parent(res->mout_hdmi, res->sclk_pixel);
>> +     if (hdata->type != HDMI_TYPE14_7) {
>> +             res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
>> +             if (IS_ERR(res->sclk_hdmi)) {
>> +                     DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
>> +                     ret = PTR_ERR(res->sclk_hdmi);
>> +                     goto fail;
>> +             }
>> +             res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
>> +             if (IS_ERR(res->sclk_pixel)) {
>> +                     DRM_ERROR("failed to get clock 'sclk_pixel'\n");
>> +                     ret = PTR_ERR(res->sclk_pixel);
>> +                     goto fail;
>> +             }
>> +             res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
>> +             if (IS_ERR(res->sclk_hdmiphy)) {
>> +                     DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
>> +                     ret = PTR_ERR(res->sclk_hdmiphy);
>> +                     goto fail;
>> +             }
>> +             res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
>> +             if (IS_ERR(res->mout_hdmi)) {
>> +                     DRM_ERROR("failed to get clock 'mout_hdmi'\n");
>> +                     ret = PTR_ERR(res->mout_hdmi);
>> +                     goto fail;
>> +             }
>> +
>> +             clk_set_parent(res->mout_hdmi, res->sclk_pixel);
>> +     } else {
>> +
>> +             res->pclk_hdmiphy = clk_get(dev, "pclk_hdmiphy");
>> +             if (IS_ERR_OR_NULL(res->pclk_hdmiphy)) {
>
> NULL clock is valid so IS_ERR_OR_NULL should be replaced with IS_ERR.
Ok, I will change it.

> By the way, it would be nice to replace this redundant clock get code
> with some helpers.
like?
>
>> +                     DRM_ERROR("failed to get clock 'pclk_hdmiphy'\n");
>> +                     ret = PTR_ERR(res->pclk_hdmiphy);
>> +                     goto fail;
>> +             }
>> +             res->hdmi_pixel = clk_get(dev, "hdmi_pixel");
>> +             if (IS_ERR_OR_NULL(res->hdmi_pixel)) {
>
> ditto
>
>> +                     DRM_ERROR("failed to get clock 'hdmi_pixel'\n");
>> +                     ret = PTR_ERR(res->hdmi_pixel);
>> +                     goto fail;
>> +             }
>> +             res->hdmi_tmds = clk_get(dev, "hdmi_tmds");
>> +             if (IS_ERR_OR_NULL(res->hdmi_tmds)) {
>
> ditto
>
>> +                     DRM_ERROR("failed to get clock 'hdmi_tmds'\n");
>> +                     ret = PTR_ERR(res->hdmi_tmds);
>> +                     goto fail;
>> +             }
>> +     }
>>
>>       res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
>>               sizeof(res->regul_bulk[0]), GFP_KERNEL);
>> @@ -2288,6 +2443,9 @@ static struct of_device_id hdmi_match_types[] = {
>>               .compatible = "samsung,exynos5420-hdmi",
>>               .data = &exynos5420_hdmi_driver_data,
>>       }, {
>> +             .compatible = "samsung,exynos7-hdmi",
>> +             .data = &exynos7_hdmi_driver_data,
>> +     }, {
>>               /* end node */
>>       }
>>  };
>> @@ -2474,6 +2632,16 @@ out_get_phy_port:
>>               goto err_hdmiphy;
>>       }
>>
>> +     if (hdata->type == HDMI_TYPE14_7) {
>> +             hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
>> +                     "samsung,sysreg-phandle");
>> +             if (IS_ERR(hdata->sysreg)) {
>> +                     DRM_ERROR("sysreg regmap lookup failed.\n");
>> +                     ret = -EPROBE_DEFER;
>> +                     goto err_hdmiphy;
>> +             }
>> +     }
>> +
>>       pm_runtime_enable(dev);
>>
>>       ret = component_add(&pdev->dev, &hdmi_component_ops);
>> diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
>> index 3f35ac6..d6c84e0 100644
>> --- a/drivers/gpu/drm/exynos/regs-hdmi.h
>> +++ b/drivers/gpu/drm/exynos/regs-hdmi.h
>> @@ -133,6 +133,7 @@
>>
>>  /* HDMI_CON_0 */
>>  #define HDMI_BLUE_SCR_EN             (1 << 5)
>> +#define HDMI_ENCODING_RETAIN         (1 << 4)
>>  #define HDMI_ASP_EN                  (1 << 2)
>>  #define HDMI_ASP_DIS                 (0 << 2)
>>  #define HDMI_ASP_MASK                        (1 << 2)
>> @@ -594,4 +595,7 @@
>>  #define PMU_HDMI_PHY_CONTROL         0x700
>>  #define PMU_HDMI_PHY_ENABLE_BIT              BIT(0)
>>
>> +#define SYSREG_DISP_HDMI_PHY         0x838
>> +#define SYSREG_HDMI_REFCLK_SEL               BIT(0)
>> +
>>  #endif /* SAMSUNG_REGS_HDMI_H */
>>
>
Ajay
Andrzej Hajda March 4, 2015, 9 a.m. UTC | #3
On 03/02/2015 09:40 AM, Ajay kumar wrote:
> Hi Andrej,
>
> On Fri, Feb 27, 2015 at 4:18 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>> Hi Ajay,
>>
>> Thanks for the patch.
> Thanks for reviewing the patch.
>
>> On 02/26/2015 04:24 PM, Ajay Kumar wrote:
>>> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
>>> * Add phy configs for Exynos7.
>>> * Exynos7 has a different clock structure for HDMI,
>>>   so introduce the new clocks.
>>> * Add sysreg support to enable HDMI SYSREG on Exynos7.
>>> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>>>   for powering up HDMI. Add support for that too.
>>>
>>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>>> ---
>>>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>>>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>>>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>>>  3 files changed, 231 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>> index 1fd8cf9..bb22a60 100644
>>> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>> @@ -6,6 +6,7 @@ Required properties:
>>>       2) "samsung,exynos4210-hdmi"
>>>       3) "samsung,exynos4212-hdmi"
>>>       4) "samsung,exynos5420-hdmi"
>>> +     5) "samsung,exynos7-hdmi"
>> Why not "samsung,exynos7420-hdmi" ?
>> What compatible will you use for Exynos7430 or higher chip number?
> I will leave this decision to Inki Dae or Kukjin.
>
>>>  - reg: physical base address of the hdmi and length of memory mapped
>>>       region.
>>>  - interrupts: interrupt number to the cpu.
>>> @@ -15,21 +16,33 @@ Required properties:
>>>       c) optional flags and pull up/down.
>>>  - clocks: list of clock IDs from SoC clock driver.
>>>       a) hdmi: Gate of HDMI IP bus clock.
>>> -     b) sclk_hdmi: Gate of HDMI special clock.
>>> -     c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>> +     HDMI clocks necessary for non exynos7:
>>> +      b) sclk_hdmi: Gate of HDMI special clock.
>>> +      c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>               HDMI clock mux.
>>> -     d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>> +      d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>               HDMI clock mux.
>>> -     e) mout_hdmi: It is required by the driver to switch between the 2
>>> +      e) mout_hdmi: It is required by the driver to switch between the 2
>>>               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>>>               after configuration, parent is set to sclk_hdmiphy else
>>>               sclk_pixel.
>>> +     HDMI clocks necessary for Exynos7:
>>> +      b) pclk_hdmiphy: Gate to HDMIPHY clock.
>> According to specs there is also pclk_hdmi, why do you specify only this
>> one?
> Right, I have reused "hdmi" gating clock for pclk_hdmi. That is why I have
> left "hdmi" clock as common for exynos7 and non-exynos7.

IMO it would be better to use separate entry for pclk_hdmi.

>>> +      c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
>>> +      d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
>> According to specs these clocks should be named i_pixel_clk and
>> i_tmds_clk, shouldn't they?
> I actually took these changes from an "internal" code(non-DRM).
> The original author used these names, and I just carried the same names. :)
>
>>>  - clock-names: aliases as per driver requirements for above clock IDs:
>>>       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>>>  - ddc: phandle to the hdmi ddc node
>>>  - phy: phandle to the hdmi phy node
>>>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>>>
>>> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
>>> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
>>> +
>>> +Optional properties:
>>> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
>>> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
>> What is purpose of these gpios?
> These 2 GPIOs need to be enabled to powerup HDMI on exynos7-espresso board.
> Other boards need not provide the GPIO.

HDMI is internal IP of SoC, so it is rather not configurable via pins.
Pin names suggests they are for DC-DC converter and level shifter, I guess
these are for HDMI connector, not the HDMI IP, am I right?

Maybe better option is to use pinctrl for these gpios, or use gpio
regulator, hard
to guess without documentation.

Regards
Andrzej
Ajay kumar March 4, 2015, 9:54 a.m. UTC | #4
On Wed, Mar 4, 2015 at 2:30 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> On 03/02/2015 09:40 AM, Ajay kumar wrote:
>> Hi Andrej,
>>
>> On Fri, Feb 27, 2015 at 4:18 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>> Hi Ajay,
>>>
>>> Thanks for the patch.
>> Thanks for reviewing the patch.
>>
>>> On 02/26/2015 04:24 PM, Ajay Kumar wrote:
>>>> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
>>>> * Add phy configs for Exynos7.
>>>> * Exynos7 has a different clock structure for HDMI,
>>>>   so introduce the new clocks.
>>>> * Add sysreg support to enable HDMI SYSREG on Exynos7.
>>>> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>>>>   for powering up HDMI. Add support for that too.
>>>>
>>>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>>>> ---
>>>>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>>>>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>>>>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>>>>  3 files changed, 231 insertions(+), 46 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>> index 1fd8cf9..bb22a60 100644
>>>> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>> @@ -6,6 +6,7 @@ Required properties:
>>>>       2) "samsung,exynos4210-hdmi"
>>>>       3) "samsung,exynos4212-hdmi"
>>>>       4) "samsung,exynos5420-hdmi"
>>>> +     5) "samsung,exynos7-hdmi"
>>> Why not "samsung,exynos7420-hdmi" ?
>>> What compatible will you use for Exynos7430 or higher chip number?
>> I will leave this decision to Inki Dae or Kukjin.
>>
>>>>  - reg: physical base address of the hdmi and length of memory mapped
>>>>       region.
>>>>  - interrupts: interrupt number to the cpu.
>>>> @@ -15,21 +16,33 @@ Required properties:
>>>>       c) optional flags and pull up/down.
>>>>  - clocks: list of clock IDs from SoC clock driver.
>>>>       a) hdmi: Gate of HDMI IP bus clock.
>>>> -     b) sclk_hdmi: Gate of HDMI special clock.
>>>> -     c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>> +     HDMI clocks necessary for non exynos7:
>>>> +      b) sclk_hdmi: Gate of HDMI special clock.
>>>> +      c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>>               HDMI clock mux.
>>>> -     d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>> +      d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>>               HDMI clock mux.
>>>> -     e) mout_hdmi: It is required by the driver to switch between the 2
>>>> +      e) mout_hdmi: It is required by the driver to switch between the 2
>>>>               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>>>>               after configuration, parent is set to sclk_hdmiphy else
>>>>               sclk_pixel.
>>>> +     HDMI clocks necessary for Exynos7:
>>>> +      b) pclk_hdmiphy: Gate to HDMIPHY clock.
>>> According to specs there is also pclk_hdmi, why do you specify only this
>>> one?
>> Right, I have reused "hdmi" gating clock for pclk_hdmi. That is why I have
>> left "hdmi" clock as common for exynos7 and non-exynos7.
>
> IMO it would be better to use separate entry for pclk_hdmi.
Ok.

>>>> +      c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
>>>> +      d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
>>> According to specs these clocks should be named i_pixel_clk and
>>> i_tmds_clk, shouldn't they?
>> I actually took these changes from an "internal" code(non-DRM).
>> The original author used these names, and I just carried the same names. :)
>>
>>>>  - clock-names: aliases as per driver requirements for above clock IDs:
>>>>       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>>>>  - ddc: phandle to the hdmi ddc node
>>>>  - phy: phandle to the hdmi phy node
>>>>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>>>>
>>>> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
>>>> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
>>>> +
>>>> +Optional properties:
>>>> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
>>>> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
>>> What is purpose of these gpios?
>> These 2 GPIOs need to be enabled to powerup HDMI on exynos7-espresso board.
>> Other boards need not provide the GPIO.
>
> HDMI is internal IP of SoC, so it is rather not configurable via pins.
> Pin names suggests they are for DC-DC converter and level shifter, I guess
> these are for HDMI connector, not the HDMI IP, am I right?
Right, this is for HDMI connector.

> Maybe better option is to use pinctrl for these gpios, or use gpio
> regulator, hard
> to guess without documentation.
Why should I not use devm_gpiod_get_optional for these GPIOs?

Ajay
Andrzej Hajda March 4, 2015, 10:32 a.m. UTC | #5
On 03/04/2015 10:54 AM, Ajay kumar wrote:
> On Wed, Mar 4, 2015 at 2:30 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>> On 03/02/2015 09:40 AM, Ajay kumar wrote:
>>> Hi Andrej,
>>>
>>> On Fri, Feb 27, 2015 at 4:18 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>>> Hi Ajay,
>>>>
>>>> Thanks for the patch.
>>> Thanks for reviewing the patch.
>>>
>>>> On 02/26/2015 04:24 PM, Ajay Kumar wrote:
>>>>> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
>>>>> * Add phy configs for Exynos7.
>>>>> * Exynos7 has a different clock structure for HDMI,
>>>>>   so introduce the new clocks.
>>>>> * Add sysreg support to enable HDMI SYSREG on Exynos7.
>>>>> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>>>>>   for powering up HDMI. Add support for that too.
>>>>>
>>>>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>>>>> ---
>>>>>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>>>>>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>>>>>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>>>>>  3 files changed, 231 insertions(+), 46 deletions(-)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>> index 1fd8cf9..bb22a60 100644
>>>>> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>> @@ -6,6 +6,7 @@ Required properties:
>>>>>       2) "samsung,exynos4210-hdmi"
>>>>>       3) "samsung,exynos4212-hdmi"
>>>>>       4) "samsung,exynos5420-hdmi"
>>>>> +     5) "samsung,exynos7-hdmi"
>>>> Why not "samsung,exynos7420-hdmi" ?
>>>> What compatible will you use for Exynos7430 or higher chip number?
>>> I will leave this decision to Inki Dae or Kukjin.
>>>
>>>>>  - reg: physical base address of the hdmi and length of memory mapped
>>>>>       region.
>>>>>  - interrupts: interrupt number to the cpu.
>>>>> @@ -15,21 +16,33 @@ Required properties:
>>>>>       c) optional flags and pull up/down.
>>>>>  - clocks: list of clock IDs from SoC clock driver.
>>>>>       a) hdmi: Gate of HDMI IP bus clock.
>>>>> -     b) sclk_hdmi: Gate of HDMI special clock.
>>>>> -     c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>>> +     HDMI clocks necessary for non exynos7:
>>>>> +      b) sclk_hdmi: Gate of HDMI special clock.
>>>>> +      c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>>>               HDMI clock mux.
>>>>> -     d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>>> +      d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>>>               HDMI clock mux.
>>>>> -     e) mout_hdmi: It is required by the driver to switch between the 2
>>>>> +      e) mout_hdmi: It is required by the driver to switch between the 2
>>>>>               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>>>>>               after configuration, parent is set to sclk_hdmiphy else
>>>>>               sclk_pixel.
>>>>> +     HDMI clocks necessary for Exynos7:
>>>>> +      b) pclk_hdmiphy: Gate to HDMIPHY clock.
>>>> According to specs there is also pclk_hdmi, why do you specify only this
>>>> one?
>>> Right, I have reused "hdmi" gating clock for pclk_hdmi. That is why I have
>>> left "hdmi" clock as common for exynos7 and non-exynos7.
>> IMO it would be better to use separate entry for pclk_hdmi.
> Ok.
>
>>>>> +      c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
>>>>> +      d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
>>>> According to specs these clocks should be named i_pixel_clk and
>>>> i_tmds_clk, shouldn't they?
>>> I actually took these changes from an "internal" code(non-DRM).
>>> The original author used these names, and I just carried the same names. :)
>>>
>>>>>  - clock-names: aliases as per driver requirements for above clock IDs:
>>>>>       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>>>>>  - ddc: phandle to the hdmi ddc node
>>>>>  - phy: phandle to the hdmi phy node
>>>>>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>>>>>
>>>>> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
>>>>> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
>>>>> +
>>>>> +Optional properties:
>>>>> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
>>>>> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
>>>> What is purpose of these gpios?
>>> These 2 GPIOs need to be enabled to powerup HDMI on exynos7-espresso board.
>>> Other boards need not provide the GPIO.
>> HDMI is internal IP of SoC, so it is rather not configurable via pins.
>> Pin names suggests they are for DC-DC converter and level shifter, I guess
>> these are for HDMI connector, not the HDMI IP, am I right?
> Right, this is for HDMI connector.
>
>> Maybe better option is to use pinctrl for these gpios, or use gpio
>> regulator, hard
>> to guess without documentation.
> Why should I not use devm_gpiod_get_optional for these GPIOs?

Because these gpios are board specific so they should not be handled by
hdmi driver.

I still do not know what exactly are they for.
If they only drive power for pin18 of hdmi connector the best solution
is to create
gpio regulator and point to it hdmi-en-supply property in hdmi node, as
this is the role of this property.
I guess it should work for you.
If they are used for some other things(??) and cannot be handled using
existing mechanisms
you can try to handle it using pinctrl property in hdmi - it should set
gpios correctly without polluting
the driver and bindings with board specific code/properties.

Regards
Andrzej

>
> Ajay
>
Ajay kumar March 4, 2015, 12:42 p.m. UTC | #6
On Wed, Mar 4, 2015 at 4:02 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
> On 03/04/2015 10:54 AM, Ajay kumar wrote:
>> On Wed, Mar 4, 2015 at 2:30 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>> On 03/02/2015 09:40 AM, Ajay kumar wrote:
>>>> Hi Andrej,
>>>>
>>>> On Fri, Feb 27, 2015 at 4:18 PM, Andrzej Hajda <a.hajda@samsung.com> wrote:
>>>>> Hi Ajay,
>>>>>
>>>>> Thanks for the patch.
>>>> Thanks for reviewing the patch.
>>>>
>>>>> On 02/26/2015 04:24 PM, Ajay Kumar wrote:
>>>>>> Modify the exynos HDMI driver to support Exynos7 HDMI 1.4.
>>>>>> * Add phy configs for Exynos7.
>>>>>> * Exynos7 has a different clock structure for HDMI,
>>>>>>   so introduce the new clocks.
>>>>>> * Add sysreg support to enable HDMI SYSREG on Exynos7.
>>>>>> * Exynos7 based boards need a DCDC_EN and LS_EN pins
>>>>>>   for powering up HDMI. Add support for that too.
>>>>>>
>>>>>> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
>>>>>> ---
>>>>>>  .../devicetree/bindings/video/exynos_hdmi.txt      |   21 +-
>>>>>>  drivers/gpu/drm/exynos/exynos_hdmi.c               |  252 ++++++++++++++++----
>>>>>>  drivers/gpu/drm/exynos/regs-hdmi.h                 |    4 +
>>>>>>  3 files changed, 231 insertions(+), 46 deletions(-)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>>> index 1fd8cf9..bb22a60 100644
>>>>>> --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>>> +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
>>>>>> @@ -6,6 +6,7 @@ Required properties:
>>>>>>       2) "samsung,exynos4210-hdmi"
>>>>>>       3) "samsung,exynos4212-hdmi"
>>>>>>       4) "samsung,exynos5420-hdmi"
>>>>>> +     5) "samsung,exynos7-hdmi"
>>>>> Why not "samsung,exynos7420-hdmi" ?
>>>>> What compatible will you use for Exynos7430 or higher chip number?
>>>> I will leave this decision to Inki Dae or Kukjin.
>>>>
>>>>>>  - reg: physical base address of the hdmi and length of memory mapped
>>>>>>       region.
>>>>>>  - interrupts: interrupt number to the cpu.
>>>>>> @@ -15,21 +16,33 @@ Required properties:
>>>>>>       c) optional flags and pull up/down.
>>>>>>  - clocks: list of clock IDs from SoC clock driver.
>>>>>>       a) hdmi: Gate of HDMI IP bus clock.
>>>>>> -     b) sclk_hdmi: Gate of HDMI special clock.
>>>>>> -     c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>>>> +     HDMI clocks necessary for non exynos7:
>>>>>> +      b) sclk_hdmi: Gate of HDMI special clock.
>>>>>> +      c) sclk_pixel: Pixel special clock, one of the two possible inputs of
>>>>>>               HDMI clock mux.
>>>>>> -     d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>>>> +      d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
>>>>>>               HDMI clock mux.
>>>>>> -     e) mout_hdmi: It is required by the driver to switch between the 2
>>>>>> +      e) mout_hdmi: It is required by the driver to switch between the 2
>>>>>>               parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
>>>>>>               after configuration, parent is set to sclk_hdmiphy else
>>>>>>               sclk_pixel.
>>>>>> +     HDMI clocks necessary for Exynos7:
>>>>>> +      b) pclk_hdmiphy: Gate to HDMIPHY clock.
>>>>> According to specs there is also pclk_hdmi, why do you specify only this
>>>>> one?
>>>> Right, I have reused "hdmi" gating clock for pclk_hdmi. That is why I have
>>>> left "hdmi" clock as common for exynos7 and non-exynos7.
>>> IMO it would be better to use separate entry for pclk_hdmi.
>> Ok.
>>
>>>>>> +      c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
>>>>>> +      d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
>>>>> According to specs these clocks should be named i_pixel_clk and
>>>>> i_tmds_clk, shouldn't they?
>>>> I actually took these changes from an "internal" code(non-DRM).
>>>> The original author used these names, and I just carried the same names. :)
>>>>
>>>>>>  - clock-names: aliases as per driver requirements for above clock IDs:
>>>>>>       "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
>>>>>>  - ddc: phandle to the hdmi ddc node
>>>>>>  - phy: phandle to the hdmi phy node
>>>>>>  - samsung,syscon-phandle: phandle for system controller node for PMU.
>>>>>>
>>>>>> +Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
>>>>>> +- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
>>>>>> +
>>>>>> +Optional properties:
>>>>>> +- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
>>>>>> +- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
>>>>> What is purpose of these gpios?
>>>> These 2 GPIOs need to be enabled to powerup HDMI on exynos7-espresso board.
>>>> Other boards need not provide the GPIO.
>>> HDMI is internal IP of SoC, so it is rather not configurable via pins.
>>> Pin names suggests they are for DC-DC converter and level shifter, I guess
>>> these are for HDMI connector, not the HDMI IP, am I right?
>> Right, this is for HDMI connector.
>>
>>> Maybe better option is to use pinctrl for these gpios, or use gpio
>>> regulator, hard
>>> to guess without documentation.
>> Why should I not use devm_gpiod_get_optional for these GPIOs?
>
> Because these gpios are board specific so they should not be handled by
> hdmi driver.
>
> I still do not know what exactly are they for.
> If they only drive power for pin18 of hdmi connector the best solution
> is to create
> gpio regulator and point to it hdmi-en-supply property in hdmi node, as
> this is the role of this property.
> I guess it should work for you.
> If they are used for some other things(??) and cannot be handled using
> existing mechanisms
> you can try to handle it using pinctrl property in hdmi - it should set
> gpios correctly without polluting
> the driver and bindings with board specific code/properties.
Ok. I will remove this change from the driver.
Did you have a look at my comments for the other patch(DECON-EXT)?

Ajay
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
index 1fd8cf9..bb22a60 100644
--- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
+++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
@@ -6,6 +6,7 @@  Required properties:
 	2) "samsung,exynos4210-hdmi"
 	3) "samsung,exynos4212-hdmi"
 	4) "samsung,exynos5420-hdmi"
+	5) "samsung,exynos7-hdmi"
 - reg: physical base address of the hdmi and length of memory mapped
 	region.
 - interrupts: interrupt number to the cpu.
@@ -15,21 +16,33 @@  Required properties:
 	c) optional flags and pull up/down.
 - clocks: list of clock IDs from SoC clock driver.
 	a) hdmi: Gate of HDMI IP bus clock.
-	b) sclk_hdmi: Gate of HDMI special clock.
-	c) sclk_pixel: Pixel special clock, one of the two possible inputs of
+	HDMI clocks necessary for non exynos7:
+	 b) sclk_hdmi: Gate of HDMI special clock.
+	 c) sclk_pixel: Pixel special clock, one of the two possible inputs of
 		HDMI clock mux.
-	d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
+	 d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of
 		HDMI clock mux.
-	e) mout_hdmi: It is required by the driver to switch between the 2
+	 e) mout_hdmi: It is required by the driver to switch between the 2
 		parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable
 		after configuration, parent is set to sclk_hdmiphy else
 		sclk_pixel.
+	HDMI clocks necessary for Exynos7:
+	 b) pclk_hdmiphy: Gate to HDMIPHY clock.
+	 c) hdmi_pixel: Gate clock of MUX output for I_PIXEL_CLK.
+	 d) hdmi_tmds: Gate clock of MUX output for I_TMDS_CLK.
 - clock-names: aliases as per driver requirements for above clock IDs:
 	"hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
 - ddc: phandle to the hdmi ddc node
 - phy: phandle to the hdmi phy node
 - samsung,syscon-phandle: phandle for system controller node for PMU.
 
+Only for Exynos7(when compatible = "samsung,exynos7-hdmi"):
+- samsung,sysreg-phandle: phandle for system controller node for SYSREG block.
+
+Optional properties:
+- dcdc-gpios: OF device-tree gpio specification for HDMI_DCDC_EN pin.
+- lsen-gpios: OF device-tree gpio specification for HDMI_LS_EN pin.
+
 Example:
 
 	hdmi {
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 229b361..1b579ea 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -67,6 +67,7 @@ 
 enum hdmi_type {
 	HDMI_TYPE13,
 	HDMI_TYPE14,
+	HDMI_TYPE14_7,
 };
 
 struct hdmi_driver_data {
@@ -82,6 +83,9 @@  struct hdmi_resources {
 	struct clk			*sclk_pixel;
 	struct clk			*sclk_hdmiphy;
 	struct clk			*mout_hdmi;
+	struct clk			*hdmi_pixel;
+	struct clk			*pclk_hdmiphy;
+	struct clk			*hdmi_tmds;
 	struct regulator_bulk_data	*regul_bulk;
 	struct regulator		*reg_hdmi_en;
 	int				regul_count;
@@ -210,6 +214,7 @@  struct hdmi_context {
 	unsigned int			phy_conf_count;
 
 	struct regmap			*pmureg;
+	struct regmap			*sysreg;
 	enum hdmi_type			type;
 };
 
@@ -584,6 +589,61 @@  static const struct hdmiphy_config hdmiphy_5420_configs[] = {
 	},
 };
 
+static const struct hdmiphy_config hdmiphy_7_configs[] = {
+	{
+		.pixel_clock = 27000000,
+		.conf = {
+			0x01, 0xD2, 0x87, 0xB0, 0x01, 0x00, 0x88, 0x02,
+			0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
+			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0B, 0x00, 0x10,
+			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
+		},
+	},
+	{
+		.pixel_clock = 27027000,
+		.conf = {
+			0x01, 0xD1, 0x5A, 0xFA, 0xE4, 0x12, 0x88, 0x43,
+			0x4F, 0x30, 0x33, 0x65, 0x00, 0xE4, 0x24, 0x80,
+			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x0F, 0x00, 0x10,
+			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
+		},
+	},
+	{
+		.pixel_clock = 74176000,
+		.conf = {
+			0x01, 0xD1, 0x3E, 0x35, 0xDB, 0xA2, 0x88, 0x42,
+			0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
+			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
+			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
+		},
+	},
+	{
+		.pixel_clock = 74250000,
+		.conf = {
+			0x01, 0xD1, 0x3E, 0x35, 0xC0, 0x90, 0x88, 0x42,
+			0x4F, 0x30, 0x33, 0x65, 0x10, 0xA6, 0x24, 0x80,
+			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x03, 0x00, 0x10,
+			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
+		},
+	},
+	{
+		.pixel_clock = 148500000,
+		.conf = {
+			0x01, 0xD1, 0x3E, 0x15, 0xC0, 0x90, 0x88, 0x42,
+			0x4F, 0x30, 0x33, 0x65, 0x20, 0xA6, 0x24, 0x80,
+			0x6C, 0xF2, 0x67, 0x00, 0x10, 0x01, 0x00, 0x10,
+			0x60, 0x0F, 0x00, 0x00, 0x08, 0x00, 0x3E, 0x00,
+		},
+	},
+};
+
+static struct hdmi_driver_data exynos7_hdmi_driver_data = {
+	.type		= HDMI_TYPE14_7,
+	.phy_confs	= hdmiphy_7_configs,
+	.phy_conf_count	= ARRAY_SIZE(hdmiphy_7_configs),
+	.is_apb_phy	= 1,
+};
+
 static struct hdmi_driver_data exynos5420_hdmi_driver_data = {
 	.type		= HDMI_TYPE14,
 	.phy_confs	= hdmiphy_5420_configs,
@@ -1355,6 +1415,9 @@  static void hdmi_start(struct hdmi_context *hdata, bool start)
 		val |= HDMI_FIELD_EN;
 
 	hdmi_reg_writemask(hdata, HDMI_CON_0, val, HDMI_EN);
+	if (hdata->type == HDMI_TYPE14_7)
+		hdmi_reg_writemask(hdata, HDMI_CON_0, HDMI_ENCODING_RETAIN,
+							HDMI_ENCODING_RETAIN);
 	hdmi_reg_writemask(hdata, HDMI_TG_CMD, val, HDMI_TG_EN | HDMI_FIELD_EN);
 }
 
@@ -1489,9 +1552,11 @@  static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
 		hdmi_regs_dump(hdata, "timing apply");
 	}
 
-	clk_disable_unprepare(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
-	clk_prepare_enable(hdata->res.sclk_hdmi);
+	if (hdata->type != HDMI_TYPE14_7) {
+		clk_disable_unprepare(hdata->res.sclk_hdmi);
+		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+		clk_prepare_enable(hdata->res.sclk_hdmi);
+	}
 
 	/* enable HDMI and timing generator */
 	hdmi_start(hdata, true);
@@ -1651,9 +1716,11 @@  static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
 		hdmi_regs_dump(hdata, "timing apply");
 	}
 
-	clk_disable_unprepare(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
-	clk_prepare_enable(hdata->res.sclk_hdmi);
+	if (hdata->type != HDMI_TYPE14_7) {
+		clk_disable_unprepare(hdata->res.sclk_hdmi);
+		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+		clk_prepare_enable(hdata->res.sclk_hdmi);
+	}
 
 	/* enable HDMI and timing generator */
 	hdmi_start(hdata, true);
@@ -1671,9 +1738,11 @@  static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 {
 	u32 reg;
 
-	clk_disable_unprepare(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
-	clk_prepare_enable(hdata->res.sclk_hdmi);
+	if (hdata->type != HDMI_TYPE14_7) {
+		clk_disable_unprepare(hdata->res.sclk_hdmi);
+		clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
+		clk_prepare_enable(hdata->res.sclk_hdmi);
+	}
 
 	/* operation mode */
 	hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
@@ -1693,7 +1762,7 @@  static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 
 static void hdmiphy_poweron(struct hdmi_context *hdata)
 {
-	if (hdata->type != HDMI_TYPE14)
+	if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))
 		return;
 
 	DRM_DEBUG_KMS("\n");
@@ -1713,7 +1782,7 @@  static void hdmiphy_poweron(struct hdmi_context *hdata)
 
 static void hdmiphy_poweroff(struct hdmi_context *hdata)
 {
-	if (hdata->type != HDMI_TYPE14)
+	if ((hdata->type != HDMI_TYPE14) || (hdata->type != HDMI_TYPE14_7))
 		return;
 
 	DRM_DEBUG_KMS("\n");
@@ -2042,6 +2111,10 @@  static void hdmi_poweron(struct hdmi_context *hdata)
 		return;
 	}
 
+	if (hdata->type == HDMI_TYPE14_7)
+		regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
+					SYSREG_HDMI_REFCLK_SEL, 1);
+
 	hdata->powered = true;
 
 	mutex_unlock(&hdata->hdmi_mutex);
@@ -2056,7 +2129,19 @@  static void hdmi_poweron(struct hdmi_context *hdata)
 			PMU_HDMI_PHY_ENABLE_BIT, 1);
 
 	clk_prepare_enable(res->hdmi);
-	clk_prepare_enable(res->sclk_hdmi);
+	if (hdata->type != HDMI_TYPE14_7)
+		clk_prepare_enable(res->sclk_hdmi);
+	else
+		clk_prepare_enable(res->pclk_hdmiphy);
+
+	if (hdata->type == HDMI_TYPE14_7)
+		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
+					HDMI_PHY_POWER_OFF_EN);
+
+	if (hdata->type == HDMI_TYPE14_7) {
+		clk_prepare_enable(res->hdmi_pixel);
+		clk_prepare_enable(res->hdmi_tmds);
+	}
 
 	hdmiphy_poweron(hdata);
 	hdmi_commit(&hdata->display);
@@ -2074,13 +2159,29 @@  static void hdmi_poweroff(struct hdmi_context *hdata)
 	/* HDMI System Disable */
 	hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
 
+	if (hdata->type == HDMI_TYPE14_7) {
+		clk_disable_unprepare(res->hdmi_pixel);
+		clk_disable_unprepare(res->hdmi_tmds);
+	}
+
+	if (hdata->type == HDMI_TYPE14_7)
+		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
+					HDMI_PHY_POWER_OFF_EN);
+
 	hdmiphy_poweroff(hdata);
 
 	cancel_delayed_work(&hdata->hotplug_work);
 
-	clk_disable_unprepare(res->sclk_hdmi);
+	if (hdata->type != HDMI_TYPE14_7)
+		clk_disable_unprepare(res->sclk_hdmi);
+	else
+		clk_disable_unprepare(res->pclk_hdmiphy);
 	clk_disable_unprepare(res->hdmi);
 
+	if (hdata->type == HDMI_TYPE14_7)
+		regmap_update_bits(hdata->sysreg, SYSREG_DISP_HDMI_PHY,
+					SYSREG_HDMI_REFCLK_SEL, 0);
+
 	/* reset pmu hdmiphy control bit to disable hdmiphy */
 	regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
 			PMU_HDMI_PHY_ENABLE_BIT, 0);
@@ -2121,10 +2222,12 @@  static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 		 * Below codes will try to disable Mixer and VP(if used)
 		 * prior to disabling HDMI.
 		 */
-		if (crtc)
-			funcs = crtc->helper_private;
-		if (funcs && funcs->dpms)
-			(*funcs->dpms)(crtc, mode);
+		if (hdata->type != HDMI_TYPE14_7) {
+			if (crtc)
+				funcs = crtc->helper_private;
+			if (funcs && funcs->dpms)
+				(*funcs->dpms)(crtc, mode);
+		}
 
 		hdmi_poweroff(hdata);
 		break;
@@ -2166,6 +2269,31 @@  static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
+static int hdmi_configure_gpios(struct hdmi_context *hdata)
+{
+	struct gpio_desc *dcdc_gpio, *lsen_gpio;
+	int err;
+
+	dcdc_gpio = devm_gpiod_get_optional(hdata->dev, "dcdc", GPIOD_OUT_LOW);
+	if (IS_ERR(dcdc_gpio)) {
+		err = PTR_ERR(dcdc_gpio);
+		dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
+		return err;
+	}
+
+	lsen_gpio = devm_gpiod_get_optional(hdata->dev, "lsen", GPIOD_OUT_LOW);
+	if (IS_ERR(lsen_gpio)) {
+		err = PTR_ERR(lsen_gpio);
+		dev_err(hdata->dev, "failed to request GPIO: %d\n", err);
+		return err;
+	}
+
+	gpiod_set_value(dcdc_gpio, 1);
+	gpiod_set_value(lsen_gpio, 1);
+
+	return 0;
+}
+
 static int hdmi_resources_init(struct hdmi_context *hdata)
 {
 	struct device *dev = hdata->dev;
@@ -2179,6 +2307,10 @@  static int hdmi_resources_init(struct hdmi_context *hdata)
 
 	DRM_DEBUG_KMS("HDMI resource init\n");
 
+	ret = hdmi_configure_gpios(hdata);
+	if (ret)
+		goto fail;
+
 	/* get clocks, power */
 	res->hdmi = devm_clk_get(dev, "hdmi");
 	if (IS_ERR(res->hdmi)) {
@@ -2186,32 +2318,55 @@  static int hdmi_resources_init(struct hdmi_context *hdata)
 		ret = PTR_ERR(res->hdmi);
 		goto fail;
 	}
-	res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
-	if (IS_ERR(res->sclk_hdmi)) {
-		DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
-		ret = PTR_ERR(res->sclk_hdmi);
-		goto fail;
-	}
-	res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
-	if (IS_ERR(res->sclk_pixel)) {
-		DRM_ERROR("failed to get clock 'sclk_pixel'\n");
-		ret = PTR_ERR(res->sclk_pixel);
-		goto fail;
-	}
-	res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
-	if (IS_ERR(res->sclk_hdmiphy)) {
-		DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
-		ret = PTR_ERR(res->sclk_hdmiphy);
-		goto fail;
-	}
-	res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
-	if (IS_ERR(res->mout_hdmi)) {
-		DRM_ERROR("failed to get clock 'mout_hdmi'\n");
-		ret = PTR_ERR(res->mout_hdmi);
-		goto fail;
-	}
 
-	clk_set_parent(res->mout_hdmi, res->sclk_pixel);
+	if (hdata->type != HDMI_TYPE14_7) {
+		res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+		if (IS_ERR(res->sclk_hdmi)) {
+			DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
+			ret = PTR_ERR(res->sclk_hdmi);
+			goto fail;
+		}
+		res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
+		if (IS_ERR(res->sclk_pixel)) {
+			DRM_ERROR("failed to get clock 'sclk_pixel'\n");
+			ret = PTR_ERR(res->sclk_pixel);
+			goto fail;
+		}
+		res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
+		if (IS_ERR(res->sclk_hdmiphy)) {
+			DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
+			ret = PTR_ERR(res->sclk_hdmiphy);
+			goto fail;
+		}
+		res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
+		if (IS_ERR(res->mout_hdmi)) {
+			DRM_ERROR("failed to get clock 'mout_hdmi'\n");
+			ret = PTR_ERR(res->mout_hdmi);
+			goto fail;
+		}
+
+		clk_set_parent(res->mout_hdmi, res->sclk_pixel);
+	} else {
+
+		res->pclk_hdmiphy = clk_get(dev, "pclk_hdmiphy");
+		if (IS_ERR_OR_NULL(res->pclk_hdmiphy)) {
+			DRM_ERROR("failed to get clock 'pclk_hdmiphy'\n");
+			ret = PTR_ERR(res->pclk_hdmiphy);
+			goto fail;
+		}
+		res->hdmi_pixel = clk_get(dev, "hdmi_pixel");
+		if (IS_ERR_OR_NULL(res->hdmi_pixel)) {
+			DRM_ERROR("failed to get clock 'hdmi_pixel'\n");
+			ret = PTR_ERR(res->hdmi_pixel);
+			goto fail;
+		}
+		res->hdmi_tmds = clk_get(dev, "hdmi_tmds");
+		if (IS_ERR_OR_NULL(res->hdmi_tmds)) {
+			DRM_ERROR("failed to get clock 'hdmi_tmds'\n");
+			ret = PTR_ERR(res->hdmi_tmds);
+			goto fail;
+		}
+	}
 
 	res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
 		sizeof(res->regul_bulk[0]), GFP_KERNEL);
@@ -2288,6 +2443,9 @@  static struct of_device_id hdmi_match_types[] = {
 		.compatible = "samsung,exynos5420-hdmi",
 		.data = &exynos5420_hdmi_driver_data,
 	}, {
+		.compatible = "samsung,exynos7-hdmi",
+		.data = &exynos7_hdmi_driver_data,
+	}, {
 		/* end node */
 	}
 };
@@ -2474,6 +2632,16 @@  out_get_phy_port:
 		goto err_hdmiphy;
 	}
 
+	if (hdata->type == HDMI_TYPE14_7) {
+		hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
+			"samsung,sysreg-phandle");
+		if (IS_ERR(hdata->sysreg)) {
+			DRM_ERROR("sysreg regmap lookup failed.\n");
+			ret = -EPROBE_DEFER;
+			goto err_hdmiphy;
+		}
+	}
+
 	pm_runtime_enable(dev);
 
 	ret = component_add(&pdev->dev, &hdmi_component_ops);
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 3f35ac6..d6c84e0 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -133,6 +133,7 @@ 
 
 /* HDMI_CON_0 */
 #define HDMI_BLUE_SCR_EN		(1 << 5)
+#define HDMI_ENCODING_RETAIN		(1 << 4)
 #define HDMI_ASP_EN			(1 << 2)
 #define HDMI_ASP_DIS			(0 << 2)
 #define HDMI_ASP_MASK			(1 << 2)
@@ -594,4 +595,7 @@ 
 #define PMU_HDMI_PHY_CONTROL		0x700
 #define PMU_HDMI_PHY_ENABLE_BIT		BIT(0)
 
+#define SYSREG_DISP_HDMI_PHY		0x838
+#define SYSREG_HDMI_REFCLK_SEL		BIT(0)
+
 #endif /* SAMSUNG_REGS_HDMI_H */