Commit | Line | Data |
---|---|---|
79e53945 JB |
1 | /* |
2 | * Copyright © 2006-2007 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
21 | * DEALINGS IN THE SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * Eric Anholt <eric@anholt.net> | |
25 | */ | |
26 | ||
8ca4013d | 27 | #include <linux/dmi.h> |
79e53945 | 28 | #include <linux/i2c.h> |
5a0e3ad6 | 29 | #include <linux/slab.h> |
760285e7 | 30 | #include <drm/drmP.h> |
c6f95f27 | 31 | #include <drm/drm_atomic_helper.h> |
760285e7 DH |
32 | #include <drm/drm_crtc.h> |
33 | #include <drm/drm_crtc_helper.h> | |
34 | #include <drm/drm_edid.h> | |
79e53945 | 35 | #include "intel_drv.h" |
760285e7 | 36 | #include <drm/i915_drm.h> |
79e53945 JB |
37 | #include "i915_drv.h" |
38 | ||
e7dbb2f2 KP |
39 | /* Here's the desired hotplug mode */ |
40 | #define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \ | |
41 | ADPA_CRT_HOTPLUG_WARMUP_10MS | \ | |
42 | ADPA_CRT_HOTPLUG_SAMPLE_4S | \ | |
43 | ADPA_CRT_HOTPLUG_VOLTAGE_50 | \ | |
44 | ADPA_CRT_HOTPLUG_VOLREF_325MV | \ | |
45 | ADPA_CRT_HOTPLUG_ENABLE) | |
46 | ||
c9a1c4cd CW |
47 | struct intel_crt { |
48 | struct intel_encoder base; | |
637f44d2 AJ |
49 | /* DPMS state is stored in the connector, which we need in the |
50 | * encoder's enable/disable callbacks */ | |
51 | struct intel_connector *connector; | |
e7dbb2f2 | 52 | bool force_hotplug_required; |
f0f59a00 | 53 | i915_reg_t adpa_reg; |
c9a1c4cd CW |
54 | }; |
55 | ||
eebe6f0b | 56 | static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder) |
c9a1c4cd | 57 | { |
eebe6f0b | 58 | return container_of(encoder, struct intel_crt, base); |
c9a1c4cd CW |
59 | } |
60 | ||
eebe6f0b | 61 | static struct intel_crt *intel_attached_crt(struct drm_connector *connector) |
79e53945 | 62 | { |
eebe6f0b | 63 | return intel_encoder_to_crt(intel_attached_encoder(connector)); |
540a8950 DV |
64 | } |
65 | ||
e403fc94 DV |
66 | static bool intel_crt_get_hw_state(struct intel_encoder *encoder, |
67 | enum pipe *pipe) | |
79e53945 | 68 | { |
e403fc94 | 69 | struct drm_device *dev = encoder->base.dev; |
fac5e23e | 70 | struct drm_i915_private *dev_priv = to_i915(dev); |
e403fc94 DV |
71 | struct intel_crt *crt = intel_encoder_to_crt(encoder); |
72 | u32 tmp; | |
1c8fdda1 | 73 | bool ret; |
e403fc94 | 74 | |
79f255a0 ACO |
75 | if (!intel_display_power_get_if_enabled(dev_priv, |
76 | encoder->power_domain)) | |
6d129bea ID |
77 | return false; |
78 | ||
1c8fdda1 ID |
79 | ret = false; |
80 | ||
e403fc94 DV |
81 | tmp = I915_READ(crt->adpa_reg); |
82 | ||
83 | if (!(tmp & ADPA_DAC_ENABLE)) | |
1c8fdda1 | 84 | goto out; |
e403fc94 | 85 | |
6e266956 | 86 | if (HAS_PCH_CPT(dev_priv)) |
e403fc94 DV |
87 | *pipe = PORT_TO_PIPE_CPT(tmp); |
88 | else | |
89 | *pipe = PORT_TO_PIPE(tmp); | |
90 | ||
1c8fdda1 ID |
91 | ret = true; |
92 | out: | |
79f255a0 | 93 | intel_display_power_put(dev_priv, encoder->power_domain); |
1c8fdda1 ID |
94 | |
95 | return ret; | |
e403fc94 DV |
96 | } |
97 | ||
6801c18c | 98 | static unsigned int intel_crt_get_flags(struct intel_encoder *encoder) |
045ac3b5 | 99 | { |
fac5e23e | 100 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
045ac3b5 JB |
101 | struct intel_crt *crt = intel_encoder_to_crt(encoder); |
102 | u32 tmp, flags = 0; | |
103 | ||
104 | tmp = I915_READ(crt->adpa_reg); | |
105 | ||
106 | if (tmp & ADPA_HSYNC_ACTIVE_HIGH) | |
107 | flags |= DRM_MODE_FLAG_PHSYNC; | |
108 | else | |
109 | flags |= DRM_MODE_FLAG_NHSYNC; | |
110 | ||
111 | if (tmp & ADPA_VSYNC_ACTIVE_HIGH) | |
112 | flags |= DRM_MODE_FLAG_PVSYNC; | |
113 | else | |
114 | flags |= DRM_MODE_FLAG_NVSYNC; | |
115 | ||
6801c18c VS |
116 | return flags; |
117 | } | |
118 | ||
119 | static void intel_crt_get_config(struct intel_encoder *encoder, | |
5cec258b | 120 | struct intel_crtc_state *pipe_config) |
6801c18c | 121 | { |
2d112de7 | 122 | pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder); |
18442d08 | 123 | |
e3b247da | 124 | pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; |
045ac3b5 JB |
125 | } |
126 | ||
6801c18c | 127 | static void hsw_crt_get_config(struct intel_encoder *encoder, |
5cec258b | 128 | struct intel_crtc_state *pipe_config) |
6801c18c | 129 | { |
8802e5b6 VS |
130 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
131 | ||
6801c18c VS |
132 | intel_ddi_get_config(encoder, pipe_config); |
133 | ||
2d112de7 | 134 | pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC | |
6801c18c VS |
135 | DRM_MODE_FLAG_NHSYNC | |
136 | DRM_MODE_FLAG_PVSYNC | | |
137 | DRM_MODE_FLAG_NVSYNC); | |
2d112de7 | 138 | pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder); |
8802e5b6 VS |
139 | |
140 | pipe_config->base.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv); | |
6801c18c VS |
141 | } |
142 | ||
b2cabb0e DV |
143 | /* Note: The caller is required to filter out dpms modes not supported by the |
144 | * platform. */ | |
225cc348 | 145 | static void intel_crt_set_dpms(struct intel_encoder *encoder, |
5f88a9c6 | 146 | const struct intel_crtc_state *crtc_state, |
225cc348 | 147 | int mode) |
df0323c4 | 148 | { |
66478475 | 149 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
b2cabb0e | 150 | struct intel_crt *crt = intel_encoder_to_crt(encoder); |
225cc348 ML |
151 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); |
152 | const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; | |
894ed1ec DV |
153 | u32 adpa; |
154 | ||
66478475 | 155 | if (INTEL_GEN(dev_priv) >= 5) |
894ed1ec DV |
156 | adpa = ADPA_HOTPLUG_BITS; |
157 | else | |
158 | adpa = 0; | |
df0323c4 | 159 | |
894ed1ec DV |
160 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
161 | adpa |= ADPA_HSYNC_ACTIVE_HIGH; | |
162 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | |
163 | adpa |= ADPA_VSYNC_ACTIVE_HIGH; | |
164 | ||
165 | /* For CPT allow 3 pipe config, for others just use A or B */ | |
6e266956 | 166 | if (HAS_PCH_LPT(dev_priv)) |
894ed1ec | 167 | ; /* Those bits don't exist here */ |
6e266956 | 168 | else if (HAS_PCH_CPT(dev_priv)) |
894ed1ec DV |
169 | adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); |
170 | else if (crtc->pipe == 0) | |
171 | adpa |= ADPA_PIPE_A_SELECT; | |
172 | else | |
173 | adpa |= ADPA_PIPE_B_SELECT; | |
174 | ||
6e266956 | 175 | if (!HAS_PCH_SPLIT(dev_priv)) |
894ed1ec | 176 | I915_WRITE(BCLRPAT(crtc->pipe), 0); |
79e53945 | 177 | |
0206e353 | 178 | switch (mode) { |
79e53945 | 179 | case DRM_MODE_DPMS_ON: |
894ed1ec | 180 | adpa |= ADPA_DAC_ENABLE; |
79e53945 JB |
181 | break; |
182 | case DRM_MODE_DPMS_STANDBY: | |
894ed1ec | 183 | adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; |
79e53945 JB |
184 | break; |
185 | case DRM_MODE_DPMS_SUSPEND: | |
894ed1ec | 186 | adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; |
79e53945 JB |
187 | break; |
188 | case DRM_MODE_DPMS_OFF: | |
894ed1ec | 189 | adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; |
79e53945 JB |
190 | break; |
191 | } | |
192 | ||
894ed1ec | 193 | I915_WRITE(crt->adpa_reg, adpa); |
df0323c4 | 194 | } |
2c07245f | 195 | |
fd6bbda9 | 196 | static void intel_disable_crt(struct intel_encoder *encoder, |
5f88a9c6 VS |
197 | const struct intel_crtc_state *old_crtc_state, |
198 | const struct drm_connector_state *old_conn_state) | |
637f44d2 | 199 | { |
225cc348 | 200 | intel_crt_set_dpms(encoder, old_crtc_state, DRM_MODE_DPMS_OFF); |
637f44d2 AJ |
201 | } |
202 | ||
fd6bbda9 | 203 | static void pch_disable_crt(struct intel_encoder *encoder, |
5f88a9c6 VS |
204 | const struct intel_crtc_state *old_crtc_state, |
205 | const struct drm_connector_state *old_conn_state) | |
1ea56e26 VS |
206 | { |
207 | } | |
208 | ||
fd6bbda9 | 209 | static void pch_post_disable_crt(struct intel_encoder *encoder, |
5f88a9c6 VS |
210 | const struct intel_crtc_state *old_crtc_state, |
211 | const struct drm_connector_state *old_conn_state) | |
1ea56e26 | 212 | { |
fd6bbda9 | 213 | intel_disable_crt(encoder, old_crtc_state, old_conn_state); |
1ea56e26 | 214 | } |
abfdc1e3 | 215 | |
3daa3cee JN |
216 | static void hsw_disable_crt(struct intel_encoder *encoder, |
217 | const struct intel_crtc_state *old_crtc_state, | |
218 | const struct drm_connector_state *old_conn_state) | |
219 | { | |
220 | struct drm_crtc *crtc = old_crtc_state->base.crtc; | |
221 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); | |
222 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | |
223 | ||
224 | WARN_ON(!intel_crtc->config->has_pch_encoder); | |
225 | ||
226 | intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); | |
227 | } | |
228 | ||
b7076546 | 229 | static void hsw_post_disable_crt(struct intel_encoder *encoder, |
5f88a9c6 VS |
230 | const struct intel_crtc_state *old_crtc_state, |
231 | const struct drm_connector_state *old_conn_state) | |
b7076546 ML |
232 | { |
233 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); | |
234 | ||
235 | pch_post_disable_crt(encoder, old_crtc_state, old_conn_state); | |
236 | ||
237 | lpt_disable_pch_transcoder(dev_priv); | |
238 | lpt_disable_iclkip(dev_priv); | |
239 | ||
240 | intel_ddi_fdi_post_disable(encoder, old_crtc_state, old_conn_state); | |
3daa3cee JN |
241 | |
242 | WARN_ON(!old_crtc_state->has_pch_encoder); | |
243 | ||
244 | intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true); | |
b7076546 ML |
245 | } |
246 | ||
51c4fa69 JN |
247 | static void hsw_pre_pll_enable_crt(struct intel_encoder *encoder, |
248 | const struct intel_crtc_state *pipe_config, | |
249 | const struct drm_connector_state *conn_state) | |
250 | { | |
251 | struct drm_crtc *crtc = pipe_config->base.crtc; | |
252 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); | |
253 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | |
254 | ||
255 | WARN_ON(!intel_crtc->config->has_pch_encoder); | |
256 | ||
257 | intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); | |
258 | } | |
259 | ||
260 | static void hsw_pre_enable_crt(struct intel_encoder *encoder, | |
261 | const struct intel_crtc_state *pipe_config, | |
262 | const struct drm_connector_state *conn_state) | |
263 | { | |
264 | struct drm_crtc *crtc = pipe_config->base.crtc; | |
265 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); | |
266 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | |
267 | int pipe = intel_crtc->pipe; | |
268 | ||
269 | WARN_ON(!intel_crtc->config->has_pch_encoder); | |
270 | ||
271 | intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); | |
27d81c28 JN |
272 | |
273 | dev_priv->display.fdi_link_train(intel_crtc, pipe_config); | |
51c4fa69 JN |
274 | } |
275 | ||
276 | static void hsw_enable_crt(struct intel_encoder *encoder, | |
277 | const struct intel_crtc_state *pipe_config, | |
278 | const struct drm_connector_state *conn_state) | |
279 | { | |
280 | struct drm_crtc *crtc = pipe_config->base.crtc; | |
281 | struct drm_i915_private *dev_priv = to_i915(crtc->dev); | |
282 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | |
283 | int pipe = intel_crtc->pipe; | |
284 | ||
285 | WARN_ON(!intel_crtc->config->has_pch_encoder); | |
286 | ||
287 | intel_crt_set_dpms(encoder, pipe_config, DRM_MODE_DPMS_ON); | |
288 | ||
289 | intel_wait_for_vblank(dev_priv, pipe); | |
290 | intel_wait_for_vblank(dev_priv, pipe); | |
291 | intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); | |
292 | intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true); | |
293 | } | |
294 | ||
fd6bbda9 | 295 | static void intel_enable_crt(struct intel_encoder *encoder, |
5f88a9c6 VS |
296 | const struct intel_crtc_state *pipe_config, |
297 | const struct drm_connector_state *conn_state) | |
637f44d2 | 298 | { |
225cc348 | 299 | intel_crt_set_dpms(encoder, pipe_config, DRM_MODE_DPMS_ON); |
637f44d2 AJ |
300 | } |
301 | ||
c19de8eb DL |
302 | static enum drm_mode_status |
303 | intel_crt_mode_valid(struct drm_connector *connector, | |
304 | struct drm_display_mode *mode) | |
79e53945 | 305 | { |
6bcdcd9e | 306 | struct drm_device *dev = connector->dev; |
6e266956 TU |
307 | struct drm_i915_private *dev_priv = to_i915(dev); |
308 | int max_dotclk = dev_priv->max_dotclk_freq; | |
debded84 | 309 | int max_clock; |
6bcdcd9e | 310 | |
79e53945 JB |
311 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
312 | return MODE_NO_DBLESCAN; | |
313 | ||
6bcdcd9e ZY |
314 | if (mode->clock < 25000) |
315 | return MODE_CLOCK_LOW; | |
316 | ||
6e266956 | 317 | if (HAS_PCH_LPT(dev_priv)) |
debded84 | 318 | max_clock = 180000; |
11a914c2 | 319 | else if (IS_VALLEYVIEW(dev_priv)) |
debded84 VS |
320 | /* |
321 | * 270 MHz due to current DPLL limits, | |
322 | * DAC limit supposedly 355 MHz. | |
323 | */ | |
324 | max_clock = 270000; | |
5db94019 | 325 | else if (IS_GEN3(dev_priv) || IS_GEN4(dev_priv)) |
6bcdcd9e | 326 | max_clock = 400000; |
debded84 VS |
327 | else |
328 | max_clock = 350000; | |
6bcdcd9e ZY |
329 | if (mode->clock > max_clock) |
330 | return MODE_CLOCK_HIGH; | |
79e53945 | 331 | |
f8700b34 MK |
332 | if (mode->clock > max_dotclk) |
333 | return MODE_CLOCK_HIGH; | |
334 | ||
d4b1931c | 335 | /* The FDI receiver on LPT only supports 8bpc and only has 2 lanes. */ |
6e266956 | 336 | if (HAS_PCH_LPT(dev_priv) && |
d4b1931c PZ |
337 | (ironlake_get_lanes_required(mode->clock, 270000, 24) > 2)) |
338 | return MODE_CLOCK_HIGH; | |
339 | ||
79e53945 JB |
340 | return MODE_OK; |
341 | } | |
342 | ||
5bfe2ac0 | 343 | static bool intel_crt_compute_config(struct intel_encoder *encoder, |
0a478c27 ML |
344 | struct intel_crtc_state *pipe_config, |
345 | struct drm_connector_state *conn_state) | |
2f26cdc0 JN |
346 | { |
347 | return true; | |
348 | } | |
349 | ||
350 | static bool pch_crt_compute_config(struct intel_encoder *encoder, | |
351 | struct intel_crtc_state *pipe_config, | |
352 | struct drm_connector_state *conn_state) | |
353 | { | |
354 | pipe_config->has_pch_encoder = true; | |
355 | ||
356 | return true; | |
357 | } | |
358 | ||
359 | static bool hsw_crt_compute_config(struct intel_encoder *encoder, | |
360 | struct intel_crtc_state *pipe_config, | |
361 | struct drm_connector_state *conn_state) | |
79e53945 | 362 | { |
4f8036a2 | 363 | struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); |
5bfe2ac0 | 364 | |
2f26cdc0 | 365 | pipe_config->has_pch_encoder = true; |
5bfe2ac0 | 366 | |
2a7aceec | 367 | /* LPT FDI RX only supports 8bpc. */ |
4f8036a2 | 368 | if (HAS_PCH_LPT(dev_priv)) { |
f58a1acc DV |
369 | if (pipe_config->bw_constrained && pipe_config->pipe_bpp < 24) { |
370 | DRM_DEBUG_KMS("LPT only supports 24bpp\n"); | |
371 | return false; | |
372 | } | |
373 | ||
2a7aceec | 374 | pipe_config->pipe_bpp = 24; |
f58a1acc | 375 | } |
2a7aceec | 376 | |
8f7abfd8 | 377 | /* FDI must always be 2.7 GHz */ |
2f26cdc0 | 378 | pipe_config->port_clock = 135000 * 2; |
00490c22 | 379 | |
79e53945 JB |
380 | return true; |
381 | } | |
382 | ||
f2b115e6 | 383 | static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) |
2c07245f ZW |
384 | { |
385 | struct drm_device *dev = connector->dev; | |
e7dbb2f2 | 386 | struct intel_crt *crt = intel_attached_crt(connector); |
fac5e23e | 387 | struct drm_i915_private *dev_priv = to_i915(dev); |
e7dbb2f2 | 388 | u32 adpa; |
2c07245f ZW |
389 | bool ret; |
390 | ||
e7dbb2f2 KP |
391 | /* The first time through, trigger an explicit detection cycle */ |
392 | if (crt->force_hotplug_required) { | |
6e266956 | 393 | bool turn_off_dac = HAS_PCH_SPLIT(dev_priv); |
e7dbb2f2 | 394 | u32 save_adpa; |
67941da2 | 395 | |
e7dbb2f2 KP |
396 | crt->force_hotplug_required = 0; |
397 | ||
ca54b810 | 398 | save_adpa = adpa = I915_READ(crt->adpa_reg); |
e7dbb2f2 KP |
399 | DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); |
400 | ||
401 | adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; | |
402 | if (turn_off_dac) | |
403 | adpa &= ~ADPA_DAC_ENABLE; | |
404 | ||
ca54b810 | 405 | I915_WRITE(crt->adpa_reg, adpa); |
e7dbb2f2 | 406 | |
e1672d1c CW |
407 | if (intel_wait_for_register(dev_priv, |
408 | crt->adpa_reg, | |
409 | ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0, | |
410 | 1000)) | |
e7dbb2f2 KP |
411 | DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); |
412 | ||
413 | if (turn_off_dac) { | |
ca54b810 VS |
414 | I915_WRITE(crt->adpa_reg, save_adpa); |
415 | POSTING_READ(crt->adpa_reg); | |
e7dbb2f2 | 416 | } |
a4a6b901 ZW |
417 | } |
418 | ||
2c07245f | 419 | /* Check the status to see if both blue and green are on now */ |
ca54b810 | 420 | adpa = I915_READ(crt->adpa_reg); |
e7dbb2f2 | 421 | if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) |
2c07245f ZW |
422 | ret = true; |
423 | else | |
424 | ret = false; | |
e7dbb2f2 | 425 | DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret); |
2c07245f | 426 | |
2c07245f | 427 | return ret; |
79e53945 JB |
428 | } |
429 | ||
7d2c24e8 JB |
430 | static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) |
431 | { | |
432 | struct drm_device *dev = connector->dev; | |
ca54b810 | 433 | struct intel_crt *crt = intel_attached_crt(connector); |
fac5e23e | 434 | struct drm_i915_private *dev_priv = to_i915(dev); |
b236d7c8 | 435 | bool reenable_hpd; |
7d2c24e8 JB |
436 | u32 adpa; |
437 | bool ret; | |
438 | u32 save_adpa; | |
439 | ||
b236d7c8 L |
440 | /* |
441 | * Doing a force trigger causes a hpd interrupt to get sent, which can | |
442 | * get us stuck in a loop if we're polling: | |
443 | * - We enable power wells and reset the ADPA | |
444 | * - output_poll_exec does force probe on VGA, triggering a hpd | |
445 | * - HPD handler waits for poll to unlock dev->mode_config.mutex | |
446 | * - output_poll_exec shuts off the ADPA, unlocks | |
447 | * dev->mode_config.mutex | |
448 | * - HPD handler runs, resets ADPA and brings us back to the start | |
449 | * | |
450 | * Just disable HPD interrupts here to prevent this | |
451 | */ | |
452 | reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin); | |
453 | ||
ca54b810 | 454 | save_adpa = adpa = I915_READ(crt->adpa_reg); |
7d2c24e8 JB |
455 | DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); |
456 | ||
457 | adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; | |
458 | ||
ca54b810 | 459 | I915_WRITE(crt->adpa_reg, adpa); |
7d2c24e8 | 460 | |
a522ae4b CW |
461 | if (intel_wait_for_register(dev_priv, |
462 | crt->adpa_reg, | |
463 | ADPA_CRT_HOTPLUG_FORCE_TRIGGER, 0, | |
464 | 1000)) { | |
7d2c24e8 | 465 | DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); |
ca54b810 | 466 | I915_WRITE(crt->adpa_reg, save_adpa); |
7d2c24e8 JB |
467 | } |
468 | ||
469 | /* Check the status to see if both blue and green are on now */ | |
ca54b810 | 470 | adpa = I915_READ(crt->adpa_reg); |
7d2c24e8 JB |
471 | if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) |
472 | ret = true; | |
473 | else | |
474 | ret = false; | |
475 | ||
476 | DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret); | |
477 | ||
b236d7c8 L |
478 | if (reenable_hpd) |
479 | intel_hpd_enable(dev_priv, crt->base.hpd_pin); | |
480 | ||
7d2c24e8 JB |
481 | return ret; |
482 | } | |
483 | ||
79e53945 JB |
484 | /** |
485 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. | |
486 | * | |
487 | * Not for i915G/i915GM | |
488 | * | |
489 | * \return true if CRT is connected. | |
490 | * \return false if CRT is disconnected. | |
491 | */ | |
492 | static bool intel_crt_detect_hotplug(struct drm_connector *connector) | |
493 | { | |
494 | struct drm_device *dev = connector->dev; | |
fac5e23e | 495 | struct drm_i915_private *dev_priv = to_i915(dev); |
0706f17c | 496 | u32 stat; |
7a772c49 | 497 | bool ret = false; |
771cb081 | 498 | int i, tries = 0; |
2c07245f | 499 | |
6e266956 | 500 | if (HAS_PCH_SPLIT(dev_priv)) |
f2b115e6 | 501 | return intel_ironlake_crt_detect_hotplug(connector); |
2c07245f | 502 | |
11a914c2 | 503 | if (IS_VALLEYVIEW(dev_priv)) |
7d2c24e8 JB |
504 | return valleyview_crt_detect_hotplug(connector); |
505 | ||
771cb081 ZY |
506 | /* |
507 | * On 4 series desktop, CRT detect sequence need to be done twice | |
508 | * to get a reliable result. | |
509 | */ | |
79e53945 | 510 | |
50a0bc90 | 511 | if (IS_G4X(dev_priv) && !IS_GM45(dev_priv)) |
771cb081 ZY |
512 | tries = 2; |
513 | else | |
514 | tries = 1; | |
771cb081 | 515 | |
771cb081 | 516 | for (i = 0; i < tries ; i++) { |
771cb081 | 517 | /* turn on the FORCE_DETECT */ |
0706f17c EE |
518 | i915_hotplug_interrupt_update(dev_priv, |
519 | CRT_HOTPLUG_FORCE_DETECT, | |
520 | CRT_HOTPLUG_FORCE_DETECT); | |
771cb081 | 521 | /* wait for FORCE_DETECT to go off */ |
fd3790d4 CW |
522 | if (intel_wait_for_register(dev_priv, PORT_HOTPLUG_EN, |
523 | CRT_HOTPLUG_FORCE_DETECT, 0, | |
524 | 1000)) | |
79077319 | 525 | DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); |
771cb081 | 526 | } |
79e53945 | 527 | |
7a772c49 AJ |
528 | stat = I915_READ(PORT_HOTPLUG_STAT); |
529 | if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE) | |
530 | ret = true; | |
531 | ||
532 | /* clear the interrupt we just generated, if any */ | |
533 | I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS); | |
79e53945 | 534 | |
0706f17c | 535 | i915_hotplug_interrupt_update(dev_priv, CRT_HOTPLUG_FORCE_DETECT, 0); |
7a772c49 AJ |
536 | |
537 | return ret; | |
79e53945 JB |
538 | } |
539 | ||
f1a2f5b7 JN |
540 | static struct edid *intel_crt_get_edid(struct drm_connector *connector, |
541 | struct i2c_adapter *i2c) | |
542 | { | |
543 | struct edid *edid; | |
544 | ||
545 | edid = drm_get_edid(connector, i2c); | |
546 | ||
547 | if (!edid && !intel_gmbus_is_forced_bit(i2c)) { | |
548 | DRM_DEBUG_KMS("CRT GMBUS EDID read failed, retry using GPIO bit-banging\n"); | |
549 | intel_gmbus_force_bit(i2c, true); | |
550 | edid = drm_get_edid(connector, i2c); | |
551 | intel_gmbus_force_bit(i2c, false); | |
552 | } | |
553 | ||
554 | return edid; | |
555 | } | |
556 | ||
557 | /* local version of intel_ddc_get_modes() to use intel_crt_get_edid() */ | |
558 | static int intel_crt_ddc_get_modes(struct drm_connector *connector, | |
559 | struct i2c_adapter *adapter) | |
560 | { | |
561 | struct edid *edid; | |
ebda95a9 | 562 | int ret; |
f1a2f5b7 JN |
563 | |
564 | edid = intel_crt_get_edid(connector, adapter); | |
565 | if (!edid) | |
566 | return 0; | |
567 | ||
ebda95a9 JN |
568 | ret = intel_connector_update_modes(connector, edid); |
569 | kfree(edid); | |
570 | ||
571 | return ret; | |
f1a2f5b7 JN |
572 | } |
573 | ||
f5afcd3d | 574 | static bool intel_crt_detect_ddc(struct drm_connector *connector) |
79e53945 | 575 | { |
f5afcd3d | 576 | struct intel_crt *crt = intel_attached_crt(connector); |
fac5e23e | 577 | struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev); |
a2bd1f54 DV |
578 | struct edid *edid; |
579 | struct i2c_adapter *i2c; | |
c96b63a6 | 580 | bool ret = false; |
79e53945 | 581 | |
a2bd1f54 | 582 | BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG); |
79e53945 | 583 | |
41aa3448 | 584 | i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); |
f1a2f5b7 | 585 | edid = intel_crt_get_edid(connector, i2c); |
a2bd1f54 DV |
586 | |
587 | if (edid) { | |
588 | bool is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; | |
f5afcd3d | 589 | |
f5afcd3d DM |
590 | /* |
591 | * This may be a DVI-I connector with a shared DDC | |
592 | * link between analog and digital outputs, so we | |
593 | * have to check the EDID input spec of the attached device. | |
594 | */ | |
f5afcd3d DM |
595 | if (!is_digital) { |
596 | DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); | |
c96b63a6 ACO |
597 | ret = true; |
598 | } else { | |
599 | DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); | |
f5afcd3d | 600 | } |
a2bd1f54 DV |
601 | } else { |
602 | DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n"); | |
6ec3d0c0 CW |
603 | } |
604 | ||
a2bd1f54 DV |
605 | kfree(edid); |
606 | ||
c96b63a6 | 607 | return ret; |
79e53945 JB |
608 | } |
609 | ||
e4a5d54f | 610 | static enum drm_connector_status |
c8ecb2f1 | 611 | intel_crt_load_detect(struct intel_crt *crt, uint32_t pipe) |
e4a5d54f | 612 | { |
7173188d | 613 | struct drm_device *dev = crt->base.base.dev; |
fac5e23e | 614 | struct drm_i915_private *dev_priv = to_i915(dev); |
e4a5d54f ML |
615 | uint32_t save_bclrpat; |
616 | uint32_t save_vtotal; | |
617 | uint32_t vtotal, vactive; | |
618 | uint32_t vsample; | |
619 | uint32_t vblank, vblank_start, vblank_end; | |
620 | uint32_t dsl; | |
f0f59a00 VS |
621 | i915_reg_t bclrpat_reg, vtotal_reg, |
622 | vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg; | |
e4a5d54f ML |
623 | uint8_t st00; |
624 | enum drm_connector_status status; | |
625 | ||
6ec3d0c0 CW |
626 | DRM_DEBUG_KMS("starting load-detect on CRT\n"); |
627 | ||
9db4a9c7 JB |
628 | bclrpat_reg = BCLRPAT(pipe); |
629 | vtotal_reg = VTOTAL(pipe); | |
630 | vblank_reg = VBLANK(pipe); | |
631 | vsync_reg = VSYNC(pipe); | |
632 | pipeconf_reg = PIPECONF(pipe); | |
633 | pipe_dsl_reg = PIPEDSL(pipe); | |
e4a5d54f ML |
634 | |
635 | save_bclrpat = I915_READ(bclrpat_reg); | |
636 | save_vtotal = I915_READ(vtotal_reg); | |
637 | vblank = I915_READ(vblank_reg); | |
638 | ||
639 | vtotal = ((save_vtotal >> 16) & 0xfff) + 1; | |
640 | vactive = (save_vtotal & 0x7ff) + 1; | |
641 | ||
642 | vblank_start = (vblank & 0xfff) + 1; | |
643 | vblank_end = ((vblank >> 16) & 0xfff) + 1; | |
644 | ||
645 | /* Set the border color to purple. */ | |
646 | I915_WRITE(bclrpat_reg, 0x500050); | |
647 | ||
5db94019 | 648 | if (!IS_GEN2(dev_priv)) { |
e4a5d54f ML |
649 | uint32_t pipeconf = I915_READ(pipeconf_reg); |
650 | I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); | |
19c55da1 | 651 | POSTING_READ(pipeconf_reg); |
e4a5d54f ML |
652 | /* Wait for next Vblank to substitue |
653 | * border color for Color info */ | |
0f0f74bc | 654 | intel_wait_for_vblank(dev_priv, pipe); |
f0f59a00 | 655 | st00 = I915_READ8(_VGA_MSR_WRITE); |
e4a5d54f ML |
656 | status = ((st00 & (1 << 4)) != 0) ? |
657 | connector_status_connected : | |
658 | connector_status_disconnected; | |
659 | ||
660 | I915_WRITE(pipeconf_reg, pipeconf); | |
661 | } else { | |
662 | bool restore_vblank = false; | |
663 | int count, detect; | |
664 | ||
665 | /* | |
666 | * If there isn't any border, add some. | |
667 | * Yes, this will flicker | |
668 | */ | |
669 | if (vblank_start <= vactive && vblank_end >= vtotal) { | |
670 | uint32_t vsync = I915_READ(vsync_reg); | |
671 | uint32_t vsync_start = (vsync & 0xffff) + 1; | |
672 | ||
673 | vblank_start = vsync_start; | |
674 | I915_WRITE(vblank_reg, | |
675 | (vblank_start - 1) | | |
676 | ((vblank_end - 1) << 16)); | |
677 | restore_vblank = true; | |
678 | } | |
679 | /* sample in the vertical border, selecting the larger one */ | |
680 | if (vblank_start - vactive >= vtotal - vblank_end) | |
681 | vsample = (vblank_start + vactive) >> 1; | |
682 | else | |
683 | vsample = (vtotal + vblank_end) >> 1; | |
684 | ||
685 | /* | |
686 | * Wait for the border to be displayed | |
687 | */ | |
688 | while (I915_READ(pipe_dsl_reg) >= vactive) | |
689 | ; | |
690 | while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) | |
691 | ; | |
692 | /* | |
693 | * Watch ST00 for an entire scanline | |
694 | */ | |
695 | detect = 0; | |
696 | count = 0; | |
697 | do { | |
698 | count++; | |
699 | /* Read the ST00 VGA status register */ | |
f0f59a00 | 700 | st00 = I915_READ8(_VGA_MSR_WRITE); |
e4a5d54f ML |
701 | if (st00 & (1 << 4)) |
702 | detect++; | |
703 | } while ((I915_READ(pipe_dsl_reg) == dsl)); | |
704 | ||
705 | /* restore vblank if necessary */ | |
706 | if (restore_vblank) | |
707 | I915_WRITE(vblank_reg, vblank); | |
708 | /* | |
709 | * If more than 3/4 of the scanline detected a monitor, | |
710 | * then it is assumed to be present. This works even on i830, | |
711 | * where there isn't any way to force the border color across | |
712 | * the screen | |
713 | */ | |
714 | status = detect * 4 > count * 3 ? | |
715 | connector_status_connected : | |
716 | connector_status_disconnected; | |
717 | } | |
718 | ||
719 | /* Restore previous settings */ | |
720 | I915_WRITE(bclrpat_reg, save_bclrpat); | |
721 | ||
722 | return status; | |
723 | } | |
724 | ||
f0dfb1a8 VS |
725 | static int intel_spurious_crt_detect_dmi_callback(const struct dmi_system_id *id) |
726 | { | |
727 | DRM_DEBUG_DRIVER("Skipping CRT detection for %s\n", id->ident); | |
728 | return 1; | |
729 | } | |
730 | ||
731 | static const struct dmi_system_id intel_spurious_crt_detect[] = { | |
732 | { | |
733 | .callback = intel_spurious_crt_detect_dmi_callback, | |
734 | .ident = "ACER ZGB", | |
735 | .matches = { | |
736 | DMI_MATCH(DMI_SYS_VENDOR, "ACER"), | |
737 | DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), | |
738 | }, | |
739 | }, | |
69a44b16 VS |
740 | { |
741 | .callback = intel_spurious_crt_detect_dmi_callback, | |
742 | .ident = "Intel DZ77BH-55K", | |
743 | .matches = { | |
744 | DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), | |
745 | DMI_MATCH(DMI_BOARD_NAME, "DZ77BH-55K"), | |
746 | }, | |
747 | }, | |
f0dfb1a8 VS |
748 | { } |
749 | }; | |
750 | ||
6c5ed5ae ML |
751 | static int |
752 | intel_crt_detect(struct drm_connector *connector, | |
753 | struct drm_modeset_acquire_ctx *ctx, | |
754 | bool force) | |
79e53945 | 755 | { |
66478475 | 756 | struct drm_i915_private *dev_priv = to_i915(connector->dev); |
c9a1c4cd | 757 | struct intel_crt *crt = intel_attached_crt(connector); |
671dedd2 | 758 | struct intel_encoder *intel_encoder = &crt->base; |
6c5ed5ae | 759 | int status, ret; |
e95c8438 | 760 | struct intel_load_detect_pipe tmp; |
79e53945 | 761 | |
164c8598 | 762 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", |
c23cc417 | 763 | connector->base.id, connector->name, |
164c8598 CW |
764 | force); |
765 | ||
f0dfb1a8 VS |
766 | /* Skip machines without VGA that falsely report hotplug events */ |
767 | if (dmi_check_system(intel_spurious_crt_detect)) | |
768 | return connector_status_disconnected; | |
769 | ||
79f255a0 | 770 | intel_display_power_get(dev_priv, intel_encoder->power_domain); |
671dedd2 | 771 | |
56b857a5 | 772 | if (I915_HAS_HOTPLUG(dev_priv)) { |
aaa37730 DV |
773 | /* We can not rely on the HPD pin always being correctly wired |
774 | * up, for example many KVM do not pass it through, and so | |
775 | * only trust an assertion that the monitor is connected. | |
776 | */ | |
6ec3d0c0 CW |
777 | if (intel_crt_detect_hotplug(connector)) { |
778 | DRM_DEBUG_KMS("CRT detected via hotplug\n"); | |
c19a0df2 PZ |
779 | status = connector_status_connected; |
780 | goto out; | |
aaa37730 | 781 | } else |
e7dbb2f2 | 782 | DRM_DEBUG_KMS("CRT not detected via hotplug\n"); |
79e53945 JB |
783 | } |
784 | ||
c19a0df2 PZ |
785 | if (intel_crt_detect_ddc(connector)) { |
786 | status = connector_status_connected; | |
787 | goto out; | |
788 | } | |
79e53945 | 789 | |
aaa37730 DV |
790 | /* Load detection is broken on HPD capable machines. Whoever wants a |
791 | * broken monitor (without edid) to work behind a broken kvm (that fails | |
792 | * to have the right resistors for HP detection) needs to fix this up. | |
793 | * For now just bail out. */ | |
4f044a88 | 794 | if (I915_HAS_HOTPLUG(dev_priv) && !i915_modparams.load_detect_test) { |
c19a0df2 PZ |
795 | status = connector_status_disconnected; |
796 | goto out; | |
797 | } | |
aaa37730 | 798 | |
c19a0df2 PZ |
799 | if (!force) { |
800 | status = connector->status; | |
801 | goto out; | |
802 | } | |
7b334fcb | 803 | |
e4a5d54f | 804 | /* for pre-945g platforms use load detect */ |
6c5ed5ae ML |
805 | ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx); |
806 | if (ret > 0) { | |
e95c8438 DV |
807 | if (intel_crt_detect_ddc(connector)) |
808 | status = connector_status_connected; | |
66478475 | 809 | else if (INTEL_GEN(dev_priv) < 4) |
c8ecb2f1 ML |
810 | status = intel_crt_load_detect(crt, |
811 | to_intel_crtc(connector->state->crtc)->pipe); | |
4f044a88 | 812 | else if (i915_modparams.load_detect_test) |
32fff610 | 813 | status = connector_status_disconnected; |
5bedeb2d DV |
814 | else |
815 | status = connector_status_unknown; | |
6c5ed5ae ML |
816 | intel_release_load_detect_pipe(connector, &tmp, ctx); |
817 | } else if (ret == 0) | |
e95c8438 | 818 | status = connector_status_unknown; |
6c5ed5ae ML |
819 | else if (ret < 0) |
820 | status = ret; | |
208bf9fd | 821 | |
c19a0df2 | 822 | out: |
79f255a0 | 823 | intel_display_power_put(dev_priv, intel_encoder->power_domain); |
e4a5d54f | 824 | return status; |
79e53945 JB |
825 | } |
826 | ||
827 | static void intel_crt_destroy(struct drm_connector *connector) | |
828 | { | |
79e53945 JB |
829 | drm_connector_cleanup(connector); |
830 | kfree(connector); | |
831 | } | |
832 | ||
833 | static int intel_crt_get_modes(struct drm_connector *connector) | |
834 | { | |
8e4d36b9 | 835 | struct drm_device *dev = connector->dev; |
fac5e23e | 836 | struct drm_i915_private *dev_priv = to_i915(dev); |
671dedd2 ID |
837 | struct intel_crt *crt = intel_attached_crt(connector); |
838 | struct intel_encoder *intel_encoder = &crt->base; | |
890f3359 | 839 | int ret; |
3bd7d909 | 840 | struct i2c_adapter *i2c; |
8e4d36b9 | 841 | |
79f255a0 | 842 | intel_display_power_get(dev_priv, intel_encoder->power_domain); |
671dedd2 | 843 | |
41aa3448 | 844 | i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); |
f1a2f5b7 | 845 | ret = intel_crt_ddc_get_modes(connector, i2c); |
9beb5fea | 846 | if (ret || !IS_G4X(dev_priv)) |
671dedd2 | 847 | goto out; |
8e4d36b9 | 848 | |
8e4d36b9 | 849 | /* Try to probe digital port for output in DVI-I -> VGA mode. */ |
988c7015 | 850 | i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPB); |
671dedd2 ID |
851 | ret = intel_crt_ddc_get_modes(connector, i2c); |
852 | ||
853 | out: | |
79f255a0 | 854 | intel_display_power_put(dev_priv, intel_encoder->power_domain); |
671dedd2 ID |
855 | |
856 | return ret; | |
79e53945 JB |
857 | } |
858 | ||
9504a892 | 859 | void intel_crt_reset(struct drm_encoder *encoder) |
f3269058 | 860 | { |
66478475 | 861 | struct drm_i915_private *dev_priv = to_i915(encoder->dev); |
28cf71ce | 862 | struct intel_crt *crt = intel_encoder_to_crt(to_intel_encoder(encoder)); |
f3269058 | 863 | |
66478475 | 864 | if (INTEL_GEN(dev_priv) >= 5) { |
2e938892 DV |
865 | u32 adpa; |
866 | ||
ca54b810 | 867 | adpa = I915_READ(crt->adpa_reg); |
2e938892 DV |
868 | adpa &= ~ADPA_CRT_HOTPLUG_MASK; |
869 | adpa |= ADPA_HOTPLUG_BITS; | |
ca54b810 VS |
870 | I915_WRITE(crt->adpa_reg, adpa); |
871 | POSTING_READ(crt->adpa_reg); | |
2e938892 | 872 | |
0039a4b3 | 873 | DRM_DEBUG_KMS("crt adpa set to 0x%x\n", adpa); |
f3269058 | 874 | crt->force_hotplug_required = 1; |
2e938892 DV |
875 | } |
876 | ||
f3269058 CW |
877 | } |
878 | ||
79e53945 JB |
879 | /* |
880 | * Routines for controlling stuff on the analog port | |
881 | */ | |
882 | ||
79e53945 | 883 | static const struct drm_connector_funcs intel_crt_connector_funcs = { |
79e53945 | 884 | .fill_modes = drm_helper_probe_single_connector_modes, |
1ebaa0b9 | 885 | .late_register = intel_connector_register, |
c191eca1 | 886 | .early_unregister = intel_connector_unregister, |
79e53945 | 887 | .destroy = intel_crt_destroy, |
c6f95f27 | 888 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
98969725 | 889 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
79e53945 JB |
890 | }; |
891 | ||
892 | static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { | |
6c5ed5ae | 893 | .detect_ctx = intel_crt_detect, |
79e53945 JB |
894 | .mode_valid = intel_crt_mode_valid, |
895 | .get_modes = intel_crt_get_modes, | |
79e53945 JB |
896 | }; |
897 | ||
79e53945 | 898 | static const struct drm_encoder_funcs intel_crt_enc_funcs = { |
28cf71ce | 899 | .reset = intel_crt_reset, |
ea5b213a | 900 | .destroy = intel_encoder_destroy, |
79e53945 JB |
901 | }; |
902 | ||
c39055b0 | 903 | void intel_crt_init(struct drm_i915_private *dev_priv) |
79e53945 JB |
904 | { |
905 | struct drm_connector *connector; | |
c9a1c4cd | 906 | struct intel_crt *crt; |
454c1ca8 | 907 | struct intel_connector *intel_connector; |
6c03a6bd VS |
908 | i915_reg_t adpa_reg; |
909 | u32 adpa; | |
79e53945 | 910 | |
6e266956 | 911 | if (HAS_PCH_SPLIT(dev_priv)) |
6c03a6bd | 912 | adpa_reg = PCH_ADPA; |
11a914c2 | 913 | else if (IS_VALLEYVIEW(dev_priv)) |
6c03a6bd VS |
914 | adpa_reg = VLV_ADPA; |
915 | else | |
916 | adpa_reg = ADPA; | |
917 | ||
918 | adpa = I915_READ(adpa_reg); | |
919 | if ((adpa & ADPA_DAC_ENABLE) == 0) { | |
920 | /* | |
921 | * On some machines (some IVB at least) CRT can be | |
922 | * fused off, but there's no known fuse bit to | |
923 | * indicate that. On these machine the ADPA register | |
924 | * works normally, except the DAC enable bit won't | |
925 | * take. So the only way to tell is attempt to enable | |
926 | * it and see what happens. | |
927 | */ | |
928 | I915_WRITE(adpa_reg, adpa | ADPA_DAC_ENABLE | | |
929 | ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); | |
930 | if ((I915_READ(adpa_reg) & ADPA_DAC_ENABLE) == 0) | |
931 | return; | |
932 | I915_WRITE(adpa_reg, adpa); | |
933 | } | |
934 | ||
c9a1c4cd CW |
935 | crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL); |
936 | if (!crt) | |
79e53945 JB |
937 | return; |
938 | ||
9bdbd0b9 | 939 | intel_connector = intel_connector_alloc(); |
454c1ca8 | 940 | if (!intel_connector) { |
c9a1c4cd | 941 | kfree(crt); |
454c1ca8 ZW |
942 | return; |
943 | } | |
944 | ||
945 | connector = &intel_connector->base; | |
637f44d2 | 946 | crt->connector = intel_connector; |
c39055b0 | 947 | drm_connector_init(&dev_priv->drm, &intel_connector->base, |
79e53945 JB |
948 | &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); |
949 | ||
c39055b0 | 950 | drm_encoder_init(&dev_priv->drm, &crt->base.base, &intel_crt_enc_funcs, |
580d8ed5 | 951 | DRM_MODE_ENCODER_DAC, "CRT"); |
79e53945 | 952 | |
c9a1c4cd | 953 | intel_connector_attach_encoder(intel_connector, &crt->base); |
79e53945 | 954 | |
c9a1c4cd | 955 | crt->base.type = INTEL_OUTPUT_ANALOG; |
301ea74a | 956 | crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI); |
50a0bc90 | 957 | if (IS_I830(dev_priv)) |
59c859d6 ED |
958 | crt->base.crtc_mask = (1 << 0); |
959 | else | |
0826874a | 960 | crt->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); |
59c859d6 | 961 | |
5db94019 | 962 | if (IS_GEN2(dev_priv)) |
dbb02575 DV |
963 | connector->interlace_allowed = 0; |
964 | else | |
965 | connector->interlace_allowed = 1; | |
79e53945 JB |
966 | connector->doublescan_allowed = 0; |
967 | ||
6c03a6bd | 968 | crt->adpa_reg = adpa_reg; |
540a8950 | 969 | |
79f255a0 ACO |
970 | crt->base.power_domain = POWER_DOMAIN_PORT_CRT; |
971 | ||
56b857a5 | 972 | if (I915_HAS_HOTPLUG(dev_priv) && |
f0dfb1a8 | 973 | !dmi_check_system(intel_spurious_crt_detect)) |
1d843f9d | 974 | crt->base.hpd_pin = HPD_CRT; |
c5ce4ef3 | 975 | |
4f8036a2 | 976 | if (HAS_DDI(dev_priv)) { |
03cdc1d4 | 977 | crt->base.port = PORT_E; |
a2985791 | 978 | crt->base.get_config = hsw_crt_get_config; |
4eda01b2 | 979 | crt->base.get_hw_state = intel_ddi_get_hw_state; |
2f26cdc0 | 980 | crt->base.compute_config = hsw_crt_compute_config; |
51c4fa69 JN |
981 | crt->base.pre_pll_enable = hsw_pre_pll_enable_crt; |
982 | crt->base.pre_enable = hsw_pre_enable_crt; | |
983 | crt->base.enable = hsw_enable_crt; | |
3daa3cee | 984 | crt->base.disable = hsw_disable_crt; |
b7076546 | 985 | crt->base.post_disable = hsw_post_disable_crt; |
a2985791 | 986 | } else { |
c5ce4ef3 | 987 | if (HAS_PCH_SPLIT(dev_priv)) { |
2f26cdc0 | 988 | crt->base.compute_config = pch_crt_compute_config; |
c5ce4ef3 JN |
989 | crt->base.disable = pch_disable_crt; |
990 | crt->base.post_disable = pch_post_disable_crt; | |
991 | } else { | |
2f26cdc0 | 992 | crt->base.compute_config = intel_crt_compute_config; |
c5ce4ef3 JN |
993 | crt->base.disable = intel_disable_crt; |
994 | } | |
03cdc1d4 | 995 | crt->base.port = PORT_NONE; |
a2985791 | 996 | crt->base.get_config = intel_crt_get_config; |
4eda01b2 | 997 | crt->base.get_hw_state = intel_crt_get_hw_state; |
51c4fa69 | 998 | crt->base.enable = intel_enable_crt; |
a2985791 | 999 | } |
e403fc94 | 1000 | intel_connector->get_hw_state = intel_connector_get_hw_state; |
df0323c4 | 1001 | |
79e53945 JB |
1002 | drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); |
1003 | ||
56b857a5 | 1004 | if (!I915_HAS_HOTPLUG(dev_priv)) |
821450c6 | 1005 | intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
eb1f8e4f | 1006 | |
e7dbb2f2 KP |
1007 | /* |
1008 | * Configure the automatic hotplug detection stuff | |
1009 | */ | |
1010 | crt->force_hotplug_required = 0; | |
e7dbb2f2 | 1011 | |
68d18ad7 | 1012 | /* |
3e68320e DL |
1013 | * TODO: find a proper way to discover whether we need to set the the |
1014 | * polarity and link reversal bits or not, instead of relying on the | |
1015 | * BIOS. | |
68d18ad7 | 1016 | */ |
6e266956 | 1017 | if (HAS_PCH_LPT(dev_priv)) { |
3e68320e DL |
1018 | u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | |
1019 | FDI_RX_LINK_REVERSAL_OVERRIDE; | |
1020 | ||
eede3b53 | 1021 | dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config; |
3e68320e | 1022 | } |
754970ee | 1023 | |
28cf71ce | 1024 | intel_crt_reset(&crt->base.base); |
79e53945 | 1025 | } |