xref: /dflybsd-src/sys/dev/drm/i915/intel_hdmi.c (revision a05eeebfe8ec06e5625c15c535aed68dbf568bd6)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright 2006 Dave Airlie <airlied@linux.ie>
3e3adcf8fSFrançois Tigeot  * Copyright © 2006-2009 Intel Corporation
4e3adcf8fSFrançois Tigeot  *
5e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
6e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
7e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
8e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
10e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
11e3adcf8fSFrançois Tigeot  *
12e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
13e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
14e3adcf8fSFrançois Tigeot  * Software.
15e3adcf8fSFrançois Tigeot  *
16e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21e3adcf8fSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22e3adcf8fSFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
23e3adcf8fSFrançois Tigeot  *
24e3adcf8fSFrançois Tigeot  * Authors:
25e3adcf8fSFrançois Tigeot  *	Eric Anholt <eric@anholt.net>
26e3adcf8fSFrançois Tigeot  *	Jesse Barnes <jesse.barnes@intel.com>
27e3adcf8fSFrançois Tigeot  */
28e3adcf8fSFrançois Tigeot 
29a2fdbec6SFrançois Tigeot #include <linux/i2c.h>
30a2fdbec6SFrançois Tigeot #include <linux/delay.h>
319edbd4a0SFrançois Tigeot #include <linux/hdmi.h>
3218e26a6dSFrançois Tigeot #include <drm/drmP.h>
332c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h>
3418e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
3518e26a6dSFrançois Tigeot #include <drm/drm_edid.h>
3618e26a6dSFrançois Tigeot #include "intel_drv.h"
375c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
38e3adcf8fSFrançois Tigeot #include "i915_drv.h"
39e3adcf8fSFrançois Tigeot 
4019df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
41e3adcf8fSFrançois Tigeot {
4219df918dSFrançois Tigeot 	return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
4319df918dSFrançois Tigeot }
4419df918dSFrançois Tigeot 
4519df918dSFrançois Tigeot static void
4619df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
4719df918dSFrançois Tigeot {
4819df918dSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
4919df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
5019df918dSFrançois Tigeot 	uint32_t enabled_bits;
5119df918dSFrançois Tigeot 
52a2fdbec6SFrançois Tigeot 	enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
5319df918dSFrançois Tigeot 
548e26cdf6SFrançois Tigeot 	WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
5519df918dSFrançois Tigeot 	     "HDMI port enabled, expecting disabled\n");
5619df918dSFrançois Tigeot }
5719df918dSFrançois Tigeot 
5819df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
5919df918dSFrançois Tigeot {
6019df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port =
6119df918dSFrançois Tigeot 		container_of(encoder, struct intel_digital_port, base.base);
6219df918dSFrançois Tigeot 	return &intel_dig_port->hdmi;
63e3adcf8fSFrançois Tigeot }
64e3adcf8fSFrançois Tigeot 
65e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
66e3adcf8fSFrançois Tigeot {
6719df918dSFrançois Tigeot 	return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
68e3adcf8fSFrançois Tigeot }
69e3adcf8fSFrançois Tigeot 
709edbd4a0SFrançois Tigeot static u32 g4x_infoframe_index(enum hdmi_infoframe_type type)
71e3adcf8fSFrançois Tigeot {
729edbd4a0SFrançois Tigeot 	switch (type) {
739edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
7419df918dSFrançois Tigeot 		return VIDEO_DIP_SELECT_AVI;
759edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
7619df918dSFrançois Tigeot 		return VIDEO_DIP_SELECT_SPD;
779edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
789edbd4a0SFrançois Tigeot 		return VIDEO_DIP_SELECT_VENDOR;
79e3adcf8fSFrançois Tigeot 	default:
809edbd4a0SFrançois Tigeot 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
8119df918dSFrançois Tigeot 		return 0;
8219df918dSFrançois Tigeot 	}
83e3adcf8fSFrançois Tigeot }
84e3adcf8fSFrançois Tigeot 
859edbd4a0SFrançois Tigeot static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type)
86e3adcf8fSFrançois Tigeot {
879edbd4a0SFrançois Tigeot 	switch (type) {
889edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
8919df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_AVI;
909edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
9119df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_SPD;
929edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
939edbd4a0SFrançois Tigeot 		return VIDEO_DIP_ENABLE_VENDOR;
94e3adcf8fSFrançois Tigeot 	default:
959edbd4a0SFrançois Tigeot 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
9619df918dSFrançois Tigeot 		return 0;
9719df918dSFrançois Tigeot 	}
98e3adcf8fSFrançois Tigeot }
99e3adcf8fSFrançois Tigeot 
1009edbd4a0SFrançois Tigeot static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
10119df918dSFrançois Tigeot {
1029edbd4a0SFrançois Tigeot 	switch (type) {
1039edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
10419df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_AVI_HSW;
1059edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
10619df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_SPD_HSW;
1079edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
1089edbd4a0SFrançois Tigeot 		return VIDEO_DIP_ENABLE_VS_HSW;
10919df918dSFrançois Tigeot 	default:
1109edbd4a0SFrançois Tigeot 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
11119df918dSFrançois Tigeot 		return 0;
11219df918dSFrançois Tigeot 	}
113e3adcf8fSFrançois Tigeot }
114e3adcf8fSFrançois Tigeot 
1159edbd4a0SFrançois Tigeot static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type,
116ba55f2f5SFrançois Tigeot 				  enum transcoder cpu_transcoder,
117ba55f2f5SFrançois Tigeot 				  struct drm_i915_private *dev_priv)
11819df918dSFrançois Tigeot {
1199edbd4a0SFrançois Tigeot 	switch (type) {
1209edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
1218e26cdf6SFrançois Tigeot 		return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder);
1229edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
1238e26cdf6SFrançois Tigeot 		return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder);
1249edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
1259edbd4a0SFrançois Tigeot 		return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder);
12619df918dSFrançois Tigeot 	default:
1279edbd4a0SFrançois Tigeot 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
12819df918dSFrançois Tigeot 		return 0;
12919df918dSFrançois Tigeot 	}
13019df918dSFrançois Tigeot }
13119df918dSFrançois Tigeot 
13219df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder,
1339edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
1349edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
135e3adcf8fSFrançois Tigeot {
1369edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
137e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
138e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
13919df918dSFrançois Tigeot 	u32 val = I915_READ(VIDEO_DIP_CTL);
1409edbd4a0SFrançois Tigeot 	int i;
141e3adcf8fSFrançois Tigeot 
14219df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
143e3adcf8fSFrançois Tigeot 
14419df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
1459edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
146e3adcf8fSFrançois Tigeot 
1479edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
148e3adcf8fSFrançois Tigeot 
14919df918dSFrançois Tigeot 	I915_WRITE(VIDEO_DIP_CTL, val);
150e3adcf8fSFrançois Tigeot 
15119df918dSFrançois Tigeot 	mmiowb();
152e3adcf8fSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
153e3adcf8fSFrançois Tigeot 		I915_WRITE(VIDEO_DIP_DATA, *data);
154e3adcf8fSFrançois Tigeot 		data++;
155e3adcf8fSFrançois Tigeot 	}
15619df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
15719df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
15819df918dSFrançois Tigeot 		I915_WRITE(VIDEO_DIP_DATA, 0);
15919df918dSFrançois Tigeot 	mmiowb();
160e3adcf8fSFrançois Tigeot 
1619edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
16219df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
16319df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
164e3adcf8fSFrançois Tigeot 
16519df918dSFrançois Tigeot 	I915_WRITE(VIDEO_DIP_CTL, val);
16619df918dSFrançois Tigeot 	POSTING_READ(VIDEO_DIP_CTL);
167e3adcf8fSFrançois Tigeot }
168e3adcf8fSFrançois Tigeot 
1692c9916cdSFrançois Tigeot static bool g4x_infoframe_enabled(struct drm_encoder *encoder)
1702c9916cdSFrançois Tigeot {
1712c9916cdSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
1722c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1732c9916cdSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
1742c9916cdSFrançois Tigeot 	u32 val = I915_READ(VIDEO_DIP_CTL);
1752c9916cdSFrançois Tigeot 
176*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
1772c9916cdSFrançois Tigeot 		return false;
178*a05eeebfSFrançois Tigeot 
179*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
180*a05eeebfSFrançois Tigeot 		return false;
181*a05eeebfSFrançois Tigeot 
182*a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
183*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
1842c9916cdSFrançois Tigeot }
1852c9916cdSFrançois Tigeot 
18619df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder,
1879edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
1889edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
189e3adcf8fSFrançois Tigeot {
1909edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
191e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
192e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
19319df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
1949edbd4a0SFrançois Tigeot 	int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
19519df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
196e3adcf8fSFrançois Tigeot 
19719df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
198e3adcf8fSFrançois Tigeot 
199e3adcf8fSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2009edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
201e3adcf8fSFrançois Tigeot 
2029edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
203e3adcf8fSFrançois Tigeot 
20419df918dSFrançois Tigeot 	I915_WRITE(reg, val);
20519df918dSFrançois Tigeot 
20619df918dSFrançois Tigeot 	mmiowb();
207e3adcf8fSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
208e3adcf8fSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
209e3adcf8fSFrançois Tigeot 		data++;
210e3adcf8fSFrançois Tigeot 	}
21119df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
21219df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
21319df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
21419df918dSFrançois Tigeot 	mmiowb();
215e3adcf8fSFrançois Tigeot 
2169edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
21719df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
21819df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
219e3adcf8fSFrançois Tigeot 
22019df918dSFrançois Tigeot 	I915_WRITE(reg, val);
22119df918dSFrançois Tigeot 	POSTING_READ(reg);
22219df918dSFrançois Tigeot }
22319df918dSFrançois Tigeot 
2242c9916cdSFrançois Tigeot static bool ibx_infoframe_enabled(struct drm_encoder *encoder)
2252c9916cdSFrançois Tigeot {
2262c9916cdSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
2272c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2282c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
22919c468b4SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
2302c9916cdSFrançois Tigeot 	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
2312c9916cdSFrançois Tigeot 	u32 val = I915_READ(reg);
2322c9916cdSFrançois Tigeot 
233*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
23419c468b4SFrançois Tigeot 		return false;
235*a05eeebfSFrançois Tigeot 
236*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
237*a05eeebfSFrançois Tigeot 		return false;
238*a05eeebfSFrançois Tigeot 
239*a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
240*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
241*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
2422c9916cdSFrançois Tigeot }
2432c9916cdSFrançois Tigeot 
24419df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder,
2459edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
2469edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
24719df918dSFrançois Tigeot {
2489edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
24919df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
25019df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
25119df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
2529edbd4a0SFrançois Tigeot 	int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
25319df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
25419df918dSFrançois Tigeot 
25519df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
25619df918dSFrançois Tigeot 
25719df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2589edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
25919df918dSFrançois Tigeot 
26019df918dSFrançois Tigeot 	/* The DIP control register spec says that we need to update the AVI
26119df918dSFrançois Tigeot 	 * infoframe without clearing its enable bit */
2629edbd4a0SFrançois Tigeot 	if (type != HDMI_INFOFRAME_TYPE_AVI)
2639edbd4a0SFrançois Tigeot 		val &= ~g4x_infoframe_enable(type);
26419df918dSFrançois Tigeot 
26519df918dSFrançois Tigeot 	I915_WRITE(reg, val);
26619df918dSFrançois Tigeot 
26719df918dSFrançois Tigeot 	mmiowb();
26819df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
26919df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
27019df918dSFrançois Tigeot 		data++;
27119df918dSFrançois Tigeot 	}
27219df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
27319df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
27419df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
27519df918dSFrançois Tigeot 	mmiowb();
27619df918dSFrançois Tigeot 
2779edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
27819df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
27919df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
28019df918dSFrançois Tigeot 
28119df918dSFrançois Tigeot 	I915_WRITE(reg, val);
28219df918dSFrançois Tigeot 	POSTING_READ(reg);
28319df918dSFrançois Tigeot }
28419df918dSFrançois Tigeot 
2852c9916cdSFrançois Tigeot static bool cpt_infoframe_enabled(struct drm_encoder *encoder)
2862c9916cdSFrançois Tigeot {
2872c9916cdSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
2882c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2892c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
2902c9916cdSFrançois Tigeot 	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
2912c9916cdSFrançois Tigeot 	u32 val = I915_READ(reg);
2922c9916cdSFrançois Tigeot 
293*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
294*a05eeebfSFrançois Tigeot 		return false;
295*a05eeebfSFrançois Tigeot 
296*a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
297*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
298*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
2992c9916cdSFrançois Tigeot }
3002c9916cdSFrançois Tigeot 
30119df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder,
3029edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
3039edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
30419df918dSFrançois Tigeot {
3059edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
30619df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
30719df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
30819df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
3099edbd4a0SFrançois Tigeot 	int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
31019df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
31119df918dSFrançois Tigeot 
31219df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
31319df918dSFrançois Tigeot 
31419df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
3159edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
31619df918dSFrançois Tigeot 
3179edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
31819df918dSFrançois Tigeot 
31919df918dSFrançois Tigeot 	I915_WRITE(reg, val);
32019df918dSFrançois Tigeot 
32119df918dSFrançois Tigeot 	mmiowb();
32219df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
32319df918dSFrançois Tigeot 		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
32419df918dSFrançois Tigeot 		data++;
32519df918dSFrançois Tigeot 	}
32619df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
32719df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
32819df918dSFrançois Tigeot 		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
32919df918dSFrançois Tigeot 	mmiowb();
33019df918dSFrançois Tigeot 
3319edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
33219df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
33319df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
33419df918dSFrançois Tigeot 
33519df918dSFrançois Tigeot 	I915_WRITE(reg, val);
33619df918dSFrançois Tigeot 	POSTING_READ(reg);
33719df918dSFrançois Tigeot }
33819df918dSFrançois Tigeot 
3392c9916cdSFrançois Tigeot static bool vlv_infoframe_enabled(struct drm_encoder *encoder)
3402c9916cdSFrançois Tigeot {
3412c9916cdSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
3422c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
3432c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
34419c468b4SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
3452c9916cdSFrançois Tigeot 	int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
3462c9916cdSFrançois Tigeot 	u32 val = I915_READ(reg);
3472c9916cdSFrançois Tigeot 
348*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
34919c468b4SFrançois Tigeot 		return false;
350*a05eeebfSFrançois Tigeot 
351*a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
352*a05eeebfSFrançois Tigeot 		return false;
353*a05eeebfSFrançois Tigeot 
354*a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
355*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
356*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
3572c9916cdSFrançois Tigeot }
3582c9916cdSFrançois Tigeot 
35919df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder,
3609edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
3619edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
36219df918dSFrançois Tigeot {
3639edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
36419df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
36519df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
36619df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
3672c9916cdSFrançois Tigeot 	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
3689edbd4a0SFrançois Tigeot 	u32 data_reg;
3699edbd4a0SFrançois Tigeot 	int i;
37019df918dSFrançois Tigeot 	u32 val = I915_READ(ctl_reg);
37119df918dSFrançois Tigeot 
3729edbd4a0SFrançois Tigeot 	data_reg = hsw_infoframe_data_reg(type,
3732c9916cdSFrançois Tigeot 					  intel_crtc->config->cpu_transcoder,
374ba55f2f5SFrançois Tigeot 					  dev_priv);
37519df918dSFrançois Tigeot 	if (data_reg == 0)
37619df918dSFrançois Tigeot 		return;
37719df918dSFrançois Tigeot 
3789edbd4a0SFrançois Tigeot 	val &= ~hsw_infoframe_enable(type);
37919df918dSFrançois Tigeot 	I915_WRITE(ctl_reg, val);
38019df918dSFrançois Tigeot 
38119df918dSFrançois Tigeot 	mmiowb();
38219df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
38319df918dSFrançois Tigeot 		I915_WRITE(data_reg + i, *data);
38419df918dSFrançois Tigeot 		data++;
38519df918dSFrançois Tigeot 	}
38619df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
38719df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
38819df918dSFrançois Tigeot 		I915_WRITE(data_reg + i, 0);
38919df918dSFrançois Tigeot 	mmiowb();
39019df918dSFrançois Tigeot 
3919edbd4a0SFrançois Tigeot 	val |= hsw_infoframe_enable(type);
39219df918dSFrançois Tigeot 	I915_WRITE(ctl_reg, val);
39319df918dSFrançois Tigeot 	POSTING_READ(ctl_reg);
394e3adcf8fSFrançois Tigeot }
395e3adcf8fSFrançois Tigeot 
3962c9916cdSFrançois Tigeot static bool hsw_infoframe_enabled(struct drm_encoder *encoder)
3972c9916cdSFrançois Tigeot {
3982c9916cdSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
3992c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
4002c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
4012c9916cdSFrançois Tigeot 	u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
4022c9916cdSFrançois Tigeot 	u32 val = I915_READ(ctl_reg);
4032c9916cdSFrançois Tigeot 
404*a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
405*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
406*a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
4072c9916cdSFrançois Tigeot }
4082c9916cdSFrançois Tigeot 
4099edbd4a0SFrançois Tigeot /*
4109edbd4a0SFrançois Tigeot  * The data we write to the DIP data buffer registers is 1 byte bigger than the
4119edbd4a0SFrançois Tigeot  * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
4129edbd4a0SFrançois Tigeot  * at 0). It's also a byte used by DisplayPort so the same DIP registers can be
4139edbd4a0SFrançois Tigeot  * used for both technologies.
4149edbd4a0SFrançois Tigeot  *
4159edbd4a0SFrançois Tigeot  * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
4169edbd4a0SFrançois Tigeot  * DW1:       DB3       | DB2 | DB1 | DB0
4179edbd4a0SFrançois Tigeot  * DW2:       DB7       | DB6 | DB5 | DB4
4189edbd4a0SFrançois Tigeot  * DW3: ...
4199edbd4a0SFrançois Tigeot  *
4209edbd4a0SFrançois Tigeot  * (HB is Header Byte, DB is Data Byte)
4219edbd4a0SFrançois Tigeot  *
4229edbd4a0SFrançois Tigeot  * The hdmi pack() functions don't know about that hardware specific hole so we
4239edbd4a0SFrançois Tigeot  * trick them by giving an offset into the buffer and moving back the header
4249edbd4a0SFrançois Tigeot  * bytes by one.
4259edbd4a0SFrançois Tigeot  */
4269edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder,
4279edbd4a0SFrançois Tigeot 				  union hdmi_infoframe *frame)
428e3adcf8fSFrançois Tigeot {
429e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
4309edbd4a0SFrançois Tigeot 	uint8_t buffer[VIDEO_DIP_DATA_SIZE];
4319edbd4a0SFrançois Tigeot 	ssize_t len;
432e3adcf8fSFrançois Tigeot 
4339edbd4a0SFrançois Tigeot 	/* see comment above for the reason for this offset */
4349edbd4a0SFrançois Tigeot 	len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
4359edbd4a0SFrançois Tigeot 	if (len < 0)
4369edbd4a0SFrançois Tigeot 		return;
4379edbd4a0SFrançois Tigeot 
4389edbd4a0SFrançois Tigeot 	/* Insert the 'hole' (see big comment above) at position 3 */
4399edbd4a0SFrançois Tigeot 	buffer[0] = buffer[1];
4409edbd4a0SFrançois Tigeot 	buffer[1] = buffer[2];
4419edbd4a0SFrançois Tigeot 	buffer[2] = buffer[3];
4429edbd4a0SFrançois Tigeot 	buffer[3] = 0;
4439edbd4a0SFrançois Tigeot 	len++;
4449edbd4a0SFrançois Tigeot 
4459edbd4a0SFrançois Tigeot 	intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len);
446e3adcf8fSFrançois Tigeot }
447e3adcf8fSFrançois Tigeot 
44819df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
44919df918dSFrançois Tigeot 					 struct drm_display_mode *adjusted_mode)
450e3adcf8fSFrançois Tigeot {
451a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
4528e26cdf6SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
4539edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4549edbd4a0SFrançois Tigeot 	int ret;
455e3adcf8fSFrançois Tigeot 
45624edb884SFrançois Tigeot 	/* Set user selected PAR to incoming mode's member */
45724edb884SFrançois Tigeot 	adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio;
45824edb884SFrançois Tigeot 
4599edbd4a0SFrançois Tigeot 	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
4609edbd4a0SFrançois Tigeot 						       adjusted_mode);
4619edbd4a0SFrançois Tigeot 	if (ret < 0) {
4629edbd4a0SFrançois Tigeot 		DRM_ERROR("couldn't fill AVI infoframe\n");
4639edbd4a0SFrançois Tigeot 		return;
4649edbd4a0SFrançois Tigeot 	}
46519df918dSFrançois Tigeot 
466a2fdbec6SFrançois Tigeot 	if (intel_hdmi->rgb_quant_range_selectable) {
4672c9916cdSFrançois Tigeot 		if (intel_crtc->config->limited_color_range)
4689edbd4a0SFrançois Tigeot 			frame.avi.quantization_range =
4699edbd4a0SFrançois Tigeot 				HDMI_QUANTIZATION_RANGE_LIMITED;
470a2fdbec6SFrançois Tigeot 		else
4719edbd4a0SFrançois Tigeot 			frame.avi.quantization_range =
4729edbd4a0SFrançois Tigeot 				HDMI_QUANTIZATION_RANGE_FULL;
473a2fdbec6SFrançois Tigeot 	}
474a2fdbec6SFrançois Tigeot 
4759edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
476e3adcf8fSFrançois Tigeot }
477e3adcf8fSFrançois Tigeot 
478e3adcf8fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
479e3adcf8fSFrançois Tigeot {
4809edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4819edbd4a0SFrançois Tigeot 	int ret;
482e3adcf8fSFrançois Tigeot 
4839edbd4a0SFrançois Tigeot 	ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
4849edbd4a0SFrançois Tigeot 	if (ret < 0) {
4859edbd4a0SFrançois Tigeot 		DRM_ERROR("couldn't fill SPD infoframe\n");
4869edbd4a0SFrançois Tigeot 		return;
4879edbd4a0SFrançois Tigeot 	}
488e3adcf8fSFrançois Tigeot 
4899edbd4a0SFrançois Tigeot 	frame.spd.sdi = HDMI_SPD_SDI_PC;
4909edbd4a0SFrançois Tigeot 
4919edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
4929edbd4a0SFrançois Tigeot }
4939edbd4a0SFrançois Tigeot 
4949edbd4a0SFrançois Tigeot static void
4959edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
4969edbd4a0SFrançois Tigeot 			      struct drm_display_mode *adjusted_mode)
4979edbd4a0SFrançois Tigeot {
4989edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4999edbd4a0SFrançois Tigeot 	int ret;
5009edbd4a0SFrançois Tigeot 
5019edbd4a0SFrançois Tigeot 	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
5029edbd4a0SFrançois Tigeot 							  adjusted_mode);
5039edbd4a0SFrançois Tigeot 	if (ret < 0)
5049edbd4a0SFrançois Tigeot 		return;
5059edbd4a0SFrançois Tigeot 
5069edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
507e3adcf8fSFrançois Tigeot }
508e3adcf8fSFrançois Tigeot 
50919df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder,
510ba55f2f5SFrançois Tigeot 			       bool enable,
51119df918dSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
51219df918dSFrançois Tigeot {
51319df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
514a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
515a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
51619df918dSFrançois Tigeot 	u32 reg = VIDEO_DIP_CTL;
51719df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
518ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
51919df918dSFrançois Tigeot 
52019df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
52119df918dSFrançois Tigeot 
52219df918dSFrançois Tigeot 	/* If the registers were not initialized yet, they might be zeroes,
52319df918dSFrançois Tigeot 	 * which means we're selecting the AVI DIP and we're setting its
52419df918dSFrançois Tigeot 	 * frequency to once. This seems to really confuse the HW and make
52519df918dSFrançois Tigeot 	 * things stop working (the register spec says the AVI always needs to
52619df918dSFrançois Tigeot 	 * be sent every VSync). So here we avoid writing to the register more
52719df918dSFrançois Tigeot 	 * than we need and also explicitly select the AVI DIP and explicitly
52819df918dSFrançois Tigeot 	 * set its frequency to every VSync. Avoiding to write it twice seems to
52919df918dSFrançois Tigeot 	 * be enough to solve the problem, but being defensive shouldn't hurt us
53019df918dSFrançois Tigeot 	 * either. */
53119df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
53219df918dSFrançois Tigeot 
533ba55f2f5SFrançois Tigeot 	if (!enable) {
53419df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
53519df918dSFrançois Tigeot 			return;
536*a05eeebfSFrançois Tigeot 		if (port != (val & VIDEO_DIP_PORT_MASK)) {
537*a05eeebfSFrançois Tigeot 			DRM_DEBUG_KMS("video DIP still enabled on port %c\n",
538*a05eeebfSFrançois Tigeot 				      (val & VIDEO_DIP_PORT_MASK) >> 29);
539*a05eeebfSFrançois Tigeot 			return;
540*a05eeebfSFrançois Tigeot 		}
541*a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
542*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
54319df918dSFrançois Tigeot 		I915_WRITE(reg, val);
54419df918dSFrançois Tigeot 		POSTING_READ(reg);
54519df918dSFrançois Tigeot 		return;
54619df918dSFrançois Tigeot 	}
54719df918dSFrançois Tigeot 
54819df918dSFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
54919df918dSFrançois Tigeot 		if (val & VIDEO_DIP_ENABLE) {
550*a05eeebfSFrançois Tigeot 			DRM_DEBUG_KMS("video DIP already enabled on port %c\n",
551*a05eeebfSFrançois Tigeot 				      (val & VIDEO_DIP_PORT_MASK) >> 29);
552*a05eeebfSFrançois Tigeot 			return;
55319df918dSFrançois Tigeot 		}
55419df918dSFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
55519df918dSFrançois Tigeot 		val |= port;
55619df918dSFrançois Tigeot 	}
55719df918dSFrançois Tigeot 
55819df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
559*a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
560*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
56119df918dSFrançois Tigeot 
56219df918dSFrançois Tigeot 	I915_WRITE(reg, val);
56319df918dSFrançois Tigeot 	POSTING_READ(reg);
56419df918dSFrançois Tigeot 
56519df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
56619df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
5679edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
56819df918dSFrançois Tigeot }
56919df918dSFrançois Tigeot 
570*a05eeebfSFrançois Tigeot static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder)
571*a05eeebfSFrançois Tigeot {
572*a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
573*a05eeebfSFrançois Tigeot 	struct drm_connector *connector;
574*a05eeebfSFrançois Tigeot 
575*a05eeebfSFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
576*a05eeebfSFrançois Tigeot 
577*a05eeebfSFrançois Tigeot 	/*
578*a05eeebfSFrançois Tigeot 	 * HDMI cloning is only supported on g4x which doesn't
579*a05eeebfSFrançois Tigeot 	 * support deep color or GCP infoframes anyway so no
580*a05eeebfSFrançois Tigeot 	 * need to worry about multiple HDMI sinks here.
581*a05eeebfSFrançois Tigeot 	 */
582*a05eeebfSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
583*a05eeebfSFrançois Tigeot 		if (connector->encoder == encoder)
584*a05eeebfSFrançois Tigeot 			return connector->display_info.bpc > 8;
585*a05eeebfSFrançois Tigeot 
586*a05eeebfSFrançois Tigeot 	return false;
587*a05eeebfSFrançois Tigeot }
588*a05eeebfSFrançois Tigeot 
589*a05eeebfSFrançois Tigeot /*
590*a05eeebfSFrançois Tigeot  * Determine if default_phase=1 can be indicated in the GCP infoframe.
591*a05eeebfSFrançois Tigeot  *
592*a05eeebfSFrançois Tigeot  * From HDMI specification 1.4a:
593*a05eeebfSFrançois Tigeot  * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0
594*a05eeebfSFrançois Tigeot  * - The first pixel following each Video Data Period shall have a pixel packing phase of 0
595*a05eeebfSFrançois Tigeot  * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase
596*a05eeebfSFrançois Tigeot  * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing
597*a05eeebfSFrançois Tigeot  *   phase of 0
598*a05eeebfSFrançois Tigeot  */
599*a05eeebfSFrançois Tigeot static bool gcp_default_phase_possible(int pipe_bpp,
600*a05eeebfSFrançois Tigeot 				       const struct drm_display_mode *mode)
601*a05eeebfSFrançois Tigeot {
602*a05eeebfSFrançois Tigeot 	unsigned int pixels_per_group;
603*a05eeebfSFrançois Tigeot 
604*a05eeebfSFrançois Tigeot 	switch (pipe_bpp) {
605*a05eeebfSFrançois Tigeot 	case 30:
606*a05eeebfSFrançois Tigeot 		/* 4 pixels in 5 clocks */
607*a05eeebfSFrançois Tigeot 		pixels_per_group = 4;
608*a05eeebfSFrançois Tigeot 		break;
609*a05eeebfSFrançois Tigeot 	case 36:
610*a05eeebfSFrançois Tigeot 		/* 2 pixels in 3 clocks */
611*a05eeebfSFrançois Tigeot 		pixels_per_group = 2;
612*a05eeebfSFrançois Tigeot 		break;
613*a05eeebfSFrançois Tigeot 	case 48:
614*a05eeebfSFrançois Tigeot 		/* 1 pixel in 2 clocks */
615*a05eeebfSFrançois Tigeot 		pixels_per_group = 1;
616*a05eeebfSFrançois Tigeot 		break;
617*a05eeebfSFrançois Tigeot 	default:
618*a05eeebfSFrançois Tigeot 		/* phase information not relevant for 8bpc */
619*a05eeebfSFrançois Tigeot 		return false;
620*a05eeebfSFrançois Tigeot 	}
621*a05eeebfSFrançois Tigeot 
622*a05eeebfSFrançois Tigeot 	return mode->crtc_hdisplay % pixels_per_group == 0 &&
623*a05eeebfSFrançois Tigeot 		mode->crtc_htotal % pixels_per_group == 0 &&
624*a05eeebfSFrançois Tigeot 		mode->crtc_hblank_start % pixels_per_group == 0 &&
625*a05eeebfSFrançois Tigeot 		mode->crtc_hblank_end % pixels_per_group == 0 &&
626*a05eeebfSFrançois Tigeot 		mode->crtc_hsync_start % pixels_per_group == 0 &&
627*a05eeebfSFrançois Tigeot 		mode->crtc_hsync_end % pixels_per_group == 0 &&
628*a05eeebfSFrançois Tigeot 		((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 ||
629*a05eeebfSFrançois Tigeot 		 mode->crtc_htotal/2 % pixels_per_group == 0);
630*a05eeebfSFrançois Tigeot }
631*a05eeebfSFrançois Tigeot 
632*a05eeebfSFrançois Tigeot static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
633*a05eeebfSFrançois Tigeot {
634*a05eeebfSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
635*a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
636*a05eeebfSFrançois Tigeot 	u32 reg, val = 0;
637*a05eeebfSFrançois Tigeot 
638*a05eeebfSFrançois Tigeot 	if (HAS_DDI(dev_priv))
639*a05eeebfSFrançois Tigeot 		reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
640*a05eeebfSFrançois Tigeot 	else if (IS_VALLEYVIEW(dev_priv))
641*a05eeebfSFrançois Tigeot 		reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
642*a05eeebfSFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev_priv->dev))
643*a05eeebfSFrançois Tigeot 		reg = TVIDEO_DIP_GCP(crtc->pipe);
644*a05eeebfSFrançois Tigeot 	else
645*a05eeebfSFrançois Tigeot 		return false;
646*a05eeebfSFrançois Tigeot 
647*a05eeebfSFrançois Tigeot 	/* Indicate color depth whenever the sink supports deep color */
648*a05eeebfSFrançois Tigeot 	if (hdmi_sink_is_deep_color(encoder))
649*a05eeebfSFrançois Tigeot 		val |= GCP_COLOR_INDICATION;
650*a05eeebfSFrançois Tigeot 
651*a05eeebfSFrançois Tigeot 	/* Enable default_phase whenever the display mode is suitably aligned */
652*a05eeebfSFrançois Tigeot 	if (gcp_default_phase_possible(crtc->config->pipe_bpp,
653*a05eeebfSFrançois Tigeot 				       &crtc->config->base.adjusted_mode))
654*a05eeebfSFrançois Tigeot 		val |= GCP_DEFAULT_PHASE_ENABLE;
655*a05eeebfSFrançois Tigeot 
656*a05eeebfSFrançois Tigeot 	I915_WRITE(reg, val);
657*a05eeebfSFrançois Tigeot 
658*a05eeebfSFrançois Tigeot 	return val != 0;
659*a05eeebfSFrançois Tigeot }
660*a05eeebfSFrançois Tigeot 
66119df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder,
662ba55f2f5SFrançois Tigeot 			       bool enable,
66319df918dSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
66419df918dSFrançois Tigeot {
66519df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
66619df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
667a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
668a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
66919df918dSFrançois Tigeot 	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
67019df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
671ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
67219df918dSFrançois Tigeot 
67319df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
67419df918dSFrançois Tigeot 
67519df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
67619df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
67719df918dSFrançois Tigeot 
678ba55f2f5SFrançois Tigeot 	if (!enable) {
67919df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
68019df918dSFrançois Tigeot 			return;
681*a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
682*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
683*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
68419df918dSFrançois Tigeot 		I915_WRITE(reg, val);
68519df918dSFrançois Tigeot 		POSTING_READ(reg);
68619df918dSFrançois Tigeot 		return;
68719df918dSFrançois Tigeot 	}
68819df918dSFrançois Tigeot 
68919df918dSFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
690*a05eeebfSFrançois Tigeot 		WARN(val & VIDEO_DIP_ENABLE,
691*a05eeebfSFrançois Tigeot 		     "DIP already enabled on port %c\n",
692*a05eeebfSFrançois Tigeot 		     (val & VIDEO_DIP_PORT_MASK) >> 29);
69319df918dSFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
69419df918dSFrançois Tigeot 		val |= port;
69519df918dSFrançois Tigeot 	}
69619df918dSFrançois Tigeot 
69719df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
698*a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
699*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
700*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
701*a05eeebfSFrançois Tigeot 
702*a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
703*a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
70419df918dSFrançois Tigeot 
70519df918dSFrançois Tigeot 	I915_WRITE(reg, val);
70619df918dSFrançois Tigeot 	POSTING_READ(reg);
70719df918dSFrançois Tigeot 
70819df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
70919df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
7109edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
71119df918dSFrançois Tigeot }
71219df918dSFrançois Tigeot 
71319df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder,
714ba55f2f5SFrançois Tigeot 			       bool enable,
71519df918dSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
71619df918dSFrançois Tigeot {
71719df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
71819df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
71919df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
72019df918dSFrançois Tigeot 	u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
72119df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
72219df918dSFrançois Tigeot 
72319df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
72419df918dSFrançois Tigeot 
72519df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
72619df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
72719df918dSFrançois Tigeot 
728ba55f2f5SFrançois Tigeot 	if (!enable) {
72919df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
73019df918dSFrançois Tigeot 			return;
731*a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
732*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
733*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
73419df918dSFrançois Tigeot 		I915_WRITE(reg, val);
73519df918dSFrançois Tigeot 		POSTING_READ(reg);
73619df918dSFrançois Tigeot 		return;
73719df918dSFrançois Tigeot 	}
73819df918dSFrançois Tigeot 
73919df918dSFrançois Tigeot 	/* Set both together, unset both together: see the spec. */
74019df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
74119df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
742*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
743*a05eeebfSFrançois Tigeot 
744*a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
745*a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
74619df918dSFrançois Tigeot 
74719df918dSFrançois Tigeot 	I915_WRITE(reg, val);
74819df918dSFrançois Tigeot 	POSTING_READ(reg);
74919df918dSFrançois Tigeot 
75019df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
75119df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
7529edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
75319df918dSFrançois Tigeot }
75419df918dSFrançois Tigeot 
75519df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder,
756ba55f2f5SFrançois Tigeot 			       bool enable,
75719df918dSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
75819df918dSFrançois Tigeot {
75919df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
760ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
76119df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
76219df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
76319df918dSFrançois Tigeot 	u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
76419df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
765ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
76619df918dSFrançois Tigeot 
76719df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
76819df918dSFrançois Tigeot 
76919df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
77019df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
77119df918dSFrançois Tigeot 
772ba55f2f5SFrançois Tigeot 	if (!enable) {
77319df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
77419df918dSFrançois Tigeot 			return;
775*a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
776*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
777*a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
77819df918dSFrançois Tigeot 		I915_WRITE(reg, val);
77919df918dSFrançois Tigeot 		POSTING_READ(reg);
78019df918dSFrançois Tigeot 		return;
78119df918dSFrançois Tigeot 	}
78219df918dSFrançois Tigeot 
783ba55f2f5SFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
784*a05eeebfSFrançois Tigeot 		WARN(val & VIDEO_DIP_ENABLE,
785*a05eeebfSFrançois Tigeot 		     "DIP already enabled on port %c\n",
786*a05eeebfSFrançois Tigeot 		     (val & VIDEO_DIP_PORT_MASK) >> 29);
787ba55f2f5SFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
788ba55f2f5SFrançois Tigeot 		val |= port;
789ba55f2f5SFrançois Tigeot 	}
790ba55f2f5SFrançois Tigeot 
79119df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
792*a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
793*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
794*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
795*a05eeebfSFrançois Tigeot 
796*a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
797*a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
79819df918dSFrançois Tigeot 
79919df918dSFrançois Tigeot 	I915_WRITE(reg, val);
80019df918dSFrançois Tigeot 	POSTING_READ(reg);
80119df918dSFrançois Tigeot 
80219df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
80319df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
8049edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
80519df918dSFrançois Tigeot }
80619df918dSFrançois Tigeot 
80719df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder,
808ba55f2f5SFrançois Tigeot 			       bool enable,
80919df918dSFrançois Tigeot 			       struct drm_display_mode *adjusted_mode)
81019df918dSFrançois Tigeot {
81119df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
81219df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
81319df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
8142c9916cdSFrançois Tigeot 	u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
81519df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
81619df918dSFrançois Tigeot 
81719df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
81819df918dSFrançois Tigeot 
819*a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
820*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
821*a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
822*a05eeebfSFrançois Tigeot 
823ba55f2f5SFrançois Tigeot 	if (!enable) {
824*a05eeebfSFrançois Tigeot 		I915_WRITE(reg, val);
82519df918dSFrançois Tigeot 		POSTING_READ(reg);
82619df918dSFrançois Tigeot 		return;
82719df918dSFrançois Tigeot 	}
82819df918dSFrançois Tigeot 
829*a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
830*a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP_HSW;
83119df918dSFrançois Tigeot 
83219df918dSFrançois Tigeot 	I915_WRITE(reg, val);
83319df918dSFrançois Tigeot 	POSTING_READ(reg);
83419df918dSFrançois Tigeot 
83519df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
83619df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
8379edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
83819df918dSFrançois Tigeot }
83919df918dSFrançois Tigeot 
840ba55f2f5SFrançois Tigeot static void intel_hdmi_prepare(struct intel_encoder *encoder)
841e3adcf8fSFrançois Tigeot {
8429edbd4a0SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
843e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
8449edbd4a0SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
8459edbd4a0SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
8462c9916cdSFrançois Tigeot 	struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
8478e26cdf6SFrançois Tigeot 	u32 hdmi_val;
848e3adcf8fSFrançois Tigeot 
8498e26cdf6SFrançois Tigeot 	hdmi_val = SDVO_ENCODING_HDMI;
8505d0b1887SFrançois Tigeot 	if (!HAS_PCH_SPLIT(dev))
8518e26cdf6SFrançois Tigeot 		hdmi_val |= intel_hdmi->color_range;
852e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
8538e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
854e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
8558e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
856e3adcf8fSFrançois Tigeot 
8572c9916cdSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24)
8588e26cdf6SFrançois Tigeot 		hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
859e3adcf8fSFrançois Tigeot 	else
8608e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
861e3adcf8fSFrançois Tigeot 
8622c9916cdSFrançois Tigeot 	if (crtc->config->has_hdmi_sink)
8638e26cdf6SFrançois Tigeot 		hdmi_val |= HDMI_MODE_SELECT_HDMI;
864e3adcf8fSFrançois Tigeot 
865e3adcf8fSFrançois Tigeot 	if (HAS_PCH_CPT(dev))
8669edbd4a0SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
867ba55f2f5SFrançois Tigeot 	else if (IS_CHERRYVIEW(dev))
868ba55f2f5SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe);
8698e26cdf6SFrançois Tigeot 	else
8709edbd4a0SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
871e3adcf8fSFrançois Tigeot 
8728e26cdf6SFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
8738e26cdf6SFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
874e3adcf8fSFrançois Tigeot }
875e3adcf8fSFrançois Tigeot 
87619df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
87719df918dSFrançois Tigeot 				    enum i915_pipe *pipe)
878e3adcf8fSFrançois Tigeot {
87919df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
880e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
88119df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
882ba55f2f5SFrançois Tigeot 	enum intel_display_power_domain power_domain;
88319df918dSFrançois Tigeot 	u32 tmp;
88419df918dSFrançois Tigeot 
885ba55f2f5SFrançois Tigeot 	power_domain = intel_display_port_power_domain(encoder);
8862c9916cdSFrançois Tigeot 	if (!intel_display_power_is_enabled(dev_priv, power_domain))
887ba55f2f5SFrançois Tigeot 		return false;
888ba55f2f5SFrançois Tigeot 
8898e26cdf6SFrançois Tigeot 	tmp = I915_READ(intel_hdmi->hdmi_reg);
89019df918dSFrançois Tigeot 
89119df918dSFrançois Tigeot 	if (!(tmp & SDVO_ENABLE))
89219df918dSFrançois Tigeot 		return false;
89319df918dSFrançois Tigeot 
89419df918dSFrançois Tigeot 	if (HAS_PCH_CPT(dev))
89519df918dSFrançois Tigeot 		*pipe = PORT_TO_PIPE_CPT(tmp);
896ba55f2f5SFrançois Tigeot 	else if (IS_CHERRYVIEW(dev))
897ba55f2f5SFrançois Tigeot 		*pipe = SDVO_PORT_TO_PIPE_CHV(tmp);
89819df918dSFrançois Tigeot 	else
89919df918dSFrançois Tigeot 		*pipe = PORT_TO_PIPE(tmp);
90019df918dSFrançois Tigeot 
90119df918dSFrançois Tigeot 	return true;
90219df918dSFrançois Tigeot }
90319df918dSFrançois Tigeot 
9045d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder,
9052c9916cdSFrançois Tigeot 				  struct intel_crtc_state *pipe_config)
9065d0b1887SFrançois Tigeot {
9075d0b1887SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
90824edb884SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
90924edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
9105d0b1887SFrançois Tigeot 	u32 tmp, flags = 0;
9119edbd4a0SFrançois Tigeot 	int dotclock;
9125d0b1887SFrançois Tigeot 
9135d0b1887SFrançois Tigeot 	tmp = I915_READ(intel_hdmi->hdmi_reg);
9145d0b1887SFrançois Tigeot 
9155d0b1887SFrançois Tigeot 	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
9165d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PHSYNC;
9175d0b1887SFrançois Tigeot 	else
9185d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NHSYNC;
9195d0b1887SFrançois Tigeot 
9205d0b1887SFrançois Tigeot 	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
9215d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PVSYNC;
9225d0b1887SFrançois Tigeot 	else
9235d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NVSYNC;
9245d0b1887SFrançois Tigeot 
925ba55f2f5SFrançois Tigeot 	if (tmp & HDMI_MODE_SELECT_HDMI)
926ba55f2f5SFrançois Tigeot 		pipe_config->has_hdmi_sink = true;
927ba55f2f5SFrançois Tigeot 
9282c9916cdSFrançois Tigeot 	if (intel_hdmi->infoframe_enabled(&encoder->base))
9292c9916cdSFrançois Tigeot 		pipe_config->has_infoframe = true;
9302c9916cdSFrançois Tigeot 
93124edb884SFrançois Tigeot 	if (tmp & SDVO_AUDIO_ENABLE)
932ba55f2f5SFrançois Tigeot 		pipe_config->has_audio = true;
933ba55f2f5SFrançois Tigeot 
93424edb884SFrançois Tigeot 	if (!HAS_PCH_SPLIT(dev) &&
93524edb884SFrançois Tigeot 	    tmp & HDMI_COLOR_RANGE_16_235)
93624edb884SFrançois Tigeot 		pipe_config->limited_color_range = true;
93724edb884SFrançois Tigeot 
9382c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.flags |= flags;
9399edbd4a0SFrançois Tigeot 
9409edbd4a0SFrançois Tigeot 	if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
9419edbd4a0SFrançois Tigeot 		dotclock = pipe_config->port_clock * 2 / 3;
9429edbd4a0SFrançois Tigeot 	else
9439edbd4a0SFrançois Tigeot 		dotclock = pipe_config->port_clock;
9449edbd4a0SFrançois Tigeot 
945*a05eeebfSFrançois Tigeot 	if (pipe_config->pixel_multiplier)
946*a05eeebfSFrançois Tigeot 		dotclock /= pipe_config->pixel_multiplier;
947*a05eeebfSFrançois Tigeot 
9489edbd4a0SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv->dev))
9499edbd4a0SFrançois Tigeot 		ironlake_check_encoder_dotclock(pipe_config, dotclock);
9509edbd4a0SFrançois Tigeot 
9512c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
9525d0b1887SFrançois Tigeot }
9535d0b1887SFrançois Tigeot 
954*a05eeebfSFrançois Tigeot static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
955*a05eeebfSFrançois Tigeot {
956*a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
957*a05eeebfSFrançois Tigeot 
958*a05eeebfSFrançois Tigeot 	WARN_ON(!crtc->config->has_hdmi_sink);
959*a05eeebfSFrançois Tigeot 	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
960*a05eeebfSFrançois Tigeot 			 pipe_name(crtc->pipe));
961*a05eeebfSFrançois Tigeot 	intel_audio_codec_enable(encoder);
962*a05eeebfSFrançois Tigeot }
963*a05eeebfSFrançois Tigeot 
964*a05eeebfSFrançois Tigeot static void g4x_enable_hdmi(struct intel_encoder *encoder)
96519df918dSFrançois Tigeot {
96619df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
96719df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
968*a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
96919df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
970e3adcf8fSFrançois Tigeot 	u32 temp;
971e3adcf8fSFrançois Tigeot 
9728e26cdf6SFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
973e3adcf8fSFrançois Tigeot 
974*a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
975*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
976*a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
97719df918dSFrançois Tigeot 
978*a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
979*a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
980*a05eeebfSFrançois Tigeot 
981*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
982*a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
983*a05eeebfSFrançois Tigeot }
984*a05eeebfSFrançois Tigeot 
985*a05eeebfSFrançois Tigeot static void ibx_enable_hdmi(struct intel_encoder *encoder)
986*a05eeebfSFrançois Tigeot {
987*a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
988*a05eeebfSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
989*a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
990*a05eeebfSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
991*a05eeebfSFrançois Tigeot 	u32 temp;
992*a05eeebfSFrançois Tigeot 
993*a05eeebfSFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
994*a05eeebfSFrançois Tigeot 
995*a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
996*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
997*a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
998*a05eeebfSFrançois Tigeot 
999*a05eeebfSFrançois Tigeot 	/*
1000*a05eeebfSFrançois Tigeot 	 * HW workaround, need to write this twice for issue
1001*a05eeebfSFrançois Tigeot 	 * that may result in first write getting masked.
1002e3adcf8fSFrançois Tigeot 	 */
1003*a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1004*a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1005*a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1006*a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1007*a05eeebfSFrançois Tigeot 
1008*a05eeebfSFrançois Tigeot 	/*
1009*a05eeebfSFrançois Tigeot 	 * HW workaround, need to toggle enable bit off and on
1010*a05eeebfSFrançois Tigeot 	 * for 12bpc with pixel repeat.
1011*a05eeebfSFrançois Tigeot 	 *
1012*a05eeebfSFrançois Tigeot 	 * FIXME: BSpec says this should be done at the end of
1013*a05eeebfSFrançois Tigeot 	 * of the modeset sequence, so not sure if this isn't too soon.
1014*a05eeebfSFrançois Tigeot 	 */
1015*a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24 &&
1016*a05eeebfSFrançois Tigeot 	    crtc->config->pixel_multiplier > 1) {
10178e26cdf6SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
10188e26cdf6SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1019e3adcf8fSFrançois Tigeot 
1020*a05eeebfSFrançois Tigeot 		/*
1021*a05eeebfSFrançois Tigeot 		 * HW workaround, need to write this twice for issue
1022*a05eeebfSFrançois Tigeot 		 * that may result in first write getting masked.
102319df918dSFrançois Tigeot 		 */
1024*a05eeebfSFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
1025*a05eeebfSFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
10268e26cdf6SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
10278e26cdf6SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1028e3adcf8fSFrançois Tigeot 	}
10292c9916cdSFrançois Tigeot 
1030*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1031*a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
10322c9916cdSFrançois Tigeot }
1033*a05eeebfSFrançois Tigeot 
1034*a05eeebfSFrançois Tigeot static void cpt_enable_hdmi(struct intel_encoder *encoder)
1035*a05eeebfSFrançois Tigeot {
1036*a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1037*a05eeebfSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1038*a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
1039*a05eeebfSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1040*a05eeebfSFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
1041*a05eeebfSFrançois Tigeot 	u32 temp;
1042*a05eeebfSFrançois Tigeot 
1043*a05eeebfSFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
1044*a05eeebfSFrançois Tigeot 
1045*a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
1046*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1047*a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
1048*a05eeebfSFrançois Tigeot 
1049*a05eeebfSFrançois Tigeot 	/*
1050*a05eeebfSFrançois Tigeot 	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb
1051*a05eeebfSFrançois Tigeot 	 *
1052*a05eeebfSFrançois Tigeot 	 * The procedure for 12bpc is as follows:
1053*a05eeebfSFrançois Tigeot 	 * 1. disable HDMI clock gating
1054*a05eeebfSFrançois Tigeot 	 * 2. enable HDMI with 8bpc
1055*a05eeebfSFrançois Tigeot 	 * 3. enable HDMI with 12bpc
1056*a05eeebfSFrançois Tigeot 	 * 4. enable HDMI clock gating
1057*a05eeebfSFrançois Tigeot 	 */
1058*a05eeebfSFrançois Tigeot 
1059*a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24) {
1060*a05eeebfSFrançois Tigeot 		I915_WRITE(TRANS_CHICKEN1(pipe),
1061*a05eeebfSFrançois Tigeot 			   I915_READ(TRANS_CHICKEN1(pipe)) |
1062*a05eeebfSFrançois Tigeot 			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1063*a05eeebfSFrançois Tigeot 
1064*a05eeebfSFrançois Tigeot 		temp &= ~SDVO_COLOR_FORMAT_MASK;
1065*a05eeebfSFrançois Tigeot 		temp |= SDVO_COLOR_FORMAT_8bpc;
1066*a05eeebfSFrançois Tigeot 	}
1067*a05eeebfSFrançois Tigeot 
1068*a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1069*a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1070*a05eeebfSFrançois Tigeot 
1071*a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24) {
1072*a05eeebfSFrançois Tigeot 		temp &= ~SDVO_COLOR_FORMAT_MASK;
1073*a05eeebfSFrançois Tigeot 		temp |= HDMI_COLOR_FORMAT_12bpc;
1074*a05eeebfSFrançois Tigeot 
1075*a05eeebfSFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
1076*a05eeebfSFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1077*a05eeebfSFrançois Tigeot 
1078*a05eeebfSFrançois Tigeot 		I915_WRITE(TRANS_CHICKEN1(pipe),
1079*a05eeebfSFrançois Tigeot 			   I915_READ(TRANS_CHICKEN1(pipe)) &
1080*a05eeebfSFrançois Tigeot 			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1081*a05eeebfSFrançois Tigeot 	}
1082*a05eeebfSFrançois Tigeot 
1083*a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1084*a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
10855d0b1887SFrançois Tigeot }
10869edbd4a0SFrançois Tigeot 
10879edbd4a0SFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder)
10889edbd4a0SFrançois Tigeot {
108919df918dSFrançois Tigeot }
109019df918dSFrançois Tigeot 
109119df918dSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder)
109219df918dSFrançois Tigeot {
109319df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
109419df918dSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
109519df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
10962c9916cdSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
109719df918dSFrançois Tigeot 	u32 temp;
109819c468b4SFrançois Tigeot 
109919c468b4SFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
110019c468b4SFrançois Tigeot 
110119c468b4SFrançois Tigeot 	temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE);
110219c468b4SFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
110319c468b4SFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
110419c468b4SFrançois Tigeot 
110519c468b4SFrançois Tigeot 	/*
110619c468b4SFrançois Tigeot 	 * HW workaround for IBX, we need to move the port
110719c468b4SFrançois Tigeot 	 * to transcoder A after disabling it to allow the
110819c468b4SFrançois Tigeot 	 * matching DP port to be enabled on transcoder A.
110919c468b4SFrançois Tigeot 	 */
111019c468b4SFrançois Tigeot 	if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
111119c468b4SFrançois Tigeot 		temp &= ~SDVO_PIPE_B_SELECT;
111219c468b4SFrançois Tigeot 		temp |= SDVO_ENABLE;
111319c468b4SFrançois Tigeot 		/*
111419c468b4SFrançois Tigeot 		 * HW workaround, need to write this twice for issue
111519c468b4SFrançois Tigeot 		 * that may result in first write getting masked.
111619c468b4SFrançois Tigeot 		 */
111719c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
111819c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
111919c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
112019c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
112119c468b4SFrançois Tigeot 
112219c468b4SFrançois Tigeot 		temp &= ~SDVO_ENABLE;
112319c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
112419c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
112519c468b4SFrançois Tigeot 	}
1126*a05eeebfSFrançois Tigeot 
1127*a05eeebfSFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base, false, NULL);
112819c468b4SFrançois Tigeot }
112919c468b4SFrançois Tigeot 
113019c468b4SFrançois Tigeot static void g4x_disable_hdmi(struct intel_encoder *encoder)
113119c468b4SFrançois Tigeot {
113219c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
113319df918dSFrançois Tigeot 
11342c9916cdSFrançois Tigeot 	if (crtc->config->has_audio)
11352c9916cdSFrançois Tigeot 		intel_audio_codec_disable(encoder);
11362c9916cdSFrançois Tigeot 
113719c468b4SFrançois Tigeot 	intel_disable_hdmi(encoder);
113819df918dSFrançois Tigeot }
113919df918dSFrançois Tigeot 
114019c468b4SFrançois Tigeot static void pch_disable_hdmi(struct intel_encoder *encoder)
114119c468b4SFrançois Tigeot {
114219c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
114319c468b4SFrançois Tigeot 
114419c468b4SFrançois Tigeot 	if (crtc->config->has_audio)
114519c468b4SFrançois Tigeot 		intel_audio_codec_disable(encoder);
114619df918dSFrançois Tigeot }
114719df918dSFrançois Tigeot 
114819c468b4SFrançois Tigeot static void pch_post_disable_hdmi(struct intel_encoder *encoder)
114919c468b4SFrançois Tigeot {
115019c468b4SFrançois Tigeot 	intel_disable_hdmi(encoder);
1151e3adcf8fSFrançois Tigeot }
1152e3adcf8fSFrançois Tigeot 
1153*a05eeebfSFrançois Tigeot static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
11545d0b1887SFrançois Tigeot {
11555d0b1887SFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
11565d0b1887SFrançois Tigeot 
1157ba55f2f5SFrançois Tigeot 	if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev))
11585d0b1887SFrançois Tigeot 		return 165000;
11599edbd4a0SFrançois Tigeot 	else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
11605d0b1887SFrançois Tigeot 		return 300000;
11615d0b1887SFrançois Tigeot 	else
11625d0b1887SFrançois Tigeot 		return 225000;
11635d0b1887SFrançois Tigeot }
11645d0b1887SFrançois Tigeot 
11659edbd4a0SFrançois Tigeot static enum drm_mode_status
1166*a05eeebfSFrançois Tigeot hdmi_port_clock_valid(struct intel_hdmi *hdmi,
1167*a05eeebfSFrançois Tigeot 		      int clock, bool respect_dvi_limit)
1168*a05eeebfSFrançois Tigeot {
1169*a05eeebfSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
1170*a05eeebfSFrançois Tigeot 
1171*a05eeebfSFrançois Tigeot 	if (clock < 25000)
1172*a05eeebfSFrançois Tigeot 		return MODE_CLOCK_LOW;
1173*a05eeebfSFrançois Tigeot 	if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit))
1174*a05eeebfSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1175*a05eeebfSFrançois Tigeot 
1176*a05eeebfSFrançois Tigeot 	/* BXT DPLL can't generate 223-240 MHz */
1177*a05eeebfSFrançois Tigeot 	if (IS_BROXTON(dev) && clock > 223333 && clock < 240000)
1178*a05eeebfSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1179*a05eeebfSFrançois Tigeot 
1180*a05eeebfSFrançois Tigeot 	/* CHV DPLL can't generate 216-240 MHz */
1181*a05eeebfSFrançois Tigeot 	if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000)
1182*a05eeebfSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1183*a05eeebfSFrançois Tigeot 
1184*a05eeebfSFrançois Tigeot 	return MODE_OK;
1185*a05eeebfSFrançois Tigeot }
1186*a05eeebfSFrançois Tigeot 
1187*a05eeebfSFrançois Tigeot static enum drm_mode_status
11889edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector,
1189e3adcf8fSFrançois Tigeot 		      struct drm_display_mode *mode)
1190e3adcf8fSFrançois Tigeot {
1191*a05eeebfSFrançois Tigeot 	struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
1192*a05eeebfSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
1193*a05eeebfSFrançois Tigeot 	enum drm_mode_status status;
1194*a05eeebfSFrançois Tigeot 	int clock;
1195e3adcf8fSFrançois Tigeot 
1196e3adcf8fSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
1197e3adcf8fSFrançois Tigeot 		return MODE_NO_DBLESCAN;
1198e3adcf8fSFrançois Tigeot 
1199*a05eeebfSFrançois Tigeot 	clock = mode->clock;
1200*a05eeebfSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1201*a05eeebfSFrançois Tigeot 		clock *= 2;
1202*a05eeebfSFrançois Tigeot 
1203*a05eeebfSFrançois Tigeot 	/* check if we can do 8bpc */
1204*a05eeebfSFrançois Tigeot 	status = hdmi_port_clock_valid(hdmi, clock, true);
1205*a05eeebfSFrançois Tigeot 
1206*a05eeebfSFrançois Tigeot 	/* if we can't do 8bpc we may still be able to do 12bpc */
1207*a05eeebfSFrançois Tigeot 	if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK)
1208*a05eeebfSFrançois Tigeot 		status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true);
1209*a05eeebfSFrançois Tigeot 
1210*a05eeebfSFrançois Tigeot 	return status;
1211e3adcf8fSFrançois Tigeot }
1212e3adcf8fSFrançois Tigeot 
1213477eb7f9SFrançois Tigeot static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
1214ba55f2f5SFrançois Tigeot {
1215477eb7f9SFrançois Tigeot 	struct drm_device *dev = crtc_state->base.crtc->dev;
1216477eb7f9SFrançois Tigeot 	struct drm_atomic_state *state;
1217ba55f2f5SFrançois Tigeot 	struct intel_encoder *encoder;
121819c468b4SFrançois Tigeot 	struct drm_connector *connector;
1219477eb7f9SFrançois Tigeot 	struct drm_connector_state *connector_state;
1220ba55f2f5SFrançois Tigeot 	int count = 0, count_hdmi = 0;
1221477eb7f9SFrançois Tigeot 	int i;
1222ba55f2f5SFrançois Tigeot 
122324edb884SFrançois Tigeot 	if (HAS_GMCH_DISPLAY(dev))
1224ba55f2f5SFrançois Tigeot 		return false;
1225ba55f2f5SFrançois Tigeot 
1226477eb7f9SFrançois Tigeot 	state = crtc_state->base.state;
1227477eb7f9SFrançois Tigeot 
122819c468b4SFrançois Tigeot 	for_each_connector_in_state(state, connector, connector_state, i) {
1229477eb7f9SFrançois Tigeot 		if (connector_state->crtc != crtc_state->base.crtc)
1230477eb7f9SFrançois Tigeot 			continue;
1231477eb7f9SFrançois Tigeot 
1232477eb7f9SFrançois Tigeot 		encoder = to_intel_encoder(connector_state->best_encoder);
1233477eb7f9SFrançois Tigeot 
1234ba55f2f5SFrançois Tigeot 		count_hdmi += encoder->type == INTEL_OUTPUT_HDMI;
1235ba55f2f5SFrançois Tigeot 		count++;
1236ba55f2f5SFrançois Tigeot 	}
1237ba55f2f5SFrançois Tigeot 
1238ba55f2f5SFrançois Tigeot 	/*
1239ba55f2f5SFrançois Tigeot 	 * HDMI 12bpc affects the clocks, so it's only possible
1240ba55f2f5SFrançois Tigeot 	 * when not cloning with other encoder types.
1241ba55f2f5SFrançois Tigeot 	 */
1242ba55f2f5SFrançois Tigeot 	return count_hdmi > 0 && count_hdmi == count;
1243ba55f2f5SFrançois Tigeot }
1244ba55f2f5SFrançois Tigeot 
12458e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder,
12462c9916cdSFrançois Tigeot 			       struct intel_crtc_state *pipe_config)
1247e3adcf8fSFrançois Tigeot {
12488e26cdf6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
12498e26cdf6SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
12502c9916cdSFrançois Tigeot 	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
1251*a05eeebfSFrançois Tigeot 	int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
1252*a05eeebfSFrançois Tigeot 	int clock_12bpc = clock_8bpc * 3 / 2;
12535d0b1887SFrançois Tigeot 	int desired_bpp;
1254a2fdbec6SFrançois Tigeot 
1255ba55f2f5SFrançois Tigeot 	pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink;
1256ba55f2f5SFrançois Tigeot 
12572c9916cdSFrançois Tigeot 	if (pipe_config->has_hdmi_sink)
12582c9916cdSFrançois Tigeot 		pipe_config->has_infoframe = true;
12592c9916cdSFrançois Tigeot 
1260a2fdbec6SFrançois Tigeot 	if (intel_hdmi->color_range_auto) {
1261a2fdbec6SFrançois Tigeot 		/* See CEA-861-E - 5.1 Default Encoding Parameters */
1262ba55f2f5SFrançois Tigeot 		if (pipe_config->has_hdmi_sink &&
1263a2fdbec6SFrançois Tigeot 		    drm_match_cea_mode(adjusted_mode) > 1)
12648e26cdf6SFrançois Tigeot 			intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
1265a2fdbec6SFrançois Tigeot 		else
1266a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range = 0;
1267a2fdbec6SFrançois Tigeot 	}
1268a2fdbec6SFrançois Tigeot 
12691b13d190SFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
12701b13d190SFrançois Tigeot 		pipe_config->pixel_multiplier = 2;
1271*a05eeebfSFrançois Tigeot 		clock_8bpc *= 2;
1272*a05eeebfSFrançois Tigeot 		clock_12bpc *= 2;
12731b13d190SFrançois Tigeot 	}
12741b13d190SFrançois Tigeot 
1275a2fdbec6SFrançois Tigeot 	if (intel_hdmi->color_range)
12768e26cdf6SFrançois Tigeot 		pipe_config->limited_color_range = true;
12778e26cdf6SFrançois Tigeot 
12788e26cdf6SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev))
12798e26cdf6SFrançois Tigeot 		pipe_config->has_pch_encoder = true;
12808e26cdf6SFrançois Tigeot 
1281ba55f2f5SFrançois Tigeot 	if (pipe_config->has_hdmi_sink && intel_hdmi->has_audio)
1282ba55f2f5SFrançois Tigeot 		pipe_config->has_audio = true;
1283ba55f2f5SFrançois Tigeot 
12848e26cdf6SFrançois Tigeot 	/*
12858e26cdf6SFrançois Tigeot 	 * HDMI is either 12 or 8, so if the display lets 10bpc sneak
12868e26cdf6SFrançois Tigeot 	 * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
12875d0b1887SFrançois Tigeot 	 * outputs. We also need to check that the higher clock still fits
12885d0b1887SFrançois Tigeot 	 * within limits.
12898e26cdf6SFrançois Tigeot 	 */
1290ba55f2f5SFrançois Tigeot 	if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
1291*a05eeebfSFrançois Tigeot 	    hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK &&
1292*a05eeebfSFrançois Tigeot 	    hdmi_12bpc_possible(pipe_config)) {
12935d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
12945d0b1887SFrançois Tigeot 		desired_bpp = 12*3;
12955d0b1887SFrançois Tigeot 
12965d0b1887SFrançois Tigeot 		/* Need to adjust the port link by 1.5x for 12bpc. */
12975d0b1887SFrançois Tigeot 		pipe_config->port_clock = clock_12bpc;
12988e26cdf6SFrançois Tigeot 	} else {
12995d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
13005d0b1887SFrançois Tigeot 		desired_bpp = 8*3;
1301*a05eeebfSFrançois Tigeot 
1302*a05eeebfSFrançois Tigeot 		pipe_config->port_clock = clock_8bpc;
13035d0b1887SFrançois Tigeot 	}
13045d0b1887SFrançois Tigeot 
13055d0b1887SFrançois Tigeot 	if (!pipe_config->bw_constrained) {
13065d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp);
13075d0b1887SFrançois Tigeot 		pipe_config->pipe_bpp = desired_bpp;
13085d0b1887SFrançois Tigeot 	}
13095d0b1887SFrançois Tigeot 
1310*a05eeebfSFrançois Tigeot 	if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
1311*a05eeebfSFrançois Tigeot 				  false) != MODE_OK) {
1312*a05eeebfSFrançois Tigeot 		DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
13135d0b1887SFrançois Tigeot 		return false;
13148e26cdf6SFrançois Tigeot 	}
1315a2fdbec6SFrançois Tigeot 
1316e3adcf8fSFrançois Tigeot 	return true;
1317e3adcf8fSFrançois Tigeot }
1318e3adcf8fSFrançois Tigeot 
13191b13d190SFrançois Tigeot static void
13201b13d190SFrançois Tigeot intel_hdmi_unset_edid(struct drm_connector *connector)
1321e3adcf8fSFrançois Tigeot {
1322e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13239edbd4a0SFrançois Tigeot 
1324e3adcf8fSFrançois Tigeot 	intel_hdmi->has_hdmi_sink = false;
1325e3adcf8fSFrançois Tigeot 	intel_hdmi->has_audio = false;
1326a2fdbec6SFrançois Tigeot 	intel_hdmi->rgb_quant_range_selectable = false;
1327e3adcf8fSFrançois Tigeot 
13281b13d190SFrançois Tigeot 	kfree(to_intel_connector(connector)->detect_edid);
13291b13d190SFrançois Tigeot 	to_intel_connector(connector)->detect_edid = NULL;
1330e3adcf8fSFrançois Tigeot }
1331e3adcf8fSFrançois Tigeot 
13321b13d190SFrançois Tigeot static bool
13331b13d190SFrançois Tigeot intel_hdmi_set_edid(struct drm_connector *connector)
1334e3adcf8fSFrançois Tigeot {
13351b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
13361b13d190SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13371b13d190SFrançois Tigeot 	struct intel_encoder *intel_encoder =
13381b13d190SFrançois Tigeot 		&hdmi_to_dig_port(intel_hdmi)->base;
1339ba55f2f5SFrançois Tigeot 	enum intel_display_power_domain power_domain;
13401b13d190SFrançois Tigeot 	struct edid *edid;
13411b13d190SFrançois Tigeot 	bool connected = false;
1342e3adcf8fSFrançois Tigeot 
1343ba55f2f5SFrançois Tigeot 	power_domain = intel_display_port_power_domain(intel_encoder);
1344ba55f2f5SFrançois Tigeot 	intel_display_power_get(dev_priv, power_domain);
1345ba55f2f5SFrançois Tigeot 
13461b13d190SFrançois Tigeot 	edid = drm_get_edid(connector,
134719df918dSFrançois Tigeot 			    intel_gmbus_get_adapter(dev_priv,
134819df918dSFrançois Tigeot 						    intel_hdmi->ddc_bus));
1349ba55f2f5SFrançois Tigeot 
1350ba55f2f5SFrançois Tigeot 	intel_display_power_put(dev_priv, power_domain);
1351ba55f2f5SFrançois Tigeot 
13521b13d190SFrançois Tigeot 	to_intel_connector(connector)->detect_edid = edid;
13531b13d190SFrançois Tigeot 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
13541b13d190SFrançois Tigeot 		intel_hdmi->rgb_quant_range_selectable =
13551b13d190SFrançois Tigeot 			drm_rgb_quant_range_selectable(edid);
13561b13d190SFrançois Tigeot 
13571b13d190SFrançois Tigeot 		intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
13581b13d190SFrançois Tigeot 		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
13591b13d190SFrançois Tigeot 			intel_hdmi->has_audio =
13601b13d190SFrançois Tigeot 				intel_hdmi->force_audio == HDMI_AUDIO_ON;
13611b13d190SFrançois Tigeot 
13621b13d190SFrançois Tigeot 		if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
13631b13d190SFrançois Tigeot 			intel_hdmi->has_hdmi_sink =
13641b13d190SFrançois Tigeot 				drm_detect_hdmi_monitor(edid);
13651b13d190SFrançois Tigeot 
13661b13d190SFrançois Tigeot 		connected = true;
13671b13d190SFrançois Tigeot 	}
13681b13d190SFrançois Tigeot 
13691b13d190SFrançois Tigeot 	return connected;
13701b13d190SFrançois Tigeot }
13711b13d190SFrançois Tigeot 
13721b13d190SFrançois Tigeot static enum drm_connector_status
13731b13d190SFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force)
13741b13d190SFrançois Tigeot {
13751b13d190SFrançois Tigeot 	enum drm_connector_status status;
13761b13d190SFrançois Tigeot 
13771b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
13781b13d190SFrançois Tigeot 		      connector->base.id, connector->name);
13791b13d190SFrançois Tigeot 
13801b13d190SFrançois Tigeot 	intel_hdmi_unset_edid(connector);
13811b13d190SFrançois Tigeot 
13821b13d190SFrançois Tigeot 	if (intel_hdmi_set_edid(connector)) {
13831b13d190SFrançois Tigeot 		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13841b13d190SFrançois Tigeot 
13851b13d190SFrançois Tigeot 		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
13861b13d190SFrançois Tigeot 		status = connector_status_connected;
13871b13d190SFrançois Tigeot 	} else
13881b13d190SFrançois Tigeot 		status = connector_status_disconnected;
13891b13d190SFrançois Tigeot 
13901b13d190SFrançois Tigeot 	return status;
13911b13d190SFrançois Tigeot }
13921b13d190SFrançois Tigeot 
13931b13d190SFrançois Tigeot static void
13941b13d190SFrançois Tigeot intel_hdmi_force(struct drm_connector *connector)
13951b13d190SFrançois Tigeot {
13961b13d190SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13971b13d190SFrançois Tigeot 
13981b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
13991b13d190SFrançois Tigeot 		      connector->base.id, connector->name);
14001b13d190SFrançois Tigeot 
14011b13d190SFrançois Tigeot 	intel_hdmi_unset_edid(connector);
14021b13d190SFrançois Tigeot 
14031b13d190SFrançois Tigeot 	if (connector->status != connector_status_connected)
14041b13d190SFrançois Tigeot 		return;
14051b13d190SFrançois Tigeot 
14061b13d190SFrançois Tigeot 	intel_hdmi_set_edid(connector);
14071b13d190SFrançois Tigeot 	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
14081b13d190SFrançois Tigeot }
14091b13d190SFrançois Tigeot 
14101b13d190SFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector)
14111b13d190SFrançois Tigeot {
14121b13d190SFrançois Tigeot 	struct edid *edid;
14131b13d190SFrançois Tigeot 
14141b13d190SFrançois Tigeot 	edid = to_intel_connector(connector)->detect_edid;
14151b13d190SFrançois Tigeot 	if (edid == NULL)
14161b13d190SFrançois Tigeot 		return 0;
14171b13d190SFrançois Tigeot 
14181b13d190SFrançois Tigeot 	return intel_connector_update_modes(connector, edid);
1419e3adcf8fSFrançois Tigeot }
1420e3adcf8fSFrançois Tigeot 
1421e3adcf8fSFrançois Tigeot static bool
1422e3adcf8fSFrançois Tigeot intel_hdmi_detect_audio(struct drm_connector *connector)
1423e3adcf8fSFrançois Tigeot {
1424e3adcf8fSFrançois Tigeot 	bool has_audio = false;
14251b13d190SFrançois Tigeot 	struct edid *edid;
1426e3adcf8fSFrançois Tigeot 
14271b13d190SFrançois Tigeot 	edid = to_intel_connector(connector)->detect_edid;
14281b13d190SFrançois Tigeot 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)
1429e3adcf8fSFrançois Tigeot 		has_audio = drm_detect_monitor_audio(edid);
1430ba55f2f5SFrançois Tigeot 
1431e3adcf8fSFrançois Tigeot 	return has_audio;
1432e3adcf8fSFrançois Tigeot }
1433e3adcf8fSFrançois Tigeot 
1434e3adcf8fSFrançois Tigeot static int
1435e3adcf8fSFrançois Tigeot intel_hdmi_set_property(struct drm_connector *connector,
1436e3adcf8fSFrançois Tigeot 			struct drm_property *property,
1437e3adcf8fSFrançois Tigeot 			uint64_t val)
1438e3adcf8fSFrançois Tigeot {
1439e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
144019df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port =
144119df918dSFrançois Tigeot 		hdmi_to_dig_port(intel_hdmi);
1442e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
1443e3adcf8fSFrançois Tigeot 	int ret;
1444e3adcf8fSFrançois Tigeot 
1445b5162e19SFrançois Tigeot 	ret = drm_object_property_set_value(&connector->base, property, val);
1446e3adcf8fSFrançois Tigeot 	if (ret)
1447e3adcf8fSFrançois Tigeot 		return ret;
1448e3adcf8fSFrançois Tigeot 
1449e3adcf8fSFrançois Tigeot 	if (property == dev_priv->force_audio_property) {
1450e3adcf8fSFrançois Tigeot 		enum hdmi_force_audio i = val;
1451e3adcf8fSFrançois Tigeot 		bool has_audio;
1452e3adcf8fSFrançois Tigeot 
1453e3adcf8fSFrançois Tigeot 		if (i == intel_hdmi->force_audio)
1454e3adcf8fSFrançois Tigeot 			return 0;
1455e3adcf8fSFrançois Tigeot 
1456e3adcf8fSFrançois Tigeot 		intel_hdmi->force_audio = i;
1457e3adcf8fSFrançois Tigeot 
1458e3adcf8fSFrançois Tigeot 		if (i == HDMI_AUDIO_AUTO)
1459e3adcf8fSFrançois Tigeot 			has_audio = intel_hdmi_detect_audio(connector);
1460e3adcf8fSFrançois Tigeot 		else
1461e3adcf8fSFrançois Tigeot 			has_audio = (i == HDMI_AUDIO_ON);
1462e3adcf8fSFrançois Tigeot 
1463e3adcf8fSFrançois Tigeot 		if (i == HDMI_AUDIO_OFF_DVI)
1464e3adcf8fSFrançois Tigeot 			intel_hdmi->has_hdmi_sink = 0;
1465e3adcf8fSFrançois Tigeot 
1466e3adcf8fSFrançois Tigeot 		intel_hdmi->has_audio = has_audio;
1467e3adcf8fSFrançois Tigeot 		goto done;
1468e3adcf8fSFrançois Tigeot 	}
1469e3adcf8fSFrançois Tigeot 
1470e3adcf8fSFrançois Tigeot 	if (property == dev_priv->broadcast_rgb_property) {
14718e26cdf6SFrançois Tigeot 		bool old_auto = intel_hdmi->color_range_auto;
14728e26cdf6SFrançois Tigeot 		uint32_t old_range = intel_hdmi->color_range;
14738e26cdf6SFrançois Tigeot 
1474a2fdbec6SFrançois Tigeot 		switch (val) {
1475a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_AUTO:
1476a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = true;
1477a2fdbec6SFrançois Tigeot 			break;
1478a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_FULL:
1479a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = false;
1480a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range = 0;
1481a2fdbec6SFrançois Tigeot 			break;
1482a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_LIMITED:
1483a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = false;
14848e26cdf6SFrançois Tigeot 			intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
1485a2fdbec6SFrançois Tigeot 			break;
1486a2fdbec6SFrançois Tigeot 		default:
1487a2fdbec6SFrançois Tigeot 			return -EINVAL;
1488a2fdbec6SFrançois Tigeot 		}
14898e26cdf6SFrançois Tigeot 
14908e26cdf6SFrançois Tigeot 		if (old_auto == intel_hdmi->color_range_auto &&
14918e26cdf6SFrançois Tigeot 		    old_range == intel_hdmi->color_range)
14928e26cdf6SFrançois Tigeot 			return 0;
14938e26cdf6SFrançois Tigeot 
1494e3adcf8fSFrançois Tigeot 		goto done;
1495e3adcf8fSFrançois Tigeot 	}
1496e3adcf8fSFrançois Tigeot 
149724edb884SFrançois Tigeot 	if (property == connector->dev->mode_config.aspect_ratio_property) {
149824edb884SFrançois Tigeot 		switch (val) {
149924edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_NONE:
150024edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
150124edb884SFrançois Tigeot 			break;
150224edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_4_3:
150324edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
150424edb884SFrançois Tigeot 			break;
150524edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_16_9:
150624edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
150724edb884SFrançois Tigeot 			break;
150824edb884SFrançois Tigeot 		default:
150924edb884SFrançois Tigeot 			return -EINVAL;
151024edb884SFrançois Tigeot 		}
151124edb884SFrançois Tigeot 		goto done;
151224edb884SFrançois Tigeot 	}
151324edb884SFrançois Tigeot 
1514e3adcf8fSFrançois Tigeot 	return -EINVAL;
1515e3adcf8fSFrançois Tigeot 
1516e3adcf8fSFrançois Tigeot done:
1517a2fdbec6SFrançois Tigeot 	if (intel_dig_port->base.base.crtc)
1518a2fdbec6SFrançois Tigeot 		intel_crtc_restore_mode(intel_dig_port->base.base.crtc);
1519e3adcf8fSFrançois Tigeot 
1520e3adcf8fSFrançois Tigeot 	return 0;
1521e3adcf8fSFrançois Tigeot }
1522e3adcf8fSFrançois Tigeot 
1523ba55f2f5SFrançois Tigeot static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
1524ba55f2f5SFrançois Tigeot {
1525ba55f2f5SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1526ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
1527ba55f2f5SFrançois Tigeot 	struct drm_display_mode *adjusted_mode =
15282c9916cdSFrançois Tigeot 		&intel_crtc->config->base.adjusted_mode;
1529ba55f2f5SFrançois Tigeot 
1530ba55f2f5SFrançois Tigeot 	intel_hdmi_prepare(encoder);
1531ba55f2f5SFrançois Tigeot 
1532ba55f2f5SFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
15332c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
1534ba55f2f5SFrançois Tigeot 				   adjusted_mode);
1535ba55f2f5SFrançois Tigeot }
1536ba55f2f5SFrançois Tigeot 
15379edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
15385d0b1887SFrançois Tigeot {
15395d0b1887SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
1540ba55f2f5SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &dport->hdmi;
15415d0b1887SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
15425d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
15435d0b1887SFrançois Tigeot 	struct intel_crtc *intel_crtc =
15445d0b1887SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
1545ba55f2f5SFrançois Tigeot 	struct drm_display_mode *adjusted_mode =
15462c9916cdSFrançois Tigeot 		&intel_crtc->config->base.adjusted_mode;
15479edbd4a0SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
15485d0b1887SFrançois Tigeot 	int pipe = intel_crtc->pipe;
15495d0b1887SFrançois Tigeot 	u32 val;
15505d0b1887SFrançois Tigeot 
15515d0b1887SFrançois Tigeot 	/* Enable clock channels for this port */
155219c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
15539edbd4a0SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port));
15545d0b1887SFrançois Tigeot 	val = 0;
15555d0b1887SFrançois Tigeot 	if (pipe)
15565d0b1887SFrançois Tigeot 		val |= (1<<21);
15575d0b1887SFrançois Tigeot 	else
15585d0b1887SFrançois Tigeot 		val &= ~(1<<21);
15595d0b1887SFrançois Tigeot 	val |= 0x001000c4;
15609edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val);
15615d0b1887SFrançois Tigeot 
15625d0b1887SFrançois Tigeot 	/* HDMI 1.0V-2dB */
15639edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0);
15649edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f);
15659edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a);
15669edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040);
15679edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878);
15689edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000);
15699edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000);
15709edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN);
15715d0b1887SFrançois Tigeot 
15725d0b1887SFrançois Tigeot 	/* Program lane clock */
15739edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018);
15749edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888);
157519c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
15769edbd4a0SFrançois Tigeot 
1577ba55f2f5SFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
15782c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
1579ba55f2f5SFrançois Tigeot 				   adjusted_mode);
1580ba55f2f5SFrançois Tigeot 
1581*a05eeebfSFrançois Tigeot 	g4x_enable_hdmi(encoder);
15829edbd4a0SFrançois Tigeot 
158319c468b4SFrançois Tigeot 	vlv_wait_port_ready(dev_priv, dport, 0x0);
15845d0b1887SFrançois Tigeot }
15855d0b1887SFrançois Tigeot 
15869edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
15875d0b1887SFrançois Tigeot {
15885d0b1887SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
15895d0b1887SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
15905d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
15919edbd4a0SFrançois Tigeot 	struct intel_crtc *intel_crtc =
15929edbd4a0SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
15939edbd4a0SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
15949edbd4a0SFrançois Tigeot 	int pipe = intel_crtc->pipe;
15955d0b1887SFrançois Tigeot 
1596ba55f2f5SFrançois Tigeot 	intel_hdmi_prepare(encoder);
15975d0b1887SFrançois Tigeot 
15985d0b1887SFrançois Tigeot 	/* Program Tx lane resets to default */
159919c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
16009edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port),
16015d0b1887SFrançois Tigeot 			 DPIO_PCS_TX_LANE2_RESET |
16025d0b1887SFrançois Tigeot 			 DPIO_PCS_TX_LANE1_RESET);
16039edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port),
16045d0b1887SFrançois Tigeot 			 DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
16055d0b1887SFrançois Tigeot 			 DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
16065d0b1887SFrançois Tigeot 			 (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
16075d0b1887SFrançois Tigeot 			 DPIO_PCS_CLK_SOFT_RESET);
16085d0b1887SFrançois Tigeot 
16095d0b1887SFrançois Tigeot 	/* Fix up inter-pair skew failure */
16109edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00);
16119edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500);
16129edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000);
16135d0b1887SFrançois Tigeot 
16149edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000);
16159edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN);
161619c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
16175d0b1887SFrançois Tigeot }
16185d0b1887SFrançois Tigeot 
161924edb884SFrançois Tigeot static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
162024edb884SFrançois Tigeot {
162124edb884SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
162224edb884SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
162324edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
162424edb884SFrançois Tigeot 	struct intel_crtc *intel_crtc =
162524edb884SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
162624edb884SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
162724edb884SFrançois Tigeot 	enum i915_pipe pipe = intel_crtc->pipe;
162824edb884SFrançois Tigeot 	u32 val;
162924edb884SFrançois Tigeot 
16301b13d190SFrançois Tigeot 	intel_hdmi_prepare(encoder);
16311b13d190SFrançois Tigeot 
163219c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
163324edb884SFrançois Tigeot 
163424edb884SFrançois Tigeot 	/* program left/right clock distribution */
163524edb884SFrançois Tigeot 	if (pipe != PIPE_B) {
163624edb884SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
163724edb884SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
163824edb884SFrançois Tigeot 		if (ch == DPIO_CH0)
163924edb884SFrançois Tigeot 			val |= CHV_BUFLEFTENA1_FORCE;
164024edb884SFrançois Tigeot 		if (ch == DPIO_CH1)
164124edb884SFrançois Tigeot 			val |= CHV_BUFRIGHTENA1_FORCE;
164224edb884SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
164324edb884SFrançois Tigeot 	} else {
164424edb884SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
164524edb884SFrançois Tigeot 		val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
164624edb884SFrançois Tigeot 		if (ch == DPIO_CH0)
164724edb884SFrançois Tigeot 			val |= CHV_BUFLEFTENA2_FORCE;
164824edb884SFrançois Tigeot 		if (ch == DPIO_CH1)
164924edb884SFrançois Tigeot 			val |= CHV_BUFRIGHTENA2_FORCE;
165024edb884SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
165124edb884SFrançois Tigeot 	}
165224edb884SFrançois Tigeot 
165324edb884SFrançois Tigeot 	/* program clock channel usage */
165424edb884SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch));
165524edb884SFrançois Tigeot 	val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
165624edb884SFrançois Tigeot 	if (pipe != PIPE_B)
165724edb884SFrançois Tigeot 		val &= ~CHV_PCS_USEDCLKCHANNEL;
165824edb884SFrançois Tigeot 	else
165924edb884SFrançois Tigeot 		val |= CHV_PCS_USEDCLKCHANNEL;
166024edb884SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val);
166124edb884SFrançois Tigeot 
166224edb884SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
166324edb884SFrançois Tigeot 	val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
166424edb884SFrançois Tigeot 	if (pipe != PIPE_B)
166524edb884SFrançois Tigeot 		val &= ~CHV_PCS_USEDCLKCHANNEL;
166624edb884SFrançois Tigeot 	else
166724edb884SFrançois Tigeot 		val |= CHV_PCS_USEDCLKCHANNEL;
166824edb884SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
166924edb884SFrançois Tigeot 
167024edb884SFrançois Tigeot 	/*
167124edb884SFrançois Tigeot 	 * This a a bit weird since generally CL
167224edb884SFrançois Tigeot 	 * matches the pipe, but here we need to
167324edb884SFrançois Tigeot 	 * pick the CL based on the port.
167424edb884SFrançois Tigeot 	 */
167524edb884SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch));
167624edb884SFrançois Tigeot 	if (pipe != PIPE_B)
167724edb884SFrançois Tigeot 		val &= ~CHV_CMN_USEDCLKCHANNEL;
167824edb884SFrançois Tigeot 	else
167924edb884SFrançois Tigeot 		val |= CHV_CMN_USEDCLKCHANNEL;
168024edb884SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val);
168124edb884SFrançois Tigeot 
168219c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
168324edb884SFrançois Tigeot }
168424edb884SFrançois Tigeot 
16859edbd4a0SFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
16865d0b1887SFrançois Tigeot {
16875d0b1887SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
16885d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
16899edbd4a0SFrançois Tigeot 	struct intel_crtc *intel_crtc =
16909edbd4a0SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
16919edbd4a0SFrançois Tigeot 	enum dpio_channel port = vlv_dport_to_channel(dport);
16929edbd4a0SFrançois Tigeot 	int pipe = intel_crtc->pipe;
16935d0b1887SFrançois Tigeot 
16945d0b1887SFrançois Tigeot 	/* Reset lanes to avoid HDMI flicker (VLV w/a) */
169519c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
16969edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000);
16979edbd4a0SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060);
169819c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
16995d0b1887SFrançois Tigeot }
17005d0b1887SFrançois Tigeot 
1701ba55f2f5SFrançois Tigeot static void chv_hdmi_post_disable(struct intel_encoder *encoder)
1702ba55f2f5SFrançois Tigeot {
1703ba55f2f5SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
1704ba55f2f5SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1705ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1706ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc =
1707ba55f2f5SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
1708ba55f2f5SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
1709ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = intel_crtc->pipe;
1710ba55f2f5SFrançois Tigeot 	u32 val;
1711ba55f2f5SFrançois Tigeot 
171219c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
1713ba55f2f5SFrançois Tigeot 
1714ba55f2f5SFrançois Tigeot 	/* Propagate soft reset to data lane reset */
1715ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
1716ba55f2f5SFrançois Tigeot 	val |= CHV_PCS_REQ_SOFTRESET_EN;
1717ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
1718ba55f2f5SFrançois Tigeot 
1719ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
1720ba55f2f5SFrançois Tigeot 	val |= CHV_PCS_REQ_SOFTRESET_EN;
1721ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
1722ba55f2f5SFrançois Tigeot 
1723ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
1724ba55f2f5SFrançois Tigeot 	val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
1725ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
1726ba55f2f5SFrançois Tigeot 
1727ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
1728ba55f2f5SFrançois Tigeot 	val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
1729ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
1730ba55f2f5SFrançois Tigeot 
173119c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
1732ba55f2f5SFrançois Tigeot }
1733ba55f2f5SFrançois Tigeot 
1734ba55f2f5SFrançois Tigeot static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
1735ba55f2f5SFrançois Tigeot {
1736ba55f2f5SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
17372c9916cdSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &dport->hdmi;
1738ba55f2f5SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1739ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1740ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc =
1741ba55f2f5SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
17422c9916cdSFrançois Tigeot 	struct drm_display_mode *adjusted_mode =
17432c9916cdSFrançois Tigeot 		&intel_crtc->config->base.adjusted_mode;
1744ba55f2f5SFrançois Tigeot 	enum dpio_channel ch = vlv_dport_to_channel(dport);
1745ba55f2f5SFrançois Tigeot 	int pipe = intel_crtc->pipe;
174619c468b4SFrançois Tigeot 	int data, i, stagger;
1747ba55f2f5SFrançois Tigeot 	u32 val;
1748ba55f2f5SFrançois Tigeot 
174919c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
1750ba55f2f5SFrançois Tigeot 
17512c9916cdSFrançois Tigeot 	/* allow hardware to manage TX FIFO reset source */
17522c9916cdSFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch));
17532c9916cdSFrançois Tigeot 	val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
17542c9916cdSFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
17552c9916cdSFrançois Tigeot 
17562c9916cdSFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
17572c9916cdSFrançois Tigeot 	val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
17582c9916cdSFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
17592c9916cdSFrançois Tigeot 
1760ba55f2f5SFrançois Tigeot 	/* Deassert soft data lane reset*/
1761ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
1762ba55f2f5SFrançois Tigeot 	val |= CHV_PCS_REQ_SOFTRESET_EN;
1763ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
1764ba55f2f5SFrançois Tigeot 
1765ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
1766ba55f2f5SFrançois Tigeot 	val |= CHV_PCS_REQ_SOFTRESET_EN;
1767ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
1768ba55f2f5SFrançois Tigeot 
1769ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
1770ba55f2f5SFrançois Tigeot 	val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
1771ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
1772ba55f2f5SFrançois Tigeot 
1773ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
1774ba55f2f5SFrançois Tigeot 	val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
1775ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
1776ba55f2f5SFrançois Tigeot 
1777ba55f2f5SFrançois Tigeot 	/* Program Tx latency optimal setting */
1778ba55f2f5SFrançois Tigeot 	for (i = 0; i < 4; i++) {
1779ba55f2f5SFrançois Tigeot 		/* Set the upar bit */
1780ba55f2f5SFrançois Tigeot 		data = (i == 1) ? 0x0 : 0x1;
1781ba55f2f5SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i),
1782ba55f2f5SFrançois Tigeot 				data << DPIO_UPAR_SHIFT);
1783ba55f2f5SFrançois Tigeot 	}
1784ba55f2f5SFrançois Tigeot 
1785ba55f2f5SFrançois Tigeot 	/* Data lane stagger programming */
178619c468b4SFrançois Tigeot 	if (intel_crtc->config->port_clock > 270000)
178719c468b4SFrançois Tigeot 		stagger = 0x18;
178819c468b4SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 135000)
178919c468b4SFrançois Tigeot 		stagger = 0xd;
179019c468b4SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 67500)
179119c468b4SFrançois Tigeot 		stagger = 0x7;
179219c468b4SFrançois Tigeot 	else if (intel_crtc->config->port_clock > 33750)
179319c468b4SFrançois Tigeot 		stagger = 0x4;
179419c468b4SFrançois Tigeot 	else
179519c468b4SFrançois Tigeot 		stagger = 0x2;
179619c468b4SFrançois Tigeot 
179719c468b4SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch));
179819c468b4SFrançois Tigeot 	val |= DPIO_TX2_STAGGER_MASK(0x1f);
179919c468b4SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
180019c468b4SFrançois Tigeot 
180119c468b4SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
180219c468b4SFrançois Tigeot 	val |= DPIO_TX2_STAGGER_MASK(0x1f);
180319c468b4SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
180419c468b4SFrançois Tigeot 
180519c468b4SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch),
180619c468b4SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP(stagger) |
180719c468b4SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP_OVRD |
180819c468b4SFrançois Tigeot 		       DPIO_TX1_STAGGER_MASK(0x1f) |
180919c468b4SFrançois Tigeot 		       DPIO_TX1_STAGGER_MULT(6) |
181019c468b4SFrançois Tigeot 		       DPIO_TX2_STAGGER_MULT(0));
181119c468b4SFrançois Tigeot 
181219c468b4SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
181319c468b4SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP(stagger) |
181419c468b4SFrançois Tigeot 		       DPIO_LANESTAGGER_STRAP_OVRD |
181519c468b4SFrançois Tigeot 		       DPIO_TX1_STAGGER_MASK(0x1f) |
181619c468b4SFrançois Tigeot 		       DPIO_TX1_STAGGER_MULT(7) |
181719c468b4SFrançois Tigeot 		       DPIO_TX2_STAGGER_MULT(5));
1818ba55f2f5SFrançois Tigeot 
1819ba55f2f5SFrançois Tigeot 	/* Clear calc init */
1820ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
1821ba55f2f5SFrançois Tigeot 	val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
18222c9916cdSFrançois Tigeot 	val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
18232c9916cdSFrançois Tigeot 	val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
1824ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
1825ba55f2f5SFrançois Tigeot 
1826ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
1827ba55f2f5SFrançois Tigeot 	val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
18282c9916cdSFrançois Tigeot 	val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
18292c9916cdSFrançois Tigeot 	val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
1830ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
1831ba55f2f5SFrançois Tigeot 
18322c9916cdSFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch));
18332c9916cdSFrançois Tigeot 	val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
18342c9916cdSFrançois Tigeot 	val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
18352c9916cdSFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
18362c9916cdSFrançois Tigeot 
18372c9916cdSFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
18382c9916cdSFrançois Tigeot 	val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
18392c9916cdSFrançois Tigeot 	val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
18402c9916cdSFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val);
18412c9916cdSFrançois Tigeot 
1842ba55f2f5SFrançois Tigeot 	/* FIXME: Program the support xxx V-dB */
1843ba55f2f5SFrançois Tigeot 	/* Use 800mV-0dB */
1844ba55f2f5SFrançois Tigeot 	for (i = 0; i < 4; i++) {
1845ba55f2f5SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
1846ba55f2f5SFrançois Tigeot 		val &= ~DPIO_SWING_DEEMPH9P5_MASK;
1847ba55f2f5SFrançois Tigeot 		val |= 128 << DPIO_SWING_DEEMPH9P5_SHIFT;
1848ba55f2f5SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val);
1849ba55f2f5SFrançois Tigeot 	}
1850ba55f2f5SFrançois Tigeot 
1851ba55f2f5SFrançois Tigeot 	for (i = 0; i < 4; i++) {
1852ba55f2f5SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
18531b13d190SFrançois Tigeot 		val &= ~DPIO_SWING_MARGIN000_MASK;
18541b13d190SFrançois Tigeot 		val |= 102 << DPIO_SWING_MARGIN000_SHIFT;
1855ba55f2f5SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
1856ba55f2f5SFrançois Tigeot 	}
1857ba55f2f5SFrançois Tigeot 
1858ba55f2f5SFrançois Tigeot 	/* Disable unique transition scale */
1859ba55f2f5SFrançois Tigeot 	for (i = 0; i < 4; i++) {
1860ba55f2f5SFrançois Tigeot 		val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
1861ba55f2f5SFrançois Tigeot 		val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
1862ba55f2f5SFrançois Tigeot 		vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
1863ba55f2f5SFrançois Tigeot 	}
1864ba55f2f5SFrançois Tigeot 
1865ba55f2f5SFrançois Tigeot 	/* Additional steps for 1200mV-0dB */
1866ba55f2f5SFrançois Tigeot #if 0
1867ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_TX_DW3(ch));
1868ba55f2f5SFrançois Tigeot 	if (ch)
1869ba55f2f5SFrançois Tigeot 		val |= DPIO_TX_UNIQ_TRANS_SCALE_CH1;
1870ba55f2f5SFrançois Tigeot 	else
1871ba55f2f5SFrançois Tigeot 		val |= DPIO_TX_UNIQ_TRANS_SCALE_CH0;
1872ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(ch), val);
1873ba55f2f5SFrançois Tigeot 
1874ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(ch),
1875ba55f2f5SFrançois Tigeot 			vlv_dpio_read(dev_priv, pipe, VLV_TX_DW2(ch)) |
1876ba55f2f5SFrançois Tigeot 				(0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT));
1877ba55f2f5SFrançois Tigeot #endif
1878ba55f2f5SFrançois Tigeot 	/* Start swing calculation */
1879ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
1880ba55f2f5SFrançois Tigeot 	val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
1881ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
1882ba55f2f5SFrançois Tigeot 
1883ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
1884ba55f2f5SFrançois Tigeot 	val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
1885ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
1886ba55f2f5SFrançois Tigeot 
1887ba55f2f5SFrançois Tigeot 	/* LRC Bypass */
1888ba55f2f5SFrançois Tigeot 	val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30);
1889ba55f2f5SFrançois Tigeot 	val |= DPIO_LRC_BYPASS;
1890ba55f2f5SFrançois Tigeot 	vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val);
1891ba55f2f5SFrançois Tigeot 
189219c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
1893ba55f2f5SFrançois Tigeot 
18942c9916cdSFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
18952c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
18962c9916cdSFrançois Tigeot 				   adjusted_mode);
18972c9916cdSFrançois Tigeot 
1898*a05eeebfSFrançois Tigeot 	g4x_enable_hdmi(encoder);
1899ba55f2f5SFrançois Tigeot 
190019c468b4SFrançois Tigeot 	vlv_wait_port_ready(dev_priv, dport, 0x0);
1901ba55f2f5SFrançois Tigeot }
1902ba55f2f5SFrançois Tigeot 
1903e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector)
1904e3adcf8fSFrançois Tigeot {
19051b13d190SFrançois Tigeot 	kfree(to_intel_connector(connector)->detect_edid);
1906e3adcf8fSFrançois Tigeot 	drm_connector_cleanup(connector);
19078e26cdf6SFrançois Tigeot 	kfree(connector);
1908e3adcf8fSFrançois Tigeot }
1909e3adcf8fSFrançois Tigeot 
1910e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
1911*a05eeebfSFrançois Tigeot 	.dpms = drm_atomic_helper_connector_dpms,
1912e3adcf8fSFrançois Tigeot 	.detect = intel_hdmi_detect,
19131b13d190SFrançois Tigeot 	.force = intel_hdmi_force,
1914e3adcf8fSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1915e3adcf8fSFrançois Tigeot 	.set_property = intel_hdmi_set_property,
19162c9916cdSFrançois Tigeot 	.atomic_get_property = intel_connector_atomic_get_property,
1917e3adcf8fSFrançois Tigeot 	.destroy = intel_hdmi_destroy,
19182c9916cdSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1919477eb7f9SFrançois Tigeot 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1920e3adcf8fSFrançois Tigeot };
1921e3adcf8fSFrançois Tigeot 
1922e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
1923e3adcf8fSFrançois Tigeot 	.get_modes = intel_hdmi_get_modes,
1924e3adcf8fSFrançois Tigeot 	.mode_valid = intel_hdmi_mode_valid,
1925e3adcf8fSFrançois Tigeot 	.best_encoder = intel_best_encoder,
1926e3adcf8fSFrançois Tigeot };
1927e3adcf8fSFrançois Tigeot 
1928e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
1929e3adcf8fSFrançois Tigeot 	.destroy = intel_encoder_destroy,
1930e3adcf8fSFrançois Tigeot };
1931e3adcf8fSFrançois Tigeot 
1932e3adcf8fSFrançois Tigeot static void
193324edb884SFrançois Tigeot intel_attach_aspect_ratio_property(struct drm_connector *connector)
193424edb884SFrançois Tigeot {
193524edb884SFrançois Tigeot 	if (!drm_mode_create_aspect_ratio_property(connector->dev))
193624edb884SFrançois Tigeot 		drm_object_attach_property(&connector->base,
193724edb884SFrançois Tigeot 			connector->dev->mode_config.aspect_ratio_property,
193824edb884SFrançois Tigeot 			DRM_MODE_PICTURE_ASPECT_NONE);
193924edb884SFrançois Tigeot }
194024edb884SFrançois Tigeot 
194124edb884SFrançois Tigeot static void
1942e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
1943e3adcf8fSFrançois Tigeot {
1944e3adcf8fSFrançois Tigeot 	intel_attach_force_audio_property(connector);
1945e3adcf8fSFrançois Tigeot 	intel_attach_broadcast_rgb_property(connector);
1946a2fdbec6SFrançois Tigeot 	intel_hdmi->color_range_auto = true;
194724edb884SFrançois Tigeot 	intel_attach_aspect_ratio_property(connector);
194824edb884SFrançois Tigeot 	intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
1949e3adcf8fSFrançois Tigeot }
1950e3adcf8fSFrançois Tigeot 
195119df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
195219df918dSFrançois Tigeot 			       struct intel_connector *intel_connector)
1953e3adcf8fSFrançois Tigeot {
195419df918dSFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
195519df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
195619df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
195719df918dSFrançois Tigeot 	struct drm_device *dev = intel_encoder->base.dev;
1958e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
195919df918dSFrançois Tigeot 	enum port port = intel_dig_port->port;
1960*a05eeebfSFrançois Tigeot 	uint8_t alternate_ddc_pin;
1961e3adcf8fSFrançois Tigeot 
1962e3adcf8fSFrançois Tigeot 	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
1963e3adcf8fSFrançois Tigeot 			   DRM_MODE_CONNECTOR_HDMIA);
1964e3adcf8fSFrançois Tigeot 	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
1965e3adcf8fSFrançois Tigeot 
1966e3adcf8fSFrançois Tigeot 	connector->interlace_allowed = 1;
1967e3adcf8fSFrançois Tigeot 	connector->doublescan_allowed = 0;
19689edbd4a0SFrançois Tigeot 	connector->stereo_allowed = 1;
1969e3adcf8fSFrançois Tigeot 
197019df918dSFrançois Tigeot 	switch (port) {
197119df918dSFrançois Tigeot 	case PORT_B:
197219c468b4SFrançois Tigeot 		if (IS_BROXTON(dev_priv))
197319c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_1_BXT;
197419c468b4SFrançois Tigeot 		else
197519c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
19768e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_B;
197719df918dSFrançois Tigeot 		break;
197819df918dSFrançois Tigeot 	case PORT_C:
197919c468b4SFrançois Tigeot 		if (IS_BROXTON(dev_priv))
198019c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_2_BXT;
198119c468b4SFrançois Tigeot 		else
198219c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
19838e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_C;
198419df918dSFrançois Tigeot 		break;
198519df918dSFrançois Tigeot 	case PORT_D:
198619c468b4SFrançois Tigeot 		if (WARN_ON(IS_BROXTON(dev_priv)))
198719c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DISABLED;
198819c468b4SFrançois Tigeot 		else if (IS_CHERRYVIEW(dev_priv))
198919c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPD_CHV;
1990ba55f2f5SFrançois Tigeot 		else
199119c468b4SFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
19928e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_D;
199319df918dSFrançois Tigeot 		break;
1994*a05eeebfSFrançois Tigeot 	case PORT_E:
1995*a05eeebfSFrançois Tigeot 		/* On SKL PORT E doesn't have seperate GMBUS pin
1996*a05eeebfSFrançois Tigeot 		 *  We rely on VBT to set a proper alternate GMBUS pin. */
1997*a05eeebfSFrançois Tigeot 		alternate_ddc_pin =
1998*a05eeebfSFrançois Tigeot 			dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin;
1999*a05eeebfSFrançois Tigeot 		switch (alternate_ddc_pin) {
2000*a05eeebfSFrançois Tigeot 		case DDC_PIN_B:
2001*a05eeebfSFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
2002*a05eeebfSFrançois Tigeot 			break;
2003*a05eeebfSFrançois Tigeot 		case DDC_PIN_C:
2004*a05eeebfSFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPC;
2005*a05eeebfSFrançois Tigeot 			break;
2006*a05eeebfSFrançois Tigeot 		case DDC_PIN_D:
2007*a05eeebfSFrançois Tigeot 			intel_hdmi->ddc_bus = GMBUS_PIN_DPD;
2008*a05eeebfSFrançois Tigeot 			break;
2009*a05eeebfSFrançois Tigeot 		default:
2010*a05eeebfSFrançois Tigeot 			MISSING_CASE(alternate_ddc_pin);
2011*a05eeebfSFrançois Tigeot 		}
2012*a05eeebfSFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_E;
2013*a05eeebfSFrançois Tigeot 		break;
201419df918dSFrançois Tigeot 	case PORT_A:
20158e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_A;
201619df918dSFrançois Tigeot 		/* Internal port only for eDP. */
201719df918dSFrançois Tigeot 	default:
201819df918dSFrançois Tigeot 		BUG();
2019e3adcf8fSFrançois Tigeot 	}
2020e3adcf8fSFrançois Tigeot 
20218e26cdf6SFrançois Tigeot 	if (IS_VALLEYVIEW(dev)) {
202219df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = vlv_write_infoframe;
202319df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = vlv_set_infoframes;
20242c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = vlv_infoframe_enabled;
202524edb884SFrançois Tigeot 	} else if (IS_G4X(dev)) {
20268e26cdf6SFrançois Tigeot 		intel_hdmi->write_infoframe = g4x_write_infoframe;
20278e26cdf6SFrançois Tigeot 		intel_hdmi->set_infoframes = g4x_set_infoframes;
20282c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = g4x_infoframe_enabled;
20298e26cdf6SFrançois Tigeot 	} else if (HAS_DDI(dev)) {
203019df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = hsw_write_infoframe;
203119df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = hsw_set_infoframes;
20322c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = hsw_infoframe_enabled;
203319df918dSFrançois Tigeot 	} else if (HAS_PCH_IBX(dev)) {
203419df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = ibx_write_infoframe;
203519df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = ibx_set_infoframes;
20362c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = ibx_infoframe_enabled;
2037e3adcf8fSFrançois Tigeot 	} else {
203819df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = cpt_write_infoframe;
203919df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = cpt_set_infoframes;
20402c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = cpt_infoframe_enabled;
2041e3adcf8fSFrançois Tigeot 	}
2042e3adcf8fSFrançois Tigeot 
2043a2fdbec6SFrançois Tigeot 	if (HAS_DDI(dev))
204419df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
204519df918dSFrançois Tigeot 	else
204619df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_connector_get_hw_state;
2047ba55f2f5SFrançois Tigeot 	intel_connector->unregister = intel_connector_unregister;
2048e3adcf8fSFrançois Tigeot 
2049e3adcf8fSFrançois Tigeot 	intel_hdmi_add_properties(intel_hdmi, connector);
2050e3adcf8fSFrançois Tigeot 
2051e3adcf8fSFrançois Tigeot 	intel_connector_attach_encoder(intel_connector, intel_encoder);
2052c6f73aabSFrançois Tigeot 	drm_connector_register(connector);
2053e3adcf8fSFrançois Tigeot 
2054e3adcf8fSFrançois Tigeot 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
2055e3adcf8fSFrançois Tigeot 	 * 0xd.  Failure to do so will result in spurious interrupts being
2056e3adcf8fSFrançois Tigeot 	 * generated on the port when a cable is not attached.
2057e3adcf8fSFrançois Tigeot 	 */
2058e3adcf8fSFrançois Tigeot 	if (IS_G4X(dev) && !IS_GM45(dev)) {
2059e3adcf8fSFrançois Tigeot 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
2060e3adcf8fSFrançois Tigeot 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
2061e3adcf8fSFrançois Tigeot 	}
2062e3adcf8fSFrançois Tigeot }
206319df918dSFrançois Tigeot 
20648e26cdf6SFrançois Tigeot void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
206519df918dSFrançois Tigeot {
206619df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
206719df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder;
206819df918dSFrançois Tigeot 	struct intel_connector *intel_connector;
206919df918dSFrançois Tigeot 
20709edbd4a0SFrançois Tigeot 	intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
207119df918dSFrançois Tigeot 	if (!intel_dig_port)
207219df918dSFrançois Tigeot 		return;
207319df918dSFrançois Tigeot 
2074477eb7f9SFrançois Tigeot 	intel_connector = intel_connector_alloc();
207519df918dSFrançois Tigeot 	if (!intel_connector) {
2076158486a6SFrançois Tigeot 		kfree(intel_dig_port);
207719df918dSFrançois Tigeot 		return;
207819df918dSFrançois Tigeot 	}
207919df918dSFrançois Tigeot 
208019df918dSFrançois Tigeot 	intel_encoder = &intel_dig_port->base;
208119df918dSFrançois Tigeot 
208219df918dSFrançois Tigeot 	drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
208319df918dSFrançois Tigeot 			 DRM_MODE_ENCODER_TMDS);
208419df918dSFrançois Tigeot 
20858e26cdf6SFrançois Tigeot 	intel_encoder->compute_config = intel_hdmi_compute_config;
208619c468b4SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev)) {
208719c468b4SFrançois Tigeot 		intel_encoder->disable = pch_disable_hdmi;
208819c468b4SFrançois Tigeot 		intel_encoder->post_disable = pch_post_disable_hdmi;
208919c468b4SFrançois Tigeot 	} else {
209019c468b4SFrançois Tigeot 		intel_encoder->disable = g4x_disable_hdmi;
209119c468b4SFrançois Tigeot 	}
209219df918dSFrançois Tigeot 	intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
20935d0b1887SFrançois Tigeot 	intel_encoder->get_config = intel_hdmi_get_config;
2094ba55f2f5SFrançois Tigeot 	if (IS_CHERRYVIEW(dev)) {
209524edb884SFrançois Tigeot 		intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable;
2096ba55f2f5SFrançois Tigeot 		intel_encoder->pre_enable = chv_hdmi_pre_enable;
2097ba55f2f5SFrançois Tigeot 		intel_encoder->enable = vlv_enable_hdmi;
2098ba55f2f5SFrançois Tigeot 		intel_encoder->post_disable = chv_hdmi_post_disable;
2099ba55f2f5SFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev)) {
21009edbd4a0SFrançois Tigeot 		intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
21019edbd4a0SFrançois Tigeot 		intel_encoder->pre_enable = vlv_hdmi_pre_enable;
21029edbd4a0SFrançois Tigeot 		intel_encoder->enable = vlv_enable_hdmi;
21039edbd4a0SFrançois Tigeot 		intel_encoder->post_disable = vlv_hdmi_post_disable;
21049edbd4a0SFrançois Tigeot 	} else {
2105ba55f2f5SFrançois Tigeot 		intel_encoder->pre_enable = intel_hdmi_pre_enable;
2106*a05eeebfSFrançois Tigeot 		if (HAS_PCH_CPT(dev))
2107*a05eeebfSFrançois Tigeot 			intel_encoder->enable = cpt_enable_hdmi;
2108*a05eeebfSFrançois Tigeot 		else if (HAS_PCH_IBX(dev))
2109*a05eeebfSFrançois Tigeot 			intel_encoder->enable = ibx_enable_hdmi;
2110*a05eeebfSFrançois Tigeot 		else
2111*a05eeebfSFrançois Tigeot 			intel_encoder->enable = g4x_enable_hdmi;
21125d0b1887SFrançois Tigeot 	}
211319df918dSFrançois Tigeot 
211419df918dSFrançois Tigeot 	intel_encoder->type = INTEL_OUTPUT_HDMI;
2115ba55f2f5SFrançois Tigeot 	if (IS_CHERRYVIEW(dev)) {
2116ba55f2f5SFrançois Tigeot 		if (port == PORT_D)
2117ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = 1 << 2;
2118ba55f2f5SFrançois Tigeot 		else
2119ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
2120ba55f2f5SFrançois Tigeot 	} else {
212119df918dSFrançois Tigeot 		intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
2122ba55f2f5SFrançois Tigeot 	}
2123ba55f2f5SFrançois Tigeot 	intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
2124ba55f2f5SFrançois Tigeot 	/*
2125ba55f2f5SFrançois Tigeot 	 * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
2126ba55f2f5SFrançois Tigeot 	 * to work on real hardware. And since g4x can send infoframes to
2127ba55f2f5SFrançois Tigeot 	 * only one port anyway, nothing is lost by allowing it.
2128ba55f2f5SFrançois Tigeot 	 */
2129ba55f2f5SFrançois Tigeot 	if (IS_G4X(dev))
2130ba55f2f5SFrançois Tigeot 		intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
213119df918dSFrançois Tigeot 
213219df918dSFrançois Tigeot 	intel_dig_port->port = port;
21338e26cdf6SFrançois Tigeot 	intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
213419df918dSFrançois Tigeot 	intel_dig_port->dp.output_reg = 0;
213519df918dSFrançois Tigeot 
213619df918dSFrançois Tigeot 	intel_hdmi_init_connector(intel_dig_port, intel_connector);
213719df918dSFrançois Tigeot }
2138