[v2,1/9] drm/i915: Implement WaEnableHDMI8bpcBefore12bpc:snb, ivb
diff mbox

Message ID 1430834787-10255-2-git-send-email-ville.syrjala@linux.intel.com
State New
Headers show

Commit Message

Ville Syrjala May 5, 2015, 2:06 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement
it, and to keep things neat pull the code into a function.

v2: Rebased due to crtc->config changes
    s/HDMI_GC/HDMIUNIT_GC/ to match spec better
    Factor out intel_enable_hdmi_audio()

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h   |  1 +
 drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++++++----
 2 files changed, 69 insertions(+), 6 deletions(-)

Comments

Jani Nikula May 5, 2015, 2:24 p.m. UTC | #1
On Tue, 05 May 2015, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement
> it, and to keep things neat pull the code into a function.
>
> v2: Rebased due to crtc->config changes
>     s/HDMI_GC/HDMIUNIT_GC/ to match spec better
>     Factor out intel_enable_hdmi_audio()
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |  1 +
>  drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++++++----
>  2 files changed, 69 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 2339ffa..e619e41 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -6149,6 +6149,7 @@ enum skl_disp_power_wells {
>  #define _TRANSA_CHICKEN1	 0xf0060
>  #define _TRANSB_CHICKEN1	 0xf1060
>  #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
> +#define  TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE	(1<<10)
>  #define  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE	(1<<4)
>  #define _TRANSA_CHICKEN2	 0xf0064
>  #define _TRANSB_CHICKEN2	 0xf1064
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index a84c040..79cf445 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -814,6 +814,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
>  }
>  
> +static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +
> +	WARN_ON(!crtc->config->has_hdmi_sink);
> +	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
> +			 pipe_name(crtc->pipe));

The debug message is redundant and should've been removed with the audio
rework, as there's plenty of debug in intel_audio.c. Please just drop it
here.

With that gone, I'm not so sure if it makes sense to have a separate
function for audio enable. But up to you.

BR,
Jani.


