Rev 3480 | Rev 4104 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2330 | Serge | 1 | /* |
2 | * Copyright 2006 Dave Airlie |
||
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 |
||
26 | * Jesse Barnes |
||
27 | */ |
||
28 | |||
29 | #include |
||
30 | #include |
||
3031 | serge | 31 | #include |
32 | #include |
||
33 | #include |
||
34 | #include |
||
2330 | Serge | 35 | #include "intel_drv.h" |
3031 | serge | 36 | #include |
2330 | Serge | 37 | #include "i915_drv.h" |
38 | |||
3243 | Serge | 39 | static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) |
40 | { |
||
41 | return hdmi_to_dig_port(intel_hdmi)->base.base.dev; |
||
42 | } |
||
43 | |||
3031 | serge | 44 | static void |
45 | assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) |
||
46 | { |
||
3243 | Serge | 47 | struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); |
3031 | serge | 48 | struct drm_i915_private *dev_priv = dev->dev_private; |
49 | uint32_t enabled_bits; |
||
2330 | Serge | 50 | |
3480 | Serge | 51 | enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; |
3031 | serge | 52 | |
3746 | Serge | 53 | WARN(I915_READ(intel_hdmi->hdmi_reg) & enabled_bits, |
3031 | serge | 54 | "HDMI port enabled, expecting disabled\n"); |
55 | } |
||
56 | |||
57 | struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) |
||
2330 | Serge | 58 | { |
3243 | Serge | 59 | struct intel_digital_port *intel_dig_port = |
60 | container_of(encoder, struct intel_digital_port, base.base); |
||
61 | return &intel_dig_port->hdmi; |
||
2330 | Serge | 62 | } |
63 | |||
64 | static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) |
||
65 | { |
||
3243 | Serge | 66 | return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); |
2330 | Serge | 67 | } |
68 | |||
69 | void intel_dip_infoframe_csum(struct dip_infoframe *frame) |
||
70 | { |
||
71 | uint8_t *data = (uint8_t *)frame; |
||
72 | uint8_t sum = 0; |
||
73 | unsigned i; |
||
74 | |||
75 | frame->checksum = 0; |
||
76 | frame->ecc = 0; |
||
77 | |||
2342 | Serge | 78 | for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++) |
2330 | Serge | 79 | sum += data[i]; |
80 | |||
81 | frame->checksum = 0x100 - sum; |
||
82 | } |
||
83 | |||
3031 | serge | 84 | static u32 g4x_infoframe_index(struct dip_infoframe *frame) |
2330 | Serge | 85 | { |
3031 | serge | 86 | switch (frame->type) { |
87 | case DIP_TYPE_AVI: |
||
88 | return VIDEO_DIP_SELECT_AVI; |
||
89 | case DIP_TYPE_SPD: |
||
90 | return VIDEO_DIP_SELECT_SPD; |
||
91 | default: |
||
92 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); |
||
93 | return 0; |
||
94 | } |
||
95 | } |
||
2330 | Serge | 96 | |
3031 | serge | 97 | static u32 g4x_infoframe_enable(struct dip_infoframe *frame) |
98 | { |
||
2330 | Serge | 99 | switch (frame->type) { |
100 | case DIP_TYPE_AVI: |
||
3031 | serge | 101 | return VIDEO_DIP_ENABLE_AVI; |
2330 | Serge | 102 | case DIP_TYPE_SPD: |
3031 | serge | 103 | return VIDEO_DIP_ENABLE_SPD; |
2330 | Serge | 104 | default: |
105 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); |
||
3031 | serge | 106 | return 0; |
2330 | Serge | 107 | } |
3031 | serge | 108 | } |
2330 | Serge | 109 | |
3031 | serge | 110 | static u32 hsw_infoframe_enable(struct dip_infoframe *frame) |
111 | { |
||
112 | switch (frame->type) { |
||
113 | case DIP_TYPE_AVI: |
||
114 | return VIDEO_DIP_ENABLE_AVI_HSW; |
||
115 | case DIP_TYPE_SPD: |
||
116 | return VIDEO_DIP_ENABLE_SPD_HSW; |
||
117 | default: |
||
118 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); |
||
119 | return 0; |
||
120 | } |
||
2330 | Serge | 121 | } |
122 | |||
3746 | Serge | 123 | static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, |
124 | enum transcoder cpu_transcoder) |
||
2330 | Serge | 125 | { |
126 | switch (frame->type) { |
||
127 | case DIP_TYPE_AVI: |
||
3746 | Serge | 128 | return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); |
2330 | Serge | 129 | case DIP_TYPE_SPD: |
3746 | Serge | 130 | return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); |
2330 | Serge | 131 | default: |
132 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); |
||
3031 | serge | 133 | return 0; |
2330 | Serge | 134 | } |
135 | } |
||
136 | |||
3031 | serge | 137 | static void g4x_write_infoframe(struct drm_encoder *encoder, |
2330 | Serge | 138 | struct dip_infoframe *frame) |
139 | { |
||
140 | uint32_t *data = (uint32_t *)frame; |
||
141 | struct drm_device *dev = encoder->dev; |
||
142 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3031 | serge | 143 | u32 val = I915_READ(VIDEO_DIP_CTL); |
2330 | Serge | 144 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
145 | |||
3031 | serge | 146 | WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); |
2330 | Serge | 147 | |
3031 | serge | 148 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
149 | val |= g4x_infoframe_index(frame); |
||
2330 | Serge | 150 | |
3031 | serge | 151 | val &= ~g4x_infoframe_enable(frame); |
2330 | Serge | 152 | |
3031 | serge | 153 | I915_WRITE(VIDEO_DIP_CTL, val); |
2330 | Serge | 154 | |
3031 | serge | 155 | mmiowb(); |
2330 | Serge | 156 | for (i = 0; i < len; i += 4) { |
157 | I915_WRITE(VIDEO_DIP_DATA, *data); |
||
158 | data++; |
||
159 | } |
||
3031 | serge | 160 | /* Write every possible data byte to force correct ECC calculation. */ |
161 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) |
||
162 | I915_WRITE(VIDEO_DIP_DATA, 0); |
||
163 | mmiowb(); |
||
2330 | Serge | 164 | |
3031 | serge | 165 | val |= g4x_infoframe_enable(frame); |
166 | val &= ~VIDEO_DIP_FREQ_MASK; |
||
167 | val |= VIDEO_DIP_FREQ_VSYNC; |
||
2330 | Serge | 168 | |
3031 | serge | 169 | I915_WRITE(VIDEO_DIP_CTL, val); |
170 | POSTING_READ(VIDEO_DIP_CTL); |
||
2330 | Serge | 171 | } |
172 | |||
3031 | serge | 173 | static void ibx_write_infoframe(struct drm_encoder *encoder, |
2330 | Serge | 174 | struct dip_infoframe *frame) |
175 | { |
||
176 | uint32_t *data = (uint32_t *)frame; |
||
177 | struct drm_device *dev = encoder->dev; |
||
178 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3031 | serge | 179 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
2330 | Serge | 180 | int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
181 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
||
3031 | serge | 182 | u32 val = I915_READ(reg); |
2330 | Serge | 183 | |
3031 | serge | 184 | WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); |
2330 | Serge | 185 | |
3031 | serge | 186 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
187 | val |= g4x_infoframe_index(frame); |
||
2330 | Serge | 188 | |
3031 | serge | 189 | val &= ~g4x_infoframe_enable(frame); |
190 | |||
191 | I915_WRITE(reg, val); |
||
192 | |||
193 | mmiowb(); |
||
194 | for (i = 0; i < len; i += 4) { |
||
195 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); |
||
196 | data++; |
||
197 | } |
||
198 | /* Write every possible data byte to force correct ECC calculation. */ |
||
199 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) |
||
200 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); |
||
201 | mmiowb(); |
||
202 | |||
203 | val |= g4x_infoframe_enable(frame); |
||
204 | val &= ~VIDEO_DIP_FREQ_MASK; |
||
205 | val |= VIDEO_DIP_FREQ_VSYNC; |
||
206 | |||
207 | I915_WRITE(reg, val); |
||
208 | POSTING_READ(reg); |
||
209 | } |
||
210 | |||
211 | static void cpt_write_infoframe(struct drm_encoder *encoder, |
||
212 | struct dip_infoframe *frame) |
||
213 | { |
||
214 | uint32_t *data = (uint32_t *)frame; |
||
215 | struct drm_device *dev = encoder->dev; |
||
216 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
217 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
218 | int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
||
219 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
||
220 | u32 val = I915_READ(reg); |
||
221 | |||
222 | WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); |
||
223 | |||
2342 | Serge | 224 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
3031 | serge | 225 | val |= g4x_infoframe_index(frame); |
2330 | Serge | 226 | |
3031 | serge | 227 | /* The DIP control register spec says that we need to update the AVI |
228 | * infoframe without clearing its enable bit */ |
||
229 | if (frame->type != DIP_TYPE_AVI) |
||
230 | val &= ~g4x_infoframe_enable(frame); |
||
2330 | Serge | 231 | |
3031 | serge | 232 | I915_WRITE(reg, val); |
233 | |||
234 | mmiowb(); |
||
2330 | Serge | 235 | for (i = 0; i < len; i += 4) { |
236 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); |
||
237 | data++; |
||
238 | } |
||
3031 | serge | 239 | /* Write every possible data byte to force correct ECC calculation. */ |
240 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) |
||
241 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); |
||
242 | mmiowb(); |
||
2330 | Serge | 243 | |
3031 | serge | 244 | val |= g4x_infoframe_enable(frame); |
245 | val &= ~VIDEO_DIP_FREQ_MASK; |
||
246 | val |= VIDEO_DIP_FREQ_VSYNC; |
||
2330 | Serge | 247 | |
3031 | serge | 248 | I915_WRITE(reg, val); |
249 | POSTING_READ(reg); |
||
2330 | Serge | 250 | } |
3031 | serge | 251 | |
252 | static void vlv_write_infoframe(struct drm_encoder *encoder, |
||
253 | struct dip_infoframe *frame) |
||
254 | { |
||
255 | uint32_t *data = (uint32_t *)frame; |
||
256 | struct drm_device *dev = encoder->dev; |
||
257 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
258 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
259 | int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); |
||
260 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
||
261 | u32 val = I915_READ(reg); |
||
262 | |||
263 | WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); |
||
264 | |||
265 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
||
266 | val |= g4x_infoframe_index(frame); |
||
267 | |||
268 | val &= ~g4x_infoframe_enable(frame); |
||
269 | |||
270 | I915_WRITE(reg, val); |
||
271 | |||
272 | mmiowb(); |
||
273 | for (i = 0; i < len; i += 4) { |
||
274 | I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data); |
||
275 | data++; |
||
276 | } |
||
277 | /* Write every possible data byte to force correct ECC calculation. */ |
||
278 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) |
||
279 | I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0); |
||
280 | mmiowb(); |
||
281 | |||
282 | val |= g4x_infoframe_enable(frame); |
||
283 | val &= ~VIDEO_DIP_FREQ_MASK; |
||
284 | val |= VIDEO_DIP_FREQ_VSYNC; |
||
285 | |||
286 | I915_WRITE(reg, val); |
||
287 | POSTING_READ(reg); |
||
288 | } |
||
289 | |||
290 | static void hsw_write_infoframe(struct drm_encoder *encoder, |
||
291 | struct dip_infoframe *frame) |
||
292 | { |
||
293 | uint32_t *data = (uint32_t *)frame; |
||
294 | struct drm_device *dev = encoder->dev; |
||
295 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
296 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
3746 | Serge | 297 | u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); |
298 | u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); |
||
3031 | serge | 299 | unsigned int i, len = DIP_HEADER_SIZE + frame->len; |
300 | u32 val = I915_READ(ctl_reg); |
||
301 | |||
302 | if (data_reg == 0) |
||
303 | return; |
||
304 | |||
305 | val &= ~hsw_infoframe_enable(frame); |
||
306 | I915_WRITE(ctl_reg, val); |
||
307 | |||
308 | mmiowb(); |
||
309 | for (i = 0; i < len; i += 4) { |
||
310 | I915_WRITE(data_reg + i, *data); |
||
311 | data++; |
||
312 | } |
||
313 | /* Write every possible data byte to force correct ECC calculation. */ |
||
314 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) |
||
315 | I915_WRITE(data_reg + i, 0); |
||
316 | mmiowb(); |
||
317 | |||
318 | val |= hsw_infoframe_enable(frame); |
||
319 | I915_WRITE(ctl_reg, val); |
||
320 | POSTING_READ(ctl_reg); |
||
321 | } |
||
322 | |||
2330 | Serge | 323 | static void intel_set_infoframe(struct drm_encoder *encoder, |
324 | struct dip_infoframe *frame) |
||
325 | { |
||
326 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
||
327 | |||
328 | intel_dip_infoframe_csum(frame); |
||
329 | intel_hdmi->write_infoframe(encoder, frame); |
||
330 | } |
||
331 | |||
3031 | serge | 332 | static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, |
333 | struct drm_display_mode *adjusted_mode) |
||
2330 | Serge | 334 | { |
3480 | Serge | 335 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
3746 | Serge | 336 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
2330 | Serge | 337 | struct dip_infoframe avi_if = { |
338 | .type = DIP_TYPE_AVI, |
||
339 | .ver = DIP_VERSION_AVI, |
||
340 | .len = DIP_LEN_AVI, |
||
341 | }; |
||
342 | |||
3031 | serge | 343 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) |
344 | avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; |
||
345 | |||
3480 | Serge | 346 | if (intel_hdmi->rgb_quant_range_selectable) { |
3746 | Serge | 347 | if (intel_crtc->config.limited_color_range) |
3480 | Serge | 348 | avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; |
349 | else |
||
350 | avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; |
||
351 | } |
||
3243 | Serge | 352 | |
3480 | Serge | 353 | avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); |
354 | |||
2330 | Serge | 355 | intel_set_infoframe(encoder, &avi_if); |
356 | } |
||
357 | |||
358 | static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) |
||
359 | { |
||
360 | struct dip_infoframe spd_if; |
||
361 | |||
362 | memset(&spd_if, 0, sizeof(spd_if)); |
||
363 | spd_if.type = DIP_TYPE_SPD; |
||
364 | spd_if.ver = DIP_VERSION_SPD; |
||
365 | spd_if.len = DIP_LEN_SPD; |
||
366 | strcpy(spd_if.body.spd.vn, "Intel"); |
||
367 | strcpy(spd_if.body.spd.pd, "Integrated gfx"); |
||
368 | spd_if.body.spd.sdi = DIP_SPD_PC; |
||
369 | |||
370 | intel_set_infoframe(encoder, &spd_if); |
||
371 | } |
||
372 | |||
3031 | serge | 373 | static void g4x_set_infoframes(struct drm_encoder *encoder, |
374 | struct drm_display_mode *adjusted_mode) |
||
375 | { |
||
376 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
||
3480 | Serge | 377 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
378 | struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; |
||
3031 | serge | 379 | u32 reg = VIDEO_DIP_CTL; |
380 | u32 val = I915_READ(reg); |
||
381 | u32 port; |
||
382 | |||
383 | assert_hdmi_port_disabled(intel_hdmi); |
||
384 | |||
385 | /* If the registers were not initialized yet, they might be zeroes, |
||
386 | * which means we're selecting the AVI DIP and we're setting its |
||
387 | * frequency to once. This seems to really confuse the HW and make |
||
388 | * things stop working (the register spec says the AVI always needs to |
||
389 | * be sent every VSync). So here we avoid writing to the register more |
||
390 | * than we need and also explicitly select the AVI DIP and explicitly |
||
391 | * set its frequency to every VSync. Avoiding to write it twice seems to |
||
392 | * be enough to solve the problem, but being defensive shouldn't hurt us |
||
393 | * either. */ |
||
394 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
||
395 | |||
396 | if (!intel_hdmi->has_hdmi_sink) { |
||
397 | if (!(val & VIDEO_DIP_ENABLE)) |
||
398 | return; |
||
399 | val &= ~VIDEO_DIP_ENABLE; |
||
400 | I915_WRITE(reg, val); |
||
401 | POSTING_READ(reg); |
||
402 | return; |
||
403 | } |
||
404 | |||
3480 | Serge | 405 | switch (intel_dig_port->port) { |
406 | case PORT_B: |
||
3031 | serge | 407 | port = VIDEO_DIP_PORT_B; |
408 | break; |
||
3480 | Serge | 409 | case PORT_C: |
3031 | serge | 410 | port = VIDEO_DIP_PORT_C; |
411 | break; |
||
412 | default: |
||
413 | BUG(); |
||
414 | return; |
||
415 | } |
||
416 | |||
417 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
||
418 | if (val & VIDEO_DIP_ENABLE) { |
||
419 | val &= ~VIDEO_DIP_ENABLE; |
||
420 | I915_WRITE(reg, val); |
||
421 | POSTING_READ(reg); |
||
422 | } |
||
423 | val &= ~VIDEO_DIP_PORT_MASK; |
||
424 | val |= port; |
||
425 | } |
||
426 | |||
427 | val |= VIDEO_DIP_ENABLE; |
||
428 | val &= ~VIDEO_DIP_ENABLE_VENDOR; |
||
429 | |||
430 | I915_WRITE(reg, val); |
||
431 | POSTING_READ(reg); |
||
432 | |||
433 | intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); |
||
434 | intel_hdmi_set_spd_infoframe(encoder); |
||
435 | } |
||
436 | |||
437 | static void ibx_set_infoframes(struct drm_encoder *encoder, |
||
438 | struct drm_display_mode *adjusted_mode) |
||
439 | { |
||
440 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
||
441 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
3480 | Serge | 442 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); |
443 | struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; |
||
3031 | serge | 444 | u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
445 | u32 val = I915_READ(reg); |
||
446 | u32 port; |
||
447 | |||
448 | assert_hdmi_port_disabled(intel_hdmi); |
||
449 | |||
450 | /* See the big comment in g4x_set_infoframes() */ |
||
451 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
||
452 | |||
453 | if (!intel_hdmi->has_hdmi_sink) { |
||
454 | if (!(val & VIDEO_DIP_ENABLE)) |
||
455 | return; |
||
456 | val &= ~VIDEO_DIP_ENABLE; |
||
457 | I915_WRITE(reg, val); |
||
458 | POSTING_READ(reg); |
||
459 | return; |
||
460 | } |
||
461 | |||
3480 | Serge | 462 | switch (intel_dig_port->port) { |
463 | case PORT_B: |
||
3031 | serge | 464 | port = VIDEO_DIP_PORT_B; |
465 | break; |
||
3480 | Serge | 466 | case PORT_C: |
3031 | serge | 467 | port = VIDEO_DIP_PORT_C; |
468 | break; |
||
3480 | Serge | 469 | case PORT_D: |
3031 | serge | 470 | port = VIDEO_DIP_PORT_D; |
471 | break; |
||
472 | default: |
||
473 | BUG(); |
||
474 | return; |
||
475 | } |
||
476 | |||
477 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
||
478 | if (val & VIDEO_DIP_ENABLE) { |
||
479 | val &= ~VIDEO_DIP_ENABLE; |
||
480 | I915_WRITE(reg, val); |
||
481 | POSTING_READ(reg); |
||
482 | } |
||
483 | val &= ~VIDEO_DIP_PORT_MASK; |
||
484 | val |= port; |
||
485 | } |
||
486 | |||
487 | val |= VIDEO_DIP_ENABLE; |
||
488 | val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | |
||
489 | VIDEO_DIP_ENABLE_GCP); |
||
490 | |||
491 | I915_WRITE(reg, val); |
||
492 | POSTING_READ(reg); |
||
493 | |||
494 | intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); |
||
495 | intel_hdmi_set_spd_infoframe(encoder); |
||
496 | } |
||
497 | |||
498 | static void cpt_set_infoframes(struct drm_encoder *encoder, |
||
499 | struct drm_display_mode *adjusted_mode) |
||
500 | { |
||
501 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
||
502 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
503 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
||
504 | u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
||
505 | u32 val = I915_READ(reg); |
||
506 | |||
507 | assert_hdmi_port_disabled(intel_hdmi); |
||
508 | |||
509 | /* See the big comment in g4x_set_infoframes() */ |
||
510 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
||
511 | |||
512 | if (!intel_hdmi->has_hdmi_sink) { |
||
513 | if (!(val & VIDEO_DIP_ENABLE)) |
||
514 | return; |
||
515 | val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); |
||
516 | I915_WRITE(reg, val); |
||
517 | POSTING_READ(reg); |
||
518 | return; |
||
519 | } |
||
520 | |||
521 | /* Set both together, unset both together: see the spec. */ |
||
522 | val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; |
||
523 | val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | |
||
524 | VIDEO_DIP_ENABLE_GCP); |
||
525 | |||
526 | I915_WRITE(reg, val); |
||
527 | POSTING_READ(reg); |
||
528 | |||
529 | intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); |
||
530 | intel_hdmi_set_spd_infoframe(encoder); |
||
531 | } |
||
532 | |||
533 | static void vlv_set_infoframes(struct drm_encoder *encoder, |
||
534 | struct drm_display_mode *adjusted_mode) |
||
535 | { |
||
536 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
||
537 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
538 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
||
539 | u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); |
||
540 | u32 val = I915_READ(reg); |
||
541 | |||
542 | assert_hdmi_port_disabled(intel_hdmi); |
||
543 | |||
544 | /* See the big comment in g4x_set_infoframes() */ |
||
545 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; |
||
546 | |||
547 | if (!intel_hdmi->has_hdmi_sink) { |
||
548 | if (!(val & VIDEO_DIP_ENABLE)) |
||
549 | return; |
||
550 | val &= ~VIDEO_DIP_ENABLE; |
||
551 | I915_WRITE(reg, val); |
||
552 | POSTING_READ(reg); |
||
553 | return; |
||
554 | } |
||
555 | |||
556 | val |= VIDEO_DIP_ENABLE; |
||
557 | val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | |
||
558 | VIDEO_DIP_ENABLE_GCP); |
||
559 | |||
560 | I915_WRITE(reg, val); |
||
561 | POSTING_READ(reg); |
||
562 | |||
563 | intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); |
||
564 | intel_hdmi_set_spd_infoframe(encoder); |
||
565 | } |
||
566 | |||
567 | static void hsw_set_infoframes(struct drm_encoder *encoder, |
||
568 | struct drm_display_mode *adjusted_mode) |
||
569 | { |
||
570 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
||
571 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
||
572 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
||
3746 | Serge | 573 | u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); |
3031 | serge | 574 | u32 val = I915_READ(reg); |
575 | |||
576 | assert_hdmi_port_disabled(intel_hdmi); |
||
577 | |||
578 | if (!intel_hdmi->has_hdmi_sink) { |
||
579 | I915_WRITE(reg, 0); |
||
580 | POSTING_READ(reg); |
||
581 | return; |
||
582 | } |
||
583 | |||
584 | val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | |
||
585 | VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); |
||
586 | |||
587 | I915_WRITE(reg, val); |
||
588 | POSTING_READ(reg); |
||
589 | |||
590 | intel_hdmi_set_avi_infoframe(encoder, adjusted_mode); |
||
591 | intel_hdmi_set_spd_infoframe(encoder); |
||
592 | } |
||
593 | |||
2330 | Serge | 594 | static void intel_hdmi_mode_set(struct drm_encoder *encoder, |
595 | struct drm_display_mode *mode, |
||
596 | struct drm_display_mode *adjusted_mode) |
||
597 | { |
||
598 | struct drm_device *dev = encoder->dev; |
||
599 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3031 | serge | 600 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); |
2330 | Serge | 601 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
3746 | Serge | 602 | u32 hdmi_val; |
2330 | Serge | 603 | |
3746 | Serge | 604 | hdmi_val = SDVO_ENCODING_HDMI; |
605 | if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) |
||
606 | hdmi_val |= intel_hdmi->color_range; |
||
2330 | Serge | 607 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
3746 | Serge | 608 | hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; |
2330 | Serge | 609 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
3746 | Serge | 610 | hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH; |
2330 | Serge | 611 | |
3746 | Serge | 612 | if (intel_crtc->config.pipe_bpp > 24) |
613 | hdmi_val |= HDMI_COLOR_FORMAT_12bpc; |
||
2330 | Serge | 614 | else |
3746 | Serge | 615 | hdmi_val |= SDVO_COLOR_FORMAT_8bpc; |
2330 | Serge | 616 | |
617 | /* Required on CPT */ |
||
618 | if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) |
||
3746 | Serge | 619 | hdmi_val |= HDMI_MODE_SELECT_HDMI; |
2330 | Serge | 620 | |
621 | if (intel_hdmi->has_audio) { |
||
2342 | Serge | 622 | DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", |
623 | pipe_name(intel_crtc->pipe)); |
||
3746 | Serge | 624 | hdmi_val |= SDVO_AUDIO_ENABLE; |
625 | hdmi_val |= HDMI_MODE_SELECT_HDMI; |
||
2342 | Serge | 626 | intel_write_eld(encoder, adjusted_mode); |
2330 | Serge | 627 | } |
628 | |||
629 | if (HAS_PCH_CPT(dev)) |
||
3746 | Serge | 630 | hdmi_val |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe); |
631 | else |
||
632 | hdmi_val |= SDVO_PIPE_SEL(intel_crtc->pipe); |
||
2330 | Serge | 633 | |
3746 | Serge | 634 | I915_WRITE(intel_hdmi->hdmi_reg, hdmi_val); |
635 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
2330 | Serge | 636 | |
3031 | serge | 637 | intel_hdmi->set_infoframes(encoder, adjusted_mode); |
2330 | Serge | 638 | } |
639 | |||
3031 | serge | 640 | static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, |
641 | enum pipe *pipe) |
||
2330 | Serge | 642 | { |
3031 | serge | 643 | struct drm_device *dev = encoder->base.dev; |
2330 | Serge | 644 | struct drm_i915_private *dev_priv = dev->dev_private; |
3031 | serge | 645 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
646 | u32 tmp; |
||
647 | |||
3746 | Serge | 648 | tmp = I915_READ(intel_hdmi->hdmi_reg); |
3031 | serge | 649 | |
650 | if (!(tmp & SDVO_ENABLE)) |
||
651 | return false; |
||
652 | |||
653 | if (HAS_PCH_CPT(dev)) |
||
654 | *pipe = PORT_TO_PIPE_CPT(tmp); |
||
655 | else |
||
656 | *pipe = PORT_TO_PIPE(tmp); |
||
657 | |||
658 | return true; |
||
659 | } |
||
660 | |||
661 | static void intel_enable_hdmi(struct intel_encoder *encoder) |
||
662 | { |
||
663 | struct drm_device *dev = encoder->base.dev; |
||
664 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3746 | Serge | 665 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
3031 | serge | 666 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
2330 | Serge | 667 | u32 temp; |
2342 | Serge | 668 | u32 enable_bits = SDVO_ENABLE; |
2330 | Serge | 669 | |
2342 | Serge | 670 | if (intel_hdmi->has_audio) |
671 | enable_bits |= SDVO_AUDIO_ENABLE; |
||
672 | |||
3746 | Serge | 673 | temp = I915_READ(intel_hdmi->hdmi_reg); |
2330 | Serge | 674 | |
3031 | serge | 675 | /* HW workaround for IBX, we need to move the port to transcoder A |
3746 | Serge | 676 | * before disabling it, so restore the transcoder select bit here. */ |
677 | if (HAS_PCH_IBX(dev)) |
||
678 | enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); |
||
3031 | serge | 679 | |
2330 | Serge | 680 | /* HW workaround, need to toggle enable bit off and on for 12bpc, but |
681 | * we do this anyway which shows more stable in testing. |
||
682 | */ |
||
683 | if (HAS_PCH_SPLIT(dev)) { |
||
3746 | Serge | 684 | I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); |
685 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
2330 | Serge | 686 | } |
687 | |||
3031 | serge | 688 | temp |= enable_bits; |
689 | |||
3746 | Serge | 690 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
691 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
3031 | serge | 692 | |
693 | /* HW workaround, need to write this twice for issue that may result |
||
694 | * in first write getting masked. |
||
695 | */ |
||
696 | if (HAS_PCH_SPLIT(dev)) { |
||
3746 | Serge | 697 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
698 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
2330 | Serge | 699 | } |
3031 | serge | 700 | } |
2330 | Serge | 701 | |
3031 | serge | 702 | static void intel_disable_hdmi(struct intel_encoder *encoder) |
703 | { |
||
704 | struct drm_device *dev = encoder->base.dev; |
||
705 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
706 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
||
707 | u32 temp; |
||
708 | u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE; |
||
709 | |||
3746 | Serge | 710 | temp = I915_READ(intel_hdmi->hdmi_reg); |
3031 | serge | 711 | |
712 | /* HW workaround for IBX, we need to move the port to transcoder A |
||
713 | * before disabling it. */ |
||
714 | if (HAS_PCH_IBX(dev)) { |
||
715 | struct drm_crtc *crtc = encoder->base.crtc; |
||
716 | int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1; |
||
717 | |||
718 | if (temp & SDVO_PIPE_B_SELECT) { |
||
719 | temp &= ~SDVO_PIPE_B_SELECT; |
||
3746 | Serge | 720 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
721 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
3031 | serge | 722 | |
723 | /* Again we need to write this twice. */ |
||
3746 | Serge | 724 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
725 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
3031 | serge | 726 | |
727 | /* Transcoder selection bits only update |
||
728 | * effectively on vblank. */ |
||
729 | if (crtc) |
||
730 | intel_wait_for_vblank(dev, pipe); |
||
731 | else |
||
732 | msleep(50); |
||
733 | } |
||
734 | } |
||
735 | |||
736 | /* HW workaround, need to toggle enable bit off and on for 12bpc, but |
||
737 | * we do this anyway which shows more stable in testing. |
||
738 | */ |
||
739 | if (HAS_PCH_SPLIT(dev)) { |
||
3746 | Serge | 740 | I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); |
741 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
3031 | serge | 742 | } |
743 | |||
744 | temp &= ~enable_bits; |
||
745 | |||
3746 | Serge | 746 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
747 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
2330 | Serge | 748 | |
749 | /* HW workaround, need to write this twice for issue that may result |
||
750 | * in first write getting masked. |
||
751 | */ |
||
752 | if (HAS_PCH_SPLIT(dev)) { |
||
3746 | Serge | 753 | I915_WRITE(intel_hdmi->hdmi_reg, temp); |
754 | POSTING_READ(intel_hdmi->hdmi_reg); |
||
2330 | Serge | 755 | } |
756 | } |
||
757 | |||
758 | static int intel_hdmi_mode_valid(struct drm_connector *connector, |
||
759 | struct drm_display_mode *mode) |
||
760 | { |
||
761 | if (mode->clock > 165000) |
||
762 | return MODE_CLOCK_HIGH; |
||
763 | if (mode->clock < 20000) |
||
764 | return MODE_CLOCK_LOW; |
||
765 | |||
766 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
||
767 | return MODE_NO_DBLESCAN; |
||
768 | |||
769 | return MODE_OK; |
||
770 | } |
||
771 | |||
3746 | Serge | 772 | bool intel_hdmi_compute_config(struct intel_encoder *encoder, |
773 | struct intel_crtc_config *pipe_config) |
||
2330 | Serge | 774 | { |
3746 | Serge | 775 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); |
776 | struct drm_device *dev = encoder->base.dev; |
||
777 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
||
2330 | Serge | 778 | |
3480 | Serge | 779 | if (intel_hdmi->color_range_auto) { |
780 | /* See CEA-861-E - 5.1 Default Encoding Parameters */ |
||
781 | if (intel_hdmi->has_hdmi_sink && |
||
782 | drm_match_cea_mode(adjusted_mode) > 1) |
||
3746 | Serge | 783 | intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; |
3480 | Serge | 784 | else |
785 | intel_hdmi->color_range = 0; |
||
3031 | serge | 786 | } |
787 | |||
3480 | Serge | 788 | if (intel_hdmi->color_range) |
3746 | Serge | 789 | pipe_config->limited_color_range = true; |
3480 | Serge | 790 | |
3746 | Serge | 791 | if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev)) |
792 | pipe_config->has_pch_encoder = true; |
||
793 | |||
794 | /* |
||
795 | * HDMI is either 12 or 8, so if the display lets 10bpc sneak |
||
796 | * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi |
||
797 | * outputs. |
||
798 | */ |
||
799 | if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) { |
||
800 | DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); |
||
801 | pipe_config->pipe_bpp = 12*3; |
||
802 | } else { |
||
803 | DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); |
||
804 | pipe_config->pipe_bpp = 8*3; |
||
805 | } |
||
806 | |||
3480 | Serge | 807 | return true; |
3031 | serge | 808 | } |
809 | |||
2330 | Serge | 810 | static enum drm_connector_status |
811 | intel_hdmi_detect(struct drm_connector *connector, bool force) |
||
812 | { |
||
3480 | Serge | 813 | struct drm_device *dev = connector->dev; |
2330 | Serge | 814 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
3243 | Serge | 815 | struct intel_digital_port *intel_dig_port = |
816 | hdmi_to_dig_port(intel_hdmi); |
||
817 | struct intel_encoder *intel_encoder = &intel_dig_port->base; |
||
3480 | Serge | 818 | struct drm_i915_private *dev_priv = dev->dev_private; |
2330 | Serge | 819 | struct edid *edid; |
820 | enum drm_connector_status status = connector_status_disconnected; |
||
821 | |||
822 | intel_hdmi->has_hdmi_sink = false; |
||
823 | intel_hdmi->has_audio = false; |
||
3480 | Serge | 824 | intel_hdmi->rgb_quant_range_selectable = false; |
2330 | Serge | 825 | edid = drm_get_edid(connector, |
3031 | serge | 826 | intel_gmbus_get_adapter(dev_priv, |
827 | intel_hdmi->ddc_bus)); |
||
2330 | Serge | 828 | |
829 | if (edid) { |
||
830 | if (edid->input & DRM_EDID_INPUT_DIGITAL) { |
||
831 | status = connector_status_connected; |
||
3031 | serge | 832 | if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI) |
833 | intel_hdmi->has_hdmi_sink = |
||
834 | drm_detect_hdmi_monitor(edid); |
||
2330 | Serge | 835 | intel_hdmi->has_audio = drm_detect_monitor_audio(edid); |
3480 | Serge | 836 | intel_hdmi->rgb_quant_range_selectable = |
837 | drm_rgb_quant_range_selectable(edid); |
||
2330 | Serge | 838 | } |
839 | kfree(edid); |
||
840 | } |
||
841 | |||
842 | if (status == connector_status_connected) { |
||
3031 | serge | 843 | if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) |
844 | intel_hdmi->has_audio = |
||
845 | (intel_hdmi->force_audio == HDMI_AUDIO_ON); |
||
3243 | Serge | 846 | intel_encoder->type = INTEL_OUTPUT_HDMI; |
2330 | Serge | 847 | } |
848 | |||
849 | return status; |
||
850 | } |
||
851 | |||
852 | static int intel_hdmi_get_modes(struct drm_connector *connector) |
||
853 | { |
||
854 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
||
855 | struct drm_i915_private *dev_priv = connector->dev->dev_private; |
||
856 | |||
857 | /* We should parse the EDID data and find out if it's an HDMI sink so |
||
858 | * we can send audio to it. |
||
859 | */ |
||
860 | |||
861 | return intel_ddc_get_modes(connector, |
||
3031 | serge | 862 | intel_gmbus_get_adapter(dev_priv, |
863 | intel_hdmi->ddc_bus)); |
||
2330 | Serge | 864 | } |
865 | |||
866 | static bool |
||
867 | intel_hdmi_detect_audio(struct drm_connector *connector) |
||
868 | { |
||
869 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
||
870 | struct drm_i915_private *dev_priv = connector->dev->dev_private; |
||
871 | struct edid *edid; |
||
872 | bool has_audio = false; |
||
873 | |||
874 | edid = drm_get_edid(connector, |
||
3031 | serge | 875 | intel_gmbus_get_adapter(dev_priv, |
876 | intel_hdmi->ddc_bus)); |
||
2330 | Serge | 877 | if (edid) { |
878 | if (edid->input & DRM_EDID_INPUT_DIGITAL) |
||
879 | has_audio = drm_detect_monitor_audio(edid); |
||
880 | kfree(edid); |
||
881 | } |
||
882 | |||
883 | return has_audio; |
||
884 | } |
||
885 | |||
886 | static int |
||
887 | intel_hdmi_set_property(struct drm_connector *connector, |
||
888 | struct drm_property *property, |
||
889 | uint64_t val) |
||
890 | { |
||
891 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
||
3243 | Serge | 892 | struct intel_digital_port *intel_dig_port = |
893 | hdmi_to_dig_port(intel_hdmi); |
||
2330 | Serge | 894 | struct drm_i915_private *dev_priv = connector->dev->dev_private; |
895 | int ret; |
||
896 | |||
3243 | Serge | 897 | ret = drm_object_property_set_value(&connector->base, property, val); |
2330 | Serge | 898 | if (ret) |
899 | return ret; |
||
3480 | Serge | 900 | |
2330 | Serge | 901 | if (property == dev_priv->force_audio_property) { |
3031 | serge | 902 | enum hdmi_force_audio i = val; |
2330 | Serge | 903 | bool has_audio; |
904 | |||
905 | if (i == intel_hdmi->force_audio) |
||
906 | return 0; |
||
907 | |||
908 | intel_hdmi->force_audio = i; |
||
909 | |||
3031 | serge | 910 | if (i == HDMI_AUDIO_AUTO) |
2330 | Serge | 911 | has_audio = intel_hdmi_detect_audio(connector); |
912 | else |
||
3031 | serge | 913 | has_audio = (i == HDMI_AUDIO_ON); |
2330 | Serge | 914 | |
3031 | serge | 915 | if (i == HDMI_AUDIO_OFF_DVI) |
916 | intel_hdmi->has_hdmi_sink = 0; |
||
2330 | Serge | 917 | |
918 | intel_hdmi->has_audio = has_audio; |
||
919 | goto done; |
||
920 | } |
||
921 | |||
922 | if (property == dev_priv->broadcast_rgb_property) { |
||
3746 | Serge | 923 | bool old_auto = intel_hdmi->color_range_auto; |
924 | uint32_t old_range = intel_hdmi->color_range; |
||
925 | |||
3480 | Serge | 926 | switch (val) { |
927 | case INTEL_BROADCAST_RGB_AUTO: |
||
928 | intel_hdmi->color_range_auto = true; |
||
929 | break; |
||
930 | case INTEL_BROADCAST_RGB_FULL: |
||
931 | intel_hdmi->color_range_auto = false; |
||
932 | intel_hdmi->color_range = 0; |
||
933 | break; |
||
934 | case INTEL_BROADCAST_RGB_LIMITED: |
||
935 | intel_hdmi->color_range_auto = false; |
||
3746 | Serge | 936 | intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235; |
3480 | Serge | 937 | break; |
938 | default: |
||
939 | return -EINVAL; |
||
940 | } |
||
3746 | Serge | 941 | |
942 | if (old_auto == intel_hdmi->color_range_auto && |
||
943 | old_range == intel_hdmi->color_range) |
||
944 | return 0; |
||
945 | |||
2330 | Serge | 946 | goto done; |
947 | } |
||
3031 | serge | 948 | |
2330 | Serge | 949 | return -EINVAL; |
950 | |||
951 | done: |
||
3480 | Serge | 952 | if (intel_dig_port->base.base.crtc) |
953 | intel_crtc_restore_mode(intel_dig_port->base.base.crtc); |
||
2330 | Serge | 954 | |
955 | return 0; |
||
956 | } |
||
957 | |||
958 | static void intel_hdmi_destroy(struct drm_connector *connector) |
||
959 | { |
||
960 | drm_sysfs_connector_remove(connector); |
||
961 | drm_connector_cleanup(connector); |
||
962 | kfree(connector); |
||
963 | } |
||
964 | |||
965 | static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { |
||
966 | .mode_set = intel_hdmi_mode_set, |
||
967 | }; |
||
968 | |||
969 | static const struct drm_connector_funcs intel_hdmi_connector_funcs = { |
||
3031 | serge | 970 | .dpms = intel_connector_dpms, |
2330 | Serge | 971 | .detect = intel_hdmi_detect, |
972 | .fill_modes = drm_helper_probe_single_connector_modes, |
||
973 | .set_property = intel_hdmi_set_property, |
||
974 | .destroy = intel_hdmi_destroy, |
||
975 | }; |
||
976 | |||
977 | static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { |
||
978 | .get_modes = intel_hdmi_get_modes, |
||
979 | .mode_valid = intel_hdmi_mode_valid, |
||
980 | .best_encoder = intel_best_encoder, |
||
981 | }; |
||
982 | |||
983 | static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { |
||
984 | .destroy = intel_encoder_destroy, |
||
985 | }; |
||
986 | |||
987 | static void |
||
988 | intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector) |
||
989 | { |
||
990 | intel_attach_force_audio_property(connector); |
||
991 | intel_attach_broadcast_rgb_property(connector); |
||
3480 | Serge | 992 | intel_hdmi->color_range_auto = true; |
2330 | Serge | 993 | } |
994 | |||
3243 | Serge | 995 | void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, |
996 | struct intel_connector *intel_connector) |
||
2330 | Serge | 997 | { |
3243 | Serge | 998 | struct drm_connector *connector = &intel_connector->base; |
999 | struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; |
||
1000 | struct intel_encoder *intel_encoder = &intel_dig_port->base; |
||
1001 | struct drm_device *dev = intel_encoder->base.dev; |
||
2330 | Serge | 1002 | struct drm_i915_private *dev_priv = dev->dev_private; |
3243 | Serge | 1003 | enum port port = intel_dig_port->port; |
2330 | Serge | 1004 | |
1005 | drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, |
||
1006 | DRM_MODE_CONNECTOR_HDMIA); |
||
1007 | drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); |
||
1008 | |||
3031 | serge | 1009 | connector->interlace_allowed = 1; |
2330 | Serge | 1010 | connector->doublescan_allowed = 0; |
1011 | |||
3031 | serge | 1012 | switch (port) { |
1013 | case PORT_B: |
||
2330 | Serge | 1014 | intel_hdmi->ddc_bus = GMBUS_PORT_DPB; |
3746 | Serge | 1015 | intel_encoder->hpd_pin = HPD_PORT_B; |
3031 | serge | 1016 | break; |
1017 | case PORT_C: |
||
2330 | Serge | 1018 | intel_hdmi->ddc_bus = GMBUS_PORT_DPC; |
3746 | Serge | 1019 | intel_encoder->hpd_pin = HPD_PORT_C; |
3031 | serge | 1020 | break; |
1021 | case PORT_D: |
||
2330 | Serge | 1022 | intel_hdmi->ddc_bus = GMBUS_PORT_DPD; |
3746 | Serge | 1023 | intel_encoder->hpd_pin = HPD_PORT_D; |
3031 | serge | 1024 | break; |
1025 | case PORT_A: |
||
3746 | Serge | 1026 | intel_encoder->hpd_pin = HPD_PORT_A; |
3031 | serge | 1027 | /* Internal port only for eDP. */ |
1028 | default: |
||
1029 | BUG(); |
||
2330 | Serge | 1030 | } |
1031 | |||
3746 | Serge | 1032 | if (IS_VALLEYVIEW(dev)) { |
1033 | intel_hdmi->write_infoframe = vlv_write_infoframe; |
||
1034 | intel_hdmi->set_infoframes = vlv_set_infoframes; |
||
1035 | } else if (!HAS_PCH_SPLIT(dev)) { |
||
3031 | serge | 1036 | intel_hdmi->write_infoframe = g4x_write_infoframe; |
1037 | intel_hdmi->set_infoframes = g4x_set_infoframes; |
||
3746 | Serge | 1038 | } else if (HAS_DDI(dev)) { |
3031 | serge | 1039 | intel_hdmi->write_infoframe = hsw_write_infoframe; |
1040 | intel_hdmi->set_infoframes = hsw_set_infoframes; |
||
1041 | } else if (HAS_PCH_IBX(dev)) { |
||
1042 | intel_hdmi->write_infoframe = ibx_write_infoframe; |
||
1043 | intel_hdmi->set_infoframes = ibx_set_infoframes; |
||
2342 | Serge | 1044 | } else { |
3031 | serge | 1045 | intel_hdmi->write_infoframe = cpt_write_infoframe; |
1046 | intel_hdmi->set_infoframes = cpt_set_infoframes; |
||
2342 | Serge | 1047 | } |
2330 | Serge | 1048 | |
3480 | Serge | 1049 | if (HAS_DDI(dev)) |
3243 | Serge | 1050 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; |
1051 | else |
||
3031 | serge | 1052 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
2330 | Serge | 1053 | |
1054 | intel_hdmi_add_properties(intel_hdmi, connector); |
||
1055 | |||
1056 | intel_connector_attach_encoder(intel_connector, intel_encoder); |
||
1057 | drm_sysfs_connector_add(connector); |
||
1058 | |||
1059 | /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written |
||
1060 | * 0xd. Failure to do so will result in spurious interrupts being |
||
1061 | * generated on the port when a cable is not attached. |
||
1062 | */ |
||
1063 | if (IS_G4X(dev) && !IS_GM45(dev)) { |
||
1064 | u32 temp = I915_READ(PEG_BAND_GAP_DATA); |
||
1065 | I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); |
||
1066 | } |
||
1067 | } |
||
3243 | Serge | 1068 | |
3746 | Serge | 1069 | void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) |
3243 | Serge | 1070 | { |
1071 | struct intel_digital_port *intel_dig_port; |
||
1072 | struct intel_encoder *intel_encoder; |
||
1073 | struct drm_encoder *encoder; |
||
1074 | struct intel_connector *intel_connector; |
||
1075 | |||
1076 | intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); |
||
1077 | if (!intel_dig_port) |
||
1078 | return; |
||
1079 | |||
1080 | intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); |
||
1081 | if (!intel_connector) { |
||
1082 | kfree(intel_dig_port); |
||
1083 | return; |
||
1084 | } |
||
1085 | |||
1086 | intel_encoder = &intel_dig_port->base; |
||
1087 | encoder = &intel_encoder->base; |
||
1088 | |||
1089 | drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs, |
||
1090 | DRM_MODE_ENCODER_TMDS); |
||
1091 | drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); |
||
1092 | |||
3746 | Serge | 1093 | intel_encoder->compute_config = intel_hdmi_compute_config; |
3243 | Serge | 1094 | intel_encoder->enable = intel_enable_hdmi; |
1095 | intel_encoder->disable = intel_disable_hdmi; |
||
1096 | intel_encoder->get_hw_state = intel_hdmi_get_hw_state; |
||
1097 | |||
1098 | intel_encoder->type = INTEL_OUTPUT_HDMI; |
||
1099 | intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); |
||
1100 | intel_encoder->cloneable = false; |
||
1101 | |||
1102 | intel_dig_port->port = port; |
||
3746 | Serge | 1103 | intel_dig_port->hdmi.hdmi_reg = hdmi_reg; |
3243 | Serge | 1104 | intel_dig_port->dp.output_reg = 0; |
1105 | |||
1106 | intel_hdmi_init_connector(intel_dig_port, intel_connector); |
||
1107 | }><>><>><>>>>>>>>>>>>> |