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>
37a85cb24fSFrançois Tigeot #include <drm/drm_scdc_helper.h>
3818e26a6dSFrançois Tigeot #include "intel_drv.h"
395c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
40a85cb24fSFrançois Tigeot #include <drm/intel_lpe_audio.h>
41e3adcf8fSFrançois Tigeot #include "i915_drv.h"
42e3adcf8fSFrançois Tigeot
intel_hdmi_to_dev(struct intel_hdmi * intel_hdmi)4319df918dSFrançois Tigeot static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
44e3adcf8fSFrançois Tigeot {
4519df918dSFrançois Tigeot return hdmi_to_dig_port(intel_hdmi)->base.base.dev;
4619df918dSFrançois Tigeot }
4719df918dSFrançois Tigeot
4819df918dSFrançois Tigeot static void
assert_hdmi_port_disabled(struct intel_hdmi * intel_hdmi)4919df918dSFrançois Tigeot assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
5019df918dSFrançois Tigeot {
5119df918dSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
52bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
5319df918dSFrançois Tigeot uint32_t enabled_bits;
5419df918dSFrançois Tigeot
551e12ee3bSFrançois Tigeot enabled_bits = HAS_DDI(dev_priv) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
5619df918dSFrançois Tigeot
578e26cdf6SFrançois Tigeot WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits,
5819df918dSFrançois Tigeot "HDMI port enabled, expecting disabled\n");
5919df918dSFrançois Tigeot }
6019df918dSFrançois Tigeot
enc_to_intel_hdmi(struct drm_encoder * encoder)6119df918dSFrançois Tigeot struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
6219df918dSFrançois Tigeot {
6319df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port =
6419df918dSFrançois Tigeot container_of(encoder, struct intel_digital_port, base.base);
6519df918dSFrançois Tigeot return &intel_dig_port->hdmi;
66e3adcf8fSFrançois Tigeot }
67e3adcf8fSFrançois Tigeot
intel_attached_hdmi(struct drm_connector * connector)68e3adcf8fSFrançois Tigeot static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
69e3adcf8fSFrançois Tigeot {
7019df918dSFrançois Tigeot return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base);
71e3adcf8fSFrançois Tigeot }
72e3adcf8fSFrançois Tigeot
g4x_infoframe_index(unsigned int type)73*3f2dd94aSFrançois Tigeot static u32 g4x_infoframe_index(unsigned int type)
74e3adcf8fSFrançois Tigeot {
759edbd4a0SFrançois Tigeot switch (type) {
769edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI:
7719df918dSFrançois Tigeot return VIDEO_DIP_SELECT_AVI;
789edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD:
7919df918dSFrançois Tigeot return VIDEO_DIP_SELECT_SPD;
809edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR:
819edbd4a0SFrançois Tigeot return VIDEO_DIP_SELECT_VENDOR;
82e3adcf8fSFrançois Tigeot default:
83aee94f86SFrançois Tigeot MISSING_CASE(type);
8419df918dSFrançois Tigeot return 0;
8519df918dSFrançois Tigeot }
86e3adcf8fSFrançois Tigeot }
87e3adcf8fSFrançois Tigeot
g4x_infoframe_enable(unsigned int type)88*3f2dd94aSFrançois Tigeot static u32 g4x_infoframe_enable(unsigned int type)
89e3adcf8fSFrançois Tigeot {
909edbd4a0SFrançois Tigeot switch (type) {
919edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI:
9219df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI;
939edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD:
9419df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD;
959edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR:
969edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VENDOR;
97e3adcf8fSFrançois Tigeot default:
98aee94f86SFrançois Tigeot MISSING_CASE(type);
9919df918dSFrançois Tigeot return 0;
10019df918dSFrançois Tigeot }
101e3adcf8fSFrançois Tigeot }
102e3adcf8fSFrançois Tigeot
hsw_infoframe_enable(unsigned int type)103*3f2dd94aSFrançois Tigeot static u32 hsw_infoframe_enable(unsigned int type)
10419df918dSFrançois Tigeot {
1059edbd4a0SFrançois Tigeot switch (type) {
106*3f2dd94aSFrançois Tigeot case DP_SDP_VSC:
107*3f2dd94aSFrançois Tigeot return VIDEO_DIP_ENABLE_VSC_HSW;
1089edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI:
10919df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_AVI_HSW;
1109edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD:
11119df918dSFrançois Tigeot return VIDEO_DIP_ENABLE_SPD_HSW;
1129edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR:
1139edbd4a0SFrançois Tigeot return VIDEO_DIP_ENABLE_VS_HSW;
11419df918dSFrançois Tigeot default:
115aee94f86SFrançois Tigeot MISSING_CASE(type);
11619df918dSFrançois Tigeot return 0;
11719df918dSFrançois Tigeot }
118e3adcf8fSFrançois Tigeot }
119e3adcf8fSFrançois Tigeot
120aee94f86SFrançois Tigeot static i915_reg_t
hsw_dip_data_reg(struct drm_i915_private * dev_priv,enum transcoder cpu_transcoder,unsigned int type,int i)121aee94f86SFrançois Tigeot hsw_dip_data_reg(struct drm_i915_private *dev_priv,
122ba55f2f5SFrançois Tigeot enum transcoder cpu_transcoder,
123*3f2dd94aSFrançois Tigeot unsigned int type,
124352ff8bdSFrançois Tigeot int i)
12519df918dSFrançois Tigeot {
1269edbd4a0SFrançois Tigeot switch (type) {
127*3f2dd94aSFrançois Tigeot case DP_SDP_VSC:
128*3f2dd94aSFrançois Tigeot return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
1299edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_AVI:
130352ff8bdSFrançois Tigeot return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
1319edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_SPD:
132352ff8bdSFrançois Tigeot return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder, i);
1339edbd4a0SFrançois Tigeot case HDMI_INFOFRAME_TYPE_VENDOR:
134352ff8bdSFrançois Tigeot return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
13519df918dSFrançois Tigeot default:
136aee94f86SFrançois Tigeot MISSING_CASE(type);
137aee94f86SFrançois Tigeot return INVALID_MMIO_REG;
13819df918dSFrançois Tigeot }
13919df918dSFrançois Tigeot }
14019df918dSFrançois Tigeot
g4x_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,unsigned int type,const void * frame,ssize_t len)14119df918dSFrançois Tigeot static void g4x_write_infoframe(struct drm_encoder *encoder,
142a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
143*3f2dd94aSFrançois Tigeot unsigned int type,
1449edbd4a0SFrançois Tigeot const void *frame, ssize_t len)
145e3adcf8fSFrançois Tigeot {
1469edbd4a0SFrançois Tigeot const uint32_t *data = frame;
147e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev;
148bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
14919df918dSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL);
1509edbd4a0SFrançois Tigeot int i;
151e3adcf8fSFrançois Tigeot
15219df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
153e3adcf8fSFrançois Tigeot
15419df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
1559edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type);
156e3adcf8fSFrançois Tigeot
1579edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type);
158e3adcf8fSFrançois Tigeot
15919df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val);
160e3adcf8fSFrançois Tigeot
16119df918dSFrançois Tigeot mmiowb();
162e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) {
163e3adcf8fSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, *data);
164e3adcf8fSFrançois Tigeot data++;
165e3adcf8fSFrançois Tigeot }
16619df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */
16719df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
16819df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_DATA, 0);
16919df918dSFrançois Tigeot mmiowb();
170e3adcf8fSFrançois Tigeot
1719edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type);
17219df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK;
17319df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC;
174e3adcf8fSFrançois Tigeot
17519df918dSFrançois Tigeot I915_WRITE(VIDEO_DIP_CTL, val);
17619df918dSFrançois Tigeot POSTING_READ(VIDEO_DIP_CTL);
177e3adcf8fSFrançois Tigeot }
178e3adcf8fSFrançois Tigeot
g4x_infoframe_enabled(struct drm_encoder * encoder,const struct intel_crtc_state * pipe_config)179aee94f86SFrançois Tigeot static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
180aee94f86SFrançois Tigeot const struct intel_crtc_state *pipe_config)
1812c9916cdSFrançois Tigeot {
182aee94f86SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
1832c9916cdSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
1842c9916cdSFrançois Tigeot u32 val = I915_READ(VIDEO_DIP_CTL);
1852c9916cdSFrançois Tigeot
186a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0)
1872c9916cdSFrançois Tigeot return false;
188a05eeebfSFrançois Tigeot
189a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
190a05eeebfSFrançois Tigeot return false;
191a05eeebfSFrançois Tigeot
192a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI |
193a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
1942c9916cdSFrançois Tigeot }
1952c9916cdSFrançois Tigeot
ibx_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,unsigned int type,const void * frame,ssize_t len)19619df918dSFrançois Tigeot static void ibx_write_infoframe(struct drm_encoder *encoder,
197a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
198*3f2dd94aSFrançois Tigeot unsigned int type,
1999edbd4a0SFrançois Tigeot const void *frame, ssize_t len)
200e3adcf8fSFrançois Tigeot {
2019edbd4a0SFrançois Tigeot const uint32_t *data = frame;
202e3adcf8fSFrançois Tigeot struct drm_device *dev = encoder->dev;
203bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
204a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
205aee94f86SFrançois Tigeot i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
20619df918dSFrançois Tigeot u32 val = I915_READ(reg);
207aee94f86SFrançois Tigeot int i;
208e3adcf8fSFrançois Tigeot
20919df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
210e3adcf8fSFrançois Tigeot
211e3adcf8fSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2129edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type);
213e3adcf8fSFrançois Tigeot
2149edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type);
215e3adcf8fSFrançois Tigeot
21619df918dSFrançois Tigeot I915_WRITE(reg, val);
21719df918dSFrançois Tigeot
21819df918dSFrançois Tigeot mmiowb();
219e3adcf8fSFrançois Tigeot for (i = 0; i < len; i += 4) {
220e3adcf8fSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
221e3adcf8fSFrançois Tigeot data++;
222e3adcf8fSFrançois Tigeot }
22319df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */
22419df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
22519df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
22619df918dSFrançois Tigeot mmiowb();
227e3adcf8fSFrançois Tigeot
2289edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type);
22919df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK;
23019df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC;
231e3adcf8fSFrançois Tigeot
23219df918dSFrançois Tigeot I915_WRITE(reg, val);
23319df918dSFrançois Tigeot POSTING_READ(reg);
23419df918dSFrançois Tigeot }
23519df918dSFrançois Tigeot
ibx_infoframe_enabled(struct drm_encoder * encoder,const struct intel_crtc_state * pipe_config)236aee94f86SFrançois Tigeot static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
237aee94f86SFrançois Tigeot const struct intel_crtc_state *pipe_config)
2382c9916cdSFrançois Tigeot {
239aee94f86SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
24019c468b4SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
241aee94f86SFrançois Tigeot enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
242aee94f86SFrançois Tigeot i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
2432c9916cdSFrançois Tigeot u32 val = I915_READ(reg);
2442c9916cdSFrançois Tigeot
245a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0)
24619c468b4SFrançois Tigeot return false;
247a05eeebfSFrançois Tigeot
248a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
249a05eeebfSFrançois Tigeot return false;
250a05eeebfSFrançois Tigeot
251a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI |
252a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
253a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
2542c9916cdSFrançois Tigeot }
2552c9916cdSFrançois Tigeot
cpt_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,unsigned int type,const void * frame,ssize_t len)25619df918dSFrançois Tigeot static void cpt_write_infoframe(struct drm_encoder *encoder,
257a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
258*3f2dd94aSFrançois Tigeot unsigned int type,
2599edbd4a0SFrançois Tigeot const void *frame, ssize_t len)
26019df918dSFrançois Tigeot {
2619edbd4a0SFrançois Tigeot const uint32_t *data = frame;
26219df918dSFrançois Tigeot struct drm_device *dev = encoder->dev;
263bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
264a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
265aee94f86SFrançois Tigeot i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
26619df918dSFrançois Tigeot u32 val = I915_READ(reg);
267aee94f86SFrançois Tigeot int i;
26819df918dSFrançois Tigeot
26919df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
27019df918dSFrançois Tigeot
27119df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
2729edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type);
27319df918dSFrançois Tigeot
27419df918dSFrançois Tigeot /* The DIP control register spec says that we need to update the AVI
27519df918dSFrançois Tigeot * infoframe without clearing its enable bit */
2769edbd4a0SFrançois Tigeot if (type != HDMI_INFOFRAME_TYPE_AVI)
2779edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type);
27819df918dSFrançois Tigeot
27919df918dSFrançois Tigeot I915_WRITE(reg, val);
28019df918dSFrançois Tigeot
28119df918dSFrançois Tigeot mmiowb();
28219df918dSFrançois Tigeot for (i = 0; i < len; i += 4) {
28319df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
28419df918dSFrançois Tigeot data++;
28519df918dSFrançois Tigeot }
28619df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */
28719df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
28819df918dSFrançois Tigeot I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
28919df918dSFrançois Tigeot mmiowb();
29019df918dSFrançois Tigeot
2919edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type);
29219df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK;
29319df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC;
29419df918dSFrançois Tigeot
29519df918dSFrançois Tigeot I915_WRITE(reg, val);
29619df918dSFrançois Tigeot POSTING_READ(reg);
29719df918dSFrançois Tigeot }
29819df918dSFrançois Tigeot
cpt_infoframe_enabled(struct drm_encoder * encoder,const struct intel_crtc_state * pipe_config)299aee94f86SFrançois Tigeot static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
300aee94f86SFrançois Tigeot const struct intel_crtc_state *pipe_config)
3012c9916cdSFrançois Tigeot {
302aee94f86SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
303aee94f86SFrançois Tigeot enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
304aee94f86SFrançois Tigeot u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
3052c9916cdSFrançois Tigeot
306a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0)
307a05eeebfSFrançois Tigeot return false;
308a05eeebfSFrançois Tigeot
309a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI |
310a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
311a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
3122c9916cdSFrançois Tigeot }
3132c9916cdSFrançois Tigeot
vlv_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,unsigned int type,const void * frame,ssize_t len)31419df918dSFrançois Tigeot static void vlv_write_infoframe(struct drm_encoder *encoder,
315a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
316*3f2dd94aSFrançois Tigeot unsigned int type,
3179edbd4a0SFrançois Tigeot const void *frame, ssize_t len)
31819df918dSFrançois Tigeot {
3199edbd4a0SFrançois Tigeot const uint32_t *data = frame;
32019df918dSFrançois Tigeot struct drm_device *dev = encoder->dev;
321bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
322a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
323aee94f86SFrançois Tigeot i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
32419df918dSFrançois Tigeot u32 val = I915_READ(reg);
325aee94f86SFrançois Tigeot int i;
32619df918dSFrançois Tigeot
32719df918dSFrançois Tigeot WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
32819df918dSFrançois Tigeot
32919df918dSFrançois Tigeot val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
3309edbd4a0SFrançois Tigeot val |= g4x_infoframe_index(type);
33119df918dSFrançois Tigeot
3329edbd4a0SFrançois Tigeot val &= ~g4x_infoframe_enable(type);
33319df918dSFrançois Tigeot
33419df918dSFrançois Tigeot I915_WRITE(reg, val);
33519df918dSFrançois Tigeot
33619df918dSFrançois Tigeot mmiowb();
33719df918dSFrançois Tigeot for (i = 0; i < len; i += 4) {
33819df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
33919df918dSFrançois Tigeot data++;
34019df918dSFrançois Tigeot }
34119df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */
34219df918dSFrançois Tigeot for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
34319df918dSFrançois Tigeot I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
34419df918dSFrançois Tigeot mmiowb();
34519df918dSFrançois Tigeot
3469edbd4a0SFrançois Tigeot val |= g4x_infoframe_enable(type);
34719df918dSFrançois Tigeot val &= ~VIDEO_DIP_FREQ_MASK;
34819df918dSFrançois Tigeot val |= VIDEO_DIP_FREQ_VSYNC;
34919df918dSFrançois Tigeot
35019df918dSFrançois Tigeot I915_WRITE(reg, val);
35119df918dSFrançois Tigeot POSTING_READ(reg);
35219df918dSFrançois Tigeot }
35319df918dSFrançois Tigeot
vlv_infoframe_enabled(struct drm_encoder * encoder,const struct intel_crtc_state * pipe_config)354aee94f86SFrançois Tigeot static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
355aee94f86SFrançois Tigeot const struct intel_crtc_state *pipe_config)
3562c9916cdSFrançois Tigeot {
357aee94f86SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
35819c468b4SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
359aee94f86SFrançois Tigeot enum i915_pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
360aee94f86SFrançois Tigeot u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
3612c9916cdSFrançois Tigeot
362a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_ENABLE) == 0)
36319c468b4SFrançois Tigeot return false;
364a05eeebfSFrançois Tigeot
365a05eeebfSFrançois Tigeot if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port))
366a05eeebfSFrançois Tigeot return false;
367a05eeebfSFrançois Tigeot
368a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_AVI |
369a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
370a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
3712c9916cdSFrançois Tigeot }
3722c9916cdSFrançois Tigeot
hsw_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,unsigned int type,const void * frame,ssize_t len)37319df918dSFrançois Tigeot static void hsw_write_infoframe(struct drm_encoder *encoder,
374a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
375*3f2dd94aSFrançois Tigeot unsigned int type,
3769edbd4a0SFrançois Tigeot const void *frame, ssize_t len)
37719df918dSFrançois Tigeot {
3789edbd4a0SFrançois Tigeot const uint32_t *data = frame;
37919df918dSFrançois Tigeot struct drm_device *dev = encoder->dev;
380bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
381a85cb24fSFrançois Tigeot enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
382aee94f86SFrançois Tigeot i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
383aee94f86SFrançois Tigeot i915_reg_t data_reg;
384*3f2dd94aSFrançois Tigeot int data_size = type == DP_SDP_VSC ?
385*3f2dd94aSFrançois Tigeot VIDEO_DIP_VSC_DATA_SIZE : VIDEO_DIP_DATA_SIZE;
3869edbd4a0SFrançois Tigeot int i;
38719df918dSFrançois Tigeot u32 val = I915_READ(ctl_reg);
38819df918dSFrançois Tigeot
389352ff8bdSFrançois Tigeot data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0);
39019df918dSFrançois Tigeot
3919edbd4a0SFrançois Tigeot val &= ~hsw_infoframe_enable(type);
39219df918dSFrançois Tigeot I915_WRITE(ctl_reg, val);
39319df918dSFrançois Tigeot
39419df918dSFrançois Tigeot mmiowb();
39519df918dSFrançois Tigeot for (i = 0; i < len; i += 4) {
396352ff8bdSFrançois Tigeot I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
397352ff8bdSFrançois Tigeot type, i >> 2), *data);
39819df918dSFrançois Tigeot data++;
39919df918dSFrançois Tigeot }
40019df918dSFrançois Tigeot /* Write every possible data byte to force correct ECC calculation. */
401*3f2dd94aSFrançois Tigeot for (; i < data_size; i += 4)
402352ff8bdSFrançois Tigeot I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
403352ff8bdSFrançois Tigeot type, i >> 2), 0);
40419df918dSFrançois Tigeot mmiowb();
40519df918dSFrançois Tigeot
4069edbd4a0SFrançois Tigeot val |= hsw_infoframe_enable(type);
40719df918dSFrançois Tigeot I915_WRITE(ctl_reg, val);
40819df918dSFrançois Tigeot POSTING_READ(ctl_reg);
409e3adcf8fSFrançois Tigeot }
410e3adcf8fSFrançois Tigeot
hsw_infoframe_enabled(struct drm_encoder * encoder,const struct intel_crtc_state * pipe_config)411aee94f86SFrançois Tigeot static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
412aee94f86SFrançois Tigeot const struct intel_crtc_state *pipe_config)
4132c9916cdSFrançois Tigeot {
414aee94f86SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
415aee94f86SFrançois Tigeot u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
4162c9916cdSFrançois Tigeot
417a05eeebfSFrançois Tigeot return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
418a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
419a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
4202c9916cdSFrançois Tigeot }
4212c9916cdSFrançois Tigeot
4229edbd4a0SFrançois Tigeot /*
4239edbd4a0SFrançois Tigeot * The data we write to the DIP data buffer registers is 1 byte bigger than the
4249edbd4a0SFrançois Tigeot * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
4259edbd4a0SFrançois Tigeot * at 0). It's also a byte used by DisplayPort so the same DIP registers can be
4269edbd4a0SFrançois Tigeot * used for both technologies.
4279edbd4a0SFrançois Tigeot *
4289edbd4a0SFrançois Tigeot * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
4299edbd4a0SFrançois Tigeot * DW1: DB3 | DB2 | DB1 | DB0
4309edbd4a0SFrançois Tigeot * DW2: DB7 | DB6 | DB5 | DB4
4319edbd4a0SFrançois Tigeot * DW3: ...
4329edbd4a0SFrançois Tigeot *
4339edbd4a0SFrançois Tigeot * (HB is Header Byte, DB is Data Byte)
4349edbd4a0SFrançois Tigeot *
4359edbd4a0SFrançois Tigeot * The hdmi pack() functions don't know about that hardware specific hole so we
4369edbd4a0SFrançois Tigeot * trick them by giving an offset into the buffer and moving back the header
4379edbd4a0SFrançois Tigeot * bytes by one.
4389edbd4a0SFrançois Tigeot */
intel_write_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,union hdmi_infoframe * frame)4399edbd4a0SFrançois Tigeot static void intel_write_infoframe(struct drm_encoder *encoder,
440a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
4419edbd4a0SFrançois Tigeot union hdmi_infoframe *frame)
442e3adcf8fSFrançois Tigeot {
443*3f2dd94aSFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
4449edbd4a0SFrançois Tigeot uint8_t buffer[VIDEO_DIP_DATA_SIZE];
4459edbd4a0SFrançois Tigeot ssize_t len;
446e3adcf8fSFrançois Tigeot
4479edbd4a0SFrançois Tigeot /* see comment above for the reason for this offset */
4489edbd4a0SFrançois Tigeot len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
4499edbd4a0SFrançois Tigeot if (len < 0)
4509edbd4a0SFrançois Tigeot return;
4519edbd4a0SFrançois Tigeot
4529edbd4a0SFrançois Tigeot /* Insert the 'hole' (see big comment above) at position 3 */
4539edbd4a0SFrançois Tigeot buffer[0] = buffer[1];
4549edbd4a0SFrançois Tigeot buffer[1] = buffer[2];
4559edbd4a0SFrançois Tigeot buffer[2] = buffer[3];
4569edbd4a0SFrançois Tigeot buffer[3] = 0;
4579edbd4a0SFrançois Tigeot len++;
4589edbd4a0SFrançois Tigeot
459*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe(encoder, crtc_state, frame->any.type, buffer, len);
460e3adcf8fSFrançois Tigeot }
461e3adcf8fSFrançois Tigeot
intel_hdmi_set_avi_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state)46219df918dSFrançois Tigeot static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
463a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state)
464e3adcf8fSFrançois Tigeot {
465a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
466a85cb24fSFrançois Tigeot const struct drm_display_mode *adjusted_mode =
467a85cb24fSFrançois Tigeot &crtc_state->base.adjusted_mode;
468*3f2dd94aSFrançois Tigeot struct drm_connector *connector = &intel_hdmi->attached_connector->base;
469*3f2dd94aSFrançois Tigeot bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
4709edbd4a0SFrançois Tigeot union hdmi_infoframe frame;
4719edbd4a0SFrançois Tigeot int ret;
472e3adcf8fSFrançois Tigeot
4739edbd4a0SFrançois Tigeot ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
474*3f2dd94aSFrançois Tigeot adjusted_mode,
475*3f2dd94aSFrançois Tigeot is_hdmi2_sink);
4769edbd4a0SFrançois Tigeot if (ret < 0) {
4779edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill AVI infoframe\n");
4789edbd4a0SFrançois Tigeot return;
4799edbd4a0SFrançois Tigeot }
48019df918dSFrançois Tigeot
481*3f2dd94aSFrançois Tigeot if (crtc_state->ycbcr420)
482*3f2dd94aSFrançois Tigeot frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
483*3f2dd94aSFrançois Tigeot else
484*3f2dd94aSFrançois Tigeot frame.avi.colorspace = HDMI_COLORSPACE_RGB;
485*3f2dd94aSFrançois Tigeot
486a85cb24fSFrançois Tigeot drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
487a85cb24fSFrançois Tigeot crtc_state->limited_color_range ?
488a85cb24fSFrançois Tigeot HDMI_QUANTIZATION_RANGE_LIMITED :
489a85cb24fSFrançois Tigeot HDMI_QUANTIZATION_RANGE_FULL,
490*3f2dd94aSFrançois Tigeot intel_hdmi->rgb_quant_range_selectable,
491*3f2dd94aSFrançois Tigeot is_hdmi2_sink);
492a85cb24fSFrançois Tigeot
493*3f2dd94aSFrançois Tigeot /* TODO: handle pixel repetition for YCBCR420 outputs */
494a85cb24fSFrançois Tigeot intel_write_infoframe(encoder, crtc_state, &frame);
495a2fdbec6SFrançois Tigeot }
496a2fdbec6SFrançois Tigeot
intel_hdmi_set_spd_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state)497a85cb24fSFrançois Tigeot static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
498a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state)
499e3adcf8fSFrançois Tigeot {
5009edbd4a0SFrançois Tigeot union hdmi_infoframe frame;
5019edbd4a0SFrançois Tigeot int ret;
502e3adcf8fSFrançois Tigeot
5039edbd4a0SFrançois Tigeot ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
5049edbd4a0SFrançois Tigeot if (ret < 0) {
5059edbd4a0SFrançois Tigeot DRM_ERROR("couldn't fill SPD infoframe\n");
5069edbd4a0SFrançois Tigeot return;
5079edbd4a0SFrançois Tigeot }
508e3adcf8fSFrançois Tigeot
5099edbd4a0SFrançois Tigeot frame.spd.sdi = HDMI_SPD_SDI_PC;
5109edbd4a0SFrançois Tigeot
511a85cb24fSFrançois Tigeot intel_write_infoframe(encoder, crtc_state, &frame);
5129edbd4a0SFrançois Tigeot }
5139edbd4a0SFrançois Tigeot
5149edbd4a0SFrançois Tigeot static void
intel_hdmi_set_hdmi_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state)5159edbd4a0SFrançois Tigeot intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
516a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state)
5179edbd4a0SFrançois Tigeot {
5189edbd4a0SFrançois Tigeot union hdmi_infoframe frame;
5199edbd4a0SFrançois Tigeot int ret;
5209edbd4a0SFrançois Tigeot
5219edbd4a0SFrançois Tigeot ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
522a85cb24fSFrançois Tigeot &crtc_state->base.adjusted_mode);
5239edbd4a0SFrançois Tigeot if (ret < 0)
5249edbd4a0SFrançois Tigeot return;
5259edbd4a0SFrançois Tigeot
526a85cb24fSFrançois Tigeot intel_write_infoframe(encoder, crtc_state, &frame);
527e3adcf8fSFrançois Tigeot }
528e3adcf8fSFrançois Tigeot
g4x_set_infoframes(struct drm_encoder * encoder,bool enable,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)52919df918dSFrançois Tigeot static void g4x_set_infoframes(struct drm_encoder *encoder,
530ba55f2f5SFrançois Tigeot bool enable,
531a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
532a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
53319df918dSFrançois Tigeot {
534bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
535a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
536a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
537aee94f86SFrançois Tigeot i915_reg_t reg = VIDEO_DIP_CTL;
53819df918dSFrançois Tigeot u32 val = I915_READ(reg);
539ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
54019df918dSFrançois Tigeot
54119df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi);
54219df918dSFrançois Tigeot
54319df918dSFrançois Tigeot /* If the registers were not initialized yet, they might be zeroes,
54419df918dSFrançois Tigeot * which means we're selecting the AVI DIP and we're setting its
54519df918dSFrançois Tigeot * frequency to once. This seems to really confuse the HW and make
54619df918dSFrançois Tigeot * things stop working (the register spec says the AVI always needs to
54719df918dSFrançois Tigeot * be sent every VSync). So here we avoid writing to the register more
54819df918dSFrançois Tigeot * than we need and also explicitly select the AVI DIP and explicitly
54919df918dSFrançois Tigeot * set its frequency to every VSync. Avoiding to write it twice seems to
55019df918dSFrançois Tigeot * be enough to solve the problem, but being defensive shouldn't hurt us
55119df918dSFrançois Tigeot * either. */
55219df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
55319df918dSFrançois Tigeot
554ba55f2f5SFrançois Tigeot if (!enable) {
55519df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE))
55619df918dSFrançois Tigeot return;
557a05eeebfSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) {
558a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("video DIP still enabled on port %c\n",
559a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29);
560a05eeebfSFrançois Tigeot return;
561a05eeebfSFrançois Tigeot }
562a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
563a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
56419df918dSFrançois Tigeot I915_WRITE(reg, val);
56519df918dSFrançois Tigeot POSTING_READ(reg);
56619df918dSFrançois Tigeot return;
56719df918dSFrançois Tigeot }
56819df918dSFrançois Tigeot
56919df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) {
57019df918dSFrançois Tigeot if (val & VIDEO_DIP_ENABLE) {
571a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("video DIP already enabled on port %c\n",
572a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29);
573a05eeebfSFrançois Tigeot return;
57419df918dSFrançois Tigeot }
57519df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK;
57619df918dSFrançois Tigeot val |= port;
57719df918dSFrançois Tigeot }
57819df918dSFrançois Tigeot
57919df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE;
580a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI |
581a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
58219df918dSFrançois Tigeot
58319df918dSFrançois Tigeot I915_WRITE(reg, val);
58419df918dSFrançois Tigeot POSTING_READ(reg);
58519df918dSFrançois Tigeot
586a85cb24fSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, crtc_state);
587a85cb24fSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder, crtc_state);
588a85cb24fSFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, crtc_state);
58919df918dSFrançois Tigeot }
59019df918dSFrançois Tigeot
hdmi_sink_is_deep_color(const struct drm_connector_state * conn_state)591a85cb24fSFrançois Tigeot static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state)
592a05eeebfSFrançois Tigeot {
593a85cb24fSFrançois Tigeot struct drm_connector *connector = conn_state->connector;
594a05eeebfSFrançois Tigeot
595a05eeebfSFrançois Tigeot /*
596a05eeebfSFrançois Tigeot * HDMI cloning is only supported on g4x which doesn't
597a05eeebfSFrançois Tigeot * support deep color or GCP infoframes anyway so no
598a05eeebfSFrançois Tigeot * need to worry about multiple HDMI sinks here.
599a05eeebfSFrançois Tigeot */
600a05eeebfSFrançois Tigeot
601a85cb24fSFrançois Tigeot return connector->display_info.bpc > 8;
602a05eeebfSFrançois Tigeot }
603a05eeebfSFrançois Tigeot
604a05eeebfSFrançois Tigeot /*
605a05eeebfSFrançois Tigeot * Determine if default_phase=1 can be indicated in the GCP infoframe.
606a05eeebfSFrançois Tigeot *
607a05eeebfSFrançois Tigeot * From HDMI specification 1.4a:
608a05eeebfSFrançois Tigeot * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0
609a05eeebfSFrançois Tigeot * - The first pixel following each Video Data Period shall have a pixel packing phase of 0
610a05eeebfSFrançois Tigeot * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase
611a05eeebfSFrançois Tigeot * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing
612a05eeebfSFrançois Tigeot * phase of 0
613a05eeebfSFrançois Tigeot */
gcp_default_phase_possible(int pipe_bpp,const struct drm_display_mode * mode)614a05eeebfSFrançois Tigeot static bool gcp_default_phase_possible(int pipe_bpp,
615a05eeebfSFrançois Tigeot const struct drm_display_mode *mode)
616a05eeebfSFrançois Tigeot {
617a05eeebfSFrançois Tigeot unsigned int pixels_per_group;
618a05eeebfSFrançois Tigeot
619a05eeebfSFrançois Tigeot switch (pipe_bpp) {
620a05eeebfSFrançois Tigeot case 30:
621a05eeebfSFrançois Tigeot /* 4 pixels in 5 clocks */
622a05eeebfSFrançois Tigeot pixels_per_group = 4;
623a05eeebfSFrançois Tigeot break;
624a05eeebfSFrançois Tigeot case 36:
625a05eeebfSFrançois Tigeot /* 2 pixels in 3 clocks */
626a05eeebfSFrançois Tigeot pixels_per_group = 2;
627a05eeebfSFrançois Tigeot break;
628a05eeebfSFrançois Tigeot case 48:
629a05eeebfSFrançois Tigeot /* 1 pixel in 2 clocks */
630a05eeebfSFrançois Tigeot pixels_per_group = 1;
631a05eeebfSFrançois Tigeot break;
632a05eeebfSFrançois Tigeot default:
633a05eeebfSFrançois Tigeot /* phase information not relevant for 8bpc */
634a05eeebfSFrançois Tigeot return false;
635a05eeebfSFrançois Tigeot }
636a05eeebfSFrançois Tigeot
637a05eeebfSFrançois Tigeot return mode->crtc_hdisplay % pixels_per_group == 0 &&
638a05eeebfSFrançois Tigeot mode->crtc_htotal % pixels_per_group == 0 &&
639a05eeebfSFrançois Tigeot mode->crtc_hblank_start % pixels_per_group == 0 &&
640a05eeebfSFrançois Tigeot mode->crtc_hblank_end % pixels_per_group == 0 &&
641a05eeebfSFrançois Tigeot mode->crtc_hsync_start % pixels_per_group == 0 &&
642a05eeebfSFrançois Tigeot mode->crtc_hsync_end % pixels_per_group == 0 &&
643a05eeebfSFrançois Tigeot ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 ||
644a05eeebfSFrançois Tigeot mode->crtc_htotal/2 % pixels_per_group == 0);
645a05eeebfSFrançois Tigeot }
646a05eeebfSFrançois Tigeot
intel_hdmi_set_gcp_infoframe(struct drm_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)647a85cb24fSFrançois Tigeot static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
648a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
649a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
650a05eeebfSFrançois Tigeot {
651bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
652a85cb24fSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
653aee94f86SFrançois Tigeot i915_reg_t reg;
654aee94f86SFrançois Tigeot u32 val = 0;
655a05eeebfSFrançois Tigeot
656a05eeebfSFrançois Tigeot if (HAS_DDI(dev_priv))
657a85cb24fSFrançois Tigeot reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
658aee94f86SFrançois Tigeot else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
659a05eeebfSFrançois Tigeot reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
6608621f407SFrançois Tigeot else if (HAS_PCH_SPLIT(dev_priv))
661a05eeebfSFrançois Tigeot reg = TVIDEO_DIP_GCP(crtc->pipe);
662a05eeebfSFrançois Tigeot else
663a05eeebfSFrançois Tigeot return false;
664a05eeebfSFrançois Tigeot
665a05eeebfSFrançois Tigeot /* Indicate color depth whenever the sink supports deep color */
666a85cb24fSFrançois Tigeot if (hdmi_sink_is_deep_color(conn_state))
667a05eeebfSFrançois Tigeot val |= GCP_COLOR_INDICATION;
668a05eeebfSFrançois Tigeot
669a05eeebfSFrançois Tigeot /* Enable default_phase whenever the display mode is suitably aligned */
670a85cb24fSFrançois Tigeot if (gcp_default_phase_possible(crtc_state->pipe_bpp,
671a85cb24fSFrançois Tigeot &crtc_state->base.adjusted_mode))
672a05eeebfSFrançois Tigeot val |= GCP_DEFAULT_PHASE_ENABLE;
673a05eeebfSFrançois Tigeot
674a05eeebfSFrançois Tigeot I915_WRITE(reg, val);
675a05eeebfSFrançois Tigeot
676a05eeebfSFrançois Tigeot return val != 0;
677a05eeebfSFrançois Tigeot }
678a05eeebfSFrançois Tigeot
ibx_set_infoframes(struct drm_encoder * encoder,bool enable,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)67919df918dSFrançois Tigeot static void ibx_set_infoframes(struct drm_encoder *encoder,
680ba55f2f5SFrançois Tigeot bool enable,
681a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
682a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
68319df918dSFrançois Tigeot {
684bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
685a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
686a2fdbec6SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
687a2fdbec6SFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
688aee94f86SFrançois Tigeot i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
68919df918dSFrançois Tigeot u32 val = I915_READ(reg);
690ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
69119df918dSFrançois Tigeot
69219df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi);
69319df918dSFrançois Tigeot
69419df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */
69519df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
69619df918dSFrançois Tigeot
697ba55f2f5SFrançois Tigeot if (!enable) {
69819df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE))
69919df918dSFrançois Tigeot return;
700a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
701a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
702a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
70319df918dSFrançois Tigeot I915_WRITE(reg, val);
70419df918dSFrançois Tigeot POSTING_READ(reg);
70519df918dSFrançois Tigeot return;
70619df918dSFrançois Tigeot }
70719df918dSFrançois Tigeot
70819df918dSFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) {
709a05eeebfSFrançois Tigeot WARN(val & VIDEO_DIP_ENABLE,
710a05eeebfSFrançois Tigeot "DIP already enabled on port %c\n",
711a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29);
71219df918dSFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK;
71319df918dSFrançois Tigeot val |= port;
71419df918dSFrançois Tigeot }
71519df918dSFrançois Tigeot
71619df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE;
717a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI |
718a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
719a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
720a05eeebfSFrançois Tigeot
721a85cb24fSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
722a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP;
72319df918dSFrançois Tigeot
72419df918dSFrançois Tigeot I915_WRITE(reg, val);
72519df918dSFrançois Tigeot POSTING_READ(reg);
72619df918dSFrançois Tigeot
727a85cb24fSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, crtc_state);
728a85cb24fSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder, crtc_state);
729a85cb24fSFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, crtc_state);
73019df918dSFrançois Tigeot }
73119df918dSFrançois Tigeot
cpt_set_infoframes(struct drm_encoder * encoder,bool enable,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)73219df918dSFrançois Tigeot static void cpt_set_infoframes(struct drm_encoder *encoder,
733ba55f2f5SFrançois Tigeot bool enable,
734a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
735a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
73619df918dSFrançois Tigeot {
737bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
738a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
73919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
740aee94f86SFrançois Tigeot i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
74119df918dSFrançois Tigeot u32 val = I915_READ(reg);
74219df918dSFrançois Tigeot
74319df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi);
74419df918dSFrançois Tigeot
74519df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */
74619df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
74719df918dSFrançois Tigeot
748ba55f2f5SFrançois Tigeot if (!enable) {
74919df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE))
75019df918dSFrançois Tigeot return;
751a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
752a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
753a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
75419df918dSFrançois Tigeot I915_WRITE(reg, val);
75519df918dSFrançois Tigeot POSTING_READ(reg);
75619df918dSFrançois Tigeot return;
75719df918dSFrançois Tigeot }
75819df918dSFrançois Tigeot
75919df918dSFrançois Tigeot /* Set both together, unset both together: see the spec. */
76019df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
76119df918dSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
762a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
763a05eeebfSFrançois Tigeot
764a85cb24fSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
765a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP;
76619df918dSFrançois Tigeot
76719df918dSFrançois Tigeot I915_WRITE(reg, val);
76819df918dSFrançois Tigeot POSTING_READ(reg);
76919df918dSFrançois Tigeot
770a85cb24fSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, crtc_state);
771a85cb24fSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder, crtc_state);
772a85cb24fSFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, crtc_state);
77319df918dSFrançois Tigeot }
77419df918dSFrançois Tigeot
vlv_set_infoframes(struct drm_encoder * encoder,bool enable,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)77519df918dSFrançois Tigeot static void vlv_set_infoframes(struct drm_encoder *encoder,
776ba55f2f5SFrançois Tigeot bool enable,
777a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
778a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
77919df918dSFrançois Tigeot {
780bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
781ba55f2f5SFrançois Tigeot struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
782a85cb24fSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
78319df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
784aee94f86SFrançois Tigeot i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
78519df918dSFrançois Tigeot u32 val = I915_READ(reg);
786ba55f2f5SFrançois Tigeot u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
78719df918dSFrançois Tigeot
78819df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi);
78919df918dSFrançois Tigeot
79019df918dSFrançois Tigeot /* See the big comment in g4x_set_infoframes() */
79119df918dSFrançois Tigeot val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
79219df918dSFrançois Tigeot
793ba55f2f5SFrançois Tigeot if (!enable) {
79419df918dSFrançois Tigeot if (!(val & VIDEO_DIP_ENABLE))
79519df918dSFrançois Tigeot return;
796a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
797a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
798a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
79919df918dSFrançois Tigeot I915_WRITE(reg, val);
80019df918dSFrançois Tigeot POSTING_READ(reg);
80119df918dSFrançois Tigeot return;
80219df918dSFrançois Tigeot }
80319df918dSFrançois Tigeot
804ba55f2f5SFrançois Tigeot if (port != (val & VIDEO_DIP_PORT_MASK)) {
805a05eeebfSFrançois Tigeot WARN(val & VIDEO_DIP_ENABLE,
806a05eeebfSFrançois Tigeot "DIP already enabled on port %c\n",
807a05eeebfSFrançois Tigeot (val & VIDEO_DIP_PORT_MASK) >> 29);
808ba55f2f5SFrançois Tigeot val &= ~VIDEO_DIP_PORT_MASK;
809ba55f2f5SFrançois Tigeot val |= port;
810ba55f2f5SFrançois Tigeot }
811ba55f2f5SFrançois Tigeot
81219df918dSFrançois Tigeot val |= VIDEO_DIP_ENABLE;
813a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_AVI |
814a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
815a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
816a05eeebfSFrançois Tigeot
817a85cb24fSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
818a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP;
81919df918dSFrançois Tigeot
82019df918dSFrançois Tigeot I915_WRITE(reg, val);
82119df918dSFrançois Tigeot POSTING_READ(reg);
82219df918dSFrançois Tigeot
823a85cb24fSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, crtc_state);
824a85cb24fSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder, crtc_state);
825a85cb24fSFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, crtc_state);
82619df918dSFrançois Tigeot }
82719df918dSFrançois Tigeot
hsw_set_infoframes(struct drm_encoder * encoder,bool enable,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)82819df918dSFrançois Tigeot static void hsw_set_infoframes(struct drm_encoder *encoder,
829ba55f2f5SFrançois Tigeot bool enable,
830a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state,
831a85cb24fSFrançois Tigeot const struct drm_connector_state *conn_state)
83219df918dSFrançois Tigeot {
833bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->dev);
83419df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
835a85cb24fSFrançois Tigeot i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
83619df918dSFrançois Tigeot u32 val = I915_READ(reg);
83719df918dSFrançois Tigeot
83819df918dSFrançois Tigeot assert_hdmi_port_disabled(intel_hdmi);
83919df918dSFrançois Tigeot
840a05eeebfSFrançois Tigeot val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
841a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW |
842a05eeebfSFrançois Tigeot VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
843a05eeebfSFrançois Tigeot
844ba55f2f5SFrançois Tigeot if (!enable) {
845a05eeebfSFrançois Tigeot I915_WRITE(reg, val);
84619df918dSFrançois Tigeot POSTING_READ(reg);
84719df918dSFrançois Tigeot return;
84819df918dSFrançois Tigeot }
84919df918dSFrançois Tigeot
850a85cb24fSFrançois Tigeot if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state))
851a05eeebfSFrançois Tigeot val |= VIDEO_DIP_ENABLE_GCP_HSW;
85219df918dSFrançois Tigeot
85319df918dSFrançois Tigeot I915_WRITE(reg, val);
85419df918dSFrançois Tigeot POSTING_READ(reg);
85519df918dSFrançois Tigeot
856a85cb24fSFrançois Tigeot intel_hdmi_set_avi_infoframe(encoder, crtc_state);
857a85cb24fSFrançois Tigeot intel_hdmi_set_spd_infoframe(encoder, crtc_state);
858a85cb24fSFrançois Tigeot intel_hdmi_set_hdmi_infoframe(encoder, crtc_state);
85919df918dSFrançois Tigeot }
86019df918dSFrançois Tigeot
intel_dp_dual_mode_set_tmds_output(struct intel_hdmi * hdmi,bool enable)8618621f407SFrançois Tigeot void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
8628621f407SFrançois Tigeot {
8638621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
8648621f407SFrançois Tigeot struct i2c_adapter *adapter =
8658621f407SFrançois Tigeot intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
8668621f407SFrançois Tigeot
8678621f407SFrançois Tigeot if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
8688621f407SFrançois Tigeot return;
8698621f407SFrançois Tigeot
8708621f407SFrançois Tigeot DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
8718621f407SFrançois Tigeot enable ? "Enabling" : "Disabling");
8728621f407SFrançois Tigeot
8738621f407SFrançois Tigeot drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type,
8748621f407SFrançois Tigeot adapter, enable);
8758621f407SFrançois Tigeot }
8768621f407SFrançois Tigeot
intel_hdmi_prepare(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)877a85cb24fSFrançois Tigeot static void intel_hdmi_prepare(struct intel_encoder *encoder,
878a85cb24fSFrançois Tigeot const struct intel_crtc_state *crtc_state)
879e3adcf8fSFrançois Tigeot {
8809edbd4a0SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
881bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
882a85cb24fSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
8839edbd4a0SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
884a85cb24fSFrançois Tigeot const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
8858e26cdf6SFrançois Tigeot u32 hdmi_val;
886e3adcf8fSFrançois Tigeot
8878621f407SFrançois Tigeot intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
8888621f407SFrançois Tigeot
8898e26cdf6SFrançois Tigeot hdmi_val = SDVO_ENCODING_HDMI;
890a85cb24fSFrançois Tigeot if (!HAS_PCH_SPLIT(dev_priv) && crtc_state->limited_color_range)
891352ff8bdSFrançois Tigeot hdmi_val |= HDMI_COLOR_RANGE_16_235;
892e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
8938e26cdf6SFrançois Tigeot hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
894e3adcf8fSFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
8958e26cdf6SFrançois Tigeot hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
896e3adcf8fSFrançois Tigeot
897a85cb24fSFrançois Tigeot if (crtc_state->pipe_bpp > 24)
8988e26cdf6SFrançois Tigeot hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
899e3adcf8fSFrançois Tigeot else
9008e26cdf6SFrançois Tigeot hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
901e3adcf8fSFrançois Tigeot
902a85cb24fSFrançois Tigeot if (crtc_state->has_hdmi_sink)
9038e26cdf6SFrançois Tigeot hdmi_val |= HDMI_MODE_SELECT_HDMI;
904e3adcf8fSFrançois Tigeot
9051e12ee3bSFrançois Tigeot if (HAS_PCH_CPT(dev_priv))
9069edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CPT(crtc->pipe);
9071e12ee3bSFrançois Tigeot else if (IS_CHERRYVIEW(dev_priv))
908ba55f2f5SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL_CHV(crtc->pipe);
9098e26cdf6SFrançois Tigeot else
9109edbd4a0SFrançois Tigeot hdmi_val |= SDVO_PIPE_SEL(crtc->pipe);
911e3adcf8fSFrançois Tigeot
9128e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val);
9138e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
914e3adcf8fSFrançois Tigeot }
915e3adcf8fSFrançois Tigeot
intel_hdmi_get_hw_state(struct intel_encoder * encoder,enum i915_pipe * pipe)91619df918dSFrançois Tigeot static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
91719df918dSFrançois Tigeot enum i915_pipe *pipe)
918e3adcf8fSFrançois Tigeot {
91919df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev;
920bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
92119df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
92219df918dSFrançois Tigeot u32 tmp;
923aee94f86SFrançois Tigeot bool ret;
92419df918dSFrançois Tigeot
925a85cb24fSFrançois Tigeot if (!intel_display_power_get_if_enabled(dev_priv,
926a85cb24fSFrançois Tigeot encoder->power_domain))
927ba55f2f5SFrançois Tigeot return false;
928ba55f2f5SFrançois Tigeot
929aee94f86SFrançois Tigeot ret = false;
930aee94f86SFrançois Tigeot
9318e26cdf6SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg);
93219df918dSFrançois Tigeot
93319df918dSFrançois Tigeot if (!(tmp & SDVO_ENABLE))
934aee94f86SFrançois Tigeot goto out;
93519df918dSFrançois Tigeot
9361e12ee3bSFrançois Tigeot if (HAS_PCH_CPT(dev_priv))
93719df918dSFrançois Tigeot *pipe = PORT_TO_PIPE_CPT(tmp);
9381e12ee3bSFrançois Tigeot else if (IS_CHERRYVIEW(dev_priv))
939ba55f2f5SFrançois Tigeot *pipe = SDVO_PORT_TO_PIPE_CHV(tmp);
94019df918dSFrançois Tigeot else
94119df918dSFrançois Tigeot *pipe = PORT_TO_PIPE(tmp);
94219df918dSFrançois Tigeot
943aee94f86SFrançois Tigeot ret = true;
944aee94f86SFrançois Tigeot
945aee94f86SFrançois Tigeot out:
946a85cb24fSFrançois Tigeot intel_display_power_put(dev_priv, encoder->power_domain);
947aee94f86SFrançois Tigeot
948aee94f86SFrançois Tigeot return ret;
94919df918dSFrançois Tigeot }
95019df918dSFrançois Tigeot
intel_hdmi_get_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)9515d0b1887SFrançois Tigeot static void intel_hdmi_get_config(struct intel_encoder *encoder,
9522c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config)
9535d0b1887SFrançois Tigeot {
9545d0b1887SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
955*3f2dd94aSFrançois Tigeot struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
95624edb884SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
957bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
9585d0b1887SFrançois Tigeot u32 tmp, flags = 0;
9599edbd4a0SFrançois Tigeot int dotclock;
9605d0b1887SFrançois Tigeot
9615d0b1887SFrançois Tigeot tmp = I915_READ(intel_hdmi->hdmi_reg);
9625d0b1887SFrançois Tigeot
9635d0b1887SFrançois Tigeot if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
9645d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC;
9655d0b1887SFrançois Tigeot else
9665d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC;
9675d0b1887SFrançois Tigeot
9685d0b1887SFrançois Tigeot if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
9695d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC;
9705d0b1887SFrançois Tigeot else
9715d0b1887SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC;
9725d0b1887SFrançois Tigeot
973ba55f2f5SFrançois Tigeot if (tmp & HDMI_MODE_SELECT_HDMI)
974ba55f2f5SFrançois Tigeot pipe_config->has_hdmi_sink = true;
975ba55f2f5SFrançois Tigeot
976*3f2dd94aSFrançois Tigeot if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
9772c9916cdSFrançois Tigeot pipe_config->has_infoframe = true;
9782c9916cdSFrançois Tigeot
97924edb884SFrançois Tigeot if (tmp & SDVO_AUDIO_ENABLE)
980ba55f2f5SFrançois Tigeot pipe_config->has_audio = true;
981ba55f2f5SFrançois Tigeot
9821e12ee3bSFrançois Tigeot if (!HAS_PCH_SPLIT(dev_priv) &&
98324edb884SFrançois Tigeot tmp & HDMI_COLOR_RANGE_16_235)
98424edb884SFrançois Tigeot pipe_config->limited_color_range = true;
98524edb884SFrançois Tigeot
9862c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.flags |= flags;
9879edbd4a0SFrançois Tigeot
9889edbd4a0SFrançois Tigeot if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
9899edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock * 2 / 3;
9909edbd4a0SFrançois Tigeot else
9919edbd4a0SFrançois Tigeot dotclock = pipe_config->port_clock;
9929edbd4a0SFrançois Tigeot
993a05eeebfSFrançois Tigeot if (pipe_config->pixel_multiplier)
994a05eeebfSFrançois Tigeot dotclock /= pipe_config->pixel_multiplier;
995a05eeebfSFrançois Tigeot
9962c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = dotclock;
9978621f407SFrançois Tigeot
9988621f407SFrançois Tigeot pipe_config->lane_count = 4;
9995d0b1887SFrançois Tigeot }
10005d0b1887SFrançois Tigeot
intel_enable_hdmi_audio(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)10014be47400SFrançois Tigeot static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
1002*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1003*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
1004a05eeebfSFrançois Tigeot {
1005a85cb24fSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
1006a05eeebfSFrançois Tigeot
1007a85cb24fSFrançois Tigeot WARN_ON(!pipe_config->has_hdmi_sink);
1008a05eeebfSFrançois Tigeot DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
1009a05eeebfSFrançois Tigeot pipe_name(crtc->pipe));
10104be47400SFrançois Tigeot intel_audio_codec_enable(encoder, pipe_config, conn_state);
1011a05eeebfSFrançois Tigeot }
1012a05eeebfSFrançois Tigeot
g4x_enable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)10131e12ee3bSFrançois Tigeot static void g4x_enable_hdmi(struct intel_encoder *encoder,
1014*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1015*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
101619df918dSFrançois Tigeot {
101719df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1018bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
101919df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1020e3adcf8fSFrançois Tigeot u32 temp;
1021e3adcf8fSFrançois Tigeot
10228e26cdf6SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg);
1023e3adcf8fSFrançois Tigeot
1024a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE;
10254be47400SFrançois Tigeot if (pipe_config->has_audio)
1026a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE;
102719df918dSFrançois Tigeot
1028a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1029a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1030a05eeebfSFrançois Tigeot
10314be47400SFrançois Tigeot if (pipe_config->has_audio)
10324be47400SFrançois Tigeot intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
1033a05eeebfSFrançois Tigeot }
1034a05eeebfSFrançois Tigeot
ibx_enable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)10351e12ee3bSFrançois Tigeot static void ibx_enable_hdmi(struct intel_encoder *encoder,
1036*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1037*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
1038a05eeebfSFrançois Tigeot {
1039a05eeebfSFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1040bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
1041a05eeebfSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1042a05eeebfSFrançois Tigeot u32 temp;
1043a05eeebfSFrançois Tigeot
1044a05eeebfSFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg);
1045a05eeebfSFrançois Tigeot
1046a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE;
1047a85cb24fSFrançois Tigeot if (pipe_config->has_audio)
1048a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE;
1049a05eeebfSFrançois Tigeot
1050a05eeebfSFrançois Tigeot /*
1051a05eeebfSFrançois Tigeot * HW workaround, need to write this twice for issue
1052a05eeebfSFrançois Tigeot * that may result in first write getting masked.
1053e3adcf8fSFrançois Tigeot */
1054a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1055a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1056a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1057a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1058a05eeebfSFrançois Tigeot
1059a05eeebfSFrançois Tigeot /*
1060a05eeebfSFrançois Tigeot * HW workaround, need to toggle enable bit off and on
1061a05eeebfSFrançois Tigeot * for 12bpc with pixel repeat.
1062a05eeebfSFrançois Tigeot *
1063a05eeebfSFrançois Tigeot * FIXME: BSpec says this should be done at the end of
1064a05eeebfSFrançois Tigeot * of the modeset sequence, so not sure if this isn't too soon.
1065a05eeebfSFrançois Tigeot */
10664be47400SFrançois Tigeot if (pipe_config->pipe_bpp > 24 &&
10674be47400SFrançois Tigeot pipe_config->pixel_multiplier > 1) {
10688e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE);
10698e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1070e3adcf8fSFrançois Tigeot
1071a05eeebfSFrançois Tigeot /*
1072a05eeebfSFrançois Tigeot * HW workaround, need to write this twice for issue
1073a05eeebfSFrançois Tigeot * that may result in first write getting masked.
107419df918dSFrançois Tigeot */
1075a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1076a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
10778e26cdf6SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
10788e26cdf6SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1079e3adcf8fSFrançois Tigeot }
10802c9916cdSFrançois Tigeot
10814be47400SFrançois Tigeot if (pipe_config->has_audio)
10824be47400SFrançois Tigeot intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
10832c9916cdSFrançois Tigeot }
1084a05eeebfSFrançois Tigeot
cpt_enable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)10851e12ee3bSFrançois Tigeot static void cpt_enable_hdmi(struct intel_encoder *encoder,
1086*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1087*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
1088a05eeebfSFrançois Tigeot {
1089a05eeebfSFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1090bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
1091a85cb24fSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
1092a05eeebfSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1093a05eeebfSFrançois Tigeot enum i915_pipe pipe = crtc->pipe;
1094a05eeebfSFrançois Tigeot u32 temp;
1095a05eeebfSFrançois Tigeot
1096a05eeebfSFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg);
1097a05eeebfSFrançois Tigeot
1098a05eeebfSFrançois Tigeot temp |= SDVO_ENABLE;
10994be47400SFrançois Tigeot if (pipe_config->has_audio)
1100a05eeebfSFrançois Tigeot temp |= SDVO_AUDIO_ENABLE;
1101a05eeebfSFrançois Tigeot
1102a05eeebfSFrançois Tigeot /*
1103a05eeebfSFrançois Tigeot * WaEnableHDMI8bpcBefore12bpc:snb,ivb
1104a05eeebfSFrançois Tigeot *
1105a05eeebfSFrançois Tigeot * The procedure for 12bpc is as follows:
1106a05eeebfSFrançois Tigeot * 1. disable HDMI clock gating
1107a05eeebfSFrançois Tigeot * 2. enable HDMI with 8bpc
1108a05eeebfSFrançois Tigeot * 3. enable HDMI with 12bpc
1109a05eeebfSFrançois Tigeot * 4. enable HDMI clock gating
1110a05eeebfSFrançois Tigeot */
1111a05eeebfSFrançois Tigeot
11124be47400SFrançois Tigeot if (pipe_config->pipe_bpp > 24) {
1113a05eeebfSFrançois Tigeot I915_WRITE(TRANS_CHICKEN1(pipe),
1114a05eeebfSFrançois Tigeot I915_READ(TRANS_CHICKEN1(pipe)) |
1115a05eeebfSFrançois Tigeot TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1116a05eeebfSFrançois Tigeot
1117a05eeebfSFrançois Tigeot temp &= ~SDVO_COLOR_FORMAT_MASK;
1118a05eeebfSFrançois Tigeot temp |= SDVO_COLOR_FORMAT_8bpc;
1119a05eeebfSFrançois Tigeot }
1120a05eeebfSFrançois Tigeot
1121a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1122a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1123a05eeebfSFrançois Tigeot
11244be47400SFrançois Tigeot if (pipe_config->pipe_bpp > 24) {
1125a05eeebfSFrançois Tigeot temp &= ~SDVO_COLOR_FORMAT_MASK;
1126a05eeebfSFrançois Tigeot temp |= HDMI_COLOR_FORMAT_12bpc;
1127a05eeebfSFrançois Tigeot
1128a05eeebfSFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
1129a05eeebfSFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1130a05eeebfSFrançois Tigeot
1131a05eeebfSFrançois Tigeot I915_WRITE(TRANS_CHICKEN1(pipe),
1132a05eeebfSFrançois Tigeot I915_READ(TRANS_CHICKEN1(pipe)) &
1133a05eeebfSFrançois Tigeot ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE);
1134a05eeebfSFrançois Tigeot }
1135a05eeebfSFrançois Tigeot
11364be47400SFrançois Tigeot if (pipe_config->has_audio)
11374be47400SFrançois Tigeot intel_enable_hdmi_audio(encoder, pipe_config, conn_state);
11385d0b1887SFrançois Tigeot }
11399edbd4a0SFrançois Tigeot
vlv_enable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)11401e12ee3bSFrançois Tigeot static void vlv_enable_hdmi(struct intel_encoder *encoder,
1141*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1142*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
11439edbd4a0SFrançois Tigeot {
114419df918dSFrançois Tigeot }
114519df918dSFrançois Tigeot
intel_disable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)11461e12ee3bSFrançois Tigeot static void intel_disable_hdmi(struct intel_encoder *encoder,
1147*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1148*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
114919df918dSFrançois Tigeot {
115019df918dSFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1151bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
115219df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1153*3f2dd94aSFrançois Tigeot struct intel_digital_port *intel_dig_port =
1154*3f2dd94aSFrançois Tigeot hdmi_to_dig_port(intel_hdmi);
1155a85cb24fSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
115619df918dSFrançois Tigeot u32 temp;
115719c468b4SFrançois Tigeot
115819c468b4SFrançois Tigeot temp = I915_READ(intel_hdmi->hdmi_reg);
115919c468b4SFrançois Tigeot
116019c468b4SFrançois Tigeot temp &= ~(SDVO_ENABLE | SDVO_AUDIO_ENABLE);
116119c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
116219c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
116319c468b4SFrançois Tigeot
116419c468b4SFrançois Tigeot /*
116519c468b4SFrançois Tigeot * HW workaround for IBX, we need to move the port
116619c468b4SFrançois Tigeot * to transcoder A after disabling it to allow the
116719c468b4SFrançois Tigeot * matching DP port to be enabled on transcoder A.
116819c468b4SFrançois Tigeot */
11691e12ee3bSFrançois Tigeot if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) {
1170aee94f86SFrançois Tigeot /*
1171aee94f86SFrançois Tigeot * We get CPU/PCH FIFO underruns on the other pipe when
1172aee94f86SFrançois Tigeot * doing the workaround. Sweep them under the rug.
1173aee94f86SFrançois Tigeot */
1174aee94f86SFrançois Tigeot intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false);
1175aee94f86SFrançois Tigeot intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false);
1176aee94f86SFrançois Tigeot
117719c468b4SFrançois Tigeot temp &= ~SDVO_PIPE_B_SELECT;
117819c468b4SFrançois Tigeot temp |= SDVO_ENABLE;
117919c468b4SFrançois Tigeot /*
118019c468b4SFrançois Tigeot * HW workaround, need to write this twice for issue
118119c468b4SFrançois Tigeot * that may result in first write getting masked.
118219c468b4SFrançois Tigeot */
118319c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
118419c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
118519c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
118619c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
118719c468b4SFrançois Tigeot
118819c468b4SFrançois Tigeot temp &= ~SDVO_ENABLE;
118919c468b4SFrançois Tigeot I915_WRITE(intel_hdmi->hdmi_reg, temp);
119019c468b4SFrançois Tigeot POSTING_READ(intel_hdmi->hdmi_reg);
1191aee94f86SFrançois Tigeot
11924be47400SFrançois Tigeot intel_wait_for_vblank_if_active(dev_priv, PIPE_A);
1193aee94f86SFrançois Tigeot intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true);
1194aee94f86SFrançois Tigeot intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
119519c468b4SFrançois Tigeot }
1196a05eeebfSFrançois Tigeot
1197*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes(&encoder->base, false,
1198*3f2dd94aSFrançois Tigeot old_crtc_state, old_conn_state);
11998621f407SFrançois Tigeot
12008621f407SFrançois Tigeot intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
120119c468b4SFrançois Tigeot }
120219c468b4SFrançois Tigeot
g4x_disable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)12031e12ee3bSFrançois Tigeot static void g4x_disable_hdmi(struct intel_encoder *encoder,
1204*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1205*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
120619c468b4SFrançois Tigeot {
12074be47400SFrançois Tigeot if (old_crtc_state->has_audio)
12082c9916cdSFrançois Tigeot intel_audio_codec_disable(encoder);
12092c9916cdSFrançois Tigeot
12101e12ee3bSFrançois Tigeot intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
121119df918dSFrançois Tigeot }
121219df918dSFrançois Tigeot
pch_disable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)12131e12ee3bSFrançois Tigeot static void pch_disable_hdmi(struct intel_encoder *encoder,
1214*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1215*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
121619c468b4SFrançois Tigeot {
12174be47400SFrançois Tigeot if (old_crtc_state->has_audio)
121819c468b4SFrançois Tigeot intel_audio_codec_disable(encoder);
121919df918dSFrançois Tigeot }
122019df918dSFrançois Tigeot
pch_post_disable_hdmi(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)12211e12ee3bSFrançois Tigeot static void pch_post_disable_hdmi(struct intel_encoder *encoder,
1222*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1223*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
122419c468b4SFrançois Tigeot {
12251e12ee3bSFrançois Tigeot intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
1226e3adcf8fSFrançois Tigeot }
1227e3adcf8fSFrançois Tigeot
intel_hdmi_source_max_tmds_clock(struct drm_i915_private * dev_priv)12288621f407SFrançois Tigeot static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv)
12295d0b1887SFrançois Tigeot {
12308621f407SFrançois Tigeot if (IS_G4X(dev_priv))
12315d0b1887SFrançois Tigeot return 165000;
1232a85cb24fSFrançois Tigeot else if (IS_GEMINILAKE(dev_priv))
1233a85cb24fSFrançois Tigeot return 594000;
12348621f407SFrançois Tigeot else if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
12355d0b1887SFrançois Tigeot return 300000;
12365d0b1887SFrançois Tigeot else
12375d0b1887SFrançois Tigeot return 225000;
12385d0b1887SFrançois Tigeot }
12395d0b1887SFrançois Tigeot
hdmi_port_clock_limit(struct intel_hdmi * hdmi,bool respect_downstream_limits,bool force_dvi)12408621f407SFrançois Tigeot static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
1241*3f2dd94aSFrançois Tigeot bool respect_downstream_limits,
1242*3f2dd94aSFrançois Tigeot bool force_dvi)
12438621f407SFrançois Tigeot {
12448621f407SFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi);
12458621f407SFrançois Tigeot int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
12468621f407SFrançois Tigeot
12478621f407SFrançois Tigeot if (respect_downstream_limits) {
12481e12ee3bSFrançois Tigeot struct intel_connector *connector = hdmi->attached_connector;
12491e12ee3bSFrançois Tigeot const struct drm_display_info *info = &connector->base.display_info;
12501e12ee3bSFrançois Tigeot
12518621f407SFrançois Tigeot if (hdmi->dp_dual_mode.max_tmds_clock)
12528621f407SFrançois Tigeot max_tmds_clock = min(max_tmds_clock,
12538621f407SFrançois Tigeot hdmi->dp_dual_mode.max_tmds_clock);
12541e12ee3bSFrançois Tigeot
12551e12ee3bSFrançois Tigeot if (info->max_tmds_clock)
12561e12ee3bSFrançois Tigeot max_tmds_clock = min(max_tmds_clock,
12571e12ee3bSFrançois Tigeot info->max_tmds_clock);
1258*3f2dd94aSFrançois Tigeot else if (!hdmi->has_hdmi_sink || force_dvi)
12598621f407SFrançois Tigeot max_tmds_clock = min(max_tmds_clock, 165000);
12608621f407SFrançois Tigeot }
12618621f407SFrançois Tigeot
12628621f407SFrançois Tigeot return max_tmds_clock;
12638621f407SFrançois Tigeot }
12648621f407SFrançois Tigeot
12659edbd4a0SFrançois Tigeot static enum drm_mode_status
hdmi_port_clock_valid(struct intel_hdmi * hdmi,int clock,bool respect_downstream_limits,bool force_dvi)1266a05eeebfSFrançois Tigeot hdmi_port_clock_valid(struct intel_hdmi *hdmi,
1267*3f2dd94aSFrançois Tigeot int clock, bool respect_downstream_limits,
1268*3f2dd94aSFrançois Tigeot bool force_dvi)
1269a05eeebfSFrançois Tigeot {
12701e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
1271a05eeebfSFrançois Tigeot
1272a05eeebfSFrançois Tigeot if (clock < 25000)
1273a05eeebfSFrançois Tigeot return MODE_CLOCK_LOW;
1274*3f2dd94aSFrançois Tigeot if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits, force_dvi))
1275a05eeebfSFrançois Tigeot return MODE_CLOCK_HIGH;
1276a05eeebfSFrançois Tigeot
1277a05eeebfSFrançois Tigeot /* BXT DPLL can't generate 223-240 MHz */
1278a85cb24fSFrançois Tigeot if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000)
1279a05eeebfSFrançois Tigeot return MODE_CLOCK_RANGE;
1280a05eeebfSFrançois Tigeot
1281a05eeebfSFrançois Tigeot /* CHV DPLL can't generate 216-240 MHz */
12821e12ee3bSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv) && clock > 216000 && clock < 240000)
1283a05eeebfSFrançois Tigeot return MODE_CLOCK_RANGE;
1284a05eeebfSFrançois Tigeot
1285a05eeebfSFrançois Tigeot return MODE_OK;
1286a05eeebfSFrançois Tigeot }
1287a05eeebfSFrançois Tigeot
1288a05eeebfSFrançois Tigeot static enum drm_mode_status
intel_hdmi_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)12899edbd4a0SFrançois Tigeot intel_hdmi_mode_valid(struct drm_connector *connector,
1290e3adcf8fSFrançois Tigeot struct drm_display_mode *mode)
1291e3adcf8fSFrançois Tigeot {
1292a05eeebfSFrançois Tigeot struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
1293a05eeebfSFrançois Tigeot struct drm_device *dev = intel_hdmi_to_dev(hdmi);
12941e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
1295a05eeebfSFrançois Tigeot enum drm_mode_status status;
1296a05eeebfSFrançois Tigeot int clock;
1297c0e85e96SFrançois Tigeot int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
1298*3f2dd94aSFrançois Tigeot bool force_dvi =
1299*3f2dd94aSFrançois Tigeot READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
1300e3adcf8fSFrançois Tigeot
1301e3adcf8fSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
1302e3adcf8fSFrançois Tigeot return MODE_NO_DBLESCAN;
1303e3adcf8fSFrançois Tigeot
1304a05eeebfSFrançois Tigeot clock = mode->clock;
1305c0e85e96SFrançois Tigeot
1306c0e85e96SFrançois Tigeot if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
1307c0e85e96SFrançois Tigeot clock *= 2;
1308c0e85e96SFrançois Tigeot
1309c0e85e96SFrançois Tigeot if (clock > max_dotclk)
1310c0e85e96SFrançois Tigeot return MODE_CLOCK_HIGH;
1311c0e85e96SFrançois Tigeot
1312a05eeebfSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLCLK)
1313a05eeebfSFrançois Tigeot clock *= 2;
1314a05eeebfSFrançois Tigeot
1315*3f2dd94aSFrançois Tigeot if (drm_mode_is_420_only(&connector->display_info, mode))
1316*3f2dd94aSFrançois Tigeot clock /= 2;
1317*3f2dd94aSFrançois Tigeot
1318a05eeebfSFrançois Tigeot /* check if we can do 8bpc */
1319*3f2dd94aSFrançois Tigeot status = hdmi_port_clock_valid(hdmi, clock, true, force_dvi);
1320a05eeebfSFrançois Tigeot
1321a05eeebfSFrançois Tigeot /* if we can't do 8bpc we may still be able to do 12bpc */
1322*3f2dd94aSFrançois Tigeot if (!HAS_GMCH_DISPLAY(dev_priv) && status != MODE_OK && hdmi->has_hdmi_sink && !force_dvi)
1323*3f2dd94aSFrançois Tigeot status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true, force_dvi);
1324a05eeebfSFrançois Tigeot
1325a05eeebfSFrançois Tigeot return status;
1326e3adcf8fSFrançois Tigeot }
1327e3adcf8fSFrançois Tigeot
hdmi_12bpc_possible(const struct intel_crtc_state * crtc_state)1328*3f2dd94aSFrançois Tigeot static bool hdmi_12bpc_possible(const struct intel_crtc_state *crtc_state)
1329ba55f2f5SFrançois Tigeot {
13304be47400SFrançois Tigeot struct drm_i915_private *dev_priv =
13314be47400SFrançois Tigeot to_i915(crtc_state->base.crtc->dev);
13324be47400SFrançois Tigeot struct drm_atomic_state *state = crtc_state->base.state;
13334be47400SFrançois Tigeot struct drm_connector_state *connector_state;
13344be47400SFrançois Tigeot struct drm_connector *connector;
13354be47400SFrançois Tigeot int i;
1336ba55f2f5SFrançois Tigeot
13374be47400SFrançois Tigeot if (HAS_GMCH_DISPLAY(dev_priv))
1338ba55f2f5SFrançois Tigeot return false;
1339ba55f2f5SFrançois Tigeot
1340ba55f2f5SFrançois Tigeot /*
1341ba55f2f5SFrançois Tigeot * HDMI 12bpc affects the clocks, so it's only possible
1342ba55f2f5SFrançois Tigeot * when not cloning with other encoder types.
1343ba55f2f5SFrançois Tigeot */
13444be47400SFrançois Tigeot if (crtc_state->output_types != 1 << INTEL_OUTPUT_HDMI)
13454be47400SFrançois Tigeot return false;
13464be47400SFrançois Tigeot
1347*3f2dd94aSFrançois Tigeot for_each_new_connector_in_state(state, connector, connector_state, i) {
13484be47400SFrançois Tigeot const struct drm_display_info *info = &connector->display_info;
13494be47400SFrançois Tigeot
13504be47400SFrançois Tigeot if (connector_state->crtc != crtc_state->base.crtc)
13514be47400SFrançois Tigeot continue;
13524be47400SFrançois Tigeot
1353*3f2dd94aSFrançois Tigeot if (crtc_state->ycbcr420) {
1354*3f2dd94aSFrançois Tigeot const struct drm_hdmi_info *hdmi = &info->hdmi;
1355*3f2dd94aSFrançois Tigeot
1356*3f2dd94aSFrançois Tigeot if (!(hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
1357*3f2dd94aSFrançois Tigeot return false;
1358*3f2dd94aSFrançois Tigeot } else {
1359*3f2dd94aSFrançois Tigeot if (!(info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36))
13604be47400SFrançois Tigeot return false;
13614be47400SFrançois Tigeot }
1362*3f2dd94aSFrançois Tigeot }
1363*3f2dd94aSFrançois Tigeot
1364*3f2dd94aSFrançois Tigeot /* Display Wa #1139 */
1365*3f2dd94aSFrançois Tigeot if (IS_GLK_REVID(dev_priv, 0, GLK_REVID_A1) &&
1366*3f2dd94aSFrançois Tigeot crtc_state->base.adjusted_mode.htotal > 5460)
1367*3f2dd94aSFrançois Tigeot return false;
1368*3f2dd94aSFrançois Tigeot
1369*3f2dd94aSFrançois Tigeot return true;
1370*3f2dd94aSFrançois Tigeot }
1371*3f2dd94aSFrançois Tigeot
1372*3f2dd94aSFrançois Tigeot static bool
intel_hdmi_ycbcr420_config(struct drm_connector * connector,struct intel_crtc_state * config,int * clock_12bpc,int * clock_8bpc)1373*3f2dd94aSFrançois Tigeot intel_hdmi_ycbcr420_config(struct drm_connector *connector,
1374*3f2dd94aSFrançois Tigeot struct intel_crtc_state *config,
1375*3f2dd94aSFrançois Tigeot int *clock_12bpc, int *clock_8bpc)
1376*3f2dd94aSFrançois Tigeot {
1377*3f2dd94aSFrançois Tigeot struct intel_crtc *intel_crtc = to_intel_crtc(config->base.crtc);
1378*3f2dd94aSFrançois Tigeot
1379*3f2dd94aSFrançois Tigeot if (!connector->ycbcr_420_allowed) {
1380*3f2dd94aSFrançois Tigeot DRM_ERROR("Platform doesn't support YCBCR420 output\n");
1381*3f2dd94aSFrançois Tigeot return false;
1382*3f2dd94aSFrançois Tigeot }
1383*3f2dd94aSFrançois Tigeot
1384*3f2dd94aSFrançois Tigeot /* YCBCR420 TMDS rate requirement is half the pixel clock */
1385*3f2dd94aSFrançois Tigeot config->port_clock /= 2;
1386*3f2dd94aSFrançois Tigeot *clock_12bpc /= 2;
1387*3f2dd94aSFrançois Tigeot *clock_8bpc /= 2;
1388*3f2dd94aSFrançois Tigeot config->ycbcr420 = true;
1389*3f2dd94aSFrançois Tigeot
1390*3f2dd94aSFrançois Tigeot /* YCBCR 420 output conversion needs a scaler */
1391*3f2dd94aSFrançois Tigeot if (skl_update_scaler_crtc(config)) {
1392*3f2dd94aSFrançois Tigeot DRM_DEBUG_KMS("Scaler allocation for output failed\n");
1393*3f2dd94aSFrançois Tigeot return false;
1394*3f2dd94aSFrançois Tigeot }
1395*3f2dd94aSFrançois Tigeot
1396*3f2dd94aSFrançois Tigeot intel_pch_panel_fitting(intel_crtc, config,
1397*3f2dd94aSFrançois Tigeot DRM_MODE_SCALE_FULLSCREEN);
13984be47400SFrançois Tigeot
13994be47400SFrançois Tigeot return true;
1400ba55f2f5SFrançois Tigeot }
1401ba55f2f5SFrançois Tigeot
intel_hdmi_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config,struct drm_connector_state * conn_state)14028e26cdf6SFrançois Tigeot bool intel_hdmi_compute_config(struct intel_encoder *encoder,
14031e12ee3bSFrançois Tigeot struct intel_crtc_state *pipe_config,
14041e12ee3bSFrançois Tigeot struct drm_connector_state *conn_state)
1405e3adcf8fSFrançois Tigeot {
14068e26cdf6SFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
14071e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
14082c9916cdSFrançois Tigeot struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
1409*3f2dd94aSFrançois Tigeot struct drm_connector *connector = conn_state->connector;
1410*3f2dd94aSFrançois Tigeot struct drm_scdc *scdc = &connector->display_info.hdmi.scdc;
1411*3f2dd94aSFrançois Tigeot struct intel_digital_connector_state *intel_conn_state =
1412*3f2dd94aSFrançois Tigeot to_intel_digital_connector_state(conn_state);
1413a05eeebfSFrançois Tigeot int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
1414a05eeebfSFrançois Tigeot int clock_12bpc = clock_8bpc * 3 / 2;
14155d0b1887SFrançois Tigeot int desired_bpp;
1416*3f2dd94aSFrançois Tigeot bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
1417a2fdbec6SFrançois Tigeot
1418*3f2dd94aSFrançois Tigeot pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
1419ba55f2f5SFrançois Tigeot
14202c9916cdSFrançois Tigeot if (pipe_config->has_hdmi_sink)
14212c9916cdSFrançois Tigeot pipe_config->has_infoframe = true;
14222c9916cdSFrançois Tigeot
1423*3f2dd94aSFrançois Tigeot if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) {
1424a2fdbec6SFrançois Tigeot /* See CEA-861-E - 5.1 Default Encoding Parameters */
1425352ff8bdSFrançois Tigeot pipe_config->limited_color_range =
1426352ff8bdSFrançois Tigeot pipe_config->has_hdmi_sink &&
1427a85cb24fSFrançois Tigeot drm_default_rgb_quant_range(adjusted_mode) ==
1428a85cb24fSFrançois Tigeot HDMI_QUANTIZATION_RANGE_LIMITED;
1429352ff8bdSFrançois Tigeot } else {
1430352ff8bdSFrançois Tigeot pipe_config->limited_color_range =
1431*3f2dd94aSFrançois Tigeot intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED;
1432a2fdbec6SFrançois Tigeot }
1433a2fdbec6SFrançois Tigeot
14341b13d190SFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
14351b13d190SFrançois Tigeot pipe_config->pixel_multiplier = 2;
1436a05eeebfSFrançois Tigeot clock_8bpc *= 2;
1437a05eeebfSFrançois Tigeot clock_12bpc *= 2;
14381b13d190SFrançois Tigeot }
14391b13d190SFrançois Tigeot
1440*3f2dd94aSFrançois Tigeot if (drm_mode_is_420_only(&connector->display_info, adjusted_mode)) {
1441*3f2dd94aSFrançois Tigeot if (!intel_hdmi_ycbcr420_config(connector, pipe_config,
1442*3f2dd94aSFrançois Tigeot &clock_12bpc, &clock_8bpc)) {
1443*3f2dd94aSFrançois Tigeot DRM_ERROR("Can't support YCBCR420 output\n");
1444*3f2dd94aSFrançois Tigeot return false;
1445*3f2dd94aSFrançois Tigeot }
1446*3f2dd94aSFrançois Tigeot }
1447*3f2dd94aSFrançois Tigeot
14481e12ee3bSFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv))
14498e26cdf6SFrançois Tigeot pipe_config->has_pch_encoder = true;
14508e26cdf6SFrançois Tigeot
1451*3f2dd94aSFrançois Tigeot if (pipe_config->has_hdmi_sink) {
1452*3f2dd94aSFrançois Tigeot if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO)
1453*3f2dd94aSFrançois Tigeot pipe_config->has_audio = intel_hdmi->has_audio;
1454*3f2dd94aSFrançois Tigeot else
1455*3f2dd94aSFrançois Tigeot pipe_config->has_audio =
1456*3f2dd94aSFrançois Tigeot intel_conn_state->force_audio == HDMI_AUDIO_ON;
1457*3f2dd94aSFrançois Tigeot }
1458ba55f2f5SFrançois Tigeot
14598e26cdf6SFrançois Tigeot /*
14608e26cdf6SFrançois Tigeot * HDMI is either 12 or 8, so if the display lets 10bpc sneak
14618e26cdf6SFrançois Tigeot * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
14625d0b1887SFrançois Tigeot * outputs. We also need to check that the higher clock still fits
14635d0b1887SFrançois Tigeot * within limits.
14648e26cdf6SFrançois Tigeot */
1465*3f2dd94aSFrançois Tigeot if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && !force_dvi &&
1466*3f2dd94aSFrançois Tigeot hdmi_port_clock_valid(intel_hdmi, clock_12bpc, true, force_dvi) == MODE_OK &&
1467a05eeebfSFrançois Tigeot hdmi_12bpc_possible(pipe_config)) {
14685d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
14695d0b1887SFrançois Tigeot desired_bpp = 12*3;
14705d0b1887SFrançois Tigeot
14715d0b1887SFrançois Tigeot /* Need to adjust the port link by 1.5x for 12bpc. */
14725d0b1887SFrançois Tigeot pipe_config->port_clock = clock_12bpc;
14738e26cdf6SFrançois Tigeot } else {
14745d0b1887SFrançois Tigeot DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
14755d0b1887SFrançois Tigeot desired_bpp = 8*3;
1476a05eeebfSFrançois Tigeot
1477a05eeebfSFrançois Tigeot pipe_config->port_clock = clock_8bpc;
14785d0b1887SFrançois Tigeot }
14795d0b1887SFrançois Tigeot
14805d0b1887SFrançois Tigeot if (!pipe_config->bw_constrained) {
1481*3f2dd94aSFrançois Tigeot DRM_DEBUG_KMS("forcing pipe bpp to %i for HDMI\n", desired_bpp);
14825d0b1887SFrançois Tigeot pipe_config->pipe_bpp = desired_bpp;
14835d0b1887SFrançois Tigeot }
14845d0b1887SFrançois Tigeot
1485a05eeebfSFrançois Tigeot if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
1486*3f2dd94aSFrançois Tigeot false, force_dvi) != MODE_OK) {
1487a05eeebfSFrançois Tigeot DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
14885d0b1887SFrançois Tigeot return false;
14898e26cdf6SFrançois Tigeot }
1490a2fdbec6SFrançois Tigeot
1491352ff8bdSFrançois Tigeot /* Set user selected PAR to incoming mode's member */
1492*3f2dd94aSFrançois Tigeot adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
1493352ff8bdSFrançois Tigeot
14948621f407SFrançois Tigeot pipe_config->lane_count = 4;
14958621f407SFrançois Tigeot
1496a85cb24fSFrançois Tigeot if (scdc->scrambling.supported && IS_GEMINILAKE(dev_priv)) {
1497a85cb24fSFrançois Tigeot if (scdc->scrambling.low_rates)
1498a85cb24fSFrançois Tigeot pipe_config->hdmi_scrambling = true;
1499a85cb24fSFrançois Tigeot
1500a85cb24fSFrançois Tigeot if (pipe_config->port_clock > 340000) {
1501a85cb24fSFrançois Tigeot pipe_config->hdmi_scrambling = true;
1502a85cb24fSFrançois Tigeot pipe_config->hdmi_high_tmds_clock_ratio = true;
1503a85cb24fSFrançois Tigeot }
1504a85cb24fSFrançois Tigeot }
1505a85cb24fSFrançois Tigeot
1506e3adcf8fSFrançois Tigeot return true;
1507e3adcf8fSFrançois Tigeot }
1508e3adcf8fSFrançois Tigeot
15091b13d190SFrançois Tigeot static void
intel_hdmi_unset_edid(struct drm_connector * connector)15101b13d190SFrançois Tigeot intel_hdmi_unset_edid(struct drm_connector *connector)
1511e3adcf8fSFrançois Tigeot {
1512e3adcf8fSFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
15139edbd4a0SFrançois Tigeot
1514e3adcf8fSFrançois Tigeot intel_hdmi->has_hdmi_sink = false;
1515e3adcf8fSFrançois Tigeot intel_hdmi->has_audio = false;
1516a2fdbec6SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable = false;
1517e3adcf8fSFrançois Tigeot
15188621f407SFrançois Tigeot intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
15198621f407SFrançois Tigeot intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
15208621f407SFrançois Tigeot
15211b13d190SFrançois Tigeot kfree(to_intel_connector(connector)->detect_edid);
15221b13d190SFrançois Tigeot to_intel_connector(connector)->detect_edid = NULL;
1523e3adcf8fSFrançois Tigeot }
1524e3adcf8fSFrançois Tigeot
15258621f407SFrançois Tigeot static void
intel_hdmi_dp_dual_mode_detect(struct drm_connector * connector,bool has_edid)15268621f407SFrançois Tigeot intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
15278621f407SFrançois Tigeot {
15288621f407SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(connector->dev);
15298621f407SFrançois Tigeot struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
15308621f407SFrançois Tigeot enum port port = hdmi_to_dig_port(hdmi)->port;
15318621f407SFrançois Tigeot struct i2c_adapter *adapter =
15328621f407SFrançois Tigeot intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
15338621f407SFrançois Tigeot enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter);
15348621f407SFrançois Tigeot
15358621f407SFrançois Tigeot /*
15368621f407SFrançois Tigeot * Type 1 DVI adaptors are not required to implement any
15378621f407SFrançois Tigeot * registers, so we can't always detect their presence.
15388621f407SFrançois Tigeot * Ideally we should be able to check the state of the
15398621f407SFrançois Tigeot * CONFIG1 pin, but no such luck on our hardware.
15408621f407SFrançois Tigeot *
15418621f407SFrançois Tigeot * The only method left to us is to check the VBT to see
15428621f407SFrançois Tigeot * if the port is a dual mode capable DP port. But let's
15438621f407SFrançois Tigeot * only do that when we sucesfully read the EDID, to avoid
15448621f407SFrançois Tigeot * confusing log messages about DP dual mode adaptors when
15458621f407SFrançois Tigeot * there's nothing connected to the port.
15468621f407SFrançois Tigeot */
15478621f407SFrançois Tigeot if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
15488621f407SFrançois Tigeot if (has_edid &&
15498621f407SFrançois Tigeot intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
15508621f407SFrançois Tigeot DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
15518621f407SFrançois Tigeot type = DRM_DP_DUAL_MODE_TYPE1_DVI;
15528621f407SFrançois Tigeot } else {
15538621f407SFrançois Tigeot type = DRM_DP_DUAL_MODE_NONE;
15548621f407SFrançois Tigeot }
15558621f407SFrançois Tigeot }
15568621f407SFrançois Tigeot
15578621f407SFrançois Tigeot if (type == DRM_DP_DUAL_MODE_NONE)
15588621f407SFrançois Tigeot return;
15598621f407SFrançois Tigeot
15608621f407SFrançois Tigeot hdmi->dp_dual_mode.type = type;
15618621f407SFrançois Tigeot hdmi->dp_dual_mode.max_tmds_clock =
15628621f407SFrançois Tigeot drm_dp_dual_mode_max_tmds_clock(type, adapter);
15638621f407SFrançois Tigeot
15648621f407SFrançois Tigeot DRM_DEBUG_KMS("DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n",
15658621f407SFrançois Tigeot drm_dp_get_dual_mode_type_name(type),
15668621f407SFrançois Tigeot hdmi->dp_dual_mode.max_tmds_clock);
15678621f407SFrançois Tigeot }
15688621f407SFrançois Tigeot
15691b13d190SFrançois Tigeot static bool
intel_hdmi_set_edid(struct drm_connector * connector)15701e12ee3bSFrançois Tigeot intel_hdmi_set_edid(struct drm_connector *connector)
1571e3adcf8fSFrançois Tigeot {
15721b13d190SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(connector->dev);
15731b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
15741e12ee3bSFrançois Tigeot struct edid *edid;
15751b13d190SFrançois Tigeot bool connected = false;
1576*3f2dd94aSFrançois Tigeot struct i2c_adapter *i2c;
1577e3adcf8fSFrançois Tigeot
1578352ff8bdSFrançois Tigeot intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
1579ba55f2f5SFrançois Tigeot
1580*3f2dd94aSFrançois Tigeot i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
1581*3f2dd94aSFrançois Tigeot
1582*3f2dd94aSFrançois Tigeot edid = drm_get_edid(connector, i2c);
1583*3f2dd94aSFrançois Tigeot
1584*3f2dd94aSFrançois Tigeot if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
1585*3f2dd94aSFrançois Tigeot DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
1586*3f2dd94aSFrançois Tigeot intel_gmbus_force_bit(i2c, true);
1587*3f2dd94aSFrançois Tigeot edid = drm_get_edid(connector, i2c);
1588*3f2dd94aSFrançois Tigeot intel_gmbus_force_bit(i2c, false);
1589*3f2dd94aSFrançois Tigeot }
1590ba55f2f5SFrançois Tigeot
15918621f407SFrançois Tigeot intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
15928621f407SFrançois Tigeot
1593352ff8bdSFrançois Tigeot intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
1594ba55f2f5SFrançois Tigeot
15951b13d190SFrançois Tigeot to_intel_connector(connector)->detect_edid = edid;
15961b13d190SFrançois Tigeot if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
15971b13d190SFrançois Tigeot intel_hdmi->rgb_quant_range_selectable =
15981b13d190SFrançois Tigeot drm_rgb_quant_range_selectable(edid);
15991b13d190SFrançois Tigeot
16001b13d190SFrançois Tigeot intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
1601*3f2dd94aSFrançois Tigeot intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
16021b13d190SFrançois Tigeot
16031b13d190SFrançois Tigeot connected = true;
16041b13d190SFrançois Tigeot }
16051b13d190SFrançois Tigeot
16061b13d190SFrançois Tigeot return connected;
16071b13d190SFrançois Tigeot }
16081b13d190SFrançois Tigeot
16091b13d190SFrançois Tigeot static enum drm_connector_status
intel_hdmi_detect(struct drm_connector * connector,bool force)16101b13d190SFrançois Tigeot intel_hdmi_detect(struct drm_connector *connector, bool force)
16111b13d190SFrançois Tigeot {
16121b13d190SFrançois Tigeot enum drm_connector_status status;
1613352ff8bdSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(connector->dev);
16141b13d190SFrançois Tigeot
16151b13d190SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
16161b13d190SFrançois Tigeot connector->base.id, connector->name);
16171b13d190SFrançois Tigeot
1618352ff8bdSFrançois Tigeot intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
1619352ff8bdSFrançois Tigeot
16201b13d190SFrançois Tigeot intel_hdmi_unset_edid(connector);
16211b13d190SFrançois Tigeot
16221e12ee3bSFrançois Tigeot if (intel_hdmi_set_edid(connector)) {
16231b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
16241b13d190SFrançois Tigeot
16251b13d190SFrançois Tigeot hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
16261b13d190SFrançois Tigeot status = connector_status_connected;
16271b13d190SFrançois Tigeot } else
16281b13d190SFrançois Tigeot status = connector_status_disconnected;
16291b13d190SFrançois Tigeot
1630352ff8bdSFrançois Tigeot intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
1631352ff8bdSFrançois Tigeot
16321b13d190SFrançois Tigeot return status;
16331b13d190SFrançois Tigeot }
16341b13d190SFrançois Tigeot
16351b13d190SFrançois Tigeot static void
intel_hdmi_force(struct drm_connector * connector)16361b13d190SFrançois Tigeot intel_hdmi_force(struct drm_connector *connector)
16371b13d190SFrançois Tigeot {
16381b13d190SFrançois Tigeot struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
16391b13d190SFrançois Tigeot
16401b13d190SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
16411b13d190SFrançois Tigeot connector->base.id, connector->name);
16421b13d190SFrançois Tigeot
16431b13d190SFrançois Tigeot intel_hdmi_unset_edid(connector);
16441b13d190SFrançois Tigeot
16451b13d190SFrançois Tigeot if (connector->status != connector_status_connected)
16461b13d190SFrançois Tigeot return;
16471b13d190SFrançois Tigeot
16481e12ee3bSFrançois Tigeot intel_hdmi_set_edid(connector);
16491b13d190SFrançois Tigeot hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
16501b13d190SFrançois Tigeot }
16511b13d190SFrançois Tigeot
intel_hdmi_get_modes(struct drm_connector * connector)16521b13d190SFrançois Tigeot static int intel_hdmi_get_modes(struct drm_connector *connector)
16531b13d190SFrançois Tigeot {
16541b13d190SFrançois Tigeot struct edid *edid;
16551b13d190SFrançois Tigeot
16561b13d190SFrançois Tigeot edid = to_intel_connector(connector)->detect_edid;
16571b13d190SFrançois Tigeot if (edid == NULL)
16581b13d190SFrançois Tigeot return 0;
16591b13d190SFrançois Tigeot
16601b13d190SFrançois Tigeot return intel_connector_update_modes(connector, edid);
1661e3adcf8fSFrançois Tigeot }
1662e3adcf8fSFrançois Tigeot
intel_hdmi_pre_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)16631e12ee3bSFrançois Tigeot static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
1664*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1665*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
1666ba55f2f5SFrançois Tigeot {
1667*3f2dd94aSFrançois Tigeot struct intel_digital_port *intel_dig_port =
1668*3f2dd94aSFrançois Tigeot enc_to_dig_port(&encoder->base);
1669ba55f2f5SFrançois Tigeot
1670a85cb24fSFrançois Tigeot intel_hdmi_prepare(encoder, pipe_config);
1671ba55f2f5SFrançois Tigeot
1672*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes(&encoder->base,
1673*3f2dd94aSFrançois Tigeot pipe_config->has_infoframe,
1674a85cb24fSFrançois Tigeot pipe_config, conn_state);
1675ba55f2f5SFrançois Tigeot }
1676ba55f2f5SFrançois Tigeot
vlv_hdmi_pre_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)16771e12ee3bSFrançois Tigeot static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
1678*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1679*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
16805d0b1887SFrançois Tigeot {
16815d0b1887SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
16825d0b1887SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1683bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
16845d0b1887SFrançois Tigeot
16851487f786SFrançois Tigeot vlv_phy_pre_encoder_enable(encoder);
16865d0b1887SFrançois Tigeot
16875d0b1887SFrançois Tigeot /* HDMI 1.0V-2dB */
16881487f786SFrançois Tigeot vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
16891487f786SFrançois Tigeot 0x2b247878);
16909edbd4a0SFrançois Tigeot
1691*3f2dd94aSFrançois Tigeot dport->set_infoframes(&encoder->base,
1692*3f2dd94aSFrançois Tigeot pipe_config->has_infoframe,
1693a85cb24fSFrançois Tigeot pipe_config, conn_state);
1694ba55f2f5SFrançois Tigeot
16951e12ee3bSFrançois Tigeot g4x_enable_hdmi(encoder, pipe_config, conn_state);
16969edbd4a0SFrançois Tigeot
169719c468b4SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport, 0x0);
16985d0b1887SFrançois Tigeot }
16995d0b1887SFrançois Tigeot
vlv_hdmi_pre_pll_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)17001e12ee3bSFrançois Tigeot static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
1701*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1702*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
17035d0b1887SFrançois Tigeot {
1704a85cb24fSFrançois Tigeot intel_hdmi_prepare(encoder, pipe_config);
17055d0b1887SFrançois Tigeot
17061487f786SFrançois Tigeot vlv_phy_pre_pll_enable(encoder);
1707352ff8bdSFrançois Tigeot }
1708352ff8bdSFrançois Tigeot
chv_hdmi_pre_pll_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)17091e12ee3bSFrançois Tigeot static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
1710*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1711*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
171224edb884SFrançois Tigeot {
1713a85cb24fSFrançois Tigeot intel_hdmi_prepare(encoder, pipe_config);
17141b13d190SFrançois Tigeot
17151487f786SFrançois Tigeot chv_phy_pre_pll_enable(encoder);
171624edb884SFrançois Tigeot }
171724edb884SFrançois Tigeot
chv_hdmi_post_pll_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)17181e12ee3bSFrançois Tigeot static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder,
1719*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1720*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
1721352ff8bdSFrançois Tigeot {
17221487f786SFrançois Tigeot chv_phy_post_pll_disable(encoder);
1723352ff8bdSFrançois Tigeot }
1724352ff8bdSFrançois Tigeot
vlv_hdmi_post_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)17251e12ee3bSFrançois Tigeot static void vlv_hdmi_post_disable(struct intel_encoder *encoder,
1726*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1727*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
17285d0b1887SFrançois Tigeot {
17295d0b1887SFrançois Tigeot /* Reset lanes to avoid HDMI flicker (VLV w/a) */
17301487f786SFrançois Tigeot vlv_phy_reset_lanes(encoder);
17315d0b1887SFrançois Tigeot }
17325d0b1887SFrançois Tigeot
chv_hdmi_post_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)17331e12ee3bSFrançois Tigeot static void chv_hdmi_post_disable(struct intel_encoder *encoder,
1734*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
1735*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
1736ba55f2f5SFrançois Tigeot {
1737ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1738bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
1739ba55f2f5SFrançois Tigeot
174019c468b4SFrançois Tigeot mutex_lock(&dev_priv->sb_lock);
1741ba55f2f5SFrançois Tigeot
1742352ff8bdSFrançois Tigeot /* Assert data lane reset */
1743352ff8bdSFrançois Tigeot chv_data_lane_soft_reset(encoder, true);
1744ba55f2f5SFrançois Tigeot
174519c468b4SFrançois Tigeot mutex_unlock(&dev_priv->sb_lock);
1746ba55f2f5SFrançois Tigeot }
1747ba55f2f5SFrançois Tigeot
chv_hdmi_pre_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)17481e12ee3bSFrançois Tigeot static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
1749*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
1750*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
1751ba55f2f5SFrançois Tigeot {
1752ba55f2f5SFrançois Tigeot struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
1753ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
1754bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
1755ba55f2f5SFrançois Tigeot
17561487f786SFrançois Tigeot chv_phy_pre_encoder_enable(encoder);
17572c9916cdSFrançois Tigeot
1758ba55f2f5SFrançois Tigeot /* FIXME: Program the support xxx V-dB */
1759ba55f2f5SFrançois Tigeot /* Use 800mV-0dB */
17601487f786SFrançois Tigeot chv_set_phy_signal_level(encoder, 128, 102, false);
1761ba55f2f5SFrançois Tigeot
1762*3f2dd94aSFrançois Tigeot dport->set_infoframes(&encoder->base,
1763*3f2dd94aSFrançois Tigeot pipe_config->has_infoframe,
1764a85cb24fSFrançois Tigeot pipe_config, conn_state);
17652c9916cdSFrançois Tigeot
17661e12ee3bSFrançois Tigeot g4x_enable_hdmi(encoder, pipe_config, conn_state);
1767ba55f2f5SFrançois Tigeot
176819c468b4SFrançois Tigeot vlv_wait_port_ready(dev_priv, dport, 0x0);
1769352ff8bdSFrançois Tigeot
1770352ff8bdSFrançois Tigeot /* Second common lane will stay alive on its own now */
17711487f786SFrançois Tigeot chv_phy_release_cl2_override(encoder);
1772ba55f2f5SFrançois Tigeot }
1773ba55f2f5SFrançois Tigeot
intel_hdmi_destroy(struct drm_connector * connector)1774e3adcf8fSFrançois Tigeot static void intel_hdmi_destroy(struct drm_connector *connector)
1775e3adcf8fSFrançois Tigeot {
17761b13d190SFrançois Tigeot kfree(to_intel_connector(connector)->detect_edid);
1777e3adcf8fSFrançois Tigeot drm_connector_cleanup(connector);
17788e26cdf6SFrançois Tigeot kfree(connector);
1779e3adcf8fSFrançois Tigeot }
1780e3adcf8fSFrançois Tigeot
1781e3adcf8fSFrançois Tigeot static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
1782e3adcf8fSFrançois Tigeot .detect = intel_hdmi_detect,
17831b13d190SFrançois Tigeot .force = intel_hdmi_force,
1784e3adcf8fSFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes,
1785*3f2dd94aSFrançois Tigeot .atomic_get_property = intel_digital_connector_atomic_get_property,
1786*3f2dd94aSFrançois Tigeot .atomic_set_property = intel_digital_connector_atomic_set_property,
17871487f786SFrançois Tigeot .late_register = intel_connector_register,
17881487f786SFrançois Tigeot .early_unregister = intel_connector_unregister,
1789e3adcf8fSFrançois Tigeot .destroy = intel_hdmi_destroy,
17902c9916cdSFrançois Tigeot .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1791*3f2dd94aSFrançois Tigeot .atomic_duplicate_state = intel_digital_connector_duplicate_state,
1792e3adcf8fSFrançois Tigeot };
1793e3adcf8fSFrançois Tigeot
1794e3adcf8fSFrançois Tigeot static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
1795e3adcf8fSFrançois Tigeot .get_modes = intel_hdmi_get_modes,
1796e3adcf8fSFrançois Tigeot .mode_valid = intel_hdmi_mode_valid,
1797*3f2dd94aSFrançois Tigeot .atomic_check = intel_digital_connector_atomic_check,
1798e3adcf8fSFrançois Tigeot };
1799e3adcf8fSFrançois Tigeot
1800e3adcf8fSFrançois Tigeot static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
1801e3adcf8fSFrançois Tigeot .destroy = intel_encoder_destroy,
1802e3adcf8fSFrançois Tigeot };
1803e3adcf8fSFrançois Tigeot
1804e3adcf8fSFrançois Tigeot static void
intel_hdmi_add_properties(struct intel_hdmi * intel_hdmi,struct drm_connector * connector)1805e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
1806e3adcf8fSFrançois Tigeot {
1807e3adcf8fSFrançois Tigeot intel_attach_force_audio_property(connector);
1808e3adcf8fSFrançois Tigeot intel_attach_broadcast_rgb_property(connector);
180924edb884SFrançois Tigeot intel_attach_aspect_ratio_property(connector);
1810*3f2dd94aSFrançois Tigeot connector->state->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
1811e3adcf8fSFrançois Tigeot }
1812e3adcf8fSFrançois Tigeot
1813a85cb24fSFrançois Tigeot /*
1814a85cb24fSFrançois Tigeot * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup
1815a85cb24fSFrançois Tigeot * @encoder: intel_encoder
1816a85cb24fSFrançois Tigeot * @connector: drm_connector
1817a85cb24fSFrançois Tigeot * @high_tmds_clock_ratio = bool to indicate if the function needs to set
1818a85cb24fSFrançois Tigeot * or reset the high tmds clock ratio for scrambling
1819a85cb24fSFrançois Tigeot * @scrambling: bool to Indicate if the function needs to set or reset
1820a85cb24fSFrançois Tigeot * sink scrambling
1821a85cb24fSFrançois Tigeot *
1822a85cb24fSFrançois Tigeot * This function handles scrambling on HDMI 2.0 capable sinks.
1823a85cb24fSFrançois Tigeot * If required clock rate is > 340 Mhz && scrambling is supported by sink
1824a85cb24fSFrançois Tigeot * it enables scrambling. This should be called before enabling the HDMI
1825a85cb24fSFrançois Tigeot * 2.0 port, as the sink can choose to disable the scrambling if it doesn't
1826a85cb24fSFrançois Tigeot * detect a scrambled clock within 100 ms.
1827a85cb24fSFrançois Tigeot */
intel_hdmi_handle_sink_scrambling(struct intel_encoder * encoder,struct drm_connector * connector,bool high_tmds_clock_ratio,bool scrambling)1828a85cb24fSFrançois Tigeot void intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
1829a85cb24fSFrançois Tigeot struct drm_connector *connector,
1830a85cb24fSFrançois Tigeot bool high_tmds_clock_ratio,
1831a85cb24fSFrançois Tigeot bool scrambling)
1832a85cb24fSFrançois Tigeot {
1833a85cb24fSFrançois Tigeot struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
1834a85cb24fSFrançois Tigeot struct drm_i915_private *dev_priv = connector->dev->dev_private;
1835a85cb24fSFrançois Tigeot struct drm_scrambling *sink_scrambling =
1836a85cb24fSFrançois Tigeot &connector->display_info.hdmi.scdc.scrambling;
1837a85cb24fSFrançois Tigeot struct i2c_adapter *adptr = intel_gmbus_get_adapter(dev_priv,
1838a85cb24fSFrançois Tigeot intel_hdmi->ddc_bus);
1839a85cb24fSFrançois Tigeot bool ret;
1840a85cb24fSFrançois Tigeot
1841a85cb24fSFrançois Tigeot if (!sink_scrambling->supported)
1842a85cb24fSFrançois Tigeot return;
1843a85cb24fSFrançois Tigeot
1844a85cb24fSFrançois Tigeot DRM_DEBUG_KMS("Setting sink scrambling for enc:%s connector:%s\n",
1845a85cb24fSFrançois Tigeot encoder->base.name, connector->name);
1846a85cb24fSFrançois Tigeot
1847a85cb24fSFrançois Tigeot /* Set TMDS bit clock ratio to 1/40 or 1/10 */
1848a85cb24fSFrançois Tigeot ret = drm_scdc_set_high_tmds_clock_ratio(adptr, high_tmds_clock_ratio);
1849a85cb24fSFrançois Tigeot if (!ret) {
1850a85cb24fSFrançois Tigeot DRM_ERROR("Set TMDS ratio failed\n");
1851a85cb24fSFrançois Tigeot return;
1852a85cb24fSFrançois Tigeot }
1853a85cb24fSFrançois Tigeot
1854a85cb24fSFrançois Tigeot /* Enable/disable sink scrambling */
1855a85cb24fSFrançois Tigeot ret = drm_scdc_set_scrambling(adptr, scrambling);
1856a85cb24fSFrançois Tigeot if (!ret) {
1857a85cb24fSFrançois Tigeot DRM_ERROR("Set sink scrambling failed\n");
1858a85cb24fSFrançois Tigeot return;
1859a85cb24fSFrançois Tigeot }
1860a85cb24fSFrançois Tigeot
1861a85cb24fSFrançois Tigeot DRM_DEBUG_KMS("sink scrambling handled\n");
1862a85cb24fSFrançois Tigeot }
1863a85cb24fSFrançois Tigeot
chv_port_to_ddc_pin(struct drm_i915_private * dev_priv,enum port port)1864*3f2dd94aSFrançois Tigeot static u8 chv_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
1865*3f2dd94aSFrançois Tigeot {
1866*3f2dd94aSFrançois Tigeot u8 ddc_pin;
1867*3f2dd94aSFrançois Tigeot
1868*3f2dd94aSFrançois Tigeot switch (port) {
1869*3f2dd94aSFrançois Tigeot case PORT_B:
1870*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPB;
1871*3f2dd94aSFrançois Tigeot break;
1872*3f2dd94aSFrançois Tigeot case PORT_C:
1873*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPC;
1874*3f2dd94aSFrançois Tigeot break;
1875*3f2dd94aSFrançois Tigeot case PORT_D:
1876*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPD_CHV;
1877*3f2dd94aSFrançois Tigeot break;
1878*3f2dd94aSFrançois Tigeot default:
1879*3f2dd94aSFrançois Tigeot MISSING_CASE(port);
1880*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPB;
1881*3f2dd94aSFrançois Tigeot break;
1882*3f2dd94aSFrançois Tigeot }
1883*3f2dd94aSFrançois Tigeot return ddc_pin;
1884*3f2dd94aSFrançois Tigeot }
1885*3f2dd94aSFrançois Tigeot
bxt_port_to_ddc_pin(struct drm_i915_private * dev_priv,enum port port)1886*3f2dd94aSFrançois Tigeot static u8 bxt_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port)
1887*3f2dd94aSFrançois Tigeot {
1888*3f2dd94aSFrançois Tigeot u8 ddc_pin;
1889*3f2dd94aSFrançois Tigeot
1890*3f2dd94aSFrançois Tigeot switch (port) {
1891*3f2dd94aSFrançois Tigeot case PORT_B:
1892*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_1_BXT;
1893*3f2dd94aSFrançois Tigeot break;
1894*3f2dd94aSFrançois Tigeot case PORT_C:
1895*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_2_BXT;
1896*3f2dd94aSFrançois Tigeot break;
1897*3f2dd94aSFrançois Tigeot default:
1898*3f2dd94aSFrançois Tigeot MISSING_CASE(port);
1899*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_1_BXT;
1900*3f2dd94aSFrançois Tigeot break;
1901*3f2dd94aSFrançois Tigeot }
1902*3f2dd94aSFrançois Tigeot return ddc_pin;
1903*3f2dd94aSFrançois Tigeot }
1904*3f2dd94aSFrançois Tigeot
cnp_port_to_ddc_pin(struct drm_i915_private * dev_priv,enum port port)1905*3f2dd94aSFrançois Tigeot static u8 cnp_port_to_ddc_pin(struct drm_i915_private *dev_priv,
1906*3f2dd94aSFrançois Tigeot enum port port)
1907*3f2dd94aSFrançois Tigeot {
1908*3f2dd94aSFrançois Tigeot u8 ddc_pin;
1909*3f2dd94aSFrançois Tigeot
1910*3f2dd94aSFrançois Tigeot switch (port) {
1911*3f2dd94aSFrançois Tigeot case PORT_B:
1912*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_1_BXT;
1913*3f2dd94aSFrançois Tigeot break;
1914*3f2dd94aSFrançois Tigeot case PORT_C:
1915*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_2_BXT;
1916*3f2dd94aSFrançois Tigeot break;
1917*3f2dd94aSFrançois Tigeot case PORT_D:
1918*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_4_CNP;
1919*3f2dd94aSFrançois Tigeot break;
1920*3f2dd94aSFrançois Tigeot default:
1921*3f2dd94aSFrançois Tigeot MISSING_CASE(port);
1922*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_1_BXT;
1923*3f2dd94aSFrançois Tigeot break;
1924*3f2dd94aSFrançois Tigeot }
1925*3f2dd94aSFrançois Tigeot return ddc_pin;
1926*3f2dd94aSFrançois Tigeot }
1927*3f2dd94aSFrançois Tigeot
g4x_port_to_ddc_pin(struct drm_i915_private * dev_priv,enum port port)1928*3f2dd94aSFrançois Tigeot static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv,
1929*3f2dd94aSFrançois Tigeot enum port port)
1930*3f2dd94aSFrançois Tigeot {
1931*3f2dd94aSFrançois Tigeot u8 ddc_pin;
1932*3f2dd94aSFrançois Tigeot
1933*3f2dd94aSFrançois Tigeot switch (port) {
1934*3f2dd94aSFrançois Tigeot case PORT_B:
1935*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPB;
1936*3f2dd94aSFrançois Tigeot break;
1937*3f2dd94aSFrançois Tigeot case PORT_C:
1938*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPC;
1939*3f2dd94aSFrançois Tigeot break;
1940*3f2dd94aSFrançois Tigeot case PORT_D:
1941*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPD;
1942*3f2dd94aSFrançois Tigeot break;
1943*3f2dd94aSFrançois Tigeot default:
1944*3f2dd94aSFrançois Tigeot MISSING_CASE(port);
1945*3f2dd94aSFrançois Tigeot ddc_pin = GMBUS_PIN_DPB;
1946*3f2dd94aSFrançois Tigeot break;
1947*3f2dd94aSFrançois Tigeot }
1948*3f2dd94aSFrançois Tigeot return ddc_pin;
1949*3f2dd94aSFrançois Tigeot }
1950*3f2dd94aSFrançois Tigeot
intel_hdmi_ddc_pin(struct drm_i915_private * dev_priv,enum port port)19511e12ee3bSFrançois Tigeot static u8 intel_hdmi_ddc_pin(struct drm_i915_private *dev_priv,
19521e12ee3bSFrançois Tigeot enum port port)
19531e12ee3bSFrançois Tigeot {
19541e12ee3bSFrançois Tigeot const struct ddi_vbt_port_info *info =
19551e12ee3bSFrançois Tigeot &dev_priv->vbt.ddi_port_info[port];
19561e12ee3bSFrançois Tigeot u8 ddc_pin;
19571e12ee3bSFrançois Tigeot
19581e12ee3bSFrançois Tigeot if (info->alternate_ddc_pin) {
19591e12ee3bSFrançois Tigeot DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (VBT)\n",
19601e12ee3bSFrançois Tigeot info->alternate_ddc_pin, port_name(port));
19611e12ee3bSFrançois Tigeot return info->alternate_ddc_pin;
19621e12ee3bSFrançois Tigeot }
19631e12ee3bSFrançois Tigeot
19641e12ee3bSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv))
1965*3f2dd94aSFrançois Tigeot ddc_pin = chv_port_to_ddc_pin(dev_priv, port);
1966*3f2dd94aSFrançois Tigeot else if (IS_GEN9_LP(dev_priv))
1967*3f2dd94aSFrançois Tigeot ddc_pin = bxt_port_to_ddc_pin(dev_priv, port);
1968*3f2dd94aSFrançois Tigeot else if (HAS_PCH_CNP(dev_priv))
1969*3f2dd94aSFrançois Tigeot ddc_pin = cnp_port_to_ddc_pin(dev_priv, port);
19701e12ee3bSFrançois Tigeot else
1971*3f2dd94aSFrançois Tigeot ddc_pin = g4x_port_to_ddc_pin(dev_priv, port);
19721e12ee3bSFrançois Tigeot
19731e12ee3bSFrançois Tigeot DRM_DEBUG_KMS("Using DDC pin 0x%x for port %c (platform default)\n",
19741e12ee3bSFrançois Tigeot ddc_pin, port_name(port));
19751e12ee3bSFrançois Tigeot
19761e12ee3bSFrançois Tigeot return ddc_pin;
19771e12ee3bSFrançois Tigeot }
19781e12ee3bSFrançois Tigeot
intel_infoframe_init(struct intel_digital_port * intel_dig_port)1979*3f2dd94aSFrançois Tigeot void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
1980*3f2dd94aSFrançois Tigeot {
1981*3f2dd94aSFrançois Tigeot struct drm_i915_private *dev_priv =
1982*3f2dd94aSFrançois Tigeot to_i915(intel_dig_port->base.base.dev);
1983*3f2dd94aSFrançois Tigeot
1984*3f2dd94aSFrançois Tigeot if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
1985*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe = vlv_write_infoframe;
1986*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes = vlv_set_infoframes;
1987*3f2dd94aSFrançois Tigeot intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
1988*3f2dd94aSFrançois Tigeot } else if (IS_G4X(dev_priv)) {
1989*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe = g4x_write_infoframe;
1990*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes = g4x_set_infoframes;
1991*3f2dd94aSFrançois Tigeot intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
1992*3f2dd94aSFrançois Tigeot } else if (HAS_DDI(dev_priv)) {
1993*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe = hsw_write_infoframe;
1994*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes = hsw_set_infoframes;
1995*3f2dd94aSFrançois Tigeot intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
1996*3f2dd94aSFrançois Tigeot } else if (HAS_PCH_IBX(dev_priv)) {
1997*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe = ibx_write_infoframe;
1998*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes = ibx_set_infoframes;
1999*3f2dd94aSFrançois Tigeot intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
2000*3f2dd94aSFrançois Tigeot } else {
2001*3f2dd94aSFrançois Tigeot intel_dig_port->write_infoframe = cpt_write_infoframe;
2002*3f2dd94aSFrançois Tigeot intel_dig_port->set_infoframes = cpt_set_infoframes;
2003*3f2dd94aSFrançois Tigeot intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
2004*3f2dd94aSFrançois Tigeot }
2005*3f2dd94aSFrançois Tigeot }
2006*3f2dd94aSFrançois Tigeot
intel_hdmi_init_connector(struct intel_digital_port * intel_dig_port,struct intel_connector * intel_connector)200719df918dSFrançois Tigeot void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
200819df918dSFrançois Tigeot struct intel_connector *intel_connector)
2009e3adcf8fSFrançois Tigeot {
201019df918dSFrançois Tigeot struct drm_connector *connector = &intel_connector->base;
201119df918dSFrançois Tigeot struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
201219df918dSFrançois Tigeot struct intel_encoder *intel_encoder = &intel_dig_port->base;
201319df918dSFrançois Tigeot struct drm_device *dev = intel_encoder->base.dev;
2014bf017597SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
201519df918dSFrançois Tigeot enum port port = intel_dig_port->port;
2016e3adcf8fSFrançois Tigeot
20178621f407SFrançois Tigeot DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
20188621f407SFrançois Tigeot port_name(port));
20198621f407SFrançois Tigeot
2020c0e85e96SFrançois Tigeot if (WARN(intel_dig_port->max_lanes < 4,
2021c0e85e96SFrançois Tigeot "Not enough lanes (%d) for HDMI on port %c\n",
2022c0e85e96SFrançois Tigeot intel_dig_port->max_lanes, port_name(port)))
2023c0e85e96SFrançois Tigeot return;
2024c0e85e96SFrançois Tigeot
2025e3adcf8fSFrançois Tigeot drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
2026e3adcf8fSFrançois Tigeot DRM_MODE_CONNECTOR_HDMIA);
2027e3adcf8fSFrançois Tigeot drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
2028e3adcf8fSFrançois Tigeot
2029e3adcf8fSFrançois Tigeot connector->interlace_allowed = 1;
2030e3adcf8fSFrançois Tigeot connector->doublescan_allowed = 0;
20319edbd4a0SFrançois Tigeot connector->stereo_allowed = 1;
2032e3adcf8fSFrançois Tigeot
2033*3f2dd94aSFrançois Tigeot if (IS_GEMINILAKE(dev_priv))
2034*3f2dd94aSFrançois Tigeot connector->ycbcr_420_allowed = true;
2035*3f2dd94aSFrançois Tigeot
20361e12ee3bSFrançois Tigeot intel_hdmi->ddc_bus = intel_hdmi_ddc_pin(dev_priv, port);
20371e12ee3bSFrançois Tigeot
2038*3f2dd94aSFrançois Tigeot if (WARN_ON(port == PORT_A))
20391e12ee3bSFrançois Tigeot return;
2040*3f2dd94aSFrançois Tigeot intel_encoder->hpd_pin = intel_hpd_pin(port);
2041e3adcf8fSFrançois Tigeot
20421e12ee3bSFrançois Tigeot if (HAS_DDI(dev_priv))
204319df918dSFrançois Tigeot intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
204419df918dSFrançois Tigeot else
204519df918dSFrançois Tigeot intel_connector->get_hw_state = intel_connector_get_hw_state;
2046e3adcf8fSFrançois Tigeot
2047e3adcf8fSFrançois Tigeot intel_hdmi_add_properties(intel_hdmi, connector);
2048e3adcf8fSFrançois Tigeot
2049e3adcf8fSFrançois Tigeot intel_connector_attach_encoder(intel_connector, intel_encoder);
2050352ff8bdSFrançois Tigeot intel_hdmi->attached_connector = intel_connector;
2051e3adcf8fSFrançois Tigeot
2052e3adcf8fSFrançois Tigeot /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
2053e3adcf8fSFrançois Tigeot * 0xd. Failure to do so will result in spurious interrupts being
2054e3adcf8fSFrançois Tigeot * generated on the port when a cable is not attached.
2055e3adcf8fSFrançois Tigeot */
20561e12ee3bSFrançois Tigeot if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) {
2057e3adcf8fSFrançois Tigeot u32 temp = I915_READ(PEG_BAND_GAP_DATA);
2058e3adcf8fSFrançois Tigeot I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
2059e3adcf8fSFrançois Tigeot }
2060e3adcf8fSFrançois Tigeot }
206119df918dSFrançois Tigeot
intel_hdmi_init(struct drm_i915_private * dev_priv,i915_reg_t hdmi_reg,enum port port)2062a85cb24fSFrançois Tigeot void intel_hdmi_init(struct drm_i915_private *dev_priv,
2063aee94f86SFrançois Tigeot i915_reg_t hdmi_reg, enum port port)
206419df918dSFrançois Tigeot {
206519df918dSFrançois Tigeot struct intel_digital_port *intel_dig_port;
206619df918dSFrançois Tigeot struct intel_encoder *intel_encoder;
206719df918dSFrançois Tigeot struct intel_connector *intel_connector;
206819df918dSFrançois Tigeot
20699edbd4a0SFrançois Tigeot intel_dig_port = kzalloc(sizeof(*intel_dig_port), GFP_KERNEL);
207019df918dSFrançois Tigeot if (!intel_dig_port)
207119df918dSFrançois Tigeot return;
207219df918dSFrançois Tigeot
2073477eb7f9SFrançois Tigeot intel_connector = intel_connector_alloc();
207419df918dSFrançois Tigeot if (!intel_connector) {
2075158486a6SFrançois Tigeot kfree(intel_dig_port);
207619df918dSFrançois Tigeot return;
207719df918dSFrançois Tigeot }
207819df918dSFrançois Tigeot
207919df918dSFrançois Tigeot intel_encoder = &intel_dig_port->base;
208019df918dSFrançois Tigeot
2081a85cb24fSFrançois Tigeot drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
2082a85cb24fSFrançois Tigeot &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
2083a85cb24fSFrançois Tigeot "HDMI %c", port_name(port));
208419df918dSFrançois Tigeot
20858e26cdf6SFrançois Tigeot intel_encoder->compute_config = intel_hdmi_compute_config;
20861e12ee3bSFrançois Tigeot if (HAS_PCH_SPLIT(dev_priv)) {
208719c468b4SFrançois Tigeot intel_encoder->disable = pch_disable_hdmi;
208819c468b4SFrançois Tigeot intel_encoder->post_disable = pch_post_disable_hdmi;
208919c468b4SFrançois Tigeot } else {
209019c468b4SFrançois Tigeot intel_encoder->disable = g4x_disable_hdmi;
209119c468b4SFrançois Tigeot }
209219df918dSFrançois Tigeot intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
20935d0b1887SFrançois Tigeot intel_encoder->get_config = intel_hdmi_get_config;
20941e12ee3bSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) {
209524edb884SFrançois Tigeot intel_encoder->pre_pll_enable = chv_hdmi_pre_pll_enable;
2096ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = chv_hdmi_pre_enable;
2097ba55f2f5SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi;
2098ba55f2f5SFrançois Tigeot intel_encoder->post_disable = chv_hdmi_post_disable;
2099352ff8bdSFrançois Tigeot intel_encoder->post_pll_disable = chv_hdmi_post_pll_disable;
21001e12ee3bSFrançois Tigeot } else if (IS_VALLEYVIEW(dev_priv)) {
21019edbd4a0SFrançois Tigeot intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
21029edbd4a0SFrançois Tigeot intel_encoder->pre_enable = vlv_hdmi_pre_enable;
21039edbd4a0SFrançois Tigeot intel_encoder->enable = vlv_enable_hdmi;
21049edbd4a0SFrançois Tigeot intel_encoder->post_disable = vlv_hdmi_post_disable;
21059edbd4a0SFrançois Tigeot } else {
2106ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = intel_hdmi_pre_enable;
21071e12ee3bSFrançois Tigeot if (HAS_PCH_CPT(dev_priv))
2108a05eeebfSFrançois Tigeot intel_encoder->enable = cpt_enable_hdmi;
21091e12ee3bSFrançois Tigeot else if (HAS_PCH_IBX(dev_priv))
2110a05eeebfSFrançois Tigeot intel_encoder->enable = ibx_enable_hdmi;
2111a05eeebfSFrançois Tigeot else
2112a05eeebfSFrançois Tigeot intel_encoder->enable = g4x_enable_hdmi;
21135d0b1887SFrançois Tigeot }
211419df918dSFrançois Tigeot
211519df918dSFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_HDMI;
2116a85cb24fSFrançois Tigeot intel_encoder->power_domain = intel_port_to_power_domain(port);
21171e12ee3bSFrançois Tigeot intel_encoder->port = port;
21181e12ee3bSFrançois Tigeot if (IS_CHERRYVIEW(dev_priv)) {
2119ba55f2f5SFrançois Tigeot if (port == PORT_D)
2120ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = 1 << 2;
2121ba55f2f5SFrançois Tigeot else
2122ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
2123ba55f2f5SFrançois Tigeot } else {
212419df918dSFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
2125ba55f2f5SFrançois Tigeot }
2126ba55f2f5SFrançois Tigeot intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
2127ba55f2f5SFrançois Tigeot /*
2128ba55f2f5SFrançois Tigeot * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
2129ba55f2f5SFrançois Tigeot * to work on real hardware. And since g4x can send infoframes to
2130ba55f2f5SFrançois Tigeot * only one port anyway, nothing is lost by allowing it.
2131ba55f2f5SFrançois Tigeot */
21321e12ee3bSFrançois Tigeot if (IS_G4X(dev_priv))
2133ba55f2f5SFrançois Tigeot intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
213419df918dSFrançois Tigeot
213519df918dSFrançois Tigeot intel_dig_port->port = port;
21368e26cdf6SFrançois Tigeot intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
2137aee94f86SFrançois Tigeot intel_dig_port->dp.output_reg = INVALID_MMIO_REG;
2138c0e85e96SFrançois Tigeot intel_dig_port->max_lanes = 4;
213919df918dSFrançois Tigeot
2140*3f2dd94aSFrançois Tigeot intel_infoframe_init(intel_dig_port);
2141*3f2dd94aSFrançois Tigeot
214219df918dSFrançois Tigeot intel_hdmi_init_connector(intel_dig_port, intel_connector);
214319df918dSFrançois Tigeot }
2144