> +	intel_audio_codec_enable(encoder);
> +}
> +
>  static void intel_enable_hdmi(struct intel_encoder *encoder)
>  {
>  	struct drm_device *dev = encoder->base.dev;
> @@ -854,12 +864,61 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
>  		POSTING_READ(intel_hdmi->hdmi_reg);
>  	}
>  
> -	if (intel_crtc->config->has_audio) {
> -		WARN_ON(!intel_crtc->config->has_hdmi_sink);
> -		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
> -				 pipe_name(intel_crtc->pipe));
> -		intel_audio_codec_enable(encoder);
> +	if (intel_crtc->config->has_audio)
> +		intel_enable_hdmi_audio(encoder);
> +}
> +
> +static void cpt_enable_hdmi(struct intel_encoder *encoder)
> +{
> +	struct drm_device *dev = encoder->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> +	enum pipe pipe = crtc->pipe;
> +	u32 temp;
> +
> +	temp = I915_READ(intel_hdmi->hdmi_reg);
> +
> +	temp |= SDVO_ENABLE;
> +	if (crtc->config->has_audio)
> +		temp |= SDVO_AUDIO_ENABLE;
> +
> +	/*
> +	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb
> +	 *
> +	 * The procedure for 12bpc is as follows:
> +	 * 1. disable HDMI clock gating
> +	 * 2. enable HDMI with 8bpc
> +	 * 3. enable HDMI with 12bpc
> +	 * 4. enable HDMI clock gating
> +	 */
> +
> +	if (crtc->config->pipe_bpp > 24) {
> +		I915_WRITE(TRANS_CHICKEN1(pipe),
> +			   I915_READ(TRANS_CHICKEN1(pipe)) |
> +			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
> +
> +		temp &= ~SDVO_COLOR_FORMAT_MASK;
> +		temp |= SDVO_COLOR_FORMAT_8bpc;
>  	}
> +
> +	I915_WRITE(intel_hdmi->hdmi_reg, temp);
> +	POSTING_READ(intel_hdmi->hdmi_reg);
> +
> +	if (crtc->config->pipe_bpp > 24) {
> +		temp &= ~SDVO_COLOR_FORMAT_MASK;
> +		temp |= HDMI_COLOR_FORMAT_12bpc;
> +
> +		I915_WRITE(intel_hdmi->hdmi_reg, temp);
> +		POSTING_READ(intel_hdmi->hdmi_reg);
> +
> +		I915_WRITE(TRANS_CHICKEN1(pipe),
> +			   I915_READ(TRANS_CHICKEN1(pipe)) &
> +			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
> +	}
> +
> +	if (crtc->config->has_audio)
> +		intel_enable_hdmi_audio(encoder);
>  }
>  
>  static void vlv_enable_hdmi(struct intel_encoder *encoder)
> @@ -1829,7 +1888,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
>  		intel_encoder->post_disable = vlv_hdmi_post_disable;
>  	} else {
>  		intel_encoder->pre_enable = intel_hdmi_pre_enable;
> -		intel_encoder->enable = intel_enable_hdmi;
> +		if (HAS_PCH_CPT(dev))
> +			intel_encoder->enable = cpt_enable_hdmi;
> +		else
> +			intel_encoder->enable = intel_enable_hdmi;
>  	}
>  
>  	intel_encoder->type = INTEL_OUTPUT_HDMI;
> -- 
> 2.0.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Ander Conselvan de Oliveira May 25, 2015, 11:39 a.m. UTC | #2
Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com>

On Tue, 2015-05-05 at 17:06 +0300, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement
> it, and to keep things neat pull the code into a function.
> 
> v2: Rebased due to crtc->config changes
>     s/HDMI_GC/HDMIUNIT_GC/ to match spec better
>     Factor out intel_enable_hdmi_audio()
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |  1 +
>  drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++++++----
>  2 files changed, 69 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 2339ffa..e619e41 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -6149,6 +6149,7 @@ enum skl_disp_power_wells {
>  #define _TRANSA_CHICKEN1	 0xf0060
>  #define _TRANSB_CHICKEN1	 0xf1060
>  #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
> +#define  TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE	(1<<10)
>  #define  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE	(1<<4)
>  #define _TRANSA_CHICKEN2	 0xf0064
>  #define _TRANSB_CHICKEN2	 0xf1064
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index a84c040..79cf445 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -814,6 +814,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
>  }
>  
> +static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
> +{
> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +
> +	WARN_ON(!crtc->config->has_hdmi_sink);
> +	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
> +			 pipe_name(crtc->pipe));
> +	intel_audio_codec_enable(encoder);
> +}
> +
>  static void intel_enable_hdmi(struct intel_encoder *encoder)
>  {
>  	struct drm_device *dev = encoder->base.dev;
> @@ -854,12 +864,61 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
>  		POSTING_READ(intel_hdmi->hdmi_reg);
>  	}
>  
> -	if (intel_crtc->config->has_audio) {
> -		WARN_ON(!intel_crtc->config->has_hdmi_sink);
> -		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
> -				 pipe_name(intel_crtc->pipe));
> -		intel_audio_codec_enable(encoder);
> +	if (intel_crtc->config->has_audio)
> +		intel_enable_hdmi_audio(encoder);
> +}
> +
> +static void cpt_enable_hdmi(struct intel_encoder *encoder)
> +{
> +	struct drm_device *dev = encoder->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> +	enum pipe pipe = crtc->pipe;
> +	u32 temp;
> +
> +	temp = I915_READ(intel_hdmi->hdmi_reg);
> +
> +	temp |= SDVO_ENABLE;
> +	if (crtc->config->has_audio)
> +		temp |= SDVO_AUDIO_ENABLE;
> +
> +	/*
> +	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb
> +	 *
> +	 * The procedure for 12bpc is as follows:
> +	 * 1. disable HDMI clock gating
> +	 * 2. enable HDMI with 8bpc
> +	 * 3. enable HDMI with 12bpc
> +	 * 4. enable HDMI clock gating
> +	 */
> +
> +	if (crtc->config->pipe_bpp > 24) {
> +		I915_WRITE(TRANS_CHICKEN1(pipe),
> +			   I915_READ(TRANS_CHICKEN1(pipe)) |
> +			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
> +
> +		temp &= ~SDVO_COLOR_FORMAT_MASK;
> +		temp |= SDVO_COLOR_FORMAT_8bpc;
>  	}
> +
> +	I915_WRITE(intel_hdmi->hdmi_reg, temp);
> +	POSTING_READ(intel_hdmi->hdmi_reg);
> +
> +	if (crtc->config->pipe_bpp > 24) {
> +		temp &= ~SDVO_COLOR_FORMAT_MASK;
> +		temp |= HDMI_COLOR_FORMAT_12bpc;
> +
> +		I915_WRITE(intel_hdmi->hdmi_reg, temp);
> +		POSTING_READ(intel_hdmi->hdmi_reg);
> +
> +		I915_WRITE(TRANS_CHICKEN1(pipe),
> +			   I915_READ(TRANS_CHICKEN1(pipe)) &
> +			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
> +	}
> +
> +	if (crtc->config->has_audio)
> +		intel_enable_hdmi_audio(encoder);
>  }
>  
>  static void vlv_enable_hdmi(struct intel_encoder *encoder)
> @@ -1829,7 +1888,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
>  		intel_encoder->post_disable = vlv_hdmi_post_disable;
>  	} else {
>  		intel_encoder->pre_enable = intel_hdmi_pre_enable;
> -		intel_encoder->enable = intel_enable_hdmi;
> +		if (HAS_PCH_CPT(dev))
> +			intel_encoder->enable = cpt_enable_hdmi;
> +		else
> +			intel_encoder->enable = intel_enable_hdmi;
>  	}
>  
>  	intel_encoder->type = INTEL_OUTPUT_HDMI;
Chandra Konduru June 1, 2015, 9:49 p.m. UTC | #3
> -----Original Message-----

> From: Intel-gfx [mailto:intel-gfx-bounces@lists.freedesktop.org] On Behalf Of

> ville.syrjala@linux.intel.com

> Sent: Tuesday, May 05, 2015 7:06 AM

> To: intel-gfx@lists.freedesktop.org

> Subject: [Intel-gfx] [PATCH v2 1/9] drm/i915: Implement

> WaEnableHDMI8bpcBefore12bpc:snb, ivb

> 

> From: Ville Syrjälä <ville.syrjala@linux.intel.com>

> 

> CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement it,

> and to keep things neat pull the code into a function.

> 

> v2: Rebased due to crtc->config changes

>     s/HDMI_GC/HDMIUNIT_GC/ to match spec better

>     Factor out intel_enable_hdmi_audio()

> 

> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>


Please call out any existing or new i-g-tests (or other tests) testing this feature.
One that is done, 
Reviewed-By: Chandra Konduru <Chandra.konduru@intel.com>


> ---

>  drivers/gpu/drm/i915/i915_reg.h   |  1 +

>  drivers/gpu/drm/i915/intel_hdmi.c | 74

> +++++++++++++++++++++++++++++++++++----

>  2 files changed, 69 insertions(+), 6 deletions(-)

> 

> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h

> index 2339ffa..e619e41 100644

> --- a/drivers/gpu/drm/i915/i915_reg.h

> +++ b/drivers/gpu/drm/i915/i915_reg.h

> @@ -6149,6 +6149,7 @@ enum skl_disp_power_wells {

>  #define _TRANSA_CHICKEN1	 0xf0060

>  #define _TRANSB_CHICKEN1	 0xf1060

>  #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1,

> _TRANSB_CHICKEN1)

> +#define  TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE	(1<<10)

>  #define  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE	(1<<4)

>  #define _TRANSA_CHICKEN2	 0xf0064

>  #define _TRANSB_CHICKEN2	 0xf1064

> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c

> b/drivers/gpu/drm/i915/intel_hdmi.c

> index a84c040..79cf445 100644

> --- a/drivers/gpu/drm/i915/intel_hdmi.c

> +++ b/drivers/gpu/drm/i915/intel_hdmi.c

> @@ -814,6 +814,16 @@ static void intel_hdmi_get_config(struct intel_encoder

> *encoder,

>  	pipe_config->base.adjusted_mode.crtc_clock = dotclock;  }

> 

> +static void intel_enable_hdmi_audio(struct intel_encoder *encoder) {

> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);

> +

> +	WARN_ON(!crtc->config->has_hdmi_sink);

> +	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",

> +			 pipe_name(crtc->pipe));

