xref: /dflybsd-src/sys/dev/drm/i915/intel_hdmi.c (revision bf0175970ba1c394f8039834a26ca6d163b23d0e)
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>
301487f786SFrançois Tigeot #include <linux/slab.h>
31a2fdbec6SFrançois Tigeot #include <linux/delay.h>
329edbd4a0SFrançois Tigeot #include <linux/hdmi.h>
3318e26a6dSFrançois Tigeot #include <drm/drmP.h>
342c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h>
3518e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
3618e26a6dSFrançois Tigeot #include <drm/drm_edid.h>
3718e26a6dSFrançois Tigeot #include "intel_drv.h"
385c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
39e3adcf8fSFrançois Tigeot #include "i915_drv.h"
40e3adcf8fSFrançois Tigeot 
4119df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
42e3adcf8fSFrançois Tigeot {
4319df918dSFrançois Tigeot 	return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
4419df918dSFrançois Tigeot }
4519df918dSFrançois Tigeot 
4619df918dSFrançois Tigeot static void
4719df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
4819df918dSFrançois Tigeot {
4919df918dSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
50*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
5119df918dSFrançois Tigeot 	uint32_t enabled_bits;
5219df918dSFrançois Tigeot 
53a2fdbec6SFrançois Tigeot 	enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
5419df918dSFrançois Tigeot 
558e26cdf6SFrançois Tigeot 	WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
5619df918dSFrançois Tigeot 	     "HDMI port enabled, expecting disabled\n");
5719df918dSFrançois Tigeot }
5819df918dSFrançois Tigeot 
5919df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
6019df918dSFrançois Tigeot {
6119df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port =
6219df918dSFrançois Tigeot 		container_of(encoder, struct intel_digital_port, base.base);
6319df918dSFrançois Tigeot 	return &intel_dig_port->hdmi;
64e3adcf8fSFrançois Tigeot }
65e3adcf8fSFrançois Tigeot 
66e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
67e3adcf8fSFrançois Tigeot {
6819df918dSFrançois Tigeot 	return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
69e3adcf8fSFrançois Tigeot }
70e3adcf8fSFrançois Tigeot 
719edbd4a0SFrançois Tigeot static u32 g4x_infoframe_index(enum hdmi_infoframe_type type)
72e3adcf8fSFrançois Tigeot {
739edbd4a0SFrançois Tigeot 	switch (type) {
749edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
7519df918dSFrançois Tigeot 		return VIDEO_DIP_SELECT_AVI;
769edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
7719df918dSFrançois Tigeot 		return VIDEO_DIP_SELECT_SPD;
789edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
799edbd4a0SFrançois Tigeot 		return VIDEO_DIP_SELECT_VENDOR;
80e3adcf8fSFrançois Tigeot 	default:
81aee94f86SFrançois Tigeot 		MISSING_CASE(type);
8219df918dSFrançois Tigeot 		return 0;
8319df918dSFrançois Tigeot 	}
84e3adcf8fSFrançois Tigeot }
85e3adcf8fSFrançois Tigeot 
869edbd4a0SFrançois Tigeot static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type)
87e3adcf8fSFrançois Tigeot {
889edbd4a0SFrançois Tigeot 	switch (type) {
899edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
9019df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_AVI;
919edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
9219df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_SPD;
939edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
949edbd4a0SFrançois Tigeot 		return VIDEO_DIP_ENABLE_VENDOR;
95e3adcf8fSFrançois Tigeot 	default:
96aee94f86SFrançois Tigeot 		MISSING_CASE(type);
9719df918dSFrançois Tigeot 		return 0;
9819df918dSFrançois Tigeot 	}
99e3adcf8fSFrançois Tigeot }
100e3adcf8fSFrançois Tigeot 
1019edbd4a0SFrançois Tigeot static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
10219df918dSFrançois Tigeot {
1039edbd4a0SFrançois Tigeot 	switch (type) {
1049edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
10519df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_AVI_HSW;
1069edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
10719df918dSFrançois Tigeot 		return VIDEO_DIP_ENABLE_SPD_HSW;
1089edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
1099edbd4a0SFrançois Tigeot 		return VIDEO_DIP_ENABLE_VS_HSW;
11019df918dSFrançois Tigeot 	default:
111aee94f86SFrançois Tigeot 		MISSING_CASE(type);
11219df918dSFrançois Tigeot 		return 0;
11319df918dSFrançois Tigeot 	}
114e3adcf8fSFrançois Tigeot }
115e3adcf8fSFrançois Tigeot 
116aee94f86SFrançois Tigeot static i915_reg_t
117aee94f86SFrançois Tigeot hsw_dip_data_reg(struct drm_i915_private *dev_priv,
118ba55f2f5SFrançois Tigeot 		 enum transcoder cpu_transcoder,
119352ff8bdSFrançois Tigeot 		 enum hdmi_infoframe_type type,
120352ff8bdSFrançois Tigeot 		 int i)
12119df918dSFrançois Tigeot {
1229edbd4a0SFrançois Tigeot 	switch (type) {
1239edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_AVI:
124352ff8bdSFrançois Tigeot 		return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
1259edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_SPD:
126352ff8bdSFrançois Tigeot 		return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder, i);
1279edbd4a0SFrançois Tigeot 	case HDMI_INFOFRAME_TYPE_VENDOR:
128352ff8bdSFrançois Tigeot 		return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
12919df918dSFrançois Tigeot 	default:
130aee94f86SFrançois Tigeot 		MISSING_CASE(type);
131aee94f86SFrançois Tigeot 		return INVALID_MMIO_REG;
13219df918dSFrançois Tigeot 	}
13319df918dSFrançois Tigeot }
13419df918dSFrançois Tigeot 
13519df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder,
1369edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
1379edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
138e3adcf8fSFrançois Tigeot {
1399edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
140e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
141*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
14219df918dSFrançois Tigeot 	u32 val = I915_READ(VIDEO_DIP_CTL);
1439edbd4a0SFrançois Tigeot 	int i;
144e3adcf8fSFrançois Tigeot 
14519df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
146e3adcf8fSFrançois Tigeot 
14719df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
1489edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
149e3adcf8fSFrançois Tigeot 
1509edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
151e3adcf8fSFrançois Tigeot 
15219df918dSFrançois Tigeot 	I915_WRITE(VIDEO_DIP_CTL, val);
153e3adcf8fSFrançois Tigeot 
15419df918dSFrançois Tigeot 	mmiowb();
155e3adcf8fSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
156e3adcf8fSFrançois Tigeot 		I915_WRITE(VIDEO_DIP_DATA, *data);
157e3adcf8fSFrançois Tigeot 		data++;
158e3adcf8fSFrançois Tigeot 	}
15919df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
16019df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
16119df918dSFrançois Tigeot 		I915_WRITE(VIDEO_DIP_DATA, 0);
16219df918dSFrançois Tigeot 	mmiowb();
163e3adcf8fSFrançois Tigeot 
1649edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
16519df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
16619df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
167e3adcf8fSFrançois Tigeot 
16819df918dSFrançois Tigeot 	I915_WRITE(VIDEO_DIP_CTL, val);
16919df918dSFrançois Tigeot 	POSTING_READ(VIDEO_DIP_CTL);
170e3adcf8fSFrançois Tigeot }
171e3adcf8fSFrançois Tigeot 
172aee94f86SFrançois Tigeot static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
173aee94f86SFrançois Tigeot 				  const struct intel_crtc_state *pipe_config)
1742c9916cdSFrançois Tigeot {
175aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
1762c9916cdSFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
1772c9916cdSFrançois Tigeot 	u32 val = I915_READ(VIDEO_DIP_CTL);
1782c9916cdSFrançois Tigeot 
179a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
1802c9916cdSFrançois Tigeot 		return false;
181a05eeebfSFrançois Tigeot 
182a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
183a05eeebfSFrançois Tigeot 		return false;
184a05eeebfSFrançois Tigeot 
185a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
186a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
1872c9916cdSFrançois Tigeot }
1882c9916cdSFrançois Tigeot 
18919df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder,
1909edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
1919edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
192e3adcf8fSFrançois Tigeot {
1939edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
194e3adcf8fSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
195*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
19619df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
197aee94f86SFrançois Tigeot 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
19819df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
199aee94f86SFrançois Tigeot 	int i;
200e3adcf8fSFrançois Tigeot 
20119df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
202e3adcf8fSFrançois Tigeot 
203e3adcf8fSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2049edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
205e3adcf8fSFrançois Tigeot 
2069edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
207e3adcf8fSFrançois Tigeot 
20819df918dSFrançois Tigeot 	I915_WRITE(reg, val);
20919df918dSFrançois Tigeot 
21019df918dSFrançois Tigeot 	mmiowb();
211e3adcf8fSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
212e3adcf8fSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
213e3adcf8fSFrançois Tigeot 		data++;
214e3adcf8fSFrançois Tigeot 	}
21519df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
21619df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
21719df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
21819df918dSFrançois Tigeot 	mmiowb();
219e3adcf8fSFrançois Tigeot 
2209edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
22119df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
22219df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
223e3adcf8fSFrançois Tigeot 
22419df918dSFrançois Tigeot 	I915_WRITE(reg, val);
22519df918dSFrançois Tigeot 	POSTING_READ(reg);
22619df918dSFrançois Tigeot }
22719df918dSFrançois Tigeot 
228aee94f86SFrançois Tigeot static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
229aee94f86SFrançois Tigeot 				  const struct intel_crtc_state *pipe_config)
2302c9916cdSFrançois Tigeot {
231aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
23219c468b4SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
233aee94f86SFrançois Tigeot 	enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
234aee94f86SFrançois Tigeot 	i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
2352c9916cdSFrançois Tigeot 	u32 val = I915_READ(reg);
2362c9916cdSFrançois Tigeot 
237a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
23819c468b4SFrançois Tigeot 		return false;
239a05eeebfSFrançois Tigeot 
240a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
241a05eeebfSFrançois Tigeot 		return false;
242a05eeebfSFrançois Tigeot 
243a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
244a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
245a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
2462c9916cdSFrançois Tigeot }
2472c9916cdSFrançois Tigeot 
24819df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder,
2499edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
2509edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
25119df918dSFrançois Tigeot {
2529edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
25319df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
254*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
25519df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
256aee94f86SFrançois Tigeot 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
25719df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
258aee94f86SFrançois Tigeot 	int i;
25919df918dSFrançois Tigeot 
26019df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
26119df918dSFrançois Tigeot 
26219df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2639edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
26419df918dSFrançois Tigeot 
26519df918dSFrançois Tigeot 	/* The DIP control register spec says that we need to update the AVI
26619df918dSFrançois Tigeot 	 * infoframe without clearing its enable bit */
2679edbd4a0SFrançois Tigeot 	if (type != HDMI_INFOFRAME_TYPE_AVI)
2689edbd4a0SFrançois Tigeot 		val &= ~g4x_infoframe_enable(type);
26919df918dSFrançois Tigeot 
27019df918dSFrançois Tigeot 	I915_WRITE(reg, val);
27119df918dSFrançois Tigeot 
27219df918dSFrançois Tigeot 	mmiowb();
27319df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
27419df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
27519df918dSFrançois Tigeot 		data++;
27619df918dSFrançois Tigeot 	}
27719df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
27819df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
27919df918dSFrançois Tigeot 		I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
28019df918dSFrançois Tigeot 	mmiowb();
28119df918dSFrançois Tigeot 
2829edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
28319df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
28419df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
28519df918dSFrançois Tigeot 
28619df918dSFrançois Tigeot 	I915_WRITE(reg, val);
28719df918dSFrançois Tigeot 	POSTING_READ(reg);
28819df918dSFrançois Tigeot }
28919df918dSFrançois Tigeot 
290aee94f86SFrançois Tigeot static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
291aee94f86SFrançois Tigeot 				  const struct intel_crtc_state *pipe_config)
2922c9916cdSFrançois Tigeot {
293aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
294aee94f86SFrançois Tigeot 	enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
295aee94f86SFrançois Tigeot 	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
2962c9916cdSFrançois Tigeot 
297a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
298a05eeebfSFrançois Tigeot 		return false;
299a05eeebfSFrançois Tigeot 
300a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
301a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
302a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
3032c9916cdSFrançois Tigeot }
3042c9916cdSFrançois Tigeot 
30519df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder,
3069edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
3079edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
30819df918dSFrançois Tigeot {
3099edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
31019df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
311*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
31219df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
313aee94f86SFrançois Tigeot 	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
31419df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
315aee94f86SFrançois Tigeot 	int i;
31619df918dSFrançois Tigeot 
31719df918dSFrançois Tigeot 	WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
31819df918dSFrançois Tigeot 
31919df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
3209edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_index(type);
32119df918dSFrançois Tigeot 
3229edbd4a0SFrançois Tigeot 	val &= ~g4x_infoframe_enable(type);
32319df918dSFrançois Tigeot 
32419df918dSFrançois Tigeot 	I915_WRITE(reg, val);
32519df918dSFrançois Tigeot 
32619df918dSFrançois Tigeot 	mmiowb();
32719df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
32819df918dSFrançois Tigeot 		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
32919df918dSFrançois Tigeot 		data++;
33019df918dSFrançois Tigeot 	}
33119df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
33219df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
33319df918dSFrançois Tigeot 		I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
33419df918dSFrançois Tigeot 	mmiowb();
33519df918dSFrançois Tigeot 
3369edbd4a0SFrançois Tigeot 	val |= g4x_infoframe_enable(type);
33719df918dSFrançois Tigeot 	val &= ~VIDEO_DIP_FREQ_MASK;
33819df918dSFrançois Tigeot 	val |= VIDEO_DIP_FREQ_VSYNC;
33919df918dSFrançois Tigeot 
34019df918dSFrançois Tigeot 	I915_WRITE(reg, val);
34119df918dSFrançois Tigeot 	POSTING_READ(reg);
34219df918dSFrançois Tigeot }
34319df918dSFrançois Tigeot 
344aee94f86SFrançois Tigeot static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
345aee94f86SFrançois Tigeot 				  const struct intel_crtc_state *pipe_config)
3462c9916cdSFrançois Tigeot {
347aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
34819c468b4SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
349aee94f86SFrançois Tigeot 	enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
350aee94f86SFrançois Tigeot 	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
3512c9916cdSFrançois Tigeot 
352a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_ENABLE) == 0)
35319c468b4SFrançois Tigeot 		return false;
354a05eeebfSFrançois Tigeot 
355a05eeebfSFrançois Tigeot 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
356a05eeebfSFrançois Tigeot 		return false;
357a05eeebfSFrançois Tigeot 
358a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_AVI |
359a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
360a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
3612c9916cdSFrançois Tigeot }
3622c9916cdSFrançois Tigeot 
36319df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder,
3649edbd4a0SFrançois Tigeot 				enum hdmi_infoframe_type type,
3659edbd4a0SFrançois Tigeot 				const void *frame, ssize_t len)
36619df918dSFrançois Tigeot {
3679edbd4a0SFrançois Tigeot 	const uint32_t *data = frame;
36819df918dSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
369*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
37019df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
371352ff8bdSFrançois Tigeot 	enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
372aee94f86SFrançois Tigeot 	i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
373aee94f86SFrançois Tigeot 	i915_reg_t data_reg;
3749edbd4a0SFrançois Tigeot 	int i;
37519df918dSFrançois Tigeot 	u32 val = I915_READ(ctl_reg);
37619df918dSFrançois Tigeot 
377352ff8bdSFrançois Tigeot 	data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0);
37819df918dSFrançois Tigeot 
3799edbd4a0SFrançois Tigeot 	val &= ~hsw_infoframe_enable(type);
38019df918dSFrançois Tigeot 	I915_WRITE(ctl_reg, val);
38119df918dSFrançois Tigeot 
38219df918dSFrançois Tigeot 	mmiowb();
38319df918dSFrançois Tigeot 	for (i = 0; i < len; i += 4) {
384352ff8bdSFrançois Tigeot 		I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
385352ff8bdSFrançois Tigeot 					    type, i >> 2), *data);
38619df918dSFrançois Tigeot 		data++;
38719df918dSFrançois Tigeot 	}
38819df918dSFrançois Tigeot 	/* Write every possible data byte to force correct ECC calculation. */
38919df918dSFrançois Tigeot 	for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
390352ff8bdSFrançois Tigeot 		I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
391352ff8bdSFrançois Tigeot 					    type, i >> 2), 0);
39219df918dSFrançois Tigeot 	mmiowb();
39319df918dSFrançois Tigeot 
3949edbd4a0SFrançois Tigeot 	val |= hsw_infoframe_enable(type);
39519df918dSFrançois Tigeot 	I915_WRITE(ctl_reg, val);
39619df918dSFrançois Tigeot 	POSTING_READ(ctl_reg);
397e3adcf8fSFrançois Tigeot }
398e3adcf8fSFrançois Tigeot 
399aee94f86SFrançois Tigeot static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
400aee94f86SFrançois Tigeot 				  const struct intel_crtc_state *pipe_config)
4012c9916cdSFrançois Tigeot {
402aee94f86SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
403aee94f86SFrançois Tigeot 	u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
4042c9916cdSFrançois Tigeot 
405a05eeebfSFrançois Tigeot 	return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
406a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
407a05eeebfSFrançois Tigeot 		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
4082c9916cdSFrançois Tigeot }
4092c9916cdSFrançois Tigeot 
4109edbd4a0SFrançois Tigeot /*
4119edbd4a0SFrançois Tigeot  * The data we write to the DIP data buffer registers is 1 byte bigger than the
4129edbd4a0SFrançois Tigeot  * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
4139edbd4a0SFrançois Tigeot  * at 0). It's also a byte used by DisplayPort so the same DIP registers can be
4149edbd4a0SFrançois Tigeot  * used for both technologies.
4159edbd4a0SFrançois Tigeot  *
4169edbd4a0SFrançois Tigeot  * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
4179edbd4a0SFrançois Tigeot  * DW1:       DB3       | DB2 | DB1 | DB0
4189edbd4a0SFrançois Tigeot  * DW2:       DB7       | DB6 | DB5 | DB4
4199edbd4a0SFrançois Tigeot  * DW3: ...
4209edbd4a0SFrançois Tigeot  *
4219edbd4a0SFrançois Tigeot  * (HB is Header Byte, DB is Data Byte)
4229edbd4a0SFrançois Tigeot  *
4239edbd4a0SFrançois Tigeot  * The hdmi pack() functions don't know about that hardware specific hole so we
4249edbd4a0SFrançois Tigeot  * trick them by giving an offset into the buffer and moving back the header
4259edbd4a0SFrançois Tigeot  * bytes by one.
4269edbd4a0SFrançois Tigeot  */
4279edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder,
4289edbd4a0SFrançois Tigeot 				  union hdmi_infoframe *frame)
429e3adcf8fSFrançois Tigeot {
430e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
4319edbd4a0SFrançois Tigeot 	uint8_t buffer[VIDEO_DIP_DATA_SIZE];
4329edbd4a0SFrançois Tigeot 	ssize_t len;
433e3adcf8fSFrançois Tigeot 
4349edbd4a0SFrançois Tigeot 	/* see comment above for the reason for this offset */
4359edbd4a0SFrançois Tigeot 	len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
4369edbd4a0SFrançois Tigeot 	if (len < 0)
4379edbd4a0SFrançois Tigeot 		return;
4389edbd4a0SFrançois Tigeot 
4399edbd4a0SFrançois Tigeot 	/* Insert the 'hole' (see big comment above) at position 3 */
4409edbd4a0SFrançois Tigeot 	buffer[0] = buffer[1];
4419edbd4a0SFrançois Tigeot 	buffer[1] = buffer[2];
4429edbd4a0SFrançois Tigeot 	buffer[2] = buffer[3];
4439edbd4a0SFrançois Tigeot 	buffer[3] = 0;
4449edbd4a0SFrançois Tigeot 	len++;
4459edbd4a0SFrançois Tigeot 
4469edbd4a0SFrançois Tigeot 	intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len);
447e3adcf8fSFrançois Tigeot }
448e3adcf8fSFrançois Tigeot 
44919df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
450352ff8bdSFrançois Tigeot 					 const struct drm_display_mode *adjusted_mode)
451e3adcf8fSFrançois Tigeot {
452a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
4538e26cdf6SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
4549edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4559edbd4a0SFrançois Tigeot 	int ret;
456e3adcf8fSFrançois Tigeot 
4579edbd4a0SFrançois Tigeot 	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
4589edbd4a0SFrançois Tigeot 						       adjusted_mode);
4599edbd4a0SFrançois Tigeot 	if (ret < 0) {
4609edbd4a0SFrançois Tigeot 		DRM_ERROR("couldn't fill AVI infoframe\n");
4619edbd4a0SFrançois Tigeot 		return;
4629edbd4a0SFrançois Tigeot 	}
46319df918dSFrançois Tigeot 
464a2fdbec6SFrançois Tigeot 	if (intel_hdmi->rgb_quant_range_selectable) {
4652c9916cdSFrançois Tigeot 		if (intel_crtc->config->limited_color_range)
4669edbd4a0SFrançois Tigeot 			frame.avi.quantization_range =
4679edbd4a0SFrançois Tigeot 				HDMI_QUANTIZATION_RANGE_LIMITED;
468a2fdbec6SFrançois Tigeot 		else
4699edbd4a0SFrançois Tigeot 			frame.avi.quantization_range =
4709edbd4a0SFrançois Tigeot 				HDMI_QUANTIZATION_RANGE_FULL;
471a2fdbec6SFrançois Tigeot 	}
472a2fdbec6SFrançois Tigeot 
4739edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
474e3adcf8fSFrançois Tigeot }
475e3adcf8fSFrançois Tigeot 
476e3adcf8fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
477e3adcf8fSFrançois Tigeot {
4789edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4799edbd4a0SFrançois Tigeot 	int ret;
480e3adcf8fSFrançois Tigeot 
4819edbd4a0SFrançois Tigeot 	ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
4829edbd4a0SFrançois Tigeot 	if (ret < 0) {
4839edbd4a0SFrançois Tigeot 		DRM_ERROR("couldn't fill SPD infoframe\n");
4849edbd4a0SFrançois Tigeot 		return;
4859edbd4a0SFrançois Tigeot 	}
486e3adcf8fSFrançois Tigeot 
4879edbd4a0SFrançois Tigeot 	frame.spd.sdi = HDMI_SPD_SDI_PC;
4889edbd4a0SFrançois Tigeot 
4899edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
4909edbd4a0SFrançois Tigeot }
4919edbd4a0SFrançois Tigeot 
4929edbd4a0SFrançois Tigeot static void
4939edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
494352ff8bdSFrançois Tigeot 			      const struct drm_display_mode *adjusted_mode)
4959edbd4a0SFrançois Tigeot {
4969edbd4a0SFrançois Tigeot 	union hdmi_infoframe frame;
4979edbd4a0SFrançois Tigeot 	int ret;
4989edbd4a0SFrançois Tigeot 
4999edbd4a0SFrançois Tigeot 	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
5009edbd4a0SFrançois Tigeot 							  adjusted_mode);
5019edbd4a0SFrançois Tigeot 	if (ret < 0)
5029edbd4a0SFrançois Tigeot 		return;
5039edbd4a0SFrançois Tigeot 
5049edbd4a0SFrançois Tigeot 	intel_write_infoframe(encoder, &frame);
505e3adcf8fSFrançois Tigeot }
506e3adcf8fSFrançois Tigeot 
50719df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder,
508ba55f2f5SFrançois Tigeot 			       bool enable,
509352ff8bdSFrançois Tigeot 			       const struct drm_display_mode *adjusted_mode)
51019df918dSFrançois Tigeot {
511*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
512a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
513a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
514aee94f86SFrançois Tigeot 	i915_reg_t reg = VIDEO_DIP_CTL;
51519df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
516ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
51719df918dSFrançois Tigeot 
51819df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
51919df918dSFrançois Tigeot 
52019df918dSFrançois Tigeot 	/* If the registers were not initialized yet, they might be zeroes,
52119df918dSFrançois Tigeot 	 * which means we're selecting the AVI DIP and we're setting its
52219df918dSFrançois Tigeot 	 * frequency to once. This seems to really confuse the HW and make
52319df918dSFrançois Tigeot 	 * things stop working (the register spec says the AVI always needs to
52419df918dSFrançois Tigeot 	 * be sent every VSync). So here we avoid writing to the register more
52519df918dSFrançois Tigeot 	 * than we need and also explicitly select the AVI DIP and explicitly
52619df918dSFrançois Tigeot 	 * set its frequency to every VSync. Avoiding to write it twice seems to
52719df918dSFrançois Tigeot 	 * be enough to solve the problem, but being defensive shouldn't hurt us
52819df918dSFrançois Tigeot 	 * either. */
52919df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
53019df918dSFrançois Tigeot 
531ba55f2f5SFrançois Tigeot 	if (!enable) {
53219df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
53319df918dSFrançois Tigeot 			return;
534a05eeebfSFrançois Tigeot 		if (port != (val & VIDEO_DIP_PORT_MASK)) {
535a05eeebfSFrançois Tigeot 			DRM_DEBUG_KMS("video DIP still enabled on port %c\n",
536a05eeebfSFrançois Tigeot 				      (val & VIDEO_DIP_PORT_MASK) >> 29);
537a05eeebfSFrançois Tigeot 			return;
538a05eeebfSFrançois Tigeot 		}
539a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
540a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
54119df918dSFrançois Tigeot 		I915_WRITE(reg, val);
54219df918dSFrançois Tigeot 		POSTING_READ(reg);
54319df918dSFrançois Tigeot 		return;
54419df918dSFrançois Tigeot 	}
54519df918dSFrançois Tigeot 
54619df918dSFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
54719df918dSFrançois Tigeot 		if (val & VIDEO_DIP_ENABLE) {
548a05eeebfSFrançois Tigeot 			DRM_DEBUG_KMS("video DIP already enabled on port %c\n",
549a05eeebfSFrançois Tigeot 				      (val & VIDEO_DIP_PORT_MASK) >> 29);
550a05eeebfSFrançois Tigeot 			return;
55119df918dSFrançois Tigeot 		}
55219df918dSFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
55319df918dSFrançois Tigeot 		val |= port;
55419df918dSFrançois Tigeot 	}
55519df918dSFrançois Tigeot 
55619df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
557a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
558a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
55919df918dSFrançois Tigeot 
56019df918dSFrançois Tigeot 	I915_WRITE(reg, val);
56119df918dSFrançois Tigeot 	POSTING_READ(reg);
56219df918dSFrançois Tigeot 
56319df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
56419df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
5659edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
56619df918dSFrançois Tigeot }
56719df918dSFrançois Tigeot 
568a05eeebfSFrançois Tigeot static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder)
569a05eeebfSFrançois Tigeot {
570a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->dev;
571a05eeebfSFrançois Tigeot 	struct drm_connector *connector;
572a05eeebfSFrançois Tigeot 
573a05eeebfSFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
574a05eeebfSFrançois Tigeot 
575a05eeebfSFrançois Tigeot 	/*
576a05eeebfSFrançois Tigeot 	 * HDMI cloning is only supported on g4x which doesn't
577a05eeebfSFrançois Tigeot 	 * support deep color or GCP infoframes anyway so no
578a05eeebfSFrançois Tigeot 	 * need to worry about multiple HDMI sinks here.
579a05eeebfSFrançois Tigeot 	 */
580a05eeebfSFrançois Tigeot 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
581a05eeebfSFrançois Tigeot 		if (connector->encoder == encoder)
582a05eeebfSFrançois Tigeot 			return connector->display_info.bpc > 8;
583a05eeebfSFrançois Tigeot 
584a05eeebfSFrançois Tigeot 	return false;
585a05eeebfSFrançois Tigeot }
586a05eeebfSFrançois Tigeot 
587a05eeebfSFrançois Tigeot /*
588a05eeebfSFrançois Tigeot  * Determine if default_phase=1 can be indicated in the GCP infoframe.
589a05eeebfSFrançois Tigeot  *
590a05eeebfSFrançois Tigeot  * From HDMI specification 1.4a:
591a05eeebfSFrançois Tigeot  * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0
592a05eeebfSFrançois Tigeot  * - The first pixel following each Video Data Period shall have a pixel packing phase of 0
593a05eeebfSFrançois Tigeot  * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase
594a05eeebfSFrançois Tigeot  * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing
595a05eeebfSFrançois Tigeot  *   phase of 0
596a05eeebfSFrançois Tigeot  */
597a05eeebfSFrançois Tigeot static bool gcp_default_phase_possible(int pipe_bpp,
598a05eeebfSFrançois Tigeot 				       const struct drm_display_mode *mode)
599a05eeebfSFrançois Tigeot {
600a05eeebfSFrançois Tigeot 	unsigned int pixels_per_group;
601a05eeebfSFrançois Tigeot 
602a05eeebfSFrançois Tigeot 	switch (pipe_bpp) {
603a05eeebfSFrançois Tigeot 	case 30:
604a05eeebfSFrançois Tigeot 		/* 4 pixels in 5 clocks */
605a05eeebfSFrançois Tigeot 		pixels_per_group = 4;
606a05eeebfSFrançois Tigeot 		break;
607a05eeebfSFrançois Tigeot 	case 36:
608a05eeebfSFrançois Tigeot 		/* 2 pixels in 3 clocks */
609a05eeebfSFrançois Tigeot 		pixels_per_group = 2;
610a05eeebfSFrançois Tigeot 		break;
611a05eeebfSFrançois Tigeot 	case 48:
612a05eeebfSFrançois Tigeot 		/* 1 pixel in 2 clocks */
613a05eeebfSFrançois Tigeot 		pixels_per_group = 1;
614a05eeebfSFrançois Tigeot 		break;
615a05eeebfSFrançois Tigeot 	default:
616a05eeebfSFrançois Tigeot 		/* phase information not relevant for 8bpc */
617a05eeebfSFrançois Tigeot 		return false;
618a05eeebfSFrançois Tigeot 	}
619a05eeebfSFrançois Tigeot 
620a05eeebfSFrançois Tigeot 	return mode->crtc_hdisplay % pixels_per_group == 0 &&
621a05eeebfSFrançois Tigeot 		mode->crtc_htotal % pixels_per_group == 0 &&
622a05eeebfSFrançois Tigeot 		mode->crtc_hblank_start % pixels_per_group == 0 &&
623a05eeebfSFrançois Tigeot 		mode->crtc_hblank_end % pixels_per_group == 0 &&
624a05eeebfSFrançois Tigeot 		mode->crtc_hsync_start % pixels_per_group == 0 &&
625a05eeebfSFrançois Tigeot 		mode->crtc_hsync_end % pixels_per_group == 0 &&
626a05eeebfSFrançois Tigeot 		((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 ||
627a05eeebfSFrançois Tigeot 		 mode->crtc_htotal/2 % pixels_per_group == 0);
628a05eeebfSFrançois Tigeot }
629a05eeebfSFrançois Tigeot 
630a05eeebfSFrançois Tigeot static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
631a05eeebfSFrançois Tigeot {
632*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
633a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
634aee94f86SFrançois Tigeot 	i915_reg_t reg;
635aee94f86SFrançois Tigeot 	u32 val = 0;
636a05eeebfSFrançois Tigeot 
637a05eeebfSFrançois Tigeot 	if (HAS_DDI(dev_priv))
638a05eeebfSFrançois Tigeot 		reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
639aee94f86SFrançois Tigeot 	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
640a05eeebfSFrançois Tigeot 		reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
6418621f407SFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev_priv))
642a05eeebfSFrançois Tigeot 		reg = TVIDEO_DIP_GCP(crtc->pipe);
643a05eeebfSFrançois Tigeot 	else
644a05eeebfSFrançois Tigeot 		return false;
645a05eeebfSFrançois Tigeot 
646a05eeebfSFrançois Tigeot 	/* Indicate color depth whenever the sink supports deep color */
647a05eeebfSFrançois Tigeot 	if (hdmi_sink_is_deep_color(encoder))
648a05eeebfSFrançois Tigeot 		val |= GCP_COLOR_INDICATION;
649a05eeebfSFrançois Tigeot 
650a05eeebfSFrançois Tigeot 	/* Enable default_phase whenever the display mode is suitably aligned */
651a05eeebfSFrançois Tigeot 	if (gcp_default_phase_possible(crtc->config->pipe_bpp,
652a05eeebfSFrançois Tigeot 				       &crtc->config->base.adjusted_mode))
653a05eeebfSFrançois Tigeot 		val |= GCP_DEFAULT_PHASE_ENABLE;
654a05eeebfSFrançois Tigeot 
655a05eeebfSFrançois Tigeot 	I915_WRITE(reg, val);
656a05eeebfSFrançois Tigeot 
657a05eeebfSFrançois Tigeot 	return val != 0;
658a05eeebfSFrançois Tigeot }
659a05eeebfSFrançois Tigeot 
66019df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder,
661ba55f2f5SFrançois Tigeot 			       bool enable,
662352ff8bdSFrançois Tigeot 			       const struct drm_display_mode *adjusted_mode)
66319df918dSFrançois Tigeot {
664*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
66519df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
666a2fdbec6SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
667a2fdbec6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
668aee94f86SFrançois Tigeot 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
66919df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
670ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
67119df918dSFrançois Tigeot 
67219df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
67319df918dSFrançois Tigeot 
67419df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
67519df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
67619df918dSFrançois Tigeot 
677ba55f2f5SFrançois Tigeot 	if (!enable) {
67819df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
67919df918dSFrançois Tigeot 			return;
680a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
681a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
682a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
68319df918dSFrançois Tigeot 		I915_WRITE(reg, val);
68419df918dSFrançois Tigeot 		POSTING_READ(reg);
68519df918dSFrançois Tigeot 		return;
68619df918dSFrançois Tigeot 	}
68719df918dSFrançois Tigeot 
68819df918dSFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
689a05eeebfSFrançois Tigeot 		WARN(val & VIDEO_DIP_ENABLE,
690a05eeebfSFrançois Tigeot 		     "DIP already enabled on port %c\n",
691a05eeebfSFrançois Tigeot 		     (val & VIDEO_DIP_PORT_MASK) >> 29);
69219df918dSFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
69319df918dSFrançois Tigeot 		val |= port;
69419df918dSFrançois Tigeot 	}
69519df918dSFrançois Tigeot 
69619df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
697a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
698a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
699a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
700a05eeebfSFrançois Tigeot 
701a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
702a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
70319df918dSFrançois Tigeot 
70419df918dSFrançois Tigeot 	I915_WRITE(reg, val);
70519df918dSFrançois Tigeot 	POSTING_READ(reg);
70619df918dSFrançois Tigeot 
70719df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
70819df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
7099edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
71019df918dSFrançois Tigeot }
71119df918dSFrançois Tigeot 
71219df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder,
713ba55f2f5SFrançois Tigeot 			       bool enable,
714352ff8bdSFrançois Tigeot 			       const struct drm_display_mode *adjusted_mode)
71519df918dSFrançois Tigeot {
716*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
71719df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
71819df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
719aee94f86SFrançois Tigeot 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
72019df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
72119df918dSFrançois Tigeot 
72219df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
72319df918dSFrançois Tigeot 
72419df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
72519df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
72619df918dSFrançois Tigeot 
727ba55f2f5SFrançois Tigeot 	if (!enable) {
72819df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
72919df918dSFrançois Tigeot 			return;
730a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
731a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
732a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
73319df918dSFrançois Tigeot 		I915_WRITE(reg, val);
73419df918dSFrançois Tigeot 		POSTING_READ(reg);
73519df918dSFrançois Tigeot 		return;
73619df918dSFrançois Tigeot 	}
73719df918dSFrançois Tigeot 
73819df918dSFrançois Tigeot 	/* Set both together, unset both together: see the spec. */
73919df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
74019df918dSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
741a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
742a05eeebfSFrançois Tigeot 
743a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
744a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
74519df918dSFrançois Tigeot 
74619df918dSFrançois Tigeot 	I915_WRITE(reg, val);
74719df918dSFrançois Tigeot 	POSTING_READ(reg);
74819df918dSFrançois Tigeot 
74919df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
75019df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
7519edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
75219df918dSFrançois Tigeot }
75319df918dSFrançois Tigeot 
75419df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder,
755ba55f2f5SFrançois Tigeot 			       bool enable,
756352ff8bdSFrançois Tigeot 			       const struct drm_display_mode *adjusted_mode)
75719df918dSFrançois Tigeot {
758*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
759ba55f2f5SFrançois Tigeot 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
76019df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
76119df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
762aee94f86SFrançois Tigeot 	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
76319df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
764ba55f2f5SFrançois Tigeot 	u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
76519df918dSFrançois Tigeot 
76619df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
76719df918dSFrançois Tigeot 
76819df918dSFrançois Tigeot 	/* See the big comment in g4x_set_infoframes() */
76919df918dSFrançois Tigeot 	val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
77019df918dSFrançois Tigeot 
771ba55f2f5SFrançois Tigeot 	if (!enable) {
77219df918dSFrançois Tigeot 		if (!(val & VIDEO_DIP_ENABLE))
77319df918dSFrançois Tigeot 			return;
774a05eeebfSFrançois Tigeot 		val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
775a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
776a05eeebfSFrançois Tigeot 			 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
77719df918dSFrançois Tigeot 		I915_WRITE(reg, val);
77819df918dSFrançois Tigeot 		POSTING_READ(reg);
77919df918dSFrançois Tigeot 		return;
78019df918dSFrançois Tigeot 	}
78119df918dSFrançois Tigeot 
782ba55f2f5SFrançois Tigeot 	if (port != (val & VIDEO_DIP_PORT_MASK)) {
783a05eeebfSFrançois Tigeot 		WARN(val & VIDEO_DIP_ENABLE,
784a05eeebfSFrançois Tigeot 		     "DIP already enabled on port %c\n",
785a05eeebfSFrançois Tigeot 		     (val & VIDEO_DIP_PORT_MASK) >> 29);
786ba55f2f5SFrançois Tigeot 		val &= ~VIDEO_DIP_PORT_MASK;
787ba55f2f5SFrançois Tigeot 		val |= port;
788ba55f2f5SFrançois Tigeot 	}
789ba55f2f5SFrançois Tigeot 
79019df918dSFrançois Tigeot 	val |= VIDEO_DIP_ENABLE;
791a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_AVI |
792a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
793a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
794a05eeebfSFrançois Tigeot 
795a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
796a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP;
79719df918dSFrançois Tigeot 
79819df918dSFrançois Tigeot 	I915_WRITE(reg, val);
79919df918dSFrançois Tigeot 	POSTING_READ(reg);
80019df918dSFrançois Tigeot 
80119df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
80219df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
8039edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
80419df918dSFrançois Tigeot }
80519df918dSFrançois Tigeot 
80619df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder,
807ba55f2f5SFrançois Tigeot 			       bool enable,
808352ff8bdSFrançois Tigeot 			       const struct drm_display_mode *adjusted_mode)
80919df918dSFrançois Tigeot {
810*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
81119df918dSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
81219df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
813aee94f86SFrançois Tigeot 	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
81419df918dSFrançois Tigeot 	u32 val = I915_READ(reg);
81519df918dSFrançois Tigeot 
81619df918dSFrançois Tigeot 	assert_hdmi_port_disabled(intel_hdmi);
81719df918dSFrançois Tigeot 
818a05eeebfSFrançois Tigeot 	val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
819a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
820a05eeebfSFrançois Tigeot 		 VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
821a05eeebfSFrançois Tigeot 
822ba55f2f5SFrançois Tigeot 	if (!enable) {
823a05eeebfSFrançois Tigeot 		I915_WRITE(reg, val);
82419df918dSFrançois Tigeot 		POSTING_READ(reg);
82519df918dSFrançois Tigeot 		return;
82619df918dSFrançois Tigeot 	}
82719df918dSFrançois Tigeot 
828a05eeebfSFrançois Tigeot 	if (intel_hdmi_set_gcp_infoframe(encoder))
829a05eeebfSFrançois Tigeot 		val |= VIDEO_DIP_ENABLE_GCP_HSW;
83019df918dSFrançois Tigeot 
83119df918dSFrançois Tigeot 	I915_WRITE(reg, val);
83219df918dSFrançois Tigeot 	POSTING_READ(reg);
83319df918dSFrançois Tigeot 
83419df918dSFrançois Tigeot 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
83519df918dSFrançois Tigeot 	intel_hdmi_set_spd_infoframe(encoder);
8369edbd4a0SFrançois Tigeot 	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
83719df918dSFrançois Tigeot }
83819df918dSFrançois Tigeot 
8398621f407SFrançois Tigeot void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
8408621f407SFrançois Tigeot {
8418621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
8428621f407SFrançois Tigeot 	struct i2c_adapter *adapter =
8438621f407SFrançois Tigeot 		intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
8448621f407SFrançois Tigeot 
8458621f407SFrançois Tigeot 	if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
8468621f407SFrançois Tigeot 		return;
8478621f407SFrançois Tigeot 
8488621f407SFrançois Tigeot 	DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
8498621f407SFrançois Tigeot 		      enable ? "Enabling" : "Disabling");
8508621f407SFrançois Tigeot 
8518621f407SFrançois Tigeot 	drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type,
8528621f407SFrançois Tigeot 					 adapter, enable);
8538621f407SFrançois Tigeot }
8548621f407SFrançois Tigeot 
855ba55f2f5SFrançois Tigeot static void intel_hdmi_prepare(struct intel_encoder *encoder)
856e3adcf8fSFrançois Tigeot {
8579edbd4a0SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
858*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
8599edbd4a0SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
8609edbd4a0SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
861352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
8628e26cdf6SFrançois Tigeot 	u32 hdmi_val;
863e3adcf8fSFrançois Tigeot 
8648621f407SFrançois Tigeot 	intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
8658621f407SFrançois Tigeot 
8668e26cdf6SFrançois Tigeot 	hdmi_val = SDVO_ENCODING_HDMI;
867352ff8bdSFrançois Tigeot 	if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
868352ff8bdSFrançois Tigeot 		hdmi_val |= HDMI_COLOR_RANGE_16_235;
869e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
8708e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
871e3adcf8fSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
8728e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
873e3adcf8fSFrançois Tigeot 
8742c9916cdSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24)
8758e26cdf6SFrançois Tigeot 		hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
876e3adcf8fSFrançois Tigeot 	else
8778e26cdf6SFrançois Tigeot 		hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
878e3adcf8fSFrançois Tigeot 
8792c9916cdSFrançois Tigeot 	if (crtc->config->has_hdmi_sink)
8808e26cdf6SFrançois Tigeot 		hdmi_val |= HDMI_MODE_SELECT_HDMI;
881e3adcf8fSFrançois Tigeot 
882e3adcf8fSFrançois Tigeot 	if (HAS_PCH_CPT(dev))
8839edbd4a0SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
884ba55f2f5SFrançois Tigeot 	else if (IS_CHERRYVIEW(dev))
885ba55f2f5SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe);
8868e26cdf6SFrançois Tigeot 	else
8879edbd4a0SFrançois Tigeot 		hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
888e3adcf8fSFrançois Tigeot 
8898e26cdf6SFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
8908e26cdf6SFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
891e3adcf8fSFrançois Tigeot }
892e3adcf8fSFrançois Tigeot 
89319df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
89419df918dSFrançois Tigeot 				    enum i915_pipe *pipe)
895e3adcf8fSFrançois Tigeot {
89619df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
897*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
89819df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
899ba55f2f5SFrançois Tigeot 	enum intel_display_power_domain power_domain;
90019df918dSFrançois Tigeot 	u32 tmp;
901aee94f86SFrançois Tigeot 	bool ret;
90219df918dSFrançois Tigeot 
903ba55f2f5SFrançois Tigeot 	power_domain = intel_display_port_power_domain(encoder);
904aee94f86SFrançois Tigeot 	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
905ba55f2f5SFrançois Tigeot 		return false;
906ba55f2f5SFrançois Tigeot 
907aee94f86SFrançois Tigeot 	ret = false;
908aee94f86SFrançois Tigeot 
9098e26cdf6SFrançois Tigeot 	tmp = I915_READ(intel_hdmi->hdmi_reg);
91019df918dSFrançois Tigeot 
91119df918dSFrançois Tigeot 	if (!(tmp & SDVO_ENABLE))
912aee94f86SFrançois Tigeot 		goto out;
91319df918dSFrançois Tigeot 
91419df918dSFrançois Tigeot 	if (HAS_PCH_CPT(dev))
91519df918dSFrançois Tigeot 		*pipe = PORT_TO_PIPE_CPT(tmp);
916ba55f2f5SFrançois Tigeot 	else if (IS_CHERRYVIEW(dev))
917ba55f2f5SFrançois Tigeot 		*pipe = SDVO_PORT_TO_PIPE_CHV(tmp);
91819df918dSFrançois Tigeot 	else
91919df918dSFrançois Tigeot 		*pipe = PORT_TO_PIPE(tmp);
92019df918dSFrançois Tigeot 
921aee94f86SFrançois Tigeot 	ret = true;
922aee94f86SFrançois Tigeot 
923aee94f86SFrançois Tigeot out:
924aee94f86SFrançois Tigeot 	intel_display_power_put(dev_priv, power_domain);
925aee94f86SFrançois Tigeot 
926aee94f86SFrançois Tigeot 	return ret;
92719df918dSFrançois Tigeot }
92819df918dSFrançois Tigeot 
9295d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder,
9302c9916cdSFrançois Tigeot 				  struct intel_crtc_state *pipe_config)
9315d0b1887SFrançois Tigeot {
9325d0b1887SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
93324edb884SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
934*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
9355d0b1887SFrançois Tigeot 	u32 tmp, flags = 0;
9369edbd4a0SFrançois Tigeot 	int dotclock;
9375d0b1887SFrançois Tigeot 
9385d0b1887SFrançois Tigeot 	tmp = I915_READ(intel_hdmi->hdmi_reg);
9395d0b1887SFrançois Tigeot 
9405d0b1887SFrançois Tigeot 	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
9415d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PHSYNC;
9425d0b1887SFrançois Tigeot 	else
9435d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NHSYNC;
9445d0b1887SFrançois Tigeot 
9455d0b1887SFrançois Tigeot 	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
9465d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_PVSYNC;
9475d0b1887SFrançois Tigeot 	else
9485d0b1887SFrançois Tigeot 		flags |= DRM_MODE_FLAG_NVSYNC;
9495d0b1887SFrançois Tigeot 
950ba55f2f5SFrançois Tigeot 	if (tmp & HDMI_MODE_SELECT_HDMI)
951ba55f2f5SFrançois Tigeot 		pipe_config->has_hdmi_sink = true;
952ba55f2f5SFrançois Tigeot 
953aee94f86SFrançois Tigeot 	if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config))
9542c9916cdSFrançois Tigeot 		pipe_config->has_infoframe = true;
9552c9916cdSFrançois Tigeot 
95624edb884SFrançois Tigeot 	if (tmp & SDVO_AUDIO_ENABLE)
957ba55f2f5SFrançois Tigeot 		pipe_config->has_audio = true;
958ba55f2f5SFrançois Tigeot 
95924edb884SFrançois Tigeot 	if (!HAS_PCH_SPLIT(dev) &&
96024edb884SFrançois Tigeot 	    tmp & HDMI_COLOR_RANGE_16_235)
96124edb884SFrançois Tigeot 		pipe_config->limited_color_range = true;
96224edb884SFrançois Tigeot 
9632c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.flags |= flags;
9649edbd4a0SFrançois Tigeot 
9659edbd4a0SFrançois Tigeot 	if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
9669edbd4a0SFrançois Tigeot 		dotclock = pipe_config->port_clock * 2 / 3;
9679edbd4a0SFrançois Tigeot 	else
9689edbd4a0SFrançois Tigeot 		dotclock = pipe_config->port_clock;
9699edbd4a0SFrançois Tigeot 
970a05eeebfSFrançois Tigeot 	if (pipe_config->pixel_multiplier)
971a05eeebfSFrançois Tigeot 		dotclock /= pipe_config->pixel_multiplier;
972a05eeebfSFrançois Tigeot 
9732c9916cdSFrançois Tigeot 	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
9748621f407SFrançois Tigeot 
9758621f407SFrançois Tigeot 	pipe_config->lane_count = 4;
9765d0b1887SFrançois Tigeot }
9775d0b1887SFrançois Tigeot 
978a05eeebfSFrançois Tigeot static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
979a05eeebfSFrançois Tigeot {
980a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
981a05eeebfSFrançois Tigeot 
982a05eeebfSFrançois Tigeot 	WARN_ON(!crtc->config->has_hdmi_sink);
983a05eeebfSFrançois Tigeot 	DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
984a05eeebfSFrançois Tigeot 			 pipe_name(crtc->pipe));
985a05eeebfSFrançois Tigeot 	intel_audio_codec_enable(encoder);
986a05eeebfSFrançois Tigeot }
987a05eeebfSFrançois Tigeot 
988a05eeebfSFrançois Tigeot static void g4x_enable_hdmi(struct intel_encoder *encoder)
98919df918dSFrançois Tigeot {
99019df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
991*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
992a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
99319df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
994e3adcf8fSFrançois Tigeot 	u32 temp;
995e3adcf8fSFrançois Tigeot 
9968e26cdf6SFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
997e3adcf8fSFrançois Tigeot 
998a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
999a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1000a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
100119df918dSFrançois Tigeot 
1002a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1003a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1004a05eeebfSFrançois Tigeot 
1005a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1006a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
1007a05eeebfSFrançois Tigeot }
1008a05eeebfSFrançois Tigeot 
1009a05eeebfSFrançois Tigeot static void ibx_enable_hdmi(struct intel_encoder *encoder)
1010a05eeebfSFrançois Tigeot {
1011a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1012*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1013a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
1014a05eeebfSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1015a05eeebfSFrançois Tigeot 	u32 temp;
1016a05eeebfSFrançois Tigeot 
1017a05eeebfSFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
1018a05eeebfSFrançois Tigeot 
1019a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
1020a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1021a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
1022a05eeebfSFrançois Tigeot 
1023a05eeebfSFrançois Tigeot 	/*
1024a05eeebfSFrançois Tigeot 	 * HW workaround, need to write this twice for issue
1025a05eeebfSFrançois Tigeot 	 * that may result in first write getting masked.
1026e3adcf8fSFrançois Tigeot 	 */
1027a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1028a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1029a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1030a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1031a05eeebfSFrançois Tigeot 
1032a05eeebfSFrançois Tigeot 	/*
1033a05eeebfSFrançois Tigeot 	 * HW workaround, need to toggle enable bit off and on
1034a05eeebfSFrançois Tigeot 	 * for 12bpc with pixel repeat.
1035a05eeebfSFrançois Tigeot 	 *
1036a05eeebfSFrançois Tigeot 	 * FIXME: BSpec says this should be done at the end of
1037a05eeebfSFrançois Tigeot 	 * of the modeset sequence, so not sure if this isn't too soon.
1038a05eeebfSFrançois Tigeot 	 */
1039a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24 &&
1040a05eeebfSFrançois Tigeot 	    crtc->config->pixel_multiplier > 1) {
10418e26cdf6SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
10428e26cdf6SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1043e3adcf8fSFrançois Tigeot 
1044a05eeebfSFrançois Tigeot 		/*
1045a05eeebfSFrançois Tigeot 		 * HW workaround, need to write this twice for issue
1046a05eeebfSFrançois Tigeot 		 * that may result in first write getting masked.
104719df918dSFrançois Tigeot 		 */
1048a05eeebfSFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
1049a05eeebfSFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
10508e26cdf6SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
10518e26cdf6SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1052e3adcf8fSFrançois Tigeot 	}
10532c9916cdSFrançois Tigeot 
1054a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1055a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
10562c9916cdSFrançois Tigeot }
1057a05eeebfSFrançois Tigeot 
1058a05eeebfSFrançois Tigeot static void cpt_enable_hdmi(struct intel_encoder *encoder)
1059a05eeebfSFrançois Tigeot {
1060a05eeebfSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1061*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1062a05eeebfSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
1063a05eeebfSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1064a05eeebfSFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
1065a05eeebfSFrançois Tigeot 	u32 temp;
1066a05eeebfSFrançois Tigeot 
1067a05eeebfSFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
1068a05eeebfSFrançois Tigeot 
1069a05eeebfSFrançois Tigeot 	temp |= SDVO_ENABLE;
1070a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1071a05eeebfSFrançois Tigeot 		temp |= SDVO_AUDIO_ENABLE;
1072a05eeebfSFrançois Tigeot 
1073a05eeebfSFrançois Tigeot 	/*
1074a05eeebfSFrançois Tigeot 	 * WaEnableHDMI8bpcBefore12bpc:snb,ivb
1075a05eeebfSFrançois Tigeot 	 *
1076a05eeebfSFrançois Tigeot 	 * The procedure for 12bpc is as follows:
1077a05eeebfSFrançois Tigeot 	 * 1. disable HDMI clock gating
1078a05eeebfSFrançois Tigeot 	 * 2. enable HDMI with 8bpc
1079a05eeebfSFrançois Tigeot 	 * 3. enable HDMI with 12bpc
1080a05eeebfSFrançois Tigeot 	 * 4. enable HDMI clock gating
1081a05eeebfSFrançois Tigeot 	 */
1082a05eeebfSFrançois Tigeot 
1083a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24) {
1084a05eeebfSFrançois Tigeot 		I915_WRITE(TRANS_CHICKEN1(pipe),
1085a05eeebfSFrançois Tigeot 			   I915_READ(TRANS_CHICKEN1(pipe)) |
1086a05eeebfSFrançois Tigeot 			   TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1087a05eeebfSFrançois Tigeot 
1088a05eeebfSFrançois Tigeot 		temp &= ~SDVO_COLOR_FORMAT_MASK;
1089a05eeebfSFrançois Tigeot 		temp |= SDVO_COLOR_FORMAT_8bpc;
1090a05eeebfSFrançois Tigeot 	}
1091a05eeebfSFrançois Tigeot 
1092a05eeebfSFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
1093a05eeebfSFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
1094a05eeebfSFrançois Tigeot 
1095a05eeebfSFrançois Tigeot 	if (crtc->config->pipe_bpp > 24) {
1096a05eeebfSFrançois Tigeot 		temp &= ~SDVO_COLOR_FORMAT_MASK;
1097a05eeebfSFrançois Tigeot 		temp |= HDMI_COLOR_FORMAT_12bpc;
1098a05eeebfSFrançois Tigeot 
1099a05eeebfSFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
1100a05eeebfSFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1101a05eeebfSFrançois Tigeot 
1102a05eeebfSFrançois Tigeot 		I915_WRITE(TRANS_CHICKEN1(pipe),
1103a05eeebfSFrançois Tigeot 			   I915_READ(TRANS_CHICKEN1(pipe)) &
1104a05eeebfSFrançois Tigeot 			   ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1105a05eeebfSFrançois Tigeot 	}
1106a05eeebfSFrançois Tigeot 
1107a05eeebfSFrançois Tigeot 	if (crtc->config->has_audio)
1108a05eeebfSFrançois Tigeot 		intel_enable_hdmi_audio(encoder);
11095d0b1887SFrançois Tigeot }
11109edbd4a0SFrançois Tigeot 
11119edbd4a0SFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder)
11129edbd4a0SFrançois Tigeot {
111319df918dSFrançois Tigeot }
111419df918dSFrançois Tigeot 
111519df918dSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder)
111619df918dSFrançois Tigeot {
111719df918dSFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1118*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
111919df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
11202c9916cdSFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
112119df918dSFrançois Tigeot 	u32 temp;
112219c468b4SFrançois Tigeot 
112319c468b4SFrançois Tigeot 	temp = I915_READ(intel_hdmi->hdmi_reg);
112419c468b4SFrançois Tigeot 
112519c468b4SFrançois Tigeot 	temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE);
112619c468b4SFrançois Tigeot 	I915_WRITE(intel_hdmi->hdmi_reg, temp);
112719c468b4SFrançois Tigeot 	POSTING_READ(intel_hdmi->hdmi_reg);
112819c468b4SFrançois Tigeot 
112919c468b4SFrançois Tigeot 	/*
113019c468b4SFrançois Tigeot 	 * HW workaround for IBX, we need to move the port
113119c468b4SFrançois Tigeot 	 * to transcoder A after disabling it to allow the
113219c468b4SFrançois Tigeot 	 * matching DP port to be enabled on transcoder A.
113319c468b4SFrançois Tigeot 	 */
113419c468b4SFrançois Tigeot 	if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) {
1135aee94f86SFrançois Tigeot 		/*
1136aee94f86SFrançois Tigeot 		 * We get CPU/PCH FIFO underruns on the other pipe when
1137aee94f86SFrançois Tigeot 		 * doing the workaround. Sweep them under the rug.
1138aee94f86SFrançois Tigeot 		 */
1139aee94f86SFrançois Tigeot 		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
1140aee94f86SFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
1141aee94f86SFrançois Tigeot 
114219c468b4SFrançois Tigeot 		temp &= ~SDVO_PIPE_B_SELECT;
114319c468b4SFrançois Tigeot 		temp |= SDVO_ENABLE;
114419c468b4SFrançois Tigeot 		/*
114519c468b4SFrançois Tigeot 		 * HW workaround, need to write this twice for issue
114619c468b4SFrançois Tigeot 		 * that may result in first write getting masked.
114719c468b4SFrançois Tigeot 		 */
114819c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
114919c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
115019c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
115119c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
115219c468b4SFrançois Tigeot 
115319c468b4SFrançois Tigeot 		temp &= ~SDVO_ENABLE;
115419c468b4SFrançois Tigeot 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
115519c468b4SFrançois Tigeot 		POSTING_READ(intel_hdmi->hdmi_reg);
1156aee94f86SFrançois Tigeot 
1157303bf270SFrançois Tigeot 		intel_wait_for_vblank_if_active(&dev_priv->drm, PIPE_A);
1158aee94f86SFrançois Tigeot 		intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
1159aee94f86SFrançois Tigeot 		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
116019c468b4SFrançois Tigeot 	}
1161a05eeebfSFrançois Tigeot 
1162a05eeebfSFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base, false, NULL);
11638621f407SFrançois Tigeot 
11648621f407SFrançois Tigeot 	intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
116519c468b4SFrançois Tigeot }
116619c468b4SFrançois Tigeot 
116719c468b4SFrançois Tigeot static void g4x_disable_hdmi(struct intel_encoder *encoder)
116819c468b4SFrançois Tigeot {
116919c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
117019df918dSFrançois Tigeot 
11712c9916cdSFrançois Tigeot 	if (crtc->config->has_audio)
11722c9916cdSFrançois Tigeot 		intel_audio_codec_disable(encoder);
11732c9916cdSFrançois Tigeot 
117419c468b4SFrançois Tigeot 	intel_disable_hdmi(encoder);
117519df918dSFrançois Tigeot }
117619df918dSFrançois Tigeot 
117719c468b4SFrançois Tigeot static void pch_disable_hdmi(struct intel_encoder *encoder)
117819c468b4SFrançois Tigeot {
117919c468b4SFrançois Tigeot 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
118019c468b4SFrançois Tigeot 
118119c468b4SFrançois Tigeot 	if (crtc->config->has_audio)
118219c468b4SFrançois Tigeot 		intel_audio_codec_disable(encoder);
118319df918dSFrançois Tigeot }
118419df918dSFrançois Tigeot 
118519c468b4SFrançois Tigeot static void pch_post_disable_hdmi(struct intel_encoder *encoder)
118619c468b4SFrançois Tigeot {
118719c468b4SFrançois Tigeot 	intel_disable_hdmi(encoder);
1188e3adcf8fSFrançois Tigeot }
1189e3adcf8fSFrançois Tigeot 
11908621f407SFrançois Tigeot static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv)
11915d0b1887SFrançois Tigeot {
11928621f407SFrançois Tigeot 	if (IS_G4X(dev_priv))
11935d0b1887SFrançois Tigeot 		return 165000;
11948621f407SFrançois Tigeot 	else if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
11955d0b1887SFrançois Tigeot 		return 300000;
11965d0b1887SFrançois Tigeot 	else
11975d0b1887SFrançois Tigeot 		return 225000;
11985d0b1887SFrançois Tigeot }
11995d0b1887SFrançois Tigeot 
12008621f407SFrançois Tigeot static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
12018621f407SFrançois Tigeot 				 bool respect_downstream_limits)
12028621f407SFrançois Tigeot {
12038621f407SFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
12048621f407SFrançois Tigeot 	int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
12058621f407SFrançois Tigeot 
12068621f407SFrançois Tigeot 	if (respect_downstream_limits) {
12078621f407SFrançois Tigeot 		if (hdmi->dp_dual_mode.max_tmds_clock)
12088621f407SFrançois Tigeot 			max_tmds_clock = min(max_tmds_clock,
12098621f407SFrançois Tigeot 					     hdmi->dp_dual_mode.max_tmds_clock);
12108621f407SFrançois Tigeot 		if (!hdmi->has_hdmi_sink)
12118621f407SFrançois Tigeot 			max_tmds_clock = min(max_tmds_clock, 165000);
12128621f407SFrançois Tigeot 	}
12138621f407SFrançois Tigeot 
12148621f407SFrançois Tigeot 	return max_tmds_clock;
12158621f407SFrançois Tigeot }
12168621f407SFrançois Tigeot 
12179edbd4a0SFrançois Tigeot static enum drm_mode_status
1218a05eeebfSFrançois Tigeot hdmi_port_clock_valid(struct intel_hdmi *hdmi,
12198621f407SFrançois Tigeot 		      int clock, bool respect_downstream_limits)
1220a05eeebfSFrançois Tigeot {
1221a05eeebfSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
1222a05eeebfSFrançois Tigeot 
1223a05eeebfSFrançois Tigeot 	if (clock < 25000)
1224a05eeebfSFrançois Tigeot 		return MODE_CLOCK_LOW;
12258621f407SFrançois Tigeot 	if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits))
1226a05eeebfSFrançois Tigeot 		return MODE_CLOCK_HIGH;
1227a05eeebfSFrançois Tigeot 
1228a05eeebfSFrançois Tigeot 	/* BXT DPLL can't generate 223-240 MHz */
1229a05eeebfSFrançois Tigeot 	if (IS_BROXTON(dev) && clock > 223333 && clock < 240000)
1230a05eeebfSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1231a05eeebfSFrançois Tigeot 
1232a05eeebfSFrançois Tigeot 	/* CHV DPLL can't generate 216-240 MHz */
1233a05eeebfSFrançois Tigeot 	if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000)
1234a05eeebfSFrançois Tigeot 		return MODE_CLOCK_RANGE;
1235a05eeebfSFrançois Tigeot 
1236a05eeebfSFrançois Tigeot 	return MODE_OK;
1237a05eeebfSFrançois Tigeot }
1238a05eeebfSFrançois Tigeot 
1239a05eeebfSFrançois Tigeot static enum drm_mode_status
12409edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector,
1241e3adcf8fSFrançois Tigeot 		      struct drm_display_mode *mode)
1242e3adcf8fSFrançois Tigeot {
1243a05eeebfSFrançois Tigeot 	struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
1244a05eeebfSFrançois Tigeot 	struct drm_device *dev = intel_hdmi_to_dev(hdmi);
1245a05eeebfSFrançois Tigeot 	enum drm_mode_status status;
1246a05eeebfSFrançois Tigeot 	int clock;
1247c0e85e96SFrançois Tigeot 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
1248e3adcf8fSFrançois Tigeot 
1249e3adcf8fSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
1250e3adcf8fSFrançois Tigeot 		return MODE_NO_DBLESCAN;
1251e3adcf8fSFrançois Tigeot 
1252a05eeebfSFrançois Tigeot 	clock = mode->clock;
1253c0e85e96SFrançois Tigeot 
1254c0e85e96SFrançois Tigeot 	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1255c0e85e96SFrançois Tigeot 		clock *= 2;
1256c0e85e96SFrançois Tigeot 
1257c0e85e96SFrançois Tigeot 	if (clock > max_dotclk)
1258c0e85e96SFrançois Tigeot 		return MODE_CLOCK_HIGH;
1259c0e85e96SFrançois Tigeot 
1260a05eeebfSFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1261a05eeebfSFrançois Tigeot 		clock *= 2;
1262a05eeebfSFrançois Tigeot 
1263a05eeebfSFrançois Tigeot 	/* check if we can do 8bpc */
1264a05eeebfSFrançois Tigeot 	status = hdmi_port_clock_valid(hdmi, clock, true);
1265a05eeebfSFrançois Tigeot 
1266a05eeebfSFrançois Tigeot 	/* if we can't do 8bpc we may still be able to do 12bpc */
1267a05eeebfSFrançois Tigeot 	if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK)
1268a05eeebfSFrançois Tigeot 		status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true);
1269a05eeebfSFrançois Tigeot 
1270a05eeebfSFrançois Tigeot 	return status;
1271e3adcf8fSFrançois Tigeot }
1272e3adcf8fSFrançois Tigeot 
1273477eb7f9SFrançois Tigeot static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
1274ba55f2f5SFrançois Tigeot {
1275477eb7f9SFrançois Tigeot 	struct drm_device *dev = crtc_state->base.crtc->dev;
1276ba55f2f5SFrançois Tigeot 
127724edb884SFrançois Tigeot 	if (HAS_GMCH_DISPLAY(dev))
1278ba55f2f5SFrançois Tigeot 		return false;
1279ba55f2f5SFrançois Tigeot 
1280ba55f2f5SFrançois Tigeot 	/*
1281ba55f2f5SFrançois Tigeot 	 * HDMI 12bpc affects the clocks, so it's only possible
1282ba55f2f5SFrançois Tigeot 	 * when not cloning with other encoder types.
1283ba55f2f5SFrançois Tigeot 	 */
1284303bf270SFrançois Tigeot 	return crtc_state->output_types == 1 << INTEL_OUTPUT_HDMI;
1285ba55f2f5SFrançois Tigeot }
1286ba55f2f5SFrançois Tigeot 
12878e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder,
12882c9916cdSFrançois Tigeot 			       struct intel_crtc_state *pipe_config)
1289e3adcf8fSFrançois Tigeot {
12908e26cdf6SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
12918e26cdf6SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
12922c9916cdSFrançois Tigeot 	struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
1293a05eeebfSFrançois Tigeot 	int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
1294a05eeebfSFrançois Tigeot 	int clock_12bpc = clock_8bpc * 3 / 2;
12955d0b1887SFrançois Tigeot 	int desired_bpp;
1296a2fdbec6SFrançois Tigeot 
1297ba55f2f5SFrançois Tigeot 	pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink;
1298ba55f2f5SFrançois Tigeot 
12992c9916cdSFrançois Tigeot 	if (pipe_config->has_hdmi_sink)
13002c9916cdSFrançois Tigeot 		pipe_config->has_infoframe = true;
13012c9916cdSFrançois Tigeot 
1302a2fdbec6SFrançois Tigeot 	if (intel_hdmi->color_range_auto) {
1303a2fdbec6SFrançois Tigeot 		/* See CEA-861-E - 5.1 Default Encoding Parameters */
1304352ff8bdSFrançois Tigeot 		pipe_config->limited_color_range =
1305352ff8bdSFrançois Tigeot 			pipe_config->has_hdmi_sink &&
1306352ff8bdSFrançois Tigeot 			drm_match_cea_mode(adjusted_mode) > 1;
1307352ff8bdSFrançois Tigeot 	} else {
1308352ff8bdSFrançois Tigeot 		pipe_config->limited_color_range =
1309352ff8bdSFrançois Tigeot 			intel_hdmi->limited_color_range;
1310a2fdbec6SFrançois Tigeot 	}
1311a2fdbec6SFrançois Tigeot 
13121b13d190SFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
13131b13d190SFrançois Tigeot 		pipe_config->pixel_multiplier = 2;
1314a05eeebfSFrançois Tigeot 		clock_8bpc *= 2;
1315a05eeebfSFrançois Tigeot 		clock_12bpc *= 2;
13161b13d190SFrançois Tigeot 	}
13171b13d190SFrançois Tigeot 
13188e26cdf6SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev))
13198e26cdf6SFrançois Tigeot 		pipe_config->has_pch_encoder = true;
13208e26cdf6SFrançois Tigeot 
1321ba55f2f5SFrançois Tigeot 	if (pipe_config->has_hdmi_sink && intel_hdmi->has_audio)
1322ba55f2f5SFrançois Tigeot 		pipe_config->has_audio = true;
1323ba55f2f5SFrançois Tigeot 
13248e26cdf6SFrançois Tigeot 	/*
13258e26cdf6SFrançois Tigeot 	 * HDMI is either 12 or 8, so if the display lets 10bpc sneak
13268e26cdf6SFrançois Tigeot 	 * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
13275d0b1887SFrançois Tigeot 	 * outputs. We also need to check that the higher clock still fits
13285d0b1887SFrançois Tigeot 	 * within limits.
13298e26cdf6SFrançois Tigeot 	 */
1330ba55f2f5SFrançois Tigeot 	if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
13318621f407SFrançois Tigeot 	    hdmi_port_clock_valid(intel_hdmi, clock_12bpc, true) == MODE_OK &&
1332a05eeebfSFrançois Tigeot 	    hdmi_12bpc_possible(pipe_config)) {
13335d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
13345d0b1887SFrançois Tigeot 		desired_bpp = 12*3;
13355d0b1887SFrançois Tigeot 
13365d0b1887SFrançois Tigeot 		/* Need to adjust the port link by 1.5x for 12bpc. */
13375d0b1887SFrançois Tigeot 		pipe_config->port_clock = clock_12bpc;
13388e26cdf6SFrançois Tigeot 	} else {
13395d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
13405d0b1887SFrançois Tigeot 		desired_bpp = 8*3;
1341a05eeebfSFrançois Tigeot 
1342a05eeebfSFrançois Tigeot 		pipe_config->port_clock = clock_8bpc;
13435d0b1887SFrançois Tigeot 	}
13445d0b1887SFrançois Tigeot 
13455d0b1887SFrançois Tigeot 	if (!pipe_config->bw_constrained) {
13465d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp);
13475d0b1887SFrançois Tigeot 		pipe_config->pipe_bpp = desired_bpp;
13485d0b1887SFrançois Tigeot 	}
13495d0b1887SFrançois Tigeot 
1350a05eeebfSFrançois Tigeot 	if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
1351a05eeebfSFrançois Tigeot 				  false) != MODE_OK) {
1352a05eeebfSFrançois Tigeot 		DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
13535d0b1887SFrançois Tigeot 		return false;
13548e26cdf6SFrançois Tigeot 	}
1355a2fdbec6SFrançois Tigeot 
1356352ff8bdSFrançois Tigeot 	/* Set user selected PAR to incoming mode's member */
1357352ff8bdSFrançois Tigeot 	adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio;
1358352ff8bdSFrançois Tigeot 
13598621f407SFrançois Tigeot 	pipe_config->lane_count = 4;
13608621f407SFrançois Tigeot 
1361e3adcf8fSFrançois Tigeot 	return true;
1362e3adcf8fSFrançois Tigeot }
1363e3adcf8fSFrançois Tigeot 
13641b13d190SFrançois Tigeot static void
13651b13d190SFrançois Tigeot intel_hdmi_unset_edid(struct drm_connector *connector)
1366e3adcf8fSFrançois Tigeot {
1367e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
13689edbd4a0SFrançois Tigeot 
1369e3adcf8fSFrançois Tigeot 	intel_hdmi->has_hdmi_sink = false;
1370e3adcf8fSFrançois Tigeot 	intel_hdmi->has_audio = false;
1371a2fdbec6SFrançois Tigeot 	intel_hdmi->rgb_quant_range_selectable = false;
1372e3adcf8fSFrançois Tigeot 
13738621f407SFrançois Tigeot 	intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
13748621f407SFrançois Tigeot 	intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
13758621f407SFrançois Tigeot 
13761b13d190SFrançois Tigeot 	kfree(to_intel_connector(connector)->detect_edid);
13771b13d190SFrançois Tigeot 	to_intel_connector(connector)->detect_edid = NULL;
1378e3adcf8fSFrançois Tigeot }
1379e3adcf8fSFrançois Tigeot 
13808621f407SFrançois Tigeot static void
13818621f407SFrançois Tigeot intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
13828621f407SFrançois Tigeot {
13838621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
13848621f407SFrançois Tigeot 	struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
13858621f407SFrançois Tigeot 	enum port port = hdmi_to_dig_port(hdmi)->port;
13868621f407SFrançois Tigeot 	struct i2c_adapter *adapter =
13878621f407SFrançois Tigeot 		intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
13888621f407SFrançois Tigeot 	enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter);
13898621f407SFrançois Tigeot 
13908621f407SFrançois Tigeot 	/*
13918621f407SFrançois Tigeot 	 * Type 1 DVI adaptors are not required to implement any
13928621f407SFrançois Tigeot 	 * registers, so we can't always detect their presence.
13938621f407SFrançois Tigeot 	 * Ideally we should be able to check the state of the
13948621f407SFrançois Tigeot 	 * CONFIG1 pin, but no such luck on our hardware.
13958621f407SFrançois Tigeot 	 *
13968621f407SFrançois Tigeot 	 * The only method left to us is to check the VBT to see
13978621f407SFrançois Tigeot 	 * if the port is a dual mode capable DP port. But let's
13988621f407SFrançois Tigeot 	 * only do that when we sucesfully read the EDID, to avoid
13998621f407SFrançois Tigeot 	 * confusing log messages about DP dual mode adaptors when
14008621f407SFrançois Tigeot 	 * there's nothing connected to the port.
14018621f407SFrançois Tigeot 	 */
14028621f407SFrançois Tigeot 	if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
14038621f407SFrançois Tigeot 		if (has_edid &&
14048621f407SFrançois Tigeot 		    intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
14058621f407SFrançois Tigeot 			DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
14068621f407SFrançois Tigeot 			type = DRM_DP_DUAL_MODE_TYPE1_DVI;
14078621f407SFrançois Tigeot 		} else {
14088621f407SFrançois Tigeot 			type = DRM_DP_DUAL_MODE_NONE;
14098621f407SFrançois Tigeot 		}
14108621f407SFrançois Tigeot 	}
14118621f407SFrançois Tigeot 
14128621f407SFrançois Tigeot 	if (type == DRM_DP_DUAL_MODE_NONE)
14138621f407SFrançois Tigeot 		return;
14148621f407SFrançois Tigeot 
14158621f407SFrançois Tigeot 	hdmi->dp_dual_mode.type = type;
14168621f407SFrançois Tigeot 	hdmi->dp_dual_mode.max_tmds_clock =
14178621f407SFrançois Tigeot 		drm_dp_dual_mode_max_tmds_clock(type, adapter);
14188621f407SFrançois Tigeot 
14198621f407SFrançois Tigeot 	DRM_DEBUG_KMS("DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n",
14208621f407SFrançois Tigeot 		      drm_dp_get_dual_mode_type_name(type),
14218621f407SFrançois Tigeot 		      hdmi->dp_dual_mode.max_tmds_clock);
14228621f407SFrançois Tigeot }
14238621f407SFrançois Tigeot 
14241b13d190SFrançois Tigeot static bool
1425*bf017597SFrançois Tigeot intel_hdmi_set_edid(struct drm_connector *connector)
1426e3adcf8fSFrançois Tigeot {
14271b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
14281b13d190SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
1429*bf017597SFrançois Tigeot 	struct edid *edid;
14301b13d190SFrançois Tigeot 	bool connected = false;
1431e3adcf8fSFrançois Tigeot 
1432352ff8bdSFrançois Tigeot 	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
1433ba55f2f5SFrançois Tigeot 
14341b13d190SFrançois Tigeot 	edid = drm_get_edid(connector,
143519df918dSFrançois Tigeot 			    intel_gmbus_get_adapter(dev_priv,
143619df918dSFrançois Tigeot 			    intel_hdmi->ddc_bus));
1437ba55f2f5SFrançois Tigeot 
14388621f407SFrançois Tigeot 	intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
14398621f407SFrançois Tigeot 
1440352ff8bdSFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
1441ba55f2f5SFrançois Tigeot 
14421b13d190SFrançois Tigeot 	to_intel_connector(connector)->detect_edid = edid;
14431b13d190SFrançois Tigeot 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
14441b13d190SFrançois Tigeot 		intel_hdmi->rgb_quant_range_selectable =
14451b13d190SFrançois Tigeot 			drm_rgb_quant_range_selectable(edid);
14461b13d190SFrançois Tigeot 
14471b13d190SFrançois Tigeot 		intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
14481b13d190SFrançois Tigeot 		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
14491b13d190SFrançois Tigeot 			intel_hdmi->has_audio =
14501b13d190SFrançois Tigeot 				intel_hdmi->force_audio == HDMI_AUDIO_ON;
14511b13d190SFrançois Tigeot 
14521b13d190SFrançois Tigeot 		if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
14531b13d190SFrançois Tigeot 			intel_hdmi->has_hdmi_sink =
14541b13d190SFrançois Tigeot 				drm_detect_hdmi_monitor(edid);
14551b13d190SFrançois Tigeot 
14561b13d190SFrançois Tigeot 		connected = true;
14571b13d190SFrançois Tigeot 	}
14581b13d190SFrançois Tigeot 
14591b13d190SFrançois Tigeot 	return connected;
14601b13d190SFrançois Tigeot }
14611b13d190SFrançois Tigeot 
14621b13d190SFrançois Tigeot static enum drm_connector_status
14631b13d190SFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force)
14641b13d190SFrançois Tigeot {
14651b13d190SFrançois Tigeot 	enum drm_connector_status status;
1466352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
14671b13d190SFrançois Tigeot 
14681b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
14691b13d190SFrançois Tigeot 		      connector->base.id, connector->name);
14701b13d190SFrançois Tigeot 
1471352ff8bdSFrançois Tigeot 	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
1472352ff8bdSFrançois Tigeot 
14731b13d190SFrançois Tigeot 	intel_hdmi_unset_edid(connector);
14741b13d190SFrançois Tigeot 
1475*bf017597SFrançois Tigeot 	if (intel_hdmi_set_edid(connector)) {
14761b13d190SFrançois Tigeot 		struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
14771b13d190SFrançois Tigeot 
14781b13d190SFrançois Tigeot 		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
14791b13d190SFrançois Tigeot 		status = connector_status_connected;
14801b13d190SFrançois Tigeot 	} else
14811b13d190SFrançois Tigeot 		status = connector_status_disconnected;
14821b13d190SFrançois Tigeot 
1483352ff8bdSFrançois Tigeot 	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
1484352ff8bdSFrançois Tigeot 
14851b13d190SFrançois Tigeot 	return status;
14861b13d190SFrançois Tigeot }
14871b13d190SFrançois Tigeot 
14881b13d190SFrançois Tigeot static void
14891b13d190SFrançois Tigeot intel_hdmi_force(struct drm_connector *connector)
14901b13d190SFrançois Tigeot {
14911b13d190SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
14921b13d190SFrançois Tigeot 
14931b13d190SFrançois Tigeot 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
14941b13d190SFrançois Tigeot 		      connector->base.id, connector->name);
14951b13d190SFrançois Tigeot 
14961b13d190SFrançois Tigeot 	intel_hdmi_unset_edid(connector);
14971b13d190SFrançois Tigeot 
14981b13d190SFrançois Tigeot 	if (connector->status != connector_status_connected)
14991b13d190SFrançois Tigeot 		return;
15001b13d190SFrançois Tigeot 
1501*bf017597SFrançois Tigeot 	intel_hdmi_set_edid(connector);
15021b13d190SFrançois Tigeot 	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
15031b13d190SFrançois Tigeot }
15041b13d190SFrançois Tigeot 
15051b13d190SFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector)
15061b13d190SFrançois Tigeot {
15071b13d190SFrançois Tigeot 	struct edid *edid;
15081b13d190SFrançois Tigeot 
15091b13d190SFrançois Tigeot 	edid = to_intel_connector(connector)->detect_edid;
15101b13d190SFrançois Tigeot 	if (edid == NULL)
15111b13d190SFrançois Tigeot 		return 0;
15121b13d190SFrançois Tigeot 
15131b13d190SFrançois Tigeot 	return intel_connector_update_modes(connector, edid);
1514e3adcf8fSFrançois Tigeot }
1515e3adcf8fSFrançois Tigeot 
1516e3adcf8fSFrançois Tigeot static bool
1517e3adcf8fSFrançois Tigeot intel_hdmi_detect_audio(struct drm_connector *connector)
1518e3adcf8fSFrançois Tigeot {
1519e3adcf8fSFrançois Tigeot 	bool has_audio = false;
15201b13d190SFrançois Tigeot 	struct edid *edid;
1521e3adcf8fSFrançois Tigeot 
15221b13d190SFrançois Tigeot 	edid = to_intel_connector(connector)->detect_edid;
15231b13d190SFrançois Tigeot 	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)
1524e3adcf8fSFrançois Tigeot 		has_audio = drm_detect_monitor_audio(edid);
1525ba55f2f5SFrançois Tigeot 
1526e3adcf8fSFrançois Tigeot 	return has_audio;
1527e3adcf8fSFrançois Tigeot }
1528e3adcf8fSFrançois Tigeot 
1529e3adcf8fSFrançois Tigeot static int
1530e3adcf8fSFrançois Tigeot intel_hdmi_set_property(struct drm_connector *connector,
1531e3adcf8fSFrançois Tigeot 			struct drm_property *property,
1532e3adcf8fSFrançois Tigeot 			uint64_t val)
1533e3adcf8fSFrançois Tigeot {
1534e3adcf8fSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
153519df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port =
153619df918dSFrançois Tigeot 		hdmi_to_dig_port(intel_hdmi);
1537*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
1538e3adcf8fSFrançois Tigeot 	int ret;
1539e3adcf8fSFrançois Tigeot 
1540b5162e19SFrançois Tigeot 	ret = drm_object_property_set_value(&connector->base, property, val);
1541e3adcf8fSFrançois Tigeot 	if (ret)
1542e3adcf8fSFrançois Tigeot 		return ret;
1543e3adcf8fSFrançois Tigeot 
1544e3adcf8fSFrançois Tigeot 	if (property == dev_priv->force_audio_property) {
1545e3adcf8fSFrançois Tigeot 		enum hdmi_force_audio i = val;
1546e3adcf8fSFrançois Tigeot 		bool has_audio;
1547e3adcf8fSFrançois Tigeot 
1548e3adcf8fSFrançois Tigeot 		if (i == intel_hdmi->force_audio)
1549e3adcf8fSFrançois Tigeot 			return 0;
1550e3adcf8fSFrançois Tigeot 
1551e3adcf8fSFrançois Tigeot 		intel_hdmi->force_audio = i;
1552e3adcf8fSFrançois Tigeot 
1553e3adcf8fSFrançois Tigeot 		if (i == HDMI_AUDIO_AUTO)
1554e3adcf8fSFrançois Tigeot 			has_audio = intel_hdmi_detect_audio(connector);
1555e3adcf8fSFrançois Tigeot 		else
1556e3adcf8fSFrançois Tigeot 			has_audio = (i == HDMI_AUDIO_ON);
1557e3adcf8fSFrançois Tigeot 
1558e3adcf8fSFrançois Tigeot 		if (i == HDMI_AUDIO_OFF_DVI)
1559e3adcf8fSFrançois Tigeot 			intel_hdmi->has_hdmi_sink = 0;
1560e3adcf8fSFrançois Tigeot 
1561e3adcf8fSFrançois Tigeot 		intel_hdmi->has_audio = has_audio;
1562e3adcf8fSFrançois Tigeot 		goto done;
1563e3adcf8fSFrançois Tigeot 	}
1564e3adcf8fSFrançois Tigeot 
1565e3adcf8fSFrançois Tigeot 	if (property == dev_priv->broadcast_rgb_property) {
15668e26cdf6SFrançois Tigeot 		bool old_auto = intel_hdmi->color_range_auto;
1567352ff8bdSFrançois Tigeot 		bool old_range = intel_hdmi->limited_color_range;
15688e26cdf6SFrançois Tigeot 
1569a2fdbec6SFrançois Tigeot 		switch (val) {
1570a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_AUTO:
1571a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = true;
1572a2fdbec6SFrançois Tigeot 			break;
1573a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_FULL:
1574a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = false;
1575352ff8bdSFrançois Tigeot 			intel_hdmi->limited_color_range = false;
1576a2fdbec6SFrançois Tigeot 			break;
1577a2fdbec6SFrançois Tigeot 		case INTEL_BROADCAST_RGB_LIMITED:
1578a2fdbec6SFrançois Tigeot 			intel_hdmi->color_range_auto = false;
1579352ff8bdSFrançois Tigeot 			intel_hdmi->limited_color_range = true;
1580a2fdbec6SFrançois Tigeot 			break;
1581a2fdbec6SFrançois Tigeot 		default:
1582a2fdbec6SFrançois Tigeot 			return -EINVAL;
1583a2fdbec6SFrançois Tigeot 		}
15848e26cdf6SFrançois Tigeot 
15858e26cdf6SFrançois Tigeot 		if (old_auto == intel_hdmi->color_range_auto &&
1586352ff8bdSFrançois Tigeot 		    old_range == intel_hdmi->limited_color_range)
15878e26cdf6SFrançois Tigeot 			return 0;
15888e26cdf6SFrançois Tigeot 
1589e3adcf8fSFrançois Tigeot 		goto done;
1590e3adcf8fSFrançois Tigeot 	}
1591e3adcf8fSFrançois Tigeot 
159224edb884SFrançois Tigeot 	if (property == connector->dev->mode_config.aspect_ratio_property) {
159324edb884SFrançois Tigeot 		switch (val) {
159424edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_NONE:
159524edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
159624edb884SFrançois Tigeot 			break;
159724edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_4_3:
159824edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
159924edb884SFrançois Tigeot 			break;
160024edb884SFrançois Tigeot 		case DRM_MODE_PICTURE_ASPECT_16_9:
160124edb884SFrançois Tigeot 			intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
160224edb884SFrançois Tigeot 			break;
160324edb884SFrançois Tigeot 		default:
160424edb884SFrançois Tigeot 			return -EINVAL;
160524edb884SFrançois Tigeot 		}
160624edb884SFrançois Tigeot 		goto done;
160724edb884SFrançois Tigeot 	}
160824edb884SFrançois Tigeot 
1609e3adcf8fSFrançois Tigeot 	return -EINVAL;
1610e3adcf8fSFrançois Tigeot 
1611e3adcf8fSFrançois Tigeot done:
1612a2fdbec6SFrançois Tigeot 	if (intel_dig_port->base.base.crtc)
1613a2fdbec6SFrançois Tigeot 		intel_crtc_restore_mode(intel_dig_port->base.base.crtc);
1614e3adcf8fSFrançois Tigeot 
1615e3adcf8fSFrançois Tigeot 	return 0;
1616e3adcf8fSFrançois Tigeot }
1617e3adcf8fSFrançois Tigeot 
1618ba55f2f5SFrançois Tigeot static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
1619ba55f2f5SFrançois Tigeot {
1620ba55f2f5SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1621ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
1622352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
1623ba55f2f5SFrançois Tigeot 
1624ba55f2f5SFrançois Tigeot 	intel_hdmi_prepare(encoder);
1625ba55f2f5SFrançois Tigeot 
1626ba55f2f5SFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
16272c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
1628ba55f2f5SFrançois Tigeot 				   adjusted_mode);
1629ba55f2f5SFrançois Tigeot }
1630ba55f2f5SFrançois Tigeot 
16319edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
16325d0b1887SFrançois Tigeot {
16335d0b1887SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
1634ba55f2f5SFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &dport->hdmi;
16355d0b1887SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1636*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
16375d0b1887SFrançois Tigeot 	struct intel_crtc *intel_crtc =
16385d0b1887SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
1639352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
16405d0b1887SFrançois Tigeot 
16411487f786SFrançois Tigeot 	vlv_phy_pre_encoder_enable(encoder);
16425d0b1887SFrançois Tigeot 
16435d0b1887SFrançois Tigeot 	/* HDMI 1.0V-2dB */
16441487f786SFrançois Tigeot 	vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
16451487f786SFrançois Tigeot 				 0x2b247878);
16469edbd4a0SFrançois Tigeot 
1647ba55f2f5SFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
16482c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
1649ba55f2f5SFrançois Tigeot 				   adjusted_mode);
1650ba55f2f5SFrançois Tigeot 
1651a05eeebfSFrançois Tigeot 	g4x_enable_hdmi(encoder);
16529edbd4a0SFrançois Tigeot 
165319c468b4SFrançois Tigeot 	vlv_wait_port_ready(dev_priv, dport, 0x0);
16545d0b1887SFrançois Tigeot }
16555d0b1887SFrançois Tigeot 
16569edbd4a0SFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
16575d0b1887SFrançois Tigeot {
1658ba55f2f5SFrançois Tigeot 	intel_hdmi_prepare(encoder);
16595d0b1887SFrançois Tigeot 
16601487f786SFrançois Tigeot 	vlv_phy_pre_pll_enable(encoder);
1661352ff8bdSFrançois Tigeot }
1662352ff8bdSFrançois Tigeot 
166324edb884SFrançois Tigeot static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
166424edb884SFrançois Tigeot {
16651b13d190SFrançois Tigeot 	intel_hdmi_prepare(encoder);
16661b13d190SFrançois Tigeot 
16671487f786SFrançois Tigeot 	chv_phy_pre_pll_enable(encoder);
166824edb884SFrançois Tigeot }
166924edb884SFrançois Tigeot 
1670352ff8bdSFrançois Tigeot static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder)
1671352ff8bdSFrançois Tigeot {
16721487f786SFrançois Tigeot 	chv_phy_post_pll_disable(encoder);
1673352ff8bdSFrançois Tigeot }
1674352ff8bdSFrançois Tigeot 
16759edbd4a0SFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
16765d0b1887SFrançois Tigeot {
16775d0b1887SFrançois Tigeot 	/* Reset lanes to avoid HDMI flicker (VLV w/a) */
16781487f786SFrançois Tigeot 	vlv_phy_reset_lanes(encoder);
16795d0b1887SFrançois Tigeot }
16805d0b1887SFrançois Tigeot 
1681ba55f2f5SFrançois Tigeot static void chv_hdmi_post_disable(struct intel_encoder *encoder)
1682ba55f2f5SFrançois Tigeot {
1683ba55f2f5SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1684*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1685ba55f2f5SFrançois Tigeot 
168619c468b4SFrançois Tigeot 	mutex_lock(&dev_priv->sb_lock);
1687ba55f2f5SFrançois Tigeot 
1688352ff8bdSFrançois Tigeot 	/* Assert data lane reset */
1689352ff8bdSFrançois Tigeot 	chv_data_lane_soft_reset(encoder, true);
1690ba55f2f5SFrançois Tigeot 
169119c468b4SFrançois Tigeot 	mutex_unlock(&dev_priv->sb_lock);
1692ba55f2f5SFrançois Tigeot }
1693ba55f2f5SFrançois Tigeot 
1694ba55f2f5SFrançois Tigeot static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
1695ba55f2f5SFrançois Tigeot {
1696ba55f2f5SFrançois Tigeot 	struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
16972c9916cdSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &dport->hdmi;
1698ba55f2f5SFrançois Tigeot 	struct drm_device *dev = encoder->base.dev;
1699*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1700ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc =
1701ba55f2f5SFrançois Tigeot 		to_intel_crtc(encoder->base.crtc);
1702352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
1703ba55f2f5SFrançois Tigeot 
17041487f786SFrançois Tigeot 	chv_phy_pre_encoder_enable(encoder);
17052c9916cdSFrançois Tigeot 
1706ba55f2f5SFrançois Tigeot 	/* FIXME: Program the support xxx V-dB */
1707ba55f2f5SFrançois Tigeot 	/* Use 800mV-0dB */
17081487f786SFrançois Tigeot 	chv_set_phy_signal_level(encoder, 128, 102, false);
1709ba55f2f5SFrançois Tigeot 
17102c9916cdSFrançois Tigeot 	intel_hdmi->set_infoframes(&encoder->base,
17112c9916cdSFrançois Tigeot 				   intel_crtc->config->has_hdmi_sink,
17122c9916cdSFrançois Tigeot 				   adjusted_mode);
17132c9916cdSFrançois Tigeot 
1714a05eeebfSFrançois Tigeot 	g4x_enable_hdmi(encoder);
1715ba55f2f5SFrançois Tigeot 
171619c468b4SFrançois Tigeot 	vlv_wait_port_ready(dev_priv, dport, 0x0);
1717352ff8bdSFrançois Tigeot 
1718352ff8bdSFrançois Tigeot 	/* Second common lane will stay alive on its own now */
17191487f786SFrançois Tigeot 	chv_phy_release_cl2_override(encoder);
1720ba55f2f5SFrançois Tigeot }
1721ba55f2f5SFrançois Tigeot 
1722e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector)
1723e3adcf8fSFrançois Tigeot {
17241b13d190SFrançois Tigeot 	kfree(to_intel_connector(connector)->detect_edid);
1725e3adcf8fSFrançois Tigeot 	drm_connector_cleanup(connector);
17268e26cdf6SFrançois Tigeot 	kfree(connector);
1727e3adcf8fSFrançois Tigeot }
1728e3adcf8fSFrançois Tigeot 
1729e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
1730a05eeebfSFrançois Tigeot 	.dpms = drm_atomic_helper_connector_dpms,
1731e3adcf8fSFrançois Tigeot 	.detect = intel_hdmi_detect,
17321b13d190SFrançois Tigeot 	.force = intel_hdmi_force,
1733e3adcf8fSFrançois Tigeot 	.fill_modes = drm_helper_probe_single_connector_modes,
1734e3adcf8fSFrançois Tigeot 	.set_property = intel_hdmi_set_property,
17352c9916cdSFrançois Tigeot 	.atomic_get_property = intel_connector_atomic_get_property,
17361487f786SFrançois Tigeot 	.late_register = intel_connector_register,
17371487f786SFrançois Tigeot 	.early_unregister = intel_connector_unregister,
1738e3adcf8fSFrançois Tigeot 	.destroy = intel_hdmi_destroy,
17392c9916cdSFrançois Tigeot 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1740477eb7f9SFrançois Tigeot 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1741e3adcf8fSFrançois Tigeot };
1742e3adcf8fSFrançois Tigeot 
1743e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
1744e3adcf8fSFrançois Tigeot 	.get_modes = intel_hdmi_get_modes,
1745e3adcf8fSFrançois Tigeot 	.mode_valid = intel_hdmi_mode_valid,
1746e3adcf8fSFrançois Tigeot };
1747e3adcf8fSFrançois Tigeot 
1748e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
1749e3adcf8fSFrançois Tigeot 	.destroy = intel_encoder_destroy,
1750e3adcf8fSFrançois Tigeot };
1751e3adcf8fSFrançois Tigeot 
1752e3adcf8fSFrançois Tigeot static void
1753e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
1754e3adcf8fSFrançois Tigeot {
1755e3adcf8fSFrançois Tigeot 	intel_attach_force_audio_property(connector);
1756e3adcf8fSFrançois Tigeot 	intel_attach_broadcast_rgb_property(connector);
1757a2fdbec6SFrançois Tigeot 	intel_hdmi->color_range_auto = true;
175824edb884SFrançois Tigeot 	intel_attach_aspect_ratio_property(connector);
175924edb884SFrançois Tigeot 	intel_hdmi->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
1760e3adcf8fSFrançois Tigeot }
1761e3adcf8fSFrançois Tigeot 
1762*bf017597SFrançois Tigeot static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
1763*bf017597SFrançois Tigeot 			     enum port port)
1764*bf017597SFrançois Tigeot {
1765*bf017597SFrançois Tigeot 	const struct ddi_vbt_port_info *info =
1766*bf017597SFrançois Tigeot 		&dev_priv->vbt.ddi_port_info[port];
1767*bf017597SFrançois Tigeot 	u8 ddc_pin;
1768*bf017597SFrançois Tigeot 
1769*bf017597SFrançois Tigeot 	if (info->alternate_ddc_pin) {
1770*bf017597SFrançois Tigeot 		DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
1771*bf017597SFrançois Tigeot 			      info->alternate_ddc_pin, port_name(port));
1772*bf017597SFrançois Tigeot 		return info->alternate_ddc_pin;
1773*bf017597SFrançois Tigeot 	}
1774*bf017597SFrançois Tigeot 
1775*bf017597SFrançois Tigeot 	switch (port) {
1776*bf017597SFrançois Tigeot 	case PORT_B:
1777*bf017597SFrançois Tigeot 		if (IS_BROXTON(dev_priv))
1778*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_1_BXT;
1779*bf017597SFrançois Tigeot 		else
1780*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_DPB;
1781*bf017597SFrançois Tigeot 		break;
1782*bf017597SFrançois Tigeot 	case PORT_C:
1783*bf017597SFrançois Tigeot 		if (IS_BROXTON(dev_priv))
1784*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_2_BXT;
1785*bf017597SFrançois Tigeot 		else
1786*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_DPC;
1787*bf017597SFrançois Tigeot 		break;
1788*bf017597SFrançois Tigeot 	case PORT_D:
1789*bf017597SFrançois Tigeot 		if (IS_CHERRYVIEW(dev_priv))
1790*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_DPD_CHV;
1791*bf017597SFrançois Tigeot 		else
1792*bf017597SFrançois Tigeot 			ddc_pin = GMBUS_PIN_DPD;
1793*bf017597SFrançois Tigeot 		break;
1794*bf017597SFrançois Tigeot 	default:
1795*bf017597SFrançois Tigeot 		MISSING_CASE(port);
1796*bf017597SFrançois Tigeot 		ddc_pin = GMBUS_PIN_DPB;
1797*bf017597SFrançois Tigeot 		break;
1798*bf017597SFrançois Tigeot 	}
1799*bf017597SFrançois Tigeot 
1800*bf017597SFrançois Tigeot 	DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
1801*bf017597SFrançois Tigeot 		      ddc_pin, port_name(port));
1802*bf017597SFrançois Tigeot 
1803*bf017597SFrançois Tigeot 	return ddc_pin;
1804*bf017597SFrançois Tigeot }
1805*bf017597SFrançois Tigeot 
180619df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
180719df918dSFrançois Tigeot 			       struct intel_connector *intel_connector)
1808e3adcf8fSFrançois Tigeot {
180919df918dSFrançois Tigeot 	struct drm_connector *connector = &intel_connector->base;
181019df918dSFrançois Tigeot 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
181119df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
181219df918dSFrançois Tigeot 	struct drm_device *dev = intel_encoder->base.dev;
1813*bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
181419df918dSFrançois Tigeot 	enum port port = intel_dig_port->port;
1815e3adcf8fSFrançois Tigeot 
18168621f407SFrançois Tigeot 	DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
18178621f407SFrançois Tigeot 		      port_name(port));
18188621f407SFrançois Tigeot 
1819c0e85e96SFrançois Tigeot 	if (WARN(intel_dig_port->max_lanes < 4,
1820c0e85e96SFrançois Tigeot 		 "Not enough lanes (%d) for HDMI on port %c\n",
1821c0e85e96SFrançois Tigeot 		 intel_dig_port->max_lanes, port_name(port)))
1822c0e85e96SFrançois Tigeot 		return;
1823c0e85e96SFrançois Tigeot 
1824e3adcf8fSFrançois Tigeot 	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
1825e3adcf8fSFrançois Tigeot 			   DRM_MODE_CONNECTOR_HDMIA);
1826e3adcf8fSFrançois Tigeot 	drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
1827e3adcf8fSFrançois Tigeot 
1828e3adcf8fSFrançois Tigeot 	connector->interlace_allowed = 1;
1829e3adcf8fSFrançois Tigeot 	connector->doublescan_allowed = 0;
18309edbd4a0SFrançois Tigeot 	connector->stereo_allowed = 1;
1831e3adcf8fSFrançois Tigeot 
1832*bf017597SFrançois Tigeot 	intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
1833*bf017597SFrançois Tigeot 
183419df918dSFrançois Tigeot 	switch (port) {
183519df918dSFrançois Tigeot 	case PORT_B:
1836352ff8bdSFrançois Tigeot 		/*
1837352ff8bdSFrançois Tigeot 		 * On BXT A0/A1, sw needs to activate DDIA HPD logic and
1838352ff8bdSFrançois Tigeot 		 * interrupts to check the external panel connection.
1839352ff8bdSFrançois Tigeot 		 */
1840aee94f86SFrançois Tigeot 		if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
1841352ff8bdSFrançois Tigeot 			intel_encoder->hpd_pin = HPD_PORT_A;
1842352ff8bdSFrançois Tigeot 		else
18438e26cdf6SFrançois Tigeot 			intel_encoder->hpd_pin = HPD_PORT_B;
184419df918dSFrançois Tigeot 		break;
184519df918dSFrançois Tigeot 	case PORT_C:
18468e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_C;
184719df918dSFrançois Tigeot 		break;
184819df918dSFrançois Tigeot 	case PORT_D:
18498e26cdf6SFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_D;
185019df918dSFrançois Tigeot 		break;
1851a05eeebfSFrançois Tigeot 	case PORT_E:
1852a05eeebfSFrançois Tigeot 		intel_encoder->hpd_pin = HPD_PORT_E;
1853a05eeebfSFrançois Tigeot 		break;
185419df918dSFrançois Tigeot 	default:
1855*bf017597SFrançois Tigeot 		MISSING_CASE(port);
1856*bf017597SFrançois Tigeot 		return;
1857e3adcf8fSFrançois Tigeot 	}
1858e3adcf8fSFrançois Tigeot 
1859aee94f86SFrançois Tigeot 	if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
186019df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = vlv_write_infoframe;
186119df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = vlv_set_infoframes;
18622c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = vlv_infoframe_enabled;
186324edb884SFrançois Tigeot 	} else if (IS_G4X(dev)) {
18648e26cdf6SFrançois Tigeot 		intel_hdmi->write_infoframe = g4x_write_infoframe;
18658e26cdf6SFrançois Tigeot 		intel_hdmi->set_infoframes = g4x_set_infoframes;
18662c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = g4x_infoframe_enabled;
18678e26cdf6SFrançois Tigeot 	} else if (HAS_DDI(dev)) {
186819df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = hsw_write_infoframe;
186919df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = hsw_set_infoframes;
18702c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = hsw_infoframe_enabled;
187119df918dSFrançois Tigeot 	} else if (HAS_PCH_IBX(dev)) {
187219df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = ibx_write_infoframe;
187319df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = ibx_set_infoframes;
18742c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = ibx_infoframe_enabled;
1875e3adcf8fSFrançois Tigeot 	} else {
187619df918dSFrançois Tigeot 		intel_hdmi->write_infoframe = cpt_write_infoframe;
187719df918dSFrançois Tigeot 		intel_hdmi->set_infoframes = cpt_set_infoframes;
18782c9916cdSFrançois Tigeot 		intel_hdmi->infoframe_enabled = cpt_infoframe_enabled;
1879e3adcf8fSFrançois Tigeot 	}
1880e3adcf8fSFrançois Tigeot 
1881a2fdbec6SFrançois Tigeot 	if (HAS_DDI(dev))
188219df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
188319df918dSFrançois Tigeot 	else
188419df918dSFrançois Tigeot 		intel_connector->get_hw_state = intel_connector_get_hw_state;
1885e3adcf8fSFrançois Tigeot 
1886e3adcf8fSFrançois Tigeot 	intel_hdmi_add_properties(intel_hdmi, connector);
1887e3adcf8fSFrançois Tigeot 
1888e3adcf8fSFrançois Tigeot 	intel_connector_attach_encoder(intel_connector, intel_encoder);
1889352ff8bdSFrançois Tigeot 	intel_hdmi->attached_connector = intel_connector;
1890e3adcf8fSFrançois Tigeot 
1891e3adcf8fSFrançois Tigeot 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
1892e3adcf8fSFrançois Tigeot 	 * 0xd.  Failure to do so will result in spurious interrupts being
1893e3adcf8fSFrançois Tigeot 	 * generated on the port when a cable is not attached.
1894e3adcf8fSFrançois Tigeot 	 */
1895e3adcf8fSFrançois Tigeot 	if (IS_G4X(dev) && !IS_GM45(dev)) {
1896e3adcf8fSFrançois Tigeot 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
1897e3adcf8fSFrançois Tigeot 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
1898e3adcf8fSFrançois Tigeot 	}
1899e3adcf8fSFrançois Tigeot }
190019df918dSFrançois Tigeot 
1901aee94f86SFrançois Tigeot void intel_hdmi_init(struct drm_device *dev,
1902aee94f86SFrançois Tigeot 		     i915_reg_t hdmi_reg, enum port port)
190319df918dSFrançois Tigeot {
190419df918dSFrançois Tigeot 	struct intel_digital_port *intel_dig_port;
190519df918dSFrançois Tigeot 	struct intel_encoder *intel_encoder;
190619df918dSFrançois Tigeot 	struct intel_connector *intel_connector;
190719df918dSFrançois Tigeot 
19089edbd4a0SFrançois Tigeot 	intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
190919df918dSFrançois Tigeot 	if (!intel_dig_port)
191019df918dSFrançois Tigeot 		return;
191119df918dSFrançois Tigeot 
1912477eb7f9SFrançois Tigeot 	intel_connector = intel_connector_alloc();
191319df918dSFrançois Tigeot 	if (!intel_connector) {
1914158486a6SFrançois Tigeot 		kfree(intel_dig_port);
191519df918dSFrançois Tigeot 		return;
191619df918dSFrançois Tigeot 	}
191719df918dSFrançois Tigeot 
191819df918dSFrançois Tigeot 	intel_encoder = &intel_dig_port->base;
191919df918dSFrançois Tigeot 
192019df918dSFrançois Tigeot 	drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
19211487f786SFrançois Tigeot 			 DRM_MODE_ENCODER_TMDS, "HDMI %c", port_name(port));
192219df918dSFrançois Tigeot 
19238e26cdf6SFrançois Tigeot 	intel_encoder->compute_config = intel_hdmi_compute_config;
192419c468b4SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev)) {
192519c468b4SFrançois Tigeot 		intel_encoder->disable = pch_disable_hdmi;
192619c468b4SFrançois Tigeot 		intel_encoder->post_disable = pch_post_disable_hdmi;
192719c468b4SFrançois Tigeot 	} else {
192819c468b4SFrançois Tigeot 		intel_encoder->disable = g4x_disable_hdmi;
192919c468b4SFrançois Tigeot 	}
193019df918dSFrançois Tigeot 	intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
19315d0b1887SFrançois Tigeot 	intel_encoder->get_config = intel_hdmi_get_config;
1932ba55f2f5SFrançois Tigeot 	if (IS_CHERRYVIEW(dev)) {
193324edb884SFrançois Tigeot 		intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable;
1934ba55f2f5SFrançois Tigeot 		intel_encoder->pre_enable = chv_hdmi_pre_enable;
1935ba55f2f5SFrançois Tigeot 		intel_encoder->enable = vlv_enable_hdmi;
1936ba55f2f5SFrançois Tigeot 		intel_encoder->post_disable = chv_hdmi_post_disable;
1937352ff8bdSFrançois Tigeot 		intel_encoder->post_pll_disable = chv_hdmi_post_pll_disable;
1938ba55f2f5SFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev)) {
19399edbd4a0SFrançois Tigeot 		intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
19409edbd4a0SFrançois Tigeot 		intel_encoder->pre_enable = vlv_hdmi_pre_enable;
19419edbd4a0SFrançois Tigeot 		intel_encoder->enable = vlv_enable_hdmi;
19429edbd4a0SFrançois Tigeot 		intel_encoder->post_disable = vlv_hdmi_post_disable;
19439edbd4a0SFrançois Tigeot 	} else {
1944ba55f2f5SFrançois Tigeot 		intel_encoder->pre_enable = intel_hdmi_pre_enable;
1945a05eeebfSFrançois Tigeot 		if (HAS_PCH_CPT(dev))
1946a05eeebfSFrançois Tigeot 			intel_encoder->enable = cpt_enable_hdmi;
1947a05eeebfSFrançois Tigeot 		else if (HAS_PCH_IBX(dev))
1948a05eeebfSFrançois Tigeot 			intel_encoder->enable = ibx_enable_hdmi;
1949a05eeebfSFrançois Tigeot 		else
1950a05eeebfSFrançois Tigeot 			intel_encoder->enable = g4x_enable_hdmi;
19515d0b1887SFrançois Tigeot 	}
195219df918dSFrançois Tigeot 
195319df918dSFrançois Tigeot 	intel_encoder->type = INTEL_OUTPUT_HDMI;
1954ba55f2f5SFrançois Tigeot 	if (IS_CHERRYVIEW(dev)) {
1955ba55f2f5SFrançois Tigeot 		if (port == PORT_D)
1956ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = 1 << 2;
1957ba55f2f5SFrançois Tigeot 		else
1958ba55f2f5SFrançois Tigeot 			intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1959ba55f2f5SFrançois Tigeot 	} else {
196019df918dSFrançois Tigeot 		intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
1961ba55f2f5SFrançois Tigeot 	}
1962ba55f2f5SFrançois Tigeot 	intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
1963ba55f2f5SFrançois Tigeot 	/*
1964ba55f2f5SFrançois Tigeot 	 * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
1965ba55f2f5SFrançois Tigeot 	 * to work on real hardware. And since g4x can send infoframes to
1966ba55f2f5SFrançois Tigeot 	 * only one port anyway, nothing is lost by allowing it.
1967ba55f2f5SFrançois Tigeot 	 */
1968ba55f2f5SFrançois Tigeot 	if (IS_G4X(dev))
1969ba55f2f5SFrançois Tigeot 		intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
197019df918dSFrançois Tigeot 
197119df918dSFrançois Tigeot 	intel_dig_port->port = port;
19728e26cdf6SFrançois Tigeot 	intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
1973aee94f86SFrançois Tigeot 	intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
1974c0e85e96SFrançois Tigeot 	intel_dig_port->max_lanes = 4;
197519df918dSFrançois Tigeot 
197619df918dSFrançois Tigeot 	intel_hdmi_init_connector(intel_dig_port, intel_connector);
197719df918dSFrançois Tigeot }
1978