diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 122 |
2 files changed, 121 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be22aebe84f2..2dd880f2b4ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -3811,8 +3811,9 @@ | |||
3811 | #define SOUTH_CHICKEN1 0xc2000 | 3811 | #define SOUTH_CHICKEN1 0xc2000 |
3812 | #define FDIA_PHASE_SYNC_SHIFT_OVR 19 | 3812 | #define FDIA_PHASE_SYNC_SHIFT_OVR 19 |
3813 | #define FDIA_PHASE_SYNC_SHIFT_EN 18 | 3813 | #define FDIA_PHASE_SYNC_SHIFT_EN 18 |
3814 | #define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) | 3814 | #define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) |
3815 | #define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) | 3815 | #define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) |
3816 | #define FDI_BC_BIFURCATION_SELECT (1 << 12) | ||
3816 | #define SOUTH_CHICKEN2 0xc2004 | 3817 | #define SOUTH_CHICKEN2 0xc2004 |
3817 | #define DPLS_EDP_PPS_FIX_DIS (1<<0) | 3818 | #define DPLS_EDP_PPS_FIX_DIS (1<<0) |
3818 | 3819 | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b2224c592d8..4e7affd268eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -2343,6 +2343,29 @@ static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) | |||
2343 | POSTING_READ(SOUTH_CHICKEN1); | 2343 | POSTING_READ(SOUTH_CHICKEN1); |
2344 | } | 2344 | } |
2345 | 2345 | ||
2346 | static void ivb_modeset_global_resources(struct drm_device *dev) | ||
2347 | { | ||
2348 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
2349 | struct intel_crtc *pipe_B_crtc = | ||
2350 | to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); | ||
2351 | struct intel_crtc *pipe_C_crtc = | ||
2352 | to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]); | ||
2353 | uint32_t temp; | ||
2354 | |||
2355 | /* When everything is off disable fdi C so that we could enable fdi B | ||
2356 | * with all lanes. XXX: This misses the case where a pipe is not using | ||
2357 | * any pch resources and so doesn't need any fdi lanes. */ | ||
2358 | if (!pipe_B_crtc->base.enabled && !pipe_C_crtc->base.enabled) { | ||
2359 | WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); | ||
2360 | WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); | ||
2361 | |||
2362 | temp = I915_READ(SOUTH_CHICKEN1); | ||
2363 | temp &= ~FDI_BC_BIFURCATION_SELECT; | ||
2364 | DRM_DEBUG_KMS("disabling fdi C rx\n"); | ||
2365 | I915_WRITE(SOUTH_CHICKEN1, temp); | ||
2366 | } | ||
2367 | } | ||
2368 | |||
2346 | /* The FDI link training functions for ILK/Ibexpeak. */ | 2369 | /* The FDI link training functions for ILK/Ibexpeak. */ |
2347 | static void ironlake_fdi_link_train(struct drm_crtc *crtc) | 2370 | static void ironlake_fdi_link_train(struct drm_crtc *crtc) |
2348 | { | 2371 | { |
@@ -2602,6 +2625,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) | |||
2602 | POSTING_READ(reg); | 2625 | POSTING_READ(reg); |
2603 | udelay(150); | 2626 | udelay(150); |
2604 | 2627 | ||
2628 | DRM_DEBUG_KMS("FDI_RX_IIR before link train 0x%x\n", | ||
2629 | I915_READ(FDI_RX_IIR(pipe))); | ||
2630 | |||
2605 | /* enable CPU FDI TX and PCH FDI RX */ | 2631 | /* enable CPU FDI TX and PCH FDI RX */ |
2606 | reg = FDI_TX_CTL(pipe); | 2632 | reg = FDI_TX_CTL(pipe); |
2607 | temp = I915_READ(reg); | 2633 | temp = I915_READ(reg); |
@@ -2648,7 +2674,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) | |||
2648 | if (temp & FDI_RX_BIT_LOCK || | 2674 | if (temp & FDI_RX_BIT_LOCK || |
2649 | (I915_READ(reg) & FDI_RX_BIT_LOCK)) { | 2675 | (I915_READ(reg) & FDI_RX_BIT_LOCK)) { |
2650 | I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); | 2676 | I915_WRITE(reg, temp | FDI_RX_BIT_LOCK); |
2651 | DRM_DEBUG_KMS("FDI train 1 done.\n"); | 2677 | DRM_DEBUG_KMS("FDI train 1 done, level %i.\n", i); |
2652 | break; | 2678 | break; |
2653 | } | 2679 | } |
2654 | } | 2680 | } |
@@ -2689,7 +2715,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) | |||
2689 | 2715 | ||
2690 | if (temp & FDI_RX_SYMBOL_LOCK) { | 2716 | if (temp & FDI_RX_SYMBOL_LOCK) { |
2691 | I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); | 2717 | I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK); |
2692 | DRM_DEBUG_KMS("FDI train 2 done.\n"); | 2718 | DRM_DEBUG_KMS("FDI train 2 done, level %i.\n", i); |
2693 | break; | 2719 | break; |
2694 | } | 2720 | } |
2695 | } | 2721 | } |
@@ -5013,6 +5039,88 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, | |||
5013 | return true; | 5039 | return true; |
5014 | } | 5040 | } |
5015 | 5041 | ||
5042 | static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) | ||
5043 | { | ||
5044 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
5045 | uint32_t temp; | ||
5046 | |||
5047 | temp = I915_READ(SOUTH_CHICKEN1); | ||
5048 | if (temp & FDI_BC_BIFURCATION_SELECT) | ||
5049 | return; | ||
5050 | |||
5051 | WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); | ||
5052 | WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); | ||
5053 | |||
5054 | temp |= FDI_BC_BIFURCATION_SELECT; | ||
5055 | DRM_DEBUG_KMS("enabling fdi C rx\n"); | ||
5056 | I915_WRITE(SOUTH_CHICKEN1, temp); | ||
5057 | POSTING_READ(SOUTH_CHICKEN1); | ||
5058 | } | ||
5059 | |||
5060 | static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) | ||
5061 | { | ||
5062 | struct drm_device *dev = intel_crtc->base.dev; | ||
5063 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
5064 | struct intel_crtc *pipe_B_crtc = | ||
5065 | to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); | ||
5066 | |||
5067 | DRM_DEBUG_KMS("checking fdi config on pipe %i, lanes %i\n", | ||
5068 | intel_crtc->pipe, intel_crtc->fdi_lanes); | ||
5069 | if (intel_crtc->fdi_lanes > 4) { | ||
5070 | DRM_DEBUG_KMS("invalid fdi lane config on pipe %i: %i lanes\n", | ||
5071 | intel_crtc->pipe, intel_crtc->fdi_lanes); | ||
5072 | /* Clamp lanes to avoid programming the hw with bogus values. */ | ||
5073 | intel_crtc->fdi_lanes = 4; | ||
5074 | |||
5075 | return false; | ||
5076 | } | ||
5077 | |||
5078 | if (dev_priv->num_pipe == 2) | ||
5079 | return true; | ||
5080 | |||
5081 | switch (intel_crtc->pipe) { | ||
5082 | case PIPE_A: | ||
5083 | return true; | ||
5084 | case PIPE_B: | ||
5085 | if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && | ||
5086 | intel_crtc->fdi_lanes > 2) { | ||
5087 | DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", | ||
5088 | intel_crtc->pipe, intel_crtc->fdi_lanes); | ||
5089 | /* Clamp lanes to avoid programming the hw with bogus values. */ | ||
5090 | intel_crtc->fdi_lanes = 2; | ||
5091 | |||
5092 | return false; | ||
5093 | } | ||
5094 | |||
5095 | if (intel_crtc->fdi_lanes > 2) | ||
5096 | WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); | ||
5097 | else | ||
5098 | cpt_enable_fdi_bc_bifurcation(dev); | ||
5099 | |||
5100 | return true; | ||
5101 | case PIPE_C: | ||
5102 | if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) { | ||
5103 | if (intel_crtc->fdi_lanes > 2) { | ||
5104 | DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", | ||
5105 | intel_crtc->pipe, intel_crtc->fdi_lanes); | ||
5106 | /* Clamp lanes to avoid programming the hw with bogus values. */ | ||
5107 | intel_crtc->fdi_lanes = 2; | ||
5108 | |||
5109 | return false; | ||
5110 | } | ||
5111 | } else { | ||
5112 | DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n"); | ||
5113 | return false; | ||
5114 | } | ||
5115 | |||
5116 | cpt_enable_fdi_bc_bifurcation(dev); | ||
5117 | |||
5118 | return true; | ||
5119 | default: | ||
5120 | BUG(); | ||
5121 | } | ||
5122 | } | ||
5123 | |||
5016 | static void ironlake_set_m_n(struct drm_crtc *crtc, | 5124 | static void ironlake_set_m_n(struct drm_crtc *crtc, |
5017 | struct drm_display_mode *mode, | 5125 | struct drm_display_mode *mode, |
5018 | struct drm_display_mode *adjusted_mode) | 5126 | struct drm_display_mode *adjusted_mode) |
@@ -5211,7 +5319,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, | |||
5211 | struct intel_encoder *encoder; | 5319 | struct intel_encoder *encoder; |
5212 | u32 temp; | 5320 | u32 temp; |
5213 | int ret; | 5321 | int ret; |
5214 | bool dither; | 5322 | bool dither, fdi_config_ok; |
5215 | 5323 | ||
5216 | for_each_encoder_on_crtc(dev, crtc, encoder) { | 5324 | for_each_encoder_on_crtc(dev, crtc, encoder) { |
5217 | switch (encoder->type) { | 5325 | switch (encoder->type) { |
@@ -5349,8 +5457,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, | |||
5349 | 5457 | ||
5350 | intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); | 5458 | intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); |
5351 | 5459 | ||
5460 | /* Note, this also computes intel_crtc->fdi_lanes which is used below in | ||
5461 | * ironlake_check_fdi_lanes. */ | ||
5352 | ironlake_set_m_n(crtc, mode, adjusted_mode); | 5462 | ironlake_set_m_n(crtc, mode, adjusted_mode); |
5353 | 5463 | ||
5464 | fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); | ||
5465 | |||
5354 | if (is_cpu_edp) | 5466 | if (is_cpu_edp) |
5355 | ironlake_set_pll_edp(crtc, adjusted_mode->clock); | 5467 | ironlake_set_pll_edp(crtc, adjusted_mode->clock); |
5356 | 5468 | ||
@@ -5368,7 +5480,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, | |||
5368 | 5480 | ||
5369 | intel_update_linetime_watermarks(dev, pipe, adjusted_mode); | 5481 | intel_update_linetime_watermarks(dev, pipe, adjusted_mode); |
5370 | 5482 | ||
5371 | return ret; | 5483 | return fdi_config_ok ? ret : -EINVAL; |
5372 | } | 5484 | } |
5373 | 5485 | ||
5374 | static int haswell_crtc_mode_set(struct drm_crtc *crtc, | 5486 | static int haswell_crtc_mode_set(struct drm_crtc *crtc, |
@@ -8331,6 +8443,8 @@ static void intel_init_display(struct drm_device *dev) | |||
8331 | /* FIXME: detect B0+ stepping and use auto training */ | 8443 | /* FIXME: detect B0+ stepping and use auto training */ |
8332 | dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; | 8444 | dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; |
8333 | dev_priv->display.write_eld = ironlake_write_eld; | 8445 | dev_priv->display.write_eld = ironlake_write_eld; |
8446 | dev_priv->display.modeset_global_resources = | ||
8447 | ivb_modeset_global_resources; | ||
8334 | } else if (IS_HASWELL(dev)) { | 8448 | } else if (IS_HASWELL(dev)) { |
8335 | dev_priv->display.fdi_link_train = hsw_fdi_link_train; | 8449 | dev_priv->display.fdi_link_train = hsw_fdi_link_train; |
8336 | dev_priv->display.write_eld = haswell_write_eld; | 8450 | dev_priv->display.write_eld = haswell_write_eld; |