> +	intel_audio_codec_enable(encoder);

> +}

> +

>  static void intel_enable_hdmi(struct intel_encoder *encoder)  {

>  	struct drm_device *dev = encoder->base.dev; @@ -854,12 +864,61 @@

> static void intel_enable_hdmi(struct intel_encoder *encoder)

>  		POSTING_READ(intel_hdmi->hdmi_reg);

>  	}

> 

> -	if (intel_crtc->config->has_audio) {

> -		WARN_ON(!intel_crtc->config->has_hdmi_sink);

> -		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",

> -				 pipe_name(intel_crtc->pipe));

> -		intel_audio_codec_enable(encoder);

> +	if (intel_crtc->config->has_audio)

> +		intel_enable_hdmi_audio(encoder);

> +}

> +

> +static void cpt_enable_hdmi(struct intel_encoder *encoder) {

> +	struct drm_device *dev = encoder->base.dev;

> +	struct drm_i915_private *dev_priv = dev->dev_private;

> +	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);

> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);

> +	enum pipe pipe = crtc->pipe;

> +	u32 temp;

> +

> +	temp = I915_READ(intel_hdmi->hdmi_reg);

> +

> +	temp |= SDVO_ENABLE;

> +	if (crtc->config->has_audio)

> +		temp |= SDVO_AUDIO_ENABLE;

