blob: 08f2b63d740ad0b66535b756e2e03482aa4d1b18 [file] [log] [blame]
Eric Anholt7d573822009-01-02 13:33:00 -08001/*
2 * Copyright 2006 Dave Airlie <airlied@linux.ie>
3 * Copyright © 2006-2009 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Eric Anholt <eric@anholt.net>
26 * Jesse Barnes <jesse.barnes@intel.com>
27 */
28
29#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Eric Anholt7d573822009-01-02 13:33:00 -080031#include <linux/delay.h>
32#include "drmP.h"
33#include "drm.h"
34#include "drm_crtc.h"
Keith Packardaa93d632009-05-05 09:52:46 -070035#include "drm_edid.h"
Eric Anholt7d573822009-01-02 13:33:00 -080036#include "intel_drv.h"
37#include "i915_drm.h"
38#include "i915_drv.h"
39
Daniel Vetterafba0182012-06-12 16:36:45 +020040static void
41assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
42{
43 struct drm_device *dev = intel_hdmi->base.base.dev;
44 struct drm_i915_private *dev_priv = dev->dev_private;
45 uint32_t enabled_bits;
46
47 enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
48
49 WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
50 "HDMI port enabled, expecting disabled\n");
51}
52
Eugeni Dodonovf5bbfca2012-05-09 15:37:30 -030053struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
Chris Wilsonea5b2132010-08-04 13:50:23 +010054{
Chris Wilson4ef69c72010-09-09 15:14:28 +010055 return container_of(encoder, struct intel_hdmi, base.base);
Chris Wilsonea5b2132010-08-04 13:50:23 +010056}
57
Chris Wilsondf0e9242010-09-09 16:20:55 +010058static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
59{
60 return container_of(intel_attached_encoder(connector),
61 struct intel_hdmi, base);
62}
63
Jesse Barnes45187ac2011-08-03 09:22:55 -070064void intel_dip_infoframe_csum(struct dip_infoframe *frame)
David Härdeman3c17fe42010-09-24 21:44:32 +020065{
Jesse Barnes45187ac2011-08-03 09:22:55 -070066 uint8_t *data = (uint8_t *)frame;
David Härdeman3c17fe42010-09-24 21:44:32 +020067 uint8_t sum = 0;
68 unsigned i;
69
Jesse Barnes45187ac2011-08-03 09:22:55 -070070 frame->checksum = 0;
71 frame->ecc = 0;
David Härdeman3c17fe42010-09-24 21:44:32 +020072
Jesse Barnes64a8fc02011-09-22 11:16:00 +053073 for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++)
David Härdeman3c17fe42010-09-24 21:44:32 +020074 sum += data[i];
75
Jesse Barnes45187ac2011-08-03 09:22:55 -070076 frame->checksum = 0x100 - sum;
David Härdeman3c17fe42010-09-24 21:44:32 +020077}
78
Daniel Vetterbc2481f2012-05-08 15:18:32 +020079static u32 g4x_infoframe_index(struct dip_infoframe *frame)
David Härdeman3c17fe42010-09-24 21:44:32 +020080{
Jesse Barnes45187ac2011-08-03 09:22:55 -070081 switch (frame->type) {
82 case DIP_TYPE_AVI:
Paulo Zanonied517fb2012-05-14 17:12:50 -030083 return VIDEO_DIP_SELECT_AVI;
Jesse Barnes45187ac2011-08-03 09:22:55 -070084 case DIP_TYPE_SPD:
Paulo Zanonied517fb2012-05-14 17:12:50 -030085 return VIDEO_DIP_SELECT_SPD;
Jesse Barnes45187ac2011-08-03 09:22:55 -070086 default:
87 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
Paulo Zanonied517fb2012-05-14 17:12:50 -030088 return 0;
Jesse Barnes45187ac2011-08-03 09:22:55 -070089 }
Jesse Barnes45187ac2011-08-03 09:22:55 -070090}
91
Daniel Vetterbc2481f2012-05-08 15:18:32 +020092static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -070093{
Jesse Barnes45187ac2011-08-03 09:22:55 -070094 switch (frame->type) {
95 case DIP_TYPE_AVI:
Paulo Zanonied517fb2012-05-14 17:12:50 -030096 return VIDEO_DIP_ENABLE_AVI;
Jesse Barnes45187ac2011-08-03 09:22:55 -070097 case DIP_TYPE_SPD:
Paulo Zanonied517fb2012-05-14 17:12:50 -030098 return VIDEO_DIP_ENABLE_SPD;
Paulo Zanonifa193ff2012-05-04 17:18:20 -030099 default:
100 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
Paulo Zanonied517fb2012-05-14 17:12:50 -0300101 return 0;
Paulo Zanonifa193ff2012-05-04 17:18:20 -0300102 }
Paulo Zanonifa193ff2012-05-04 17:18:20 -0300103}
104
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300105static u32 hsw_infoframe_enable(struct dip_infoframe *frame)
106{
107 switch (frame->type) {
108 case DIP_TYPE_AVI:
109 return VIDEO_DIP_ENABLE_AVI_HSW;
110 case DIP_TYPE_SPD:
111 return VIDEO_DIP_ENABLE_SPD_HSW;
112 default:
113 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
114 return 0;
115 }
116}
117
118static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
119{
120 switch (frame->type) {
121 case DIP_TYPE_AVI:
122 return HSW_TVIDEO_DIP_AVI_DATA(pipe);
123 case DIP_TYPE_SPD:
124 return HSW_TVIDEO_DIP_SPD_DATA(pipe);
125 default:
126 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
127 return 0;
128 }
129}
130
Daniel Vettera3da1df2012-05-08 15:19:06 +0200131static void g4x_write_infoframe(struct drm_encoder *encoder,
132 struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -0700133{
134 uint32_t *data = (uint32_t *)frame;
David Härdeman3c17fe42010-09-24 21:44:32 +0200135 struct drm_device *dev = encoder->dev;
136 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300137 u32 val = I915_READ(VIDEO_DIP_CTL);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700138 unsigned i, len = DIP_HEADER_SIZE + frame->len;
David Härdeman3c17fe42010-09-24 21:44:32 +0200139
Paulo Zanoni822974a2012-05-28 16:42:51 -0300140 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
141
Paulo Zanoni1d4f85a2012-05-04 17:18:18 -0300142 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200143 val |= g4x_infoframe_index(frame);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700144
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200145 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300146
147 I915_WRITE(VIDEO_DIP_CTL, val);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700148
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300149 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700150 for (i = 0; i < len; i += 4) {
David Härdeman3c17fe42010-09-24 21:44:32 +0200151 I915_WRITE(VIDEO_DIP_DATA, *data);
152 data++;
153 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300154 /* Write every possible data byte to force correct ECC calculation. */
155 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
156 I915_WRITE(VIDEO_DIP_DATA, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300157 mmiowb();
David Härdeman3c17fe42010-09-24 21:44:32 +0200158
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200159 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300160 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200161 val |= VIDEO_DIP_FREQ_VSYNC;
Jesse Barnes45187ac2011-08-03 09:22:55 -0700162
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300163 I915_WRITE(VIDEO_DIP_CTL, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300164 POSTING_READ(VIDEO_DIP_CTL);
David Härdeman3c17fe42010-09-24 21:44:32 +0200165}
166
Paulo Zanonifdf12502012-05-04 17:18:24 -0300167static void ibx_write_infoframe(struct drm_encoder *encoder,
168 struct dip_infoframe *frame)
169{
170 uint32_t *data = (uint32_t *)frame;
171 struct drm_device *dev = encoder->dev;
172 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300173 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300174 int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
175 unsigned i, len = DIP_HEADER_SIZE + frame->len;
176 u32 val = I915_READ(reg);
177
Paulo Zanoni822974a2012-05-28 16:42:51 -0300178 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
179
Paulo Zanonifdf12502012-05-04 17:18:24 -0300180 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200181 val |= g4x_infoframe_index(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300182
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200183 val &= ~g4x_infoframe_enable(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300184
185 I915_WRITE(reg, val);
186
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300187 mmiowb();
Paulo Zanonifdf12502012-05-04 17:18:24 -0300188 for (i = 0; i < len; i += 4) {
189 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
190 data++;
191 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300192 /* Write every possible data byte to force correct ECC calculation. */
193 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
194 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300195 mmiowb();
Paulo Zanonifdf12502012-05-04 17:18:24 -0300196
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200197 val |= g4x_infoframe_enable(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300198 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200199 val |= VIDEO_DIP_FREQ_VSYNC;
Paulo Zanonifdf12502012-05-04 17:18:24 -0300200
201 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300202 POSTING_READ(reg);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300203}
204
205static void cpt_write_infoframe(struct drm_encoder *encoder,
206 struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -0700207{
208 uint32_t *data = (uint32_t *)frame;
209 struct drm_device *dev = encoder->dev;
210 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300211 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700212 int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
213 unsigned i, len = DIP_HEADER_SIZE + frame->len;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300214 u32 val = I915_READ(reg);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700215
Paulo Zanoni822974a2012-05-28 16:42:51 -0300216 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
217
Jesse Barnes64a8fc02011-09-22 11:16:00 +0530218 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200219 val |= g4x_infoframe_index(frame);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700220
Paulo Zanoniecb97852012-05-04 17:18:21 -0300221 /* The DIP control register spec says that we need to update the AVI
222 * infoframe without clearing its enable bit */
Paulo Zanoni822974a2012-05-28 16:42:51 -0300223 if (frame->type != DIP_TYPE_AVI)
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200224 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoniecb97852012-05-04 17:18:21 -0300225
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300226 I915_WRITE(reg, val);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700227
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300228 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700229 for (i = 0; i < len; i += 4) {
230 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
231 data++;
232 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300233 /* Write every possible data byte to force correct ECC calculation. */
234 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
235 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300236 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700237
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200238 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300239 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200240 val |= VIDEO_DIP_FREQ_VSYNC;
Jesse Barnes45187ac2011-08-03 09:22:55 -0700241
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300242 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300243 POSTING_READ(reg);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700244}
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700245
246static void vlv_write_infoframe(struct drm_encoder *encoder,
247 struct dip_infoframe *frame)
248{
249 uint32_t *data = (uint32_t *)frame;
250 struct drm_device *dev = encoder->dev;
251 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300252 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700253 int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
254 unsigned i, len = DIP_HEADER_SIZE + frame->len;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300255 u32 val = I915_READ(reg);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700256
Paulo Zanoni822974a2012-05-28 16:42:51 -0300257 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
258
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700259 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200260 val |= g4x_infoframe_index(frame);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700261
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200262 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300263
264 I915_WRITE(reg, val);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700265
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300266 mmiowb();
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700267 for (i = 0; i < len; i += 4) {
268 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
269 data++;
270 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300271 /* Write every possible data byte to force correct ECC calculation. */
272 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
273 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300274 mmiowb();
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700275
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200276 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300277 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200278 val |= VIDEO_DIP_FREQ_VSYNC;
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700279
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300280 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300281 POSTING_READ(reg);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700282}
283
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300284static void hsw_write_infoframe(struct drm_encoder *encoder,
Paulo Zanonied517fb2012-05-14 17:12:50 -0300285 struct dip_infoframe *frame)
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300286{
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300287 uint32_t *data = (uint32_t *)frame;
288 struct drm_device *dev = encoder->dev;
289 struct drm_i915_private *dev_priv = dev->dev_private;
290 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
291 u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
292 u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
293 unsigned int i, len = DIP_HEADER_SIZE + frame->len;
294 u32 val = I915_READ(ctl_reg);
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300295
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300296 if (data_reg == 0)
297 return;
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300298
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300299 val &= ~hsw_infoframe_enable(frame);
300 I915_WRITE(ctl_reg, val);
301
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300302 mmiowb();
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300303 for (i = 0; i < len; i += 4) {
304 I915_WRITE(data_reg + i, *data);
305 data++;
306 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300307 /* Write every possible data byte to force correct ECC calculation. */
308 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
309 I915_WRITE(data_reg + i, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300310 mmiowb();
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300311
312 val |= hsw_infoframe_enable(frame);
313 I915_WRITE(ctl_reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300314 POSTING_READ(ctl_reg);
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300315}
316
Jesse Barnes45187ac2011-08-03 09:22:55 -0700317static void intel_set_infoframe(struct drm_encoder *encoder,
318 struct dip_infoframe *frame)
319{
320 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
321
Jesse Barnes45187ac2011-08-03 09:22:55 -0700322 intel_dip_infoframe_csum(frame);
323 intel_hdmi->write_infoframe(encoder, frame);
324}
325
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300326static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
Paulo Zanonic846b612012-04-13 16:31:41 -0300327 struct drm_display_mode *adjusted_mode)
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700328{
329 struct dip_infoframe avi_if = {
330 .type = DIP_TYPE_AVI,
331 .ver = DIP_VERSION_AVI,
332 .len = DIP_LEN_AVI,
333 };
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700334
Paulo Zanonic846b612012-04-13 16:31:41 -0300335 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
336 avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
337
Jesse Barnes45187ac2011-08-03 09:22:55 -0700338 intel_set_infoframe(encoder, &avi_if);
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700339}
340
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300341static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
Jesse Barnesc0864cb2011-08-03 09:22:56 -0700342{
343 struct dip_infoframe spd_if;
344
345 memset(&spd_if, 0, sizeof(spd_if));
346 spd_if.type = DIP_TYPE_SPD;
347 spd_if.ver = DIP_VERSION_SPD;
348 spd_if.len = DIP_LEN_SPD;
349 strcpy(spd_if.body.spd.vn, "Intel");
350 strcpy(spd_if.body.spd.pd, "Integrated gfx");
351 spd_if.body.spd.sdi = DIP_SPD_PC;
352
353 intel_set_infoframe(encoder, &spd_if);
354}
355
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300356static void g4x_set_infoframes(struct drm_encoder *encoder,
357 struct drm_display_mode *adjusted_mode)
358{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300359 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
360 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
361 u32 reg = VIDEO_DIP_CTL;
362 u32 val = I915_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300363 u32 port;
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300364
Daniel Vetterafba0182012-06-12 16:36:45 +0200365 assert_hdmi_port_disabled(intel_hdmi);
366
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300367 /* If the registers were not initialized yet, they might be zeroes,
368 * which means we're selecting the AVI DIP and we're setting its
369 * frequency to once. This seems to really confuse the HW and make
370 * things stop working (the register spec says the AVI always needs to
371 * be sent every VSync). So here we avoid writing to the register more
372 * than we need and also explicitly select the AVI DIP and explicitly
373 * set its frequency to every VSync. Avoiding to write it twice seems to
374 * be enough to solve the problem, but being defensive shouldn't hurt us
375 * either. */
376 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
377
378 if (!intel_hdmi->has_hdmi_sink) {
379 if (!(val & VIDEO_DIP_ENABLE))
380 return;
381 val &= ~VIDEO_DIP_ENABLE;
382 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300383 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300384 return;
385 }
386
Paulo Zanonif278d972012-05-28 16:42:50 -0300387 switch (intel_hdmi->sdvox_reg) {
388 case SDVOB:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300389 port = VIDEO_DIP_PORT_B;
Paulo Zanonif278d972012-05-28 16:42:50 -0300390 break;
391 case SDVOC:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300392 port = VIDEO_DIP_PORT_C;
Paulo Zanonif278d972012-05-28 16:42:50 -0300393 break;
394 default:
Paulo Zanoni57df2ae2012-09-24 10:32:54 -0300395 BUG();
Paulo Zanonif278d972012-05-28 16:42:50 -0300396 return;
397 }
398
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300399 if (port != (val & VIDEO_DIP_PORT_MASK)) {
400 if (val & VIDEO_DIP_ENABLE) {
401 val &= ~VIDEO_DIP_ENABLE;
402 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300403 POSTING_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300404 }
405 val &= ~VIDEO_DIP_PORT_MASK;
406 val |= port;
407 }
408
Paulo Zanoni822974a2012-05-28 16:42:51 -0300409 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300410 val &= ~VIDEO_DIP_ENABLE_VENDOR;
Paulo Zanoni822974a2012-05-28 16:42:51 -0300411
Paulo Zanonif278d972012-05-28 16:42:50 -0300412 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300413 POSTING_READ(reg);
Paulo Zanonif278d972012-05-28 16:42:50 -0300414
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300415 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
416 intel_hdmi_set_spd_infoframe(encoder);
417}
418
419static void ibx_set_infoframes(struct drm_encoder *encoder,
420 struct drm_display_mode *adjusted_mode)
421{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300422 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
423 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
424 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
425 u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
426 u32 val = I915_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300427 u32 port;
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300428
Daniel Vetterafba0182012-06-12 16:36:45 +0200429 assert_hdmi_port_disabled(intel_hdmi);
430
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300431 /* See the big comment in g4x_set_infoframes() */
432 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
433
434 if (!intel_hdmi->has_hdmi_sink) {
435 if (!(val & VIDEO_DIP_ENABLE))
436 return;
437 val &= ~VIDEO_DIP_ENABLE;
438 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300439 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300440 return;
441 }
442
Paulo Zanonif278d972012-05-28 16:42:50 -0300443 switch (intel_hdmi->sdvox_reg) {
444 case HDMIB:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300445 port = VIDEO_DIP_PORT_B;
Paulo Zanonif278d972012-05-28 16:42:50 -0300446 break;
447 case HDMIC:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300448 port = VIDEO_DIP_PORT_C;
Paulo Zanonif278d972012-05-28 16:42:50 -0300449 break;
450 case HDMID:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300451 port = VIDEO_DIP_PORT_D;
Paulo Zanonif278d972012-05-28 16:42:50 -0300452 break;
453 default:
Paulo Zanoni57df2ae2012-09-24 10:32:54 -0300454 BUG();
Paulo Zanonif278d972012-05-28 16:42:50 -0300455 return;
456 }
457
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300458 if (port != (val & VIDEO_DIP_PORT_MASK)) {
459 if (val & VIDEO_DIP_ENABLE) {
460 val &= ~VIDEO_DIP_ENABLE;
461 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300462 POSTING_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300463 }
464 val &= ~VIDEO_DIP_PORT_MASK;
465 val |= port;
466 }
467
Paulo Zanoni822974a2012-05-28 16:42:51 -0300468 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300469 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
470 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300471
Paulo Zanonif278d972012-05-28 16:42:50 -0300472 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300473 POSTING_READ(reg);
Paulo Zanonif278d972012-05-28 16:42:50 -0300474
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300475 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
476 intel_hdmi_set_spd_infoframe(encoder);
477}
478
479static void cpt_set_infoframes(struct drm_encoder *encoder,
480 struct drm_display_mode *adjusted_mode)
481{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300482 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
483 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
484 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
485 u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
486 u32 val = I915_READ(reg);
487
Daniel Vetterafba0182012-06-12 16:36:45 +0200488 assert_hdmi_port_disabled(intel_hdmi);
489
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300490 /* See the big comment in g4x_set_infoframes() */
491 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
492
493 if (!intel_hdmi->has_hdmi_sink) {
494 if (!(val & VIDEO_DIP_ENABLE))
495 return;
496 val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI);
497 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300498 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300499 return;
500 }
501
Paulo Zanoni822974a2012-05-28 16:42:51 -0300502 /* Set both together, unset both together: see the spec. */
503 val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300504 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
505 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300506
507 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300508 POSTING_READ(reg);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300509
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300510 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
511 intel_hdmi_set_spd_infoframe(encoder);
512}
513
514static void vlv_set_infoframes(struct drm_encoder *encoder,
515 struct drm_display_mode *adjusted_mode)
516{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300517 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
518 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
519 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
520 u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
521 u32 val = I915_READ(reg);
522
Daniel Vetterafba0182012-06-12 16:36:45 +0200523 assert_hdmi_port_disabled(intel_hdmi);
524
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300525 /* See the big comment in g4x_set_infoframes() */
526 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
527
528 if (!intel_hdmi->has_hdmi_sink) {
529 if (!(val & VIDEO_DIP_ENABLE))
530 return;
531 val &= ~VIDEO_DIP_ENABLE;
532 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300533 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300534 return;
535 }
536
Paulo Zanoni822974a2012-05-28 16:42:51 -0300537 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300538 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
539 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300540
541 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300542 POSTING_READ(reg);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300543
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300544 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
545 intel_hdmi_set_spd_infoframe(encoder);
546}
547
548static void hsw_set_infoframes(struct drm_encoder *encoder,
549 struct drm_display_mode *adjusted_mode)
550{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300551 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
552 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
553 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
554 u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300555 u32 val = I915_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300556
Daniel Vetterafba0182012-06-12 16:36:45 +0200557 assert_hdmi_port_disabled(intel_hdmi);
558
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300559 if (!intel_hdmi->has_hdmi_sink) {
560 I915_WRITE(reg, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300561 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300562 return;
563 }
564
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300565 val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
566 VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
567
568 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300569 POSTING_READ(reg);
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300570
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300571 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
572 intel_hdmi_set_spd_infoframe(encoder);
573}
574
Eric Anholt7d573822009-01-02 13:33:00 -0800575static void intel_hdmi_mode_set(struct drm_encoder *encoder,
576 struct drm_display_mode *mode,
577 struct drm_display_mode *adjusted_mode)
578{
579 struct drm_device *dev = encoder->dev;
580 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300581 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100582 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
Eric Anholt7d573822009-01-02 13:33:00 -0800583 u32 sdvox;
584
Paulo Zanonib659c3d2012-05-28 16:42:56 -0300585 sdvox = SDVO_ENCODING_HDMI;
Jesse Barnes5d4fac92011-06-24 12:19:19 -0700586 if (!HAS_PCH_SPLIT(dev))
587 sdvox |= intel_hdmi->color_range;
Adam Jacksonb599c0b2010-07-16 14:46:31 -0400588 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
589 sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
590 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
591 sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
Eric Anholt7d573822009-01-02 13:33:00 -0800592
Jesse Barnes020f6702011-06-24 12:19:25 -0700593 if (intel_crtc->bpp > 24)
594 sdvox |= COLOR_FORMAT_12bpc;
595 else
596 sdvox |= COLOR_FORMAT_8bpc;
597
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800598 /* Required on CPT */
599 if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
600 sdvox |= HDMI_MODE_SELECT;
601
David Härdeman3c17fe42010-09-24 21:44:32 +0200602 if (intel_hdmi->has_audio) {
Wu Fengguange0dac652011-09-05 14:25:34 +0800603 DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
604 pipe_name(intel_crtc->pipe));
Eric Anholt7d573822009-01-02 13:33:00 -0800605 sdvox |= SDVO_AUDIO_ENABLE;
David Härdeman3c17fe42010-09-24 21:44:32 +0200606 sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
Wu Fengguange0dac652011-09-05 14:25:34 +0800607 intel_write_eld(encoder, adjusted_mode);
David Härdeman3c17fe42010-09-24 21:44:32 +0200608 }
Eric Anholt7d573822009-01-02 13:33:00 -0800609
Jesse Barnes75770562011-10-12 09:01:58 -0700610 if (HAS_PCH_CPT(dev))
611 sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
Daniel Vetter7a87c282012-06-05 11:03:39 +0200612 else if (intel_crtc->pipe == PIPE_B)
Jesse Barnes75770562011-10-12 09:01:58 -0700613 sdvox |= SDVO_PIPE_B_SELECT;
Eric Anholt7d573822009-01-02 13:33:00 -0800614
Chris Wilsonea5b2132010-08-04 13:50:23 +0100615 I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
616 POSTING_READ(intel_hdmi->sdvox_reg);
David Härdeman3c17fe42010-09-24 21:44:32 +0200617
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300618 intel_hdmi->set_infoframes(encoder, adjusted_mode);
Eric Anholt7d573822009-01-02 13:33:00 -0800619}
620
Daniel Vetter85234cd2012-07-02 13:27:29 +0200621static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
622 enum pipe *pipe)
Eric Anholt7d573822009-01-02 13:33:00 -0800623{
Daniel Vetter85234cd2012-07-02 13:27:29 +0200624 struct drm_device *dev = encoder->base.dev;
Eric Anholt7d573822009-01-02 13:33:00 -0800625 struct drm_i915_private *dev_priv = dev->dev_private;
Daniel Vetter85234cd2012-07-02 13:27:29 +0200626 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
627 u32 tmp;
628
629 tmp = I915_READ(intel_hdmi->sdvox_reg);
630
631 if (!(tmp & SDVO_ENABLE))
632 return false;
633
634 if (HAS_PCH_CPT(dev))
635 *pipe = PORT_TO_PIPE_CPT(tmp);
636 else
637 *pipe = PORT_TO_PIPE(tmp);
638
639 return true;
640}
641
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200642static void intel_enable_hdmi(struct intel_encoder *encoder)
Eric Anholt7d573822009-01-02 13:33:00 -0800643{
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200644 struct drm_device *dev = encoder->base.dev;
Eric Anholt7d573822009-01-02 13:33:00 -0800645 struct drm_i915_private *dev_priv = dev->dev_private;
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200646 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
Eric Anholt7d573822009-01-02 13:33:00 -0800647 u32 temp;
Wu Fengguang2deed762011-12-09 20:42:20 +0800648 u32 enable_bits = SDVO_ENABLE;
649
650 if (intel_hdmi->has_audio)
651 enable_bits |= SDVO_AUDIO_ENABLE;
Eric Anholt7d573822009-01-02 13:33:00 -0800652
Chris Wilsonea5b2132010-08-04 13:50:23 +0100653 temp = I915_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000654
Daniel Vetter7a87c282012-06-05 11:03:39 +0200655 /* HW workaround for IBX, we need to move the port to transcoder A
656 * before disabling it. */
657 if (HAS_PCH_IBX(dev)) {
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200658 struct drm_crtc *crtc = encoder->base.crtc;
Daniel Vetter7a87c282012-06-05 11:03:39 +0200659 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
660
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200661 /* Restore the transcoder select bit. */
662 if (pipe == PIPE_B)
663 enable_bits |= SDVO_PIPE_B_SELECT;
664 }
Daniel Vetter7a87c282012-06-05 11:03:39 +0200665
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200666 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
667 * we do this anyway which shows more stable in testing.
668 */
669 if (HAS_PCH_SPLIT(dev)) {
670 I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
671 POSTING_READ(intel_hdmi->sdvox_reg);
672 }
Daniel Vetter7a87c282012-06-05 11:03:39 +0200673
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200674 temp |= enable_bits;
675
676 I915_WRITE(intel_hdmi->sdvox_reg, temp);
677 POSTING_READ(intel_hdmi->sdvox_reg);
678
679 /* HW workaround, need to write this twice for issue that may result
680 * in first write getting masked.
681 */
682 if (HAS_PCH_SPLIT(dev)) {
683 I915_WRITE(intel_hdmi->sdvox_reg, temp);
684 POSTING_READ(intel_hdmi->sdvox_reg);
685 }
686}
687
688static void intel_disable_hdmi(struct intel_encoder *encoder)
689{
690 struct drm_device *dev = encoder->base.dev;
691 struct drm_i915_private *dev_priv = dev->dev_private;
692 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
693 u32 temp;
Wang Xingchao3cce5742012-09-13 11:19:00 +0800694 u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200695
696 temp = I915_READ(intel_hdmi->sdvox_reg);
697
698 /* HW workaround for IBX, we need to move the port to transcoder A
699 * before disabling it. */
700 if (HAS_PCH_IBX(dev)) {
701 struct drm_crtc *crtc = encoder->base.crtc;
702 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
703
704 if (temp & SDVO_PIPE_B_SELECT) {
705 temp &= ~SDVO_PIPE_B_SELECT;
706 I915_WRITE(intel_hdmi->sdvox_reg, temp);
707 POSTING_READ(intel_hdmi->sdvox_reg);
708
709 /* Again we need to write this twice. */
710 I915_WRITE(intel_hdmi->sdvox_reg, temp);
711 POSTING_READ(intel_hdmi->sdvox_reg);
712
713 /* Transcoder selection bits only update
714 * effectively on vblank. */
715 if (crtc)
716 intel_wait_for_vblank(dev, pipe);
717 else
718 msleep(50);
Daniel Vetter7a87c282012-06-05 11:03:39 +0200719 }
720 }
721
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000722 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
723 * we do this anyway which shows more stable in testing.
724 */
Eric Anholtc619eed2010-01-28 16:45:52 -0800725 if (HAS_PCH_SPLIT(dev)) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100726 I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
727 POSTING_READ(intel_hdmi->sdvox_reg);
Eric Anholt7d573822009-01-02 13:33:00 -0800728 }
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000729
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200730 temp &= ~enable_bits;
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000731
Chris Wilsonea5b2132010-08-04 13:50:23 +0100732 I915_WRITE(intel_hdmi->sdvox_reg, temp);
733 POSTING_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000734
735 /* HW workaround, need to write this twice for issue that may result
736 * in first write getting masked.
737 */
Eric Anholtc619eed2010-01-28 16:45:52 -0800738 if (HAS_PCH_SPLIT(dev)) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100739 I915_WRITE(intel_hdmi->sdvox_reg, temp);
740 POSTING_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000741 }
Eric Anholt7d573822009-01-02 13:33:00 -0800742}
743
Eric Anholt7d573822009-01-02 13:33:00 -0800744static int intel_hdmi_mode_valid(struct drm_connector *connector,
745 struct drm_display_mode *mode)
746{
747 if (mode->clock > 165000)
748 return MODE_CLOCK_HIGH;
749 if (mode->clock < 20000)
Nicolas Kaiser5cbba412011-05-30 12:48:26 +0200750 return MODE_CLOCK_LOW;
Eric Anholt7d573822009-01-02 13:33:00 -0800751
752 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
753 return MODE_NO_DBLESCAN;
754
755 return MODE_OK;
756}
757
758static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +0200759 const struct drm_display_mode *mode,
Eric Anholt7d573822009-01-02 13:33:00 -0800760 struct drm_display_mode *adjusted_mode)
761{
762 return true;
763}
764
Chris Wilson8ec22b22012-05-11 18:01:34 +0100765static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
766{
767 struct drm_device *dev = intel_hdmi->base.base.dev;
768 struct drm_i915_private *dev_priv = dev->dev_private;
769 uint32_t bit;
770
771 switch (intel_hdmi->sdvox_reg) {
Chris Wilsoneeafaac2012-05-25 10:23:37 +0100772 case SDVOB:
Chris Wilson8ec22b22012-05-11 18:01:34 +0100773 bit = HDMIB_HOTPLUG_LIVE_STATUS;
774 break;
Chris Wilsoneeafaac2012-05-25 10:23:37 +0100775 case SDVOC:
Chris Wilson8ec22b22012-05-11 18:01:34 +0100776 bit = HDMIC_HOTPLUG_LIVE_STATUS;
777 break;
Chris Wilson8ec22b22012-05-11 18:01:34 +0100778 default:
779 bit = 0;
780 break;
781 }
782
783 return I915_READ(PORT_HOTPLUG_STAT) & bit;
784}
785
Keith Packardaa93d632009-05-05 09:52:46 -0700786static enum drm_connector_status
Chris Wilson930a9e22010-09-14 11:07:23 +0100787intel_hdmi_detect(struct drm_connector *connector, bool force)
Ma Ling9dff6af2009-04-02 13:13:26 +0800788{
Chris Wilsondf0e9242010-09-09 16:20:55 +0100789 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsonf899fc62010-07-20 15:44:45 -0700790 struct drm_i915_private *dev_priv = connector->dev->dev_private;
791 struct edid *edid;
Keith Packardaa93d632009-05-05 09:52:46 -0700792 enum drm_connector_status status = connector_status_disconnected;
Ma Ling9dff6af2009-04-02 13:13:26 +0800793
Chris Wilson8ec22b22012-05-11 18:01:34 +0100794 if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
795 return status;
796
Chris Wilsonea5b2132010-08-04 13:50:23 +0100797 intel_hdmi->has_hdmi_sink = false;
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800798 intel_hdmi->has_audio = false;
Chris Wilsonf899fc62010-07-20 15:44:45 -0700799 edid = drm_get_edid(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800800 intel_gmbus_get_adapter(dev_priv,
801 intel_hdmi->ddc_bus));
ling.ma@intel.com2ded9e22009-07-16 17:23:09 +0800802
Keith Packardaa93d632009-05-05 09:52:46 -0700803 if (edid) {
Eric Anholtbe9f1c42009-06-21 22:14:55 -0700804 if (edid->input & DRM_EDID_INPUT_DIGITAL) {
Keith Packardaa93d632009-05-05 09:52:46 -0700805 status = connector_status_connected;
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800806 if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
807 intel_hdmi->has_hdmi_sink =
808 drm_detect_hdmi_monitor(edid);
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800809 intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
Keith Packardaa93d632009-05-05 09:52:46 -0700810 }
Keith Packardaa93d632009-05-05 09:52:46 -0700811 kfree(edid);
Ma Ling9dff6af2009-04-02 13:13:26 +0800812 }
ling.ma@intel.com2ded9e22009-07-16 17:23:09 +0800813
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100814 if (status == connector_status_connected) {
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800815 if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
816 intel_hdmi->has_audio =
817 (intel_hdmi->force_audio == HDMI_AUDIO_ON);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100818 }
819
Keith Packardaa93d632009-05-05 09:52:46 -0700820 return status;
Ma Ling9dff6af2009-04-02 13:13:26 +0800821}
822
Eric Anholt7d573822009-01-02 13:33:00 -0800823static int intel_hdmi_get_modes(struct drm_connector *connector)
824{
Chris Wilsondf0e9242010-09-09 16:20:55 +0100825 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsonf899fc62010-07-20 15:44:45 -0700826 struct drm_i915_private *dev_priv = connector->dev->dev_private;
Eric Anholt7d573822009-01-02 13:33:00 -0800827
828 /* We should parse the EDID data and find out if it's an HDMI sink so
829 * we can send audio to it.
830 */
831
Chris Wilsonf899fc62010-07-20 15:44:45 -0700832 return intel_ddc_get_modes(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800833 intel_gmbus_get_adapter(dev_priv,
834 intel_hdmi->ddc_bus));
Eric Anholt7d573822009-01-02 13:33:00 -0800835}
836
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000837static bool
838intel_hdmi_detect_audio(struct drm_connector *connector)
839{
840 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
841 struct drm_i915_private *dev_priv = connector->dev->dev_private;
842 struct edid *edid;
843 bool has_audio = false;
844
845 edid = drm_get_edid(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800846 intel_gmbus_get_adapter(dev_priv,
847 intel_hdmi->ddc_bus));
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000848 if (edid) {
849 if (edid->input & DRM_EDID_INPUT_DIGITAL)
850 has_audio = drm_detect_monitor_audio(edid);
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000851 kfree(edid);
852 }
853
854 return has_audio;
855}
856
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100857static int
858intel_hdmi_set_property(struct drm_connector *connector,
Paulo Zanonied517fb2012-05-14 17:12:50 -0300859 struct drm_property *property,
860 uint64_t val)
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100861{
862 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsone953fd72011-02-21 22:23:52 +0000863 struct drm_i915_private *dev_priv = connector->dev->dev_private;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100864 int ret;
865
866 ret = drm_connector_property_set_value(connector, property, val);
867 if (ret)
868 return ret;
869
Chris Wilson3f43c482011-05-12 22:17:24 +0100870 if (property == dev_priv->force_audio_property) {
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800871 enum hdmi_force_audio i = val;
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000872 bool has_audio;
873
874 if (i == intel_hdmi->force_audio)
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100875 return 0;
876
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000877 intel_hdmi->force_audio = i;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100878
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800879 if (i == HDMI_AUDIO_AUTO)
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000880 has_audio = intel_hdmi_detect_audio(connector);
881 else
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800882 has_audio = (i == HDMI_AUDIO_ON);
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000883
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800884 if (i == HDMI_AUDIO_OFF_DVI)
885 intel_hdmi->has_hdmi_sink = 0;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100886
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000887 intel_hdmi->has_audio = has_audio;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100888 goto done;
889 }
890
Chris Wilsone953fd72011-02-21 22:23:52 +0000891 if (property == dev_priv->broadcast_rgb_property) {
892 if (val == !!intel_hdmi->color_range)
893 return 0;
894
895 intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
896 goto done;
897 }
898
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100899 return -EINVAL;
900
901done:
902 if (intel_hdmi->base.base.crtc) {
903 struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
Daniel Vettera6778b32012-07-02 09:56:42 +0200904 intel_set_mode(crtc, &crtc->mode,
905 crtc->x, crtc->y, crtc->fb);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100906 }
907
908 return 0;
909}
910
Eric Anholt7d573822009-01-02 13:33:00 -0800911static void intel_hdmi_destroy(struct drm_connector *connector)
912{
Eric Anholt7d573822009-01-02 13:33:00 -0800913 drm_sysfs_connector_remove(connector);
914 drm_connector_cleanup(connector);
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800915 kfree(connector);
Eric Anholt7d573822009-01-02 13:33:00 -0800916}
917
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300918static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300919 .mode_fixup = intel_hdmi_mode_fixup,
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300920 .mode_set = intel_ddi_mode_set,
Daniel Vetter1f703852012-07-11 16:51:39 +0200921 .disable = intel_encoder_noop,
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300922};
923
Eric Anholt7d573822009-01-02 13:33:00 -0800924static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
Eric Anholt7d573822009-01-02 13:33:00 -0800925 .mode_fixup = intel_hdmi_mode_fixup,
Eric Anholt7d573822009-01-02 13:33:00 -0800926 .mode_set = intel_hdmi_mode_set,
Daniel Vetter1f703852012-07-11 16:51:39 +0200927 .disable = intel_encoder_noop,
Eric Anholt7d573822009-01-02 13:33:00 -0800928};
929
930static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200931 .dpms = intel_connector_dpms,
Eric Anholt7d573822009-01-02 13:33:00 -0800932 .detect = intel_hdmi_detect,
933 .fill_modes = drm_helper_probe_single_connector_modes,
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100934 .set_property = intel_hdmi_set_property,
Eric Anholt7d573822009-01-02 13:33:00 -0800935 .destroy = intel_hdmi_destroy,
936};
937
938static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
939 .get_modes = intel_hdmi_get_modes,
940 .mode_valid = intel_hdmi_mode_valid,
Chris Wilsondf0e9242010-09-09 16:20:55 +0100941 .best_encoder = intel_best_encoder,
Eric Anholt7d573822009-01-02 13:33:00 -0800942};
943
Eric Anholt7d573822009-01-02 13:33:00 -0800944static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100945 .destroy = intel_encoder_destroy,
Eric Anholt7d573822009-01-02 13:33:00 -0800946};
947
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100948static void
949intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
950{
Chris Wilson3f43c482011-05-12 22:17:24 +0100951 intel_attach_force_audio_property(connector);
Chris Wilsone953fd72011-02-21 22:23:52 +0000952 intel_attach_broadcast_rgb_property(connector);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100953}
954
Daniel Vetter08d644a2012-07-12 20:19:59 +0200955void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
Eric Anholt7d573822009-01-02 13:33:00 -0800956{
957 struct drm_i915_private *dev_priv = dev->dev_private;
958 struct drm_connector *connector;
Eric Anholt21d40d32010-03-25 11:11:14 -0700959 struct intel_encoder *intel_encoder;
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800960 struct intel_connector *intel_connector;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100961 struct intel_hdmi *intel_hdmi;
Eric Anholt7d573822009-01-02 13:33:00 -0800962
Chris Wilsonea5b2132010-08-04 13:50:23 +0100963 intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL);
964 if (!intel_hdmi)
Eric Anholt7d573822009-01-02 13:33:00 -0800965 return;
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800966
967 intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
968 if (!intel_connector) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100969 kfree(intel_hdmi);
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800970 return;
971 }
972
Chris Wilsonea5b2132010-08-04 13:50:23 +0100973 intel_encoder = &intel_hdmi->base;
Chris Wilson373a3cf2010-09-15 12:03:59 +0100974 drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
975 DRM_MODE_ENCODER_TMDS);
976
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800977 connector = &intel_connector->base;
Eric Anholt7d573822009-01-02 13:33:00 -0800978 drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
Adam Jackson8d911042009-09-23 15:08:29 -0400979 DRM_MODE_CONNECTOR_HDMIA);
Eric Anholt7d573822009-01-02 13:33:00 -0800980 drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
981
Eric Anholt21d40d32010-03-25 11:11:14 -0700982 intel_encoder->type = INTEL_OUTPUT_HDMI;
Eric Anholt7d573822009-01-02 13:33:00 -0800983
Dave Airlieeb1f8e42010-05-07 06:42:51 +0000984 connector->polled = DRM_CONNECTOR_POLL_HPD;
Peter Rossc3febcc2012-01-28 14:49:26 +0100985 connector->interlace_allowed = 1;
Eric Anholt7d573822009-01-02 13:33:00 -0800986 connector->doublescan_allowed = 0;
Jesse Barnes27f82272011-09-02 12:54:37 -0700987 intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
Eric Anholt7d573822009-01-02 13:33:00 -0800988
Daniel Vetter66a92782012-07-12 20:08:18 +0200989 intel_encoder->cloneable = false;
990
Daniel Vetter08d644a2012-07-12 20:19:59 +0200991 intel_hdmi->ddi_port = port;
992 switch (port) {
993 case PORT_B:
Chris Wilsonf899fc62010-07-20 15:44:45 -0700994 intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
Jesse Barnesb01f2c32009-12-11 11:07:17 -0800995 dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +0200996 break;
997 case PORT_C:
Chris Wilsonf899fc62010-07-20 15:44:45 -0700998 intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
Jesse Barnesb01f2c32009-12-11 11:07:17 -0800999 dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +02001000 break;
1001 case PORT_D:
Chris Wilsonf899fc62010-07-20 15:44:45 -07001002 intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
Jesse Barnesb01f2c32009-12-11 11:07:17 -08001003 dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +02001004 break;
1005 case PORT_A:
1006 /* Internal port only for eDP. */
1007 default:
Eugeni Dodonov6e4c1672012-05-09 15:37:13 -03001008 BUG();
Ma Lingf8aed702009-08-24 13:50:24 +08001009 }
Eric Anholt7d573822009-01-02 13:33:00 -08001010
Chris Wilsonea5b2132010-08-04 13:50:23 +01001011 intel_hdmi->sdvox_reg = sdvox_reg;
Eric Anholt7d573822009-01-02 13:33:00 -08001012
Jesse Barnes64a8fc02011-09-22 11:16:00 +05301013 if (!HAS_PCH_SPLIT(dev)) {
Daniel Vettera3da1df2012-05-08 15:19:06 +02001014 intel_hdmi->write_infoframe = g4x_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001015 intel_hdmi->set_infoframes = g4x_set_infoframes;
Shobhit Kumar90b107c2012-03-28 13:39:32 -07001016 } else if (IS_VALLEYVIEW(dev)) {
1017 intel_hdmi->write_infoframe = vlv_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001018 intel_hdmi->set_infoframes = vlv_set_infoframes;
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -03001019 } else if (IS_HASWELL(dev)) {
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -03001020 intel_hdmi->write_infoframe = hsw_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001021 intel_hdmi->set_infoframes = hsw_set_infoframes;
Paulo Zanonifdf12502012-05-04 17:18:24 -03001022 } else if (HAS_PCH_IBX(dev)) {
1023 intel_hdmi->write_infoframe = ibx_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001024 intel_hdmi->set_infoframes = ibx_set_infoframes;
Paulo Zanonifdf12502012-05-04 17:18:24 -03001025 } else {
1026 intel_hdmi->write_infoframe = cpt_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001027 intel_hdmi->set_infoframes = cpt_set_infoframes;
Jesse Barnes64a8fc02011-09-22 11:16:00 +05301028 }
Jesse Barnes45187ac2011-08-03 09:22:55 -07001029
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001030 if (IS_HASWELL(dev)) {
1031 intel_encoder->enable = intel_enable_ddi;
1032 intel_encoder->disable = intel_disable_ddi;
Daniel Vetter85234cd2012-07-02 13:27:29 +02001033 intel_encoder->get_hw_state = intel_ddi_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001034 drm_encoder_helper_add(&intel_encoder->base,
1035 &intel_hdmi_helper_funcs_hsw);
1036 } else {
1037 intel_encoder->enable = intel_enable_hdmi;
1038 intel_encoder->disable = intel_disable_hdmi;
Daniel Vetter85234cd2012-07-02 13:27:29 +02001039 intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001040 drm_encoder_helper_add(&intel_encoder->base,
1041 &intel_hdmi_helper_funcs);
1042 }
Daniel Vetter85234cd2012-07-02 13:27:29 +02001043 intel_connector->get_hw_state = intel_connector_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001044
Eric Anholt7d573822009-01-02 13:33:00 -08001045
Chris Wilson55b7d6e82010-09-19 09:29:33 +01001046 intel_hdmi_add_properties(intel_hdmi, connector);
1047
Chris Wilsondf0e9242010-09-09 16:20:55 +01001048 intel_connector_attach_encoder(intel_connector, intel_encoder);
Eric Anholt7d573822009-01-02 13:33:00 -08001049 drm_sysfs_connector_add(connector);
1050
1051 /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
1052 * 0xd. Failure to do so will result in spurious interrupts being
1053 * generated on the port when a cable is not attached.
1054 */
1055 if (IS_G4X(dev) && !IS_GM45(dev)) {
1056 u32 temp = I915_READ(PEG_BAND_GAP_DATA);
1057 I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
1058 }
Eric Anholt7d573822009-01-02 13:33:00 -08001059}