diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-07-21 11:00:03 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-07-26 13:44:53 -0400 |
commit | bc86625a4ff7574d4d4dba79723457711eb784e0 (patch) | |
tree | f1a0b96ba0a111ddaf5fd95e42322c0e31f53928 /drivers/gpu/drm/i915/intel_dp.c | |
parent | b8f102e8bf71cacf33326360fdf9dcfd1a63925b (diff) |
drm/i915: Retry DP aux_ch communications with a different clock after failure
The w/a db makes the recommendation to both use a non-default value for
the initial clock and then to retry with an alternative clock for
Haswell with the Lakeport PCH.
"On LPT:H, use a divider value of 63 decimal (03Fh). If there is a
failure, retry at least three times with 63, then retry at least three
times with 72 decimal (048h)."
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 92 |
1 files changed, 51 insertions, 41 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c6996ced2e5f..4a7ba5ea9ee3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -276,7 +276,8 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) | |||
276 | return status; | 276 | return status; |
277 | } | 277 | } |
278 | 278 | ||
279 | static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp) | 279 | static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp, |
280 | int index) | ||
280 | { | 281 | { |
281 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | 282 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
282 | struct drm_device *dev = intel_dig_port->base.base.dev; | 283 | struct drm_device *dev = intel_dig_port->base.base.dev; |
@@ -290,22 +291,27 @@ static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp) | |||
290 | * clock divider. | 291 | * clock divider. |
291 | */ | 292 | */ |
292 | if (IS_VALLEYVIEW(dev)) { | 293 | if (IS_VALLEYVIEW(dev)) { |
293 | return 100; | 294 | return index ? 0 : 100; |
294 | } else if (intel_dig_port->port == PORT_A) { | 295 | } else if (intel_dig_port->port == PORT_A) { |
296 | if (index) | ||
297 | return 0; | ||
295 | if (HAS_DDI(dev)) | 298 | if (HAS_DDI(dev)) |
296 | return DIV_ROUND_CLOSEST( | 299 | return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000); |
297 | intel_ddi_get_cdclk_freq(dev_priv), 2000); | ||
298 | else if (IS_GEN6(dev) || IS_GEN7(dev)) | 300 | else if (IS_GEN6(dev) || IS_GEN7(dev)) |
299 | return 200; /* SNB & IVB eDP input clock at 400Mhz */ | 301 | return 200; /* SNB & IVB eDP input clock at 400Mhz */ |
300 | else | 302 | else |
301 | return 225; /* eDP input clock at 450Mhz */ | 303 | return 225; /* eDP input clock at 450Mhz */ |
302 | } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { | 304 | } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { |
303 | /* Workaround for non-ULT HSW */ | 305 | /* Workaround for non-ULT HSW */ |
304 | return 74; | 306 | switch (index) { |
307 | case 0: return 63; | ||
308 | case 1: return 72; | ||
309 | default: return 0; | ||
310 | } | ||
305 | } else if (HAS_PCH_SPLIT(dev)) { | 311 | } else if (HAS_PCH_SPLIT(dev)) { |
306 | return DIV_ROUND_UP(intel_pch_rawclk(dev), 2); | 312 | return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2); |
307 | } else { | 313 | } else { |
308 | return intel_hrawclk(dev) / 2; | 314 | return index ? 0 :intel_hrawclk(dev) / 2; |
309 | } | 315 | } |
310 | } | 316 | } |
311 | 317 | ||
@@ -319,10 +325,10 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, | |||
319 | struct drm_i915_private *dev_priv = dev->dev_private; | 325 | struct drm_i915_private *dev_priv = dev->dev_private; |
320 | uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; | 326 | uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; |
321 | uint32_t ch_data = ch_ctl + 4; | 327 | uint32_t ch_data = ch_ctl + 4; |
328 | uint32_t aux_clock_divider; | ||
322 | int i, ret, recv_bytes; | 329 | int i, ret, recv_bytes; |
323 | uint32_t status; | 330 | uint32_t status; |
324 | uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp); | 331 | int try, precharge, clock = 0; |
325 | int try, precharge; | ||
326 | bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); | 332 | bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); |
327 | 333 | ||
328 | /* dp aux is extremely sensitive to irq latency, hence request the | 334 | /* dp aux is extremely sensitive to irq latency, hence request the |
@@ -353,37 +359,41 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, | |||
353 | goto out; | 359 | goto out; |
354 | } | 360 | } |
355 | 361 | ||
356 | /* Must try at least 3 times according to DP spec */ | 362 | while ((aux_clock_divider = get_aux_clock_divider(intel_dp, clock++))) { |
357 | for (try = 0; try < 5; try++) { | 363 | /* Must try at least 3 times according to DP spec */ |
358 | /* Load the send data into the aux channel data registers */ | 364 | for (try = 0; try < 5; try++) { |
359 | for (i = 0; i < send_bytes; i += 4) | 365 | /* Load the send data into the aux channel data registers */ |
360 | I915_WRITE(ch_data + i, | 366 | for (i = 0; i < send_bytes; i += 4) |
361 | pack_aux(send + i, send_bytes - i)); | 367 | I915_WRITE(ch_data + i, |
362 | 368 | pack_aux(send + i, send_bytes - i)); | |
363 | /* Send the command and wait for it to complete */ | 369 | |
364 | I915_WRITE(ch_ctl, | 370 | /* Send the command and wait for it to complete */ |
365 | DP_AUX_CH_CTL_SEND_BUSY | | 371 | I915_WRITE(ch_ctl, |
366 | (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | | 372 | DP_AUX_CH_CTL_SEND_BUSY | |
367 | DP_AUX_CH_CTL_TIME_OUT_400us | | 373 | (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | |
368 | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | | 374 | DP_AUX_CH_CTL_TIME_OUT_400us | |
369 | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | | 375 | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | |
370 | (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | | 376 | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | |
371 | DP_AUX_CH_CTL_DONE | | 377 | (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | |
372 | DP_AUX_CH_CTL_TIME_OUT_ERROR | | 378 | DP_AUX_CH_CTL_DONE | |
373 | DP_AUX_CH_CTL_RECEIVE_ERROR); | 379 | DP_AUX_CH_CTL_TIME_OUT_ERROR | |
374 | 380 | DP_AUX_CH_CTL_RECEIVE_ERROR); | |
375 | status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); | 381 | |
376 | 382 | status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); | |
377 | /* Clear done status and any errors */ | 383 | |
378 | I915_WRITE(ch_ctl, | 384 | /* Clear done status and any errors */ |
379 | status | | 385 | I915_WRITE(ch_ctl, |
380 | DP_AUX_CH_CTL_DONE | | 386 | status | |
381 | DP_AUX_CH_CTL_TIME_OUT_ERROR | | 387 | DP_AUX_CH_CTL_DONE | |
382 | DP_AUX_CH_CTL_RECEIVE_ERROR); | 388 | DP_AUX_CH_CTL_TIME_OUT_ERROR | |
383 | 389 | DP_AUX_CH_CTL_RECEIVE_ERROR); | |
384 | if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | | 390 | |
385 | DP_AUX_CH_CTL_RECEIVE_ERROR)) | 391 | if (status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | |
386 | continue; | 392 | DP_AUX_CH_CTL_RECEIVE_ERROR)) |
393 | continue; | ||
394 | if (status & DP_AUX_CH_CTL_DONE) | ||
395 | break; | ||
396 | } | ||
387 | if (status & DP_AUX_CH_CTL_DONE) | 397 | if (status & DP_AUX_CH_CTL_DONE) |
388 | break; | 398 | break; |
389 | } | 399 | } |
@@ -1453,7 +1463,7 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp) | |||
1453 | { | 1463 | { |
1454 | struct drm_device *dev = intel_dp_to_dev(intel_dp); | 1464 | struct drm_device *dev = intel_dp_to_dev(intel_dp); |
1455 | struct drm_i915_private *dev_priv = dev->dev_private; | 1465 | struct drm_i915_private *dev_priv = dev->dev_private; |
1456 | uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp); | 1466 | uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp, 0); |
1457 | int precharge = 0x3; | 1467 | int precharge = 0x3; |
1458 | int msg_size = 5; /* Header(4) + Message(1) */ | 1468 | int msg_size = 5; /* Header(4) + Message(1) */ |
1459 | 1469 | ||