> +

> +	/*

> +	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb

> +	 *

> +	 * The procedure for 12bpc is as follows:

> +	 * 1. disable HDMI clock gating

> +	 * 2. enable HDMI with 8bpc

> +	 * 3. enable HDMI with 12bpc

> +	 * 4. enable HDMI clock gating

> +	 */

> +

> +	if (crtc->config->pipe_bpp > 24) {

> +		I915_WRITE(TRANS_CHICKEN1(pipe),

> +			   I915_READ(TRANS_CHICKEN1(pipe)) |

> +			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);

> +

> +		temp &= ~SDVO_COLOR_FORMAT_MASK;

> +		temp |= SDVO_COLOR_FORMAT_8bpc;

>  	}

> +

> +	I915_WRITE(intel_hdmi->hdmi_reg, temp);

> +	POSTING_READ(intel_hdmi->hdmi_reg);

> +

> +	if (crtc->config->pipe_bpp > 24) {

> +		temp &= ~SDVO_COLOR_FORMAT_MASK;

> +		temp |= HDMI_COLOR_FORMAT_12bpc;

> +

> +		I915_WRITE(intel_hdmi->hdmi_reg, temp);

> +		POSTING_READ(intel_hdmi->hdmi_reg);

> +

> +		I915_WRITE(TRANS_CHICKEN1(pipe),

> +			   I915_READ(TRANS_CHICKEN1(pipe)) &

> +			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);

> +	}

> +

> +	if (crtc->config->has_audio)

> +		intel_enable_hdmi_audio(encoder);

>  }

> 

>  static void vlv_enable_hdmi(struct intel_encoder *encoder) @@ -1829,7

> +1888,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum

> port port)

>  		intel_encoder->post_disable = vlv_hdmi_post_disable;

>  	} else {

>  		intel_encoder->pre_enable = intel_hdmi_pre_enable;

> -		intel_encoder->enable = intel_enable_hdmi;

> +		if (HAS_PCH_CPT(dev))

> +			intel_encoder->enable = cpt_enable_hdmi;

> +		else

> +			intel_encoder->enable = intel_enable_hdmi;

>  	}

> 

>  	intel_encoder->type = INTEL_OUTPUT_HDMI;

> --

> 2.0.5

> 

> _______________________________________________

> Intel-gfx mailing list

> Intel-gfx@lists.freedesktop.org

> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2339ffa..e619e41 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6149,6 +6149,7 @@  enum skl_disp_power_wells {
 #define _TRANSA_CHICKEN1	 0xf0060
 #define _TRANSB_CHICKEN1	 0xf1060
 #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1)
+#define  TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE	(1<<10)
 #define  TRANS_CHICKEN1_DP0UNIT_GC_DISABLE	(1<<4)
 #define _TRANSA_CHICKEN2	 0xf0064
 #define _TRANSB_CHICKEN2	 0xf1064
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a84c040..79cf445 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -814,6 +814,16 @@  static void intel_hdmi_get_config(struct intel_encoder *encoder,
 	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 }
 
+static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
+{
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+
+	WARN_ON(!crtc->config->has_hdmi_sink);
+	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
+			 pipe_name(crtc->pipe));
+	intel_audio_codec_enable(encoder);
+}
+
 static void intel_enable_hdmi(struct intel_encoder *encoder)
 {
 	struct drm_device *dev = encoder->base.dev;
@@ -854,12 +864,61 @@  static void intel_enable_hdmi(struct intel_encoder *encoder)
 		POSTING_READ(intel_hdmi->hdmi_reg);
 	}
 
-	if (intel_crtc->config->has_audio) {
-		WARN_ON(!intel_crtc->config->has_hdmi_sink);
-		DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
-				 pipe_name(intel_crtc->pipe));
-		intel_audio_codec_enable(encoder);
+	if (intel_crtc->config->has_audio)
+		intel_enable_hdmi_audio(encoder);
+}
+
+static void cpt_enable_hdmi(struct intel_encoder *encoder)
+{
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+	enum pipe pipe = crtc->pipe;
+	u32 temp;
+
+	temp = I915_READ(intel_hdmi->hdmi_reg);
+
+	temp |= SDVO_ENABLE;
+	if (crtc->config->has_audio)
+		temp |= SDVO_AUDIO_ENABLE;
+
+	/*
+	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb
+	 *
+	 * The procedure for 12bpc is as follows:
+	 * 1. disable HDMI clock gating
+	 * 2. enable HDMI with 8bpc
+	 * 3. enable HDMI with 12bpc
+	 * 4. enable HDMI clock gating
+	 */
+
+	if (crtc->config->pipe_bpp > 24) {
+		I915_WRITE(TRANS_CHICKEN1(pipe),
+			   I915_READ(TRANS_CHICKEN1(pipe)) |
+			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
+
+		temp &= ~SDVO_COLOR_FORMAT_MASK;
+		temp |= SDVO_COLOR_FORMAT_8bpc;
 	}
+
+	I915_WRITE(intel_hdmi->hdmi_reg, temp);
+	POSTING_READ(intel_hdmi->hdmi_reg);
+
+	if (crtc->config->pipe_bpp > 24) {
+		temp &= ~SDVO_COLOR_FORMAT_MASK;
+		temp |= HDMI_COLOR_FORMAT_12bpc;
+
+		I915_WRITE(intel_hdmi->hdmi_reg, temp);
+		POSTING_READ(intel_hdmi->hdmi_reg);
+
+		I915_WRITE(TRANS_CHICKEN1(pipe),
+			   I915_READ(TRANS_CHICKEN1(pipe)) &
+			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
+	}
+
+	if (crtc->config->has_audio)
+		intel_enable_hdmi_audio(encoder);
 }
 
 static void vlv_enable_hdmi(struct intel_encoder *encoder)
@@ -1829,7 +1888,10 @@  void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 		intel_encoder->post_disable = vlv_hdmi_post_disable;
 	} else {
 		intel_encoder->pre_enable = intel_hdmi_pre_enable;
-		intel_encoder->enable = intel_enable_hdmi;
+		if (HAS_PCH_CPT(dev))
+			intel_encoder->enable = cpt_enable_hdmi;
+		else
+			intel_encoder->enable = intel_enable_hdmi;
 	}
 
 	intel_encoder->type = INTEL_OUTPUT_HDMI;