blob: e2215a4fa9e1e72a82981264bc2510ced0144f0c [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>
David Howells760285e2012-10-02 18:01:07 +010032#include <drm/drmP.h>
33#include <drm/drm_crtc.h>
34#include <drm/drm_edid.h>
Eric Anholt7d573822009-01-02 13:33:00 -080035#include "intel_drv.h"
David Howells760285e2012-10-02 18:01:07 +010036#include <drm/i915_drm.h>
Eric Anholt7d573822009-01-02 13:33:00 -080037#include "i915_drv.h"
38
Paulo Zanoni30add222012-10-26 19:05:45 -020039static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
40{
41 return intel_hdmi->base.base.dev;
42}
43
Daniel Vetterafba0182012-06-12 16:36:45 +020044static void
45assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi)
46{
Paulo Zanoni30add222012-10-26 19:05:45 -020047 struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
Daniel Vetterafba0182012-06-12 16:36:45 +020048 struct drm_i915_private *dev_priv = dev->dev_private;
49 uint32_t enabled_bits;
50
51 enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE;
52
53 WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits,
54 "HDMI port enabled, expecting disabled\n");
55}
56
Eugeni Dodonovf5bbfca2012-05-09 15:37:30 -030057struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
Chris Wilsonea5b2132010-08-04 13:50:23 +010058{
Chris Wilson4ef69c72010-09-09 15:14:28 +010059 return container_of(encoder, struct intel_hdmi, base.base);
Chris Wilsonea5b2132010-08-04 13:50:23 +010060}
61
Chris Wilsondf0e9242010-09-09 16:20:55 +010062static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
63{
64 return container_of(intel_attached_encoder(connector),
65 struct intel_hdmi, base);
66}
67
Jesse Barnes45187ac2011-08-03 09:22:55 -070068void intel_dip_infoframe_csum(struct dip_infoframe *frame)
David Härdeman3c17fe42010-09-24 21:44:32 +020069{
Jesse Barnes45187ac2011-08-03 09:22:55 -070070 uint8_t *data = (uint8_t *)frame;
David Härdeman3c17fe42010-09-24 21:44:32 +020071 uint8_t sum = 0;
72 unsigned i;
73
Jesse Barnes45187ac2011-08-03 09:22:55 -070074 frame->checksum = 0;
75 frame->ecc = 0;
David Härdeman3c17fe42010-09-24 21:44:32 +020076
Jesse Barnes64a8fc02011-09-22 11:16:00 +053077 for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++)
David Härdeman3c17fe42010-09-24 21:44:32 +020078 sum += data[i];
79
Jesse Barnes45187ac2011-08-03 09:22:55 -070080 frame->checksum = 0x100 - sum;
David Härdeman3c17fe42010-09-24 21:44:32 +020081}
82
Daniel Vetterbc2481f2012-05-08 15:18:32 +020083static u32 g4x_infoframe_index(struct dip_infoframe *frame)
David Härdeman3c17fe42010-09-24 21:44:32 +020084{
Jesse Barnes45187ac2011-08-03 09:22:55 -070085 switch (frame->type) {
86 case DIP_TYPE_AVI:
Paulo Zanonied517fb2012-05-14 17:12:50 -030087 return VIDEO_DIP_SELECT_AVI;
Jesse Barnes45187ac2011-08-03 09:22:55 -070088 case DIP_TYPE_SPD:
Paulo Zanonied517fb2012-05-14 17:12:50 -030089 return VIDEO_DIP_SELECT_SPD;
Jesse Barnes45187ac2011-08-03 09:22:55 -070090 default:
91 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
Paulo Zanonied517fb2012-05-14 17:12:50 -030092 return 0;
Jesse Barnes45187ac2011-08-03 09:22:55 -070093 }
Jesse Barnes45187ac2011-08-03 09:22:55 -070094}
95
Daniel Vetterbc2481f2012-05-08 15:18:32 +020096static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -070097{
Jesse Barnes45187ac2011-08-03 09:22:55 -070098 switch (frame->type) {
99 case DIP_TYPE_AVI:
Paulo Zanonied517fb2012-05-14 17:12:50 -0300100 return VIDEO_DIP_ENABLE_AVI;
Jesse Barnes45187ac2011-08-03 09:22:55 -0700101 case DIP_TYPE_SPD:
Paulo Zanonied517fb2012-05-14 17:12:50 -0300102 return VIDEO_DIP_ENABLE_SPD;
Paulo Zanonifa193ff2012-05-04 17:18:20 -0300103 default:
104 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
Paulo Zanonied517fb2012-05-14 17:12:50 -0300105 return 0;
Paulo Zanonifa193ff2012-05-04 17:18:20 -0300106 }
Paulo Zanonifa193ff2012-05-04 17:18:20 -0300107}
108
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300109static u32 hsw_infoframe_enable(struct dip_infoframe *frame)
110{
111 switch (frame->type) {
112 case DIP_TYPE_AVI:
113 return VIDEO_DIP_ENABLE_AVI_HSW;
114 case DIP_TYPE_SPD:
115 return VIDEO_DIP_ENABLE_SPD_HSW;
116 default:
117 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
118 return 0;
119 }
120}
121
122static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
123{
124 switch (frame->type) {
125 case DIP_TYPE_AVI:
126 return HSW_TVIDEO_DIP_AVI_DATA(pipe);
127 case DIP_TYPE_SPD:
128 return HSW_TVIDEO_DIP_SPD_DATA(pipe);
129 default:
130 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
131 return 0;
132 }
133}
134
Daniel Vettera3da1df2012-05-08 15:19:06 +0200135static void g4x_write_infoframe(struct drm_encoder *encoder,
136 struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -0700137{
138 uint32_t *data = (uint32_t *)frame;
David Härdeman3c17fe42010-09-24 21:44:32 +0200139 struct drm_device *dev = encoder->dev;
140 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300141 u32 val = I915_READ(VIDEO_DIP_CTL);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700142 unsigned i, len = DIP_HEADER_SIZE + frame->len;
David Härdeman3c17fe42010-09-24 21:44:32 +0200143
Paulo Zanoni822974a2012-05-28 16:42:51 -0300144 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
145
Paulo Zanoni1d4f85a2012-05-04 17:18:18 -0300146 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200147 val |= g4x_infoframe_index(frame);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700148
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200149 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300150
151 I915_WRITE(VIDEO_DIP_CTL, val);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700152
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300153 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700154 for (i = 0; i < len; i += 4) {
David Härdeman3c17fe42010-09-24 21:44:32 +0200155 I915_WRITE(VIDEO_DIP_DATA, *data);
156 data++;
157 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300158 /* Write every possible data byte to force correct ECC calculation. */
159 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
160 I915_WRITE(VIDEO_DIP_DATA, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300161 mmiowb();
David Härdeman3c17fe42010-09-24 21:44:32 +0200162
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200163 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300164 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200165 val |= VIDEO_DIP_FREQ_VSYNC;
Jesse Barnes45187ac2011-08-03 09:22:55 -0700166
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300167 I915_WRITE(VIDEO_DIP_CTL, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300168 POSTING_READ(VIDEO_DIP_CTL);
David Härdeman3c17fe42010-09-24 21:44:32 +0200169}
170
Paulo Zanonifdf12502012-05-04 17:18:24 -0300171static void ibx_write_infoframe(struct drm_encoder *encoder,
172 struct dip_infoframe *frame)
173{
174 uint32_t *data = (uint32_t *)frame;
175 struct drm_device *dev = encoder->dev;
176 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300177 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300178 int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
179 unsigned i, len = DIP_HEADER_SIZE + frame->len;
180 u32 val = I915_READ(reg);
181
Paulo Zanoni822974a2012-05-28 16:42:51 -0300182 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
183
Paulo Zanonifdf12502012-05-04 17:18:24 -0300184 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200185 val |= g4x_infoframe_index(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300186
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200187 val &= ~g4x_infoframe_enable(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300188
189 I915_WRITE(reg, val);
190
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300191 mmiowb();
Paulo Zanonifdf12502012-05-04 17:18:24 -0300192 for (i = 0; i < len; i += 4) {
193 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
194 data++;
195 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300196 /* Write every possible data byte to force correct ECC calculation. */
197 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
198 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300199 mmiowb();
Paulo Zanonifdf12502012-05-04 17:18:24 -0300200
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200201 val |= g4x_infoframe_enable(frame);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300202 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200203 val |= VIDEO_DIP_FREQ_VSYNC;
Paulo Zanonifdf12502012-05-04 17:18:24 -0300204
205 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300206 POSTING_READ(reg);
Paulo Zanonifdf12502012-05-04 17:18:24 -0300207}
208
209static void cpt_write_infoframe(struct drm_encoder *encoder,
210 struct dip_infoframe *frame)
Jesse Barnes45187ac2011-08-03 09:22:55 -0700211{
212 uint32_t *data = (uint32_t *)frame;
213 struct drm_device *dev = encoder->dev;
214 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300215 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700216 int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
217 unsigned i, len = DIP_HEADER_SIZE + frame->len;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300218 u32 val = I915_READ(reg);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700219
Paulo Zanoni822974a2012-05-28 16:42:51 -0300220 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
221
Jesse Barnes64a8fc02011-09-22 11:16:00 +0530222 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200223 val |= g4x_infoframe_index(frame);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700224
Paulo Zanoniecb97852012-05-04 17:18:21 -0300225 /* The DIP control register spec says that we need to update the AVI
226 * infoframe without clearing its enable bit */
Paulo Zanoni822974a2012-05-28 16:42:51 -0300227 if (frame->type != DIP_TYPE_AVI)
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200228 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoniecb97852012-05-04 17:18:21 -0300229
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300230 I915_WRITE(reg, val);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700231
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300232 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700233 for (i = 0; i < len; i += 4) {
234 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
235 data++;
236 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300237 /* Write every possible data byte to force correct ECC calculation. */
238 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
239 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300240 mmiowb();
Jesse Barnes45187ac2011-08-03 09:22:55 -0700241
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200242 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300243 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200244 val |= VIDEO_DIP_FREQ_VSYNC;
Jesse Barnes45187ac2011-08-03 09:22:55 -0700245
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300246 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300247 POSTING_READ(reg);
Jesse Barnes45187ac2011-08-03 09:22:55 -0700248}
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700249
250static void vlv_write_infoframe(struct drm_encoder *encoder,
251 struct dip_infoframe *frame)
252{
253 uint32_t *data = (uint32_t *)frame;
254 struct drm_device *dev = encoder->dev;
255 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300256 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700257 int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
258 unsigned i, len = DIP_HEADER_SIZE + frame->len;
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300259 u32 val = I915_READ(reg);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700260
Paulo Zanoni822974a2012-05-28 16:42:51 -0300261 WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
262
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700263 val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200264 val |= g4x_infoframe_index(frame);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700265
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200266 val &= ~g4x_infoframe_enable(frame);
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300267
268 I915_WRITE(reg, val);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700269
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300270 mmiowb();
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700271 for (i = 0; i < len; i += 4) {
272 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
273 data++;
274 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300275 /* Write every possible data byte to force correct ECC calculation. */
276 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
277 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300278 mmiowb();
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700279
Daniel Vetterbc2481f2012-05-08 15:18:32 +0200280 val |= g4x_infoframe_enable(frame);
Paulo Zanoni60c5ea22012-05-04 17:18:22 -0300281 val &= ~VIDEO_DIP_FREQ_MASK;
Daniel Vetter4b24c932012-05-08 14:41:00 +0200282 val |= VIDEO_DIP_FREQ_VSYNC;
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700283
Paulo Zanoni22509ec2012-05-04 17:18:17 -0300284 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300285 POSTING_READ(reg);
Shobhit Kumar90b107c2012-03-28 13:39:32 -0700286}
287
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300288static void hsw_write_infoframe(struct drm_encoder *encoder,
Paulo Zanonied517fb2012-05-14 17:12:50 -0300289 struct dip_infoframe *frame)
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300290{
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300291 uint32_t *data = (uint32_t *)frame;
292 struct drm_device *dev = encoder->dev;
293 struct drm_i915_private *dev_priv = dev->dev_private;
294 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
295 u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
296 u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
297 unsigned int i, len = DIP_HEADER_SIZE + frame->len;
298 u32 val = I915_READ(ctl_reg);
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300299
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300300 if (data_reg == 0)
301 return;
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300302
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300303 val &= ~hsw_infoframe_enable(frame);
304 I915_WRITE(ctl_reg, val);
305
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300306 mmiowb();
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300307 for (i = 0; i < len; i += 4) {
308 I915_WRITE(data_reg + i, *data);
309 data++;
310 }
Paulo Zanoniadf00b22012-09-25 13:23:34 -0300311 /* Write every possible data byte to force correct ECC calculation. */
312 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
313 I915_WRITE(data_reg + i, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300314 mmiowb();
Paulo Zanoni2da8af52012-05-14 17:12:51 -0300315
316 val |= hsw_infoframe_enable(frame);
317 I915_WRITE(ctl_reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300318 POSTING_READ(ctl_reg);
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -0300319}
320
Jesse Barnes45187ac2011-08-03 09:22:55 -0700321static void intel_set_infoframe(struct drm_encoder *encoder,
322 struct dip_infoframe *frame)
323{
324 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
325
Jesse Barnes45187ac2011-08-03 09:22:55 -0700326 intel_dip_infoframe_csum(frame);
327 intel_hdmi->write_infoframe(encoder, frame);
328}
329
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300330static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
Paulo Zanonic846b612012-04-13 16:31:41 -0300331 struct drm_display_mode *adjusted_mode)
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700332{
333 struct dip_infoframe avi_if = {
334 .type = DIP_TYPE_AVI,
335 .ver = DIP_VERSION_AVI,
336 .len = DIP_LEN_AVI,
337 };
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700338
Paulo Zanonic846b612012-04-13 16:31:41 -0300339 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
340 avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
341
Jesse Barnes45187ac2011-08-03 09:22:55 -0700342 intel_set_infoframe(encoder, &avi_if);
Jesse Barnesb055c8f2011-07-08 11:31:57 -0700343}
344
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300345static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
Jesse Barnesc0864cb2011-08-03 09:22:56 -0700346{
347 struct dip_infoframe spd_if;
348
349 memset(&spd_if, 0, sizeof(spd_if));
350 spd_if.type = DIP_TYPE_SPD;
351 spd_if.ver = DIP_VERSION_SPD;
352 spd_if.len = DIP_LEN_SPD;
353 strcpy(spd_if.body.spd.vn, "Intel");
354 strcpy(spd_if.body.spd.pd, "Integrated gfx");
355 spd_if.body.spd.sdi = DIP_SPD_PC;
356
357 intel_set_infoframe(encoder, &spd_if);
358}
359
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300360static void g4x_set_infoframes(struct drm_encoder *encoder,
361 struct drm_display_mode *adjusted_mode)
362{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300363 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
364 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
365 u32 reg = VIDEO_DIP_CTL;
366 u32 val = I915_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300367 u32 port;
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300368
Daniel Vetterafba0182012-06-12 16:36:45 +0200369 assert_hdmi_port_disabled(intel_hdmi);
370
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300371 /* If the registers were not initialized yet, they might be zeroes,
372 * which means we're selecting the AVI DIP and we're setting its
373 * frequency to once. This seems to really confuse the HW and make
374 * things stop working (the register spec says the AVI always needs to
375 * be sent every VSync). So here we avoid writing to the register more
376 * than we need and also explicitly select the AVI DIP and explicitly
377 * set its frequency to every VSync. Avoiding to write it twice seems to
378 * be enough to solve the problem, but being defensive shouldn't hurt us
379 * either. */
380 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
381
382 if (!intel_hdmi->has_hdmi_sink) {
383 if (!(val & VIDEO_DIP_ENABLE))
384 return;
385 val &= ~VIDEO_DIP_ENABLE;
386 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300387 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300388 return;
389 }
390
Paulo Zanonif278d972012-05-28 16:42:50 -0300391 switch (intel_hdmi->sdvox_reg) {
392 case SDVOB:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300393 port = VIDEO_DIP_PORT_B;
Paulo Zanonif278d972012-05-28 16:42:50 -0300394 break;
395 case SDVOC:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300396 port = VIDEO_DIP_PORT_C;
Paulo Zanonif278d972012-05-28 16:42:50 -0300397 break;
398 default:
Paulo Zanoni57df2ae2012-09-24 10:32:54 -0300399 BUG();
Paulo Zanonif278d972012-05-28 16:42:50 -0300400 return;
401 }
402
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300403 if (port != (val & VIDEO_DIP_PORT_MASK)) {
404 if (val & VIDEO_DIP_ENABLE) {
405 val &= ~VIDEO_DIP_ENABLE;
406 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300407 POSTING_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300408 }
409 val &= ~VIDEO_DIP_PORT_MASK;
410 val |= port;
411 }
412
Paulo Zanoni822974a2012-05-28 16:42:51 -0300413 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300414 val &= ~VIDEO_DIP_ENABLE_VENDOR;
Paulo Zanoni822974a2012-05-28 16:42:51 -0300415
Paulo Zanonif278d972012-05-28 16:42:50 -0300416 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300417 POSTING_READ(reg);
Paulo Zanonif278d972012-05-28 16:42:50 -0300418
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300419 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
420 intel_hdmi_set_spd_infoframe(encoder);
421}
422
423static void ibx_set_infoframes(struct drm_encoder *encoder,
424 struct drm_display_mode *adjusted_mode)
425{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300426 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
427 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
428 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
429 u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
430 u32 val = I915_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300431 u32 port;
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300432
Daniel Vetterafba0182012-06-12 16:36:45 +0200433 assert_hdmi_port_disabled(intel_hdmi);
434
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300435 /* See the big comment in g4x_set_infoframes() */
436 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
437
438 if (!intel_hdmi->has_hdmi_sink) {
439 if (!(val & VIDEO_DIP_ENABLE))
440 return;
441 val &= ~VIDEO_DIP_ENABLE;
442 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300443 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300444 return;
445 }
446
Paulo Zanonif278d972012-05-28 16:42:50 -0300447 switch (intel_hdmi->sdvox_reg) {
448 case HDMIB:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300449 port = VIDEO_DIP_PORT_B;
Paulo Zanonif278d972012-05-28 16:42:50 -0300450 break;
451 case HDMIC:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300452 port = VIDEO_DIP_PORT_C;
Paulo Zanonif278d972012-05-28 16:42:50 -0300453 break;
454 case HDMID:
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300455 port = VIDEO_DIP_PORT_D;
Paulo Zanonif278d972012-05-28 16:42:50 -0300456 break;
457 default:
Paulo Zanoni57df2ae2012-09-24 10:32:54 -0300458 BUG();
Paulo Zanonif278d972012-05-28 16:42:50 -0300459 return;
460 }
461
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300462 if (port != (val & VIDEO_DIP_PORT_MASK)) {
463 if (val & VIDEO_DIP_ENABLE) {
464 val &= ~VIDEO_DIP_ENABLE;
465 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300466 POSTING_READ(reg);
Paulo Zanoni72b78c92012-05-28 16:42:54 -0300467 }
468 val &= ~VIDEO_DIP_PORT_MASK;
469 val |= port;
470 }
471
Paulo Zanoni822974a2012-05-28 16:42:51 -0300472 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300473 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
474 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300475
Paulo Zanonif278d972012-05-28 16:42:50 -0300476 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300477 POSTING_READ(reg);
Paulo Zanonif278d972012-05-28 16:42:50 -0300478
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300479 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
480 intel_hdmi_set_spd_infoframe(encoder);
481}
482
483static void cpt_set_infoframes(struct drm_encoder *encoder,
484 struct drm_display_mode *adjusted_mode)
485{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300486 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
487 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
488 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
489 u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
490 u32 val = I915_READ(reg);
491
Daniel Vetterafba0182012-06-12 16:36:45 +0200492 assert_hdmi_port_disabled(intel_hdmi);
493
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300494 /* See the big comment in g4x_set_infoframes() */
495 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
496
497 if (!intel_hdmi->has_hdmi_sink) {
498 if (!(val & VIDEO_DIP_ENABLE))
499 return;
500 val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI);
501 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300502 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300503 return;
504 }
505
Paulo Zanoni822974a2012-05-28 16:42:51 -0300506 /* Set both together, unset both together: see the spec. */
507 val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300508 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
509 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300510
511 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300512 POSTING_READ(reg);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300513
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300514 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
515 intel_hdmi_set_spd_infoframe(encoder);
516}
517
518static void vlv_set_infoframes(struct drm_encoder *encoder,
519 struct drm_display_mode *adjusted_mode)
520{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300521 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
522 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
523 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
524 u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
525 u32 val = I915_READ(reg);
526
Daniel Vetterafba0182012-06-12 16:36:45 +0200527 assert_hdmi_port_disabled(intel_hdmi);
528
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300529 /* See the big comment in g4x_set_infoframes() */
530 val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC;
531
532 if (!intel_hdmi->has_hdmi_sink) {
533 if (!(val & VIDEO_DIP_ENABLE))
534 return;
535 val &= ~VIDEO_DIP_ENABLE;
536 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300537 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300538 return;
539 }
540
Paulo Zanoni822974a2012-05-28 16:42:51 -0300541 val |= VIDEO_DIP_ENABLE;
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300542 val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
543 VIDEO_DIP_ENABLE_GCP);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300544
545 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300546 POSTING_READ(reg);
Paulo Zanoni822974a2012-05-28 16:42:51 -0300547
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300548 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
549 intel_hdmi_set_spd_infoframe(encoder);
550}
551
552static void hsw_set_infoframes(struct drm_encoder *encoder,
553 struct drm_display_mode *adjusted_mode)
554{
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300555 struct drm_i915_private *dev_priv = encoder->dev->dev_private;
556 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
557 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
558 u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300559 u32 val = I915_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300560
Daniel Vetterafba0182012-06-12 16:36:45 +0200561 assert_hdmi_port_disabled(intel_hdmi);
562
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300563 if (!intel_hdmi->has_hdmi_sink) {
564 I915_WRITE(reg, 0);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300565 POSTING_READ(reg);
Paulo Zanoni0c14c7f2012-05-28 16:42:49 -0300566 return;
567 }
568
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300569 val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
570 VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
571
572 I915_WRITE(reg, val);
Paulo Zanoni9d9740f2012-05-28 16:43:00 -0300573 POSTING_READ(reg);
Paulo Zanoni0dd87d22012-05-28 16:42:53 -0300574
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300575 intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
576 intel_hdmi_set_spd_infoframe(encoder);
577}
578
Eric Anholt7d573822009-01-02 13:33:00 -0800579static void intel_hdmi_mode_set(struct drm_encoder *encoder,
580 struct drm_display_mode *mode,
581 struct drm_display_mode *adjusted_mode)
582{
583 struct drm_device *dev = encoder->dev;
584 struct drm_i915_private *dev_priv = dev->dev_private;
Paulo Zanonied517fb2012-05-14 17:12:50 -0300585 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100586 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
Eric Anholt7d573822009-01-02 13:33:00 -0800587 u32 sdvox;
588
Paulo Zanonib659c3d2012-05-28 16:42:56 -0300589 sdvox = SDVO_ENCODING_HDMI;
Jesse Barnes5d4fac92011-06-24 12:19:19 -0700590 if (!HAS_PCH_SPLIT(dev))
591 sdvox |= intel_hdmi->color_range;
Adam Jacksonb599c0b2010-07-16 14:46:31 -0400592 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
593 sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
594 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
595 sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
Eric Anholt7d573822009-01-02 13:33:00 -0800596
Jesse Barnes020f6702011-06-24 12:19:25 -0700597 if (intel_crtc->bpp > 24)
598 sdvox |= COLOR_FORMAT_12bpc;
599 else
600 sdvox |= COLOR_FORMAT_8bpc;
601
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800602 /* Required on CPT */
603 if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
604 sdvox |= HDMI_MODE_SELECT;
605
David Härdeman3c17fe42010-09-24 21:44:32 +0200606 if (intel_hdmi->has_audio) {
Wu Fengguange0dac652011-09-05 14:25:34 +0800607 DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
608 pipe_name(intel_crtc->pipe));
Eric Anholt7d573822009-01-02 13:33:00 -0800609 sdvox |= SDVO_AUDIO_ENABLE;
David Härdeman3c17fe42010-09-24 21:44:32 +0200610 sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
Wu Fengguange0dac652011-09-05 14:25:34 +0800611 intel_write_eld(encoder, adjusted_mode);
David Härdeman3c17fe42010-09-24 21:44:32 +0200612 }
Eric Anholt7d573822009-01-02 13:33:00 -0800613
Jesse Barnes75770562011-10-12 09:01:58 -0700614 if (HAS_PCH_CPT(dev))
615 sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
Daniel Vetter7a87c282012-06-05 11:03:39 +0200616 else if (intel_crtc->pipe == PIPE_B)
Jesse Barnes75770562011-10-12 09:01:58 -0700617 sdvox |= SDVO_PIPE_B_SELECT;
Eric Anholt7d573822009-01-02 13:33:00 -0800618
Chris Wilsonea5b2132010-08-04 13:50:23 +0100619 I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
620 POSTING_READ(intel_hdmi->sdvox_reg);
David Härdeman3c17fe42010-09-24 21:44:32 +0200621
Paulo Zanoni687f4d02012-05-28 16:42:48 -0300622 intel_hdmi->set_infoframes(encoder, adjusted_mode);
Eric Anholt7d573822009-01-02 13:33:00 -0800623}
624
Daniel Vetter85234cd2012-07-02 13:27:29 +0200625static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
626 enum pipe *pipe)
Eric Anholt7d573822009-01-02 13:33:00 -0800627{
Daniel Vetter85234cd2012-07-02 13:27:29 +0200628 struct drm_device *dev = encoder->base.dev;
Eric Anholt7d573822009-01-02 13:33:00 -0800629 struct drm_i915_private *dev_priv = dev->dev_private;
Daniel Vetter85234cd2012-07-02 13:27:29 +0200630 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
631 u32 tmp;
632
633 tmp = I915_READ(intel_hdmi->sdvox_reg);
634
635 if (!(tmp & SDVO_ENABLE))
636 return false;
637
638 if (HAS_PCH_CPT(dev))
639 *pipe = PORT_TO_PIPE_CPT(tmp);
640 else
641 *pipe = PORT_TO_PIPE(tmp);
642
643 return true;
644}
645
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200646static void intel_enable_hdmi(struct intel_encoder *encoder)
Eric Anholt7d573822009-01-02 13:33:00 -0800647{
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200648 struct drm_device *dev = encoder->base.dev;
Eric Anholt7d573822009-01-02 13:33:00 -0800649 struct drm_i915_private *dev_priv = dev->dev_private;
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200650 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
Eric Anholt7d573822009-01-02 13:33:00 -0800651 u32 temp;
Wu Fengguang2deed762011-12-09 20:42:20 +0800652 u32 enable_bits = SDVO_ENABLE;
653
654 if (intel_hdmi->has_audio)
655 enable_bits |= SDVO_AUDIO_ENABLE;
Eric Anholt7d573822009-01-02 13:33:00 -0800656
Chris Wilsonea5b2132010-08-04 13:50:23 +0100657 temp = I915_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000658
Daniel Vetter7a87c282012-06-05 11:03:39 +0200659 /* HW workaround for IBX, we need to move the port to transcoder A
660 * before disabling it. */
661 if (HAS_PCH_IBX(dev)) {
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200662 struct drm_crtc *crtc = encoder->base.crtc;
Daniel Vetter7a87c282012-06-05 11:03:39 +0200663 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
664
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200665 /* Restore the transcoder select bit. */
666 if (pipe == PIPE_B)
667 enable_bits |= SDVO_PIPE_B_SELECT;
668 }
Daniel Vetter7a87c282012-06-05 11:03:39 +0200669
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200670 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
671 * we do this anyway which shows more stable in testing.
672 */
673 if (HAS_PCH_SPLIT(dev)) {
674 I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
675 POSTING_READ(intel_hdmi->sdvox_reg);
676 }
Daniel Vetter7a87c282012-06-05 11:03:39 +0200677
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200678 temp |= enable_bits;
679
680 I915_WRITE(intel_hdmi->sdvox_reg, temp);
681 POSTING_READ(intel_hdmi->sdvox_reg);
682
683 /* HW workaround, need to write this twice for issue that may result
684 * in first write getting masked.
685 */
686 if (HAS_PCH_SPLIT(dev)) {
687 I915_WRITE(intel_hdmi->sdvox_reg, temp);
688 POSTING_READ(intel_hdmi->sdvox_reg);
689 }
690}
691
692static void intel_disable_hdmi(struct intel_encoder *encoder)
693{
694 struct drm_device *dev = encoder->base.dev;
695 struct drm_i915_private *dev_priv = dev->dev_private;
696 struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
697 u32 temp;
Wang Xingchao3cce5742012-09-13 11:19:00 +0800698 u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200699
700 temp = I915_READ(intel_hdmi->sdvox_reg);
701
702 /* HW workaround for IBX, we need to move the port to transcoder A
703 * before disabling it. */
704 if (HAS_PCH_IBX(dev)) {
705 struct drm_crtc *crtc = encoder->base.crtc;
706 int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
707
708 if (temp & SDVO_PIPE_B_SELECT) {
709 temp &= ~SDVO_PIPE_B_SELECT;
710 I915_WRITE(intel_hdmi->sdvox_reg, temp);
711 POSTING_READ(intel_hdmi->sdvox_reg);
712
713 /* Again we need to write this twice. */
714 I915_WRITE(intel_hdmi->sdvox_reg, temp);
715 POSTING_READ(intel_hdmi->sdvox_reg);
716
717 /* Transcoder selection bits only update
718 * effectively on vblank. */
719 if (crtc)
720 intel_wait_for_vblank(dev, pipe);
721 else
722 msleep(50);
Daniel Vetter7a87c282012-06-05 11:03:39 +0200723 }
724 }
725
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000726 /* HW workaround, need to toggle enable bit off and on for 12bpc, but
727 * we do this anyway which shows more stable in testing.
728 */
Eric Anholtc619eed2010-01-28 16:45:52 -0800729 if (HAS_PCH_SPLIT(dev)) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100730 I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
731 POSTING_READ(intel_hdmi->sdvox_reg);
Eric Anholt7d573822009-01-02 13:33:00 -0800732 }
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000733
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200734 temp &= ~enable_bits;
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000735
Chris Wilsonea5b2132010-08-04 13:50:23 +0100736 I915_WRITE(intel_hdmi->sdvox_reg, temp);
737 POSTING_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000738
739 /* HW workaround, need to write this twice for issue that may result
740 * in first write getting masked.
741 */
Eric Anholtc619eed2010-01-28 16:45:52 -0800742 if (HAS_PCH_SPLIT(dev)) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100743 I915_WRITE(intel_hdmi->sdvox_reg, temp);
744 POSTING_READ(intel_hdmi->sdvox_reg);
Zhenyu Wangd8a2d0e2009-11-02 07:52:30 +0000745 }
Eric Anholt7d573822009-01-02 13:33:00 -0800746}
747
Eric Anholt7d573822009-01-02 13:33:00 -0800748static int intel_hdmi_mode_valid(struct drm_connector *connector,
749 struct drm_display_mode *mode)
750{
751 if (mode->clock > 165000)
752 return MODE_CLOCK_HIGH;
753 if (mode->clock < 20000)
Nicolas Kaiser5cbba412011-05-30 12:48:26 +0200754 return MODE_CLOCK_LOW;
Eric Anholt7d573822009-01-02 13:33:00 -0800755
756 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
757 return MODE_NO_DBLESCAN;
758
759 return MODE_OK;
760}
761
762static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
Laurent Pincharte811f5a2012-07-17 17:56:50 +0200763 const struct drm_display_mode *mode,
Eric Anholt7d573822009-01-02 13:33:00 -0800764 struct drm_display_mode *adjusted_mode)
765{
766 return true;
767}
768
Chris Wilson8ec22b22012-05-11 18:01:34 +0100769static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi)
770{
Paulo Zanoni30add222012-10-26 19:05:45 -0200771 struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi);
Chris Wilson8ec22b22012-05-11 18:01:34 +0100772 struct drm_i915_private *dev_priv = dev->dev_private;
773 uint32_t bit;
774
775 switch (intel_hdmi->sdvox_reg) {
Chris Wilsoneeafaac2012-05-25 10:23:37 +0100776 case SDVOB:
Chris Wilson8ec22b22012-05-11 18:01:34 +0100777 bit = HDMIB_HOTPLUG_LIVE_STATUS;
778 break;
Chris Wilsoneeafaac2012-05-25 10:23:37 +0100779 case SDVOC:
Chris Wilson8ec22b22012-05-11 18:01:34 +0100780 bit = HDMIC_HOTPLUG_LIVE_STATUS;
781 break;
Chris Wilson8ec22b22012-05-11 18:01:34 +0100782 default:
783 bit = 0;
784 break;
785 }
786
787 return I915_READ(PORT_HOTPLUG_STAT) & bit;
788}
789
Keith Packardaa93d632009-05-05 09:52:46 -0700790static enum drm_connector_status
Chris Wilson930a9e22010-09-14 11:07:23 +0100791intel_hdmi_detect(struct drm_connector *connector, bool force)
Ma Ling9dff6af2009-04-02 13:13:26 +0800792{
Chris Wilsondf0e9242010-09-09 16:20:55 +0100793 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsonf899fc62010-07-20 15:44:45 -0700794 struct drm_i915_private *dev_priv = connector->dev->dev_private;
795 struct edid *edid;
Keith Packardaa93d632009-05-05 09:52:46 -0700796 enum drm_connector_status status = connector_status_disconnected;
Ma Ling9dff6af2009-04-02 13:13:26 +0800797
Chris Wilson8ec22b22012-05-11 18:01:34 +0100798 if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi))
799 return status;
800
Chris Wilsonea5b2132010-08-04 13:50:23 +0100801 intel_hdmi->has_hdmi_sink = false;
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800802 intel_hdmi->has_audio = false;
Chris Wilsonf899fc62010-07-20 15:44:45 -0700803 edid = drm_get_edid(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800804 intel_gmbus_get_adapter(dev_priv,
805 intel_hdmi->ddc_bus));
ling.ma@intel.com2ded9e22009-07-16 17:23:09 +0800806
Keith Packardaa93d632009-05-05 09:52:46 -0700807 if (edid) {
Eric Anholtbe9f1c42009-06-21 22:14:55 -0700808 if (edid->input & DRM_EDID_INPUT_DIGITAL) {
Keith Packardaa93d632009-05-05 09:52:46 -0700809 status = connector_status_connected;
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800810 if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
811 intel_hdmi->has_hdmi_sink =
812 drm_detect_hdmi_monitor(edid);
Zhenyu Wang2e3d6002010-09-10 10:39:40 +0800813 intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
Keith Packardaa93d632009-05-05 09:52:46 -0700814 }
Keith Packardaa93d632009-05-05 09:52:46 -0700815 kfree(edid);
Ma Ling9dff6af2009-04-02 13:13:26 +0800816 }
ling.ma@intel.com2ded9e22009-07-16 17:23:09 +0800817
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100818 if (status == connector_status_connected) {
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800819 if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
820 intel_hdmi->has_audio =
821 (intel_hdmi->force_audio == HDMI_AUDIO_ON);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100822 }
823
Keith Packardaa93d632009-05-05 09:52:46 -0700824 return status;
Ma Ling9dff6af2009-04-02 13:13:26 +0800825}
826
Eric Anholt7d573822009-01-02 13:33:00 -0800827static int intel_hdmi_get_modes(struct drm_connector *connector)
828{
Chris Wilsondf0e9242010-09-09 16:20:55 +0100829 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsonf899fc62010-07-20 15:44:45 -0700830 struct drm_i915_private *dev_priv = connector->dev->dev_private;
Eric Anholt7d573822009-01-02 13:33:00 -0800831
832 /* We should parse the EDID data and find out if it's an HDMI sink so
833 * we can send audio to it.
834 */
835
Chris Wilsonf899fc62010-07-20 15:44:45 -0700836 return intel_ddc_get_modes(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800837 intel_gmbus_get_adapter(dev_priv,
838 intel_hdmi->ddc_bus));
Eric Anholt7d573822009-01-02 13:33:00 -0800839}
840
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000841static bool
842intel_hdmi_detect_audio(struct drm_connector *connector)
843{
844 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
845 struct drm_i915_private *dev_priv = connector->dev->dev_private;
846 struct edid *edid;
847 bool has_audio = false;
848
849 edid = drm_get_edid(connector,
Daniel Kurtz3bd7d902012-03-28 02:36:14 +0800850 intel_gmbus_get_adapter(dev_priv,
851 intel_hdmi->ddc_bus));
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000852 if (edid) {
853 if (edid->input & DRM_EDID_INPUT_DIGITAL)
854 has_audio = drm_detect_monitor_audio(edid);
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000855 kfree(edid);
856 }
857
858 return has_audio;
859}
860
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100861static int
862intel_hdmi_set_property(struct drm_connector *connector,
Paulo Zanonied517fb2012-05-14 17:12:50 -0300863 struct drm_property *property,
864 uint64_t val)
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100865{
866 struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
Chris Wilsone953fd72011-02-21 22:23:52 +0000867 struct drm_i915_private *dev_priv = connector->dev->dev_private;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100868 int ret;
869
870 ret = drm_connector_property_set_value(connector, property, val);
871 if (ret)
872 return ret;
873
Chris Wilson3f43c482011-05-12 22:17:24 +0100874 if (property == dev_priv->force_audio_property) {
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800875 enum hdmi_force_audio i = val;
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000876 bool has_audio;
877
878 if (i == intel_hdmi->force_audio)
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100879 return 0;
880
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000881 intel_hdmi->force_audio = i;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100882
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800883 if (i == HDMI_AUDIO_AUTO)
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000884 has_audio = intel_hdmi_detect_audio(connector);
885 else
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800886 has_audio = (i == HDMI_AUDIO_ON);
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000887
Wu Fengguangb1d7e4b2012-02-14 11:45:36 +0800888 if (i == HDMI_AUDIO_OFF_DVI)
889 intel_hdmi->has_hdmi_sink = 0;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100890
Chris Wilson1aad7ac2011-02-09 18:46:58 +0000891 intel_hdmi->has_audio = has_audio;
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100892 goto done;
893 }
894
Chris Wilsone953fd72011-02-21 22:23:52 +0000895 if (property == dev_priv->broadcast_rgb_property) {
896 if (val == !!intel_hdmi->color_range)
897 return 0;
898
899 intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
900 goto done;
901 }
902
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100903 return -EINVAL;
904
905done:
906 if (intel_hdmi->base.base.crtc) {
907 struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
Daniel Vettera6778b32012-07-02 09:56:42 +0200908 intel_set_mode(crtc, &crtc->mode,
909 crtc->x, crtc->y, crtc->fb);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100910 }
911
912 return 0;
913}
914
Eric Anholt7d573822009-01-02 13:33:00 -0800915static void intel_hdmi_destroy(struct drm_connector *connector)
916{
Eric Anholt7d573822009-01-02 13:33:00 -0800917 drm_sysfs_connector_remove(connector);
918 drm_connector_cleanup(connector);
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800919 kfree(connector);
Eric Anholt7d573822009-01-02 13:33:00 -0800920}
921
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300922static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300923 .mode_fixup = intel_hdmi_mode_fixup,
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300924 .mode_set = intel_ddi_mode_set,
Daniel Vetter1f703852012-07-11 16:51:39 +0200925 .disable = intel_encoder_noop,
Eugeni Dodonov72662e12012-05-09 15:37:31 -0300926};
927
Eric Anholt7d573822009-01-02 13:33:00 -0800928static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
Eric Anholt7d573822009-01-02 13:33:00 -0800929 .mode_fixup = intel_hdmi_mode_fixup,
Eric Anholt7d573822009-01-02 13:33:00 -0800930 .mode_set = intel_hdmi_mode_set,
Daniel Vetter1f703852012-07-11 16:51:39 +0200931 .disable = intel_encoder_noop,
Eric Anholt7d573822009-01-02 13:33:00 -0800932};
933
934static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
Daniel Vetter5ab432e2012-06-30 08:59:56 +0200935 .dpms = intel_connector_dpms,
Eric Anholt7d573822009-01-02 13:33:00 -0800936 .detect = intel_hdmi_detect,
937 .fill_modes = drm_helper_probe_single_connector_modes,
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100938 .set_property = intel_hdmi_set_property,
Eric Anholt7d573822009-01-02 13:33:00 -0800939 .destroy = intel_hdmi_destroy,
940};
941
942static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
943 .get_modes = intel_hdmi_get_modes,
944 .mode_valid = intel_hdmi_mode_valid,
Chris Wilsondf0e9242010-09-09 16:20:55 +0100945 .best_encoder = intel_best_encoder,
Eric Anholt7d573822009-01-02 13:33:00 -0800946};
947
Eric Anholt7d573822009-01-02 13:33:00 -0800948static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100949 .destroy = intel_encoder_destroy,
Eric Anholt7d573822009-01-02 13:33:00 -0800950};
951
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100952static void
953intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
954{
Chris Wilson3f43c482011-05-12 22:17:24 +0100955 intel_attach_force_audio_property(connector);
Chris Wilsone953fd72011-02-21 22:23:52 +0000956 intel_attach_broadcast_rgb_property(connector);
Chris Wilson55b7d6e82010-09-19 09:29:33 +0100957}
958
Daniel Vetter08d644a2012-07-12 20:19:59 +0200959void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
Eric Anholt7d573822009-01-02 13:33:00 -0800960{
961 struct drm_i915_private *dev_priv = dev->dev_private;
962 struct drm_connector *connector;
Eric Anholt21d40d32010-03-25 11:11:14 -0700963 struct intel_encoder *intel_encoder;
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800964 struct intel_connector *intel_connector;
Chris Wilsonea5b2132010-08-04 13:50:23 +0100965 struct intel_hdmi *intel_hdmi;
Eric Anholt7d573822009-01-02 13:33:00 -0800966
Chris Wilsonea5b2132010-08-04 13:50:23 +0100967 intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL);
968 if (!intel_hdmi)
Eric Anholt7d573822009-01-02 13:33:00 -0800969 return;
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800970
971 intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
972 if (!intel_connector) {
Chris Wilsonea5b2132010-08-04 13:50:23 +0100973 kfree(intel_hdmi);
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800974 return;
975 }
976
Chris Wilsonea5b2132010-08-04 13:50:23 +0100977 intel_encoder = &intel_hdmi->base;
Chris Wilson373a3cf2010-09-15 12:03:59 +0100978 drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
979 DRM_MODE_ENCODER_TMDS);
980
Zhenyu Wang674e2d02010-03-29 15:57:42 +0800981 connector = &intel_connector->base;
Eric Anholt7d573822009-01-02 13:33:00 -0800982 drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
Adam Jackson8d911042009-09-23 15:08:29 -0400983 DRM_MODE_CONNECTOR_HDMIA);
Eric Anholt7d573822009-01-02 13:33:00 -0800984 drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
985
Eric Anholt21d40d32010-03-25 11:11:14 -0700986 intel_encoder->type = INTEL_OUTPUT_HDMI;
Eric Anholt7d573822009-01-02 13:33:00 -0800987
Dave Airlieeb1f8e42010-05-07 06:42:51 +0000988 connector->polled = DRM_CONNECTOR_POLL_HPD;
Peter Rossc3febcc2012-01-28 14:49:26 +0100989 connector->interlace_allowed = 1;
Eric Anholt7d573822009-01-02 13:33:00 -0800990 connector->doublescan_allowed = 0;
Jesse Barnes27f82272011-09-02 12:54:37 -0700991 intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
Eric Anholt7d573822009-01-02 13:33:00 -0800992
Daniel Vetter66a92782012-07-12 20:08:18 +0200993 intel_encoder->cloneable = false;
994
Daniel Vetter08d644a2012-07-12 20:19:59 +0200995 intel_hdmi->ddi_port = port;
996 switch (port) {
997 case PORT_B:
Chris Wilsonf899fc62010-07-20 15:44:45 -0700998 intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
Jesse Barnesb01f2c32009-12-11 11:07:17 -0800999 dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +02001000 break;
1001 case PORT_C:
Chris Wilsonf899fc62010-07-20 15:44:45 -07001002 intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
Jesse Barnesb01f2c32009-12-11 11:07:17 -08001003 dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +02001004 break;
1005 case PORT_D:
Chris Wilsonf899fc62010-07-20 15:44:45 -07001006 intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
Jesse Barnesb01f2c32009-12-11 11:07:17 -08001007 dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
Daniel Vetter08d644a2012-07-12 20:19:59 +02001008 break;
1009 case PORT_A:
1010 /* Internal port only for eDP. */
1011 default:
Eugeni Dodonov6e4c1672012-05-09 15:37:13 -03001012 BUG();
Ma Lingf8aed702009-08-24 13:50:24 +08001013 }
Eric Anholt7d573822009-01-02 13:33:00 -08001014
Chris Wilsonea5b2132010-08-04 13:50:23 +01001015 intel_hdmi->sdvox_reg = sdvox_reg;
Eric Anholt7d573822009-01-02 13:33:00 -08001016
Jesse Barnes64a8fc02011-09-22 11:16:00 +05301017 if (!HAS_PCH_SPLIT(dev)) {
Daniel Vettera3da1df2012-05-08 15:19:06 +02001018 intel_hdmi->write_infoframe = g4x_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001019 intel_hdmi->set_infoframes = g4x_set_infoframes;
Shobhit Kumar90b107c2012-03-28 13:39:32 -07001020 } else if (IS_VALLEYVIEW(dev)) {
1021 intel_hdmi->write_infoframe = vlv_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001022 intel_hdmi->set_infoframes = vlv_set_infoframes;
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -03001023 } else if (IS_HASWELL(dev)) {
Eugeni Dodonov8c5f5f72012-05-10 10:18:02 -03001024 intel_hdmi->write_infoframe = hsw_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001025 intel_hdmi->set_infoframes = hsw_set_infoframes;
Paulo Zanonifdf12502012-05-04 17:18:24 -03001026 } else if (HAS_PCH_IBX(dev)) {
1027 intel_hdmi->write_infoframe = ibx_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001028 intel_hdmi->set_infoframes = ibx_set_infoframes;
Paulo Zanonifdf12502012-05-04 17:18:24 -03001029 } else {
1030 intel_hdmi->write_infoframe = cpt_write_infoframe;
Paulo Zanoni687f4d02012-05-28 16:42:48 -03001031 intel_hdmi->set_infoframes = cpt_set_infoframes;
Jesse Barnes64a8fc02011-09-22 11:16:00 +05301032 }
Jesse Barnes45187ac2011-08-03 09:22:55 -07001033
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001034 if (IS_HASWELL(dev)) {
Paulo Zanoni6441ab52012-10-05 12:05:58 -03001035 intel_encoder->pre_enable = intel_ddi_pre_enable;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001036 intel_encoder->enable = intel_enable_ddi;
1037 intel_encoder->disable = intel_disable_ddi;
Paulo Zanoni6441ab52012-10-05 12:05:58 -03001038 intel_encoder->post_disable = intel_ddi_post_disable;
Daniel Vetter85234cd2012-07-02 13:27:29 +02001039 intel_encoder->get_hw_state = intel_ddi_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001040 drm_encoder_helper_add(&intel_encoder->base,
1041 &intel_hdmi_helper_funcs_hsw);
1042 } else {
1043 intel_encoder->enable = intel_enable_hdmi;
1044 intel_encoder->disable = intel_disable_hdmi;
Daniel Vetter85234cd2012-07-02 13:27:29 +02001045 intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001046 drm_encoder_helper_add(&intel_encoder->base,
1047 &intel_hdmi_helper_funcs);
1048 }
Daniel Vetter85234cd2012-07-02 13:27:29 +02001049 intel_connector->get_hw_state = intel_connector_get_hw_state;
Daniel Vetter5ab432e2012-06-30 08:59:56 +02001050
Eric Anholt7d573822009-01-02 13:33:00 -08001051
Chris Wilson55b7d6e82010-09-19 09:29:33 +01001052 intel_hdmi_add_properties(intel_hdmi, connector);
1053
Chris Wilsondf0e9242010-09-09 16:20:55 +01001054 intel_connector_attach_encoder(intel_connector, intel_encoder);
Eric Anholt7d573822009-01-02 13:33:00 -08001055 drm_sysfs_connector_add(connector);
1056
1057 /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
1058 * 0xd. Failure to do so will result in spurious interrupts being
1059 * generated on the port when a cable is not attached.
1060 */
1061 if (IS_G4X(dev) && !IS_GM45(dev)) {
1062 u32 temp = I915_READ(PEG_BAND_GAP_DATA);
1063 I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
1064 }
Eric Anholt7d573822009-01-02 13:33:00 -08001065}