From d59f9f4d68ca82985a3b4578caa0485a9cb2b71b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:07 +0200 Subject: drm/i915: don't enable the plane too early in i9xx_crtc_mode_set This is horrible lore and we should be able to get rid of it now that the lvds/pfit handling code actually does the right thing. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6e423e04c35e..8b1cfc92849d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4733,8 +4733,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, i9xx_set_pipeconf(intel_crtc); - intel_enable_pipe(dev_priv, pipe, false); - intel_wait_for_vblank(dev, pipe); I915_WRITE(DSPCNTR(plane), dspcntr); -- cgit v1.2.3 From 4667730163a6d0afb04cefae9805ca1cdad1df46 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:08 +0200 Subject: drm/i915: drop redundant vblank waits Just blows through 50ms for naught, since the pipe is off. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8b1cfc92849d..5a904ddbb0df 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4733,8 +4733,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, i9xx_set_pipeconf(intel_crtc); - intel_wait_for_vblank(dev, pipe); - I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); @@ -5704,8 +5702,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ironlake_set_pipeconf(crtc, adjusted_mode, dither); - intel_wait_for_vblank(dev, pipe); - /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); POSTING_READ(DSPCNTR(plane)); -- cgit v1.2.3 From 58c6eaa24dbd8c97ef5f643324f087271aa79d64 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:09 +0200 Subject: drm/i915: add pipe asserts for the crtc enable sequence The i9xx modeset sequence is currently pretty fishy, so tight it all up with some good assert-sprinkling. We already have good coverage on the disable side, but the enable side is spotty (since until recently it was wrong). Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5a904ddbb0df..62fd5eae61c8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1474,6 +1474,8 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) int reg; u32 val; + assert_pipe_disabled(dev_priv, pipe); + /* No really, not for ILK+ */ BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5); @@ -1835,6 +1837,9 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int reg; u32 val; + assert_planes_disabled(dev_priv, pipe); + assert_sprites_disabled(dev_priv, pipe); + if (HAS_PCH_LPT(dev_priv->dev)) pch_transcoder = TRANSCODER_A; else -- cgit v1.2.3 From e29a18faaa18470f313b570fdf2d0f75c35e6cb2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:10 +0200 Subject: drm/i915: add i9xx pfit pipe asserts We can only enable the pfit if the pipe is disabled. Ensure that this is obeyed with a neat assert. Also check whether the pfit is off before enabling it - if not we've lost track of things somewhere since the pfit is only ever used by the lvds output. v2: Fix spell fail in the commit message pointed out by Ville&Jani. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index f36f1baabd5a..563f5052fcfc 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -159,6 +159,9 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder) if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) return; + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe); + /* * Enable automatic panel scaling so that non-native modes * fill the screen. The panel fitter should only be -- cgit v1.2.3 From e3641d3f77bb9aea8442dc25018d651d3a348d76 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 19:49:07 +0200 Subject: drm/i915: move debug output back to the right place When adding the pipe config computation step I've accidentally moved this a bit away. Which momentarily confused me since the pipe config step rejected some modesetting operations I expected and so left me looking in vain for that debug output. v2: Move the debug output into the right function to prevent this from happening again. v3: Make it compile (Ville). Also reorder the patch so that the two bugfixes are first. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62fd5eae61c8..ae7c3779baef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7744,6 +7744,9 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, */ *modeset_pipes &= 1 << intel_crtc->pipe; *prepare_pipes &= 1 << intel_crtc->pipe; + + DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", + *modeset_pipes, *prepare_pipes, *disable_pipes); } static bool intel_crtc_in_use(struct drm_crtc *crtc) @@ -7974,9 +7977,6 @@ static int __intel_set_mode(struct drm_crtc *crtc, } } - DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", - modeset_pipes, prepare_pipes, disable_pipes); - for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); -- cgit v1.2.3 From 2582a8504dbdc80b6e16ac8dfd6a7f9d03bece73 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Apr 2013 17:48:47 +0300 Subject: drm/i915: Use pipe_name() and port_name() where appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the few remaining open coded copies of pipe_name() and port_name(). Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ae7c3779baef..462c81a871ab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4723,7 +4723,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); @@ -6109,7 +6109,7 @@ static void ironlake_write_eld(struct drm_connector *connector, eldv |= IBX_ELD_VALIDB << 4; eldv |= IBX_ELD_VALIDB << 8; } else { - DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i); + DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i)); eldv = IBX_ELD_VALIDB << ((i - 1) * 4); } -- cgit v1.2.3 From cfc33bf75bfbf8f95bffe040ee1a5ab1cda8c34c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Apr 2013 17:48:48 +0300 Subject: drm/i915: Use port_name() in PCH port audio power change message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0aa2ef0d2ae0..3af983fad67c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -763,10 +763,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } - if (pch_iir & SDE_AUDIO_POWER_MASK) + if (pch_iir & SDE_AUDIO_POWER_MASK) { + int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> + SDE_AUDIO_POWER_SHIFT); DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", - (pch_iir & SDE_AUDIO_POWER_MASK) >> - SDE_AUDIO_POWER_SHIFT); + port_name(port)); + } if (pch_iir & SDE_AUX_MASK) dp_aux_irq_handler(dev); @@ -812,10 +814,12 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } - if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) - DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", - (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> - SDE_AUDIO_POWER_SHIFT_CPT); + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { + int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> + SDE_AUDIO_POWER_SHIFT_CPT); + DRM_DEBUG_DRIVER("PCH audio power change on port %c\n", + port_name(port)); + } if (pch_iir & SDE_AUX_MASK_CPT) dp_aux_irq_handler(dev); -- cgit v1.2.3 From 84f44ce795b3da9a08dc2041ecd60550d34c123e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Apr 2013 17:48:49 +0300 Subject: drm/i915: Print plane, pipe, port names as alphabetical insted of decimal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alway use the alphabetical names in debug/error messages for planes, pipes and ports, instead of using decimal numbers occasionally. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 10 ++++----- drivers/gpu/drm/i915/intel_display.c | 42 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_pm.c | 26 +++++++++++----------- 3 files changed, 39 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 26a0a570f92e..e14fe5f569ee 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -748,8 +748,8 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc) } if (num_encoders != 1) - WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders, - intel_crtc->pipe); + WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders, + pipe_name(intel_crtc->pipe)); BUG_ON(ret == NULL); return ret; @@ -1047,8 +1047,8 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) } } else { - WARN(1, "Invalid encoder type %d for pipe %d\n", - intel_encoder->type, pipe); + WARN(1, "Invalid encoder type %d for pipe %c\n", + intel_encoder->type, pipe_name(pipe)); } I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); @@ -1148,7 +1148,7 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, } } - DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port); + DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port)); return false; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 462c81a871ab..e472488394ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2101,7 +2101,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, case 1: break; default: - DRM_ERROR("Can't update plane %d in SAREA\n", plane); + DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); return -EINVAL; } @@ -2198,7 +2198,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, case 2: break; default: - DRM_ERROR("Can't update plane %d in SAREA\n", plane); + DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane)); return -EINVAL; } @@ -2389,9 +2389,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) { - DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n", - intel_crtc->plane, - INTEL_INFO(dev)->num_pipes); + DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n", + plane_name(intel_crtc->plane), + INTEL_INFO(dev)->num_pipes); return -EINVAL; } @@ -3299,7 +3299,7 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 found: intel_crtc->pch_pll = pll; pll->refcount++; - DRM_DEBUG_DRIVER("using pll %d for pipe %d\n", i, intel_crtc->pipe); + DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe)); prepare: /* separate function? */ DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg); @@ -3324,7 +3324,7 @@ void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) udelay(500); if (wait_for(I915_READ(dslreg) != temp, 5)) { if (wait_for(I915_READ(dslreg) != temp, 5)) - DRM_ERROR("mode set failed: pipe %d stuck\n", pipe); + DRM_ERROR("mode set failed: pipe %c stuck\n", pipe_name(pipe)); } } @@ -5344,11 +5344,11 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) struct intel_crtc *pipe_B_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); - DRM_DEBUG_KMS("checking fdi config on pipe %i, lanes %i\n", - intel_crtc->pipe, intel_crtc->fdi_lanes); + DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n", + pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); if (intel_crtc->fdi_lanes > 4) { - DRM_DEBUG_KMS("invalid fdi lane config on pipe %i: %i lanes\n", - intel_crtc->pipe, intel_crtc->fdi_lanes); + DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n", + pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ intel_crtc->fdi_lanes = 4; @@ -5364,8 +5364,8 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) case PIPE_B: if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && intel_crtc->fdi_lanes > 2) { - DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", - intel_crtc->pipe, intel_crtc->fdi_lanes); + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ intel_crtc->fdi_lanes = 2; @@ -5381,8 +5381,8 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) case PIPE_C: if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) { if (intel_crtc->fdi_lanes > 2) { - DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n", - intel_crtc->pipe, intel_crtc->fdi_lanes); + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ intel_crtc->fdi_lanes = 2; @@ -5647,7 +5647,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); - DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ @@ -5656,8 +5656,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, pll = intel_get_pch_pll(intel_crtc, dpll, fp); if (pll == NULL) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", - pipe); + DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", + pipe_name(pipe)); return -EINVAL; } } else @@ -5821,7 +5821,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, /* determine panel color depth */ dither = intel_crtc->config.dither; - DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); + DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); if (intel_crtc->config.has_dp_encoder) @@ -9051,8 +9051,8 @@ void intel_modeset_init(struct drm_device *dev) for (j = 0; j < dev_priv->num_plane; j++) { ret = intel_plane_init(dev, i, j); if (ret) - DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n", - i, j, ret); + DRM_DEBUG_KMS("pipe %c plane %d init failed: %d\n", + pipe_name(i), j, ret); } } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e34ad9642519..413877d4afea 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -113,8 +113,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) fbc_ctl |= obj->fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); - DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", - cfb_pitch, crtc->y, intel_crtc->plane); + DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c, ", + cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); } static bool i8xx_fbc_enabled(struct drm_device *dev) @@ -148,7 +148,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* enable it... */ I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } static void g4x_disable_fbc(struct drm_device *dev) @@ -228,7 +228,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) sandybridge_blit_fbc_update(dev); } - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } static void ironlake_disable_fbc(struct drm_device *dev) @@ -2146,15 +2146,15 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, &sandybridge_display_wm_info, latency, &sprite_wm); if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", - pipe); + DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n", + pipe_name(pipe)); return; } val = I915_READ(reg); val &= ~WM0_PIPE_SPRITE_MASK; I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); - DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); + DRM_DEBUG_KMS("sprite watermarks For pipe %c - %d\n", pipe_name(pipe), sprite_wm); ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, @@ -2163,8 +2163,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, SNB_READ_WM1_LATENCY() * 500, &sprite_wm); if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", - pipe); + DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n", + pipe_name(pipe)); return; } I915_WRITE(WM1S_LP_ILK, sprite_wm); @@ -2179,8 +2179,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, SNB_READ_WM2_LATENCY() * 500, &sprite_wm); if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", - pipe); + DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n", + pipe_name(pipe)); return; } I915_WRITE(WM2S_LP_IVB, sprite_wm); @@ -2191,8 +2191,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, SNB_READ_WM3_LATENCY() * 500, &sprite_wm); if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", - pipe); + DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n", + pipe_name(pipe)); return; } I915_WRITE(WM3S_LP_IVB, sprite_wm); -- cgit v1.2.3 From 4bb6f1f3270923cdcd57293ea736955d5c35db72 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Apr 2013 17:48:50 +0300 Subject: drm/i915: Use alphabetical names for transcoders too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the alphabetical name for transcoders. The code already used the pipe_name() macro for transcoders, so I did the same. But we do have the (unused) transcoder_name() macro which could be used instead. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e472488394ae..81ae89b9c794 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1097,14 +1097,14 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv, pch_dpll = I915_READ(PCH_DPLL_SEL); cur_state = pll->pll_reg == _PCH_DPLL_B; if (!WARN(((pch_dpll >> (4 * crtc->pipe)) & 1) != cur_state, - "PLL[%d] not attached to this transcoder %d: %08x\n", - cur_state, crtc->pipe, pch_dpll)) { + "PLL[%d] not attached to this transcoder %c: %08x\n", + cur_state, pipe_name(crtc->pipe), pch_dpll)) { cur_state = !!(val >> (4*crtc->pipe + 3)); WARN(cur_state != state, - "PLL[%d] not %s on this transcoder %d: %08x\n", + "PLL[%d] not %s on this transcoder %c: %08x\n", pll->pll_reg == _PCH_DPLL_B, state_string(state), - crtc->pipe, + pipe_name(crtc->pipe), val); } } @@ -1733,7 +1733,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, I915_WRITE(reg, val | TRANS_ENABLE); if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) - DRM_ERROR("failed to enable transcoder %d\n", pipe); + DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe)); } static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, @@ -1786,7 +1786,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, I915_WRITE(reg, val); /* wait for PCH transcoder off, transcoder state */ if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) - DRM_ERROR("failed to disable transcoder %d\n", pipe); + DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe)); if (!HAS_PCH_IBX(dev)) { /* Workaround: Clear the timing override chicken bit again. */ -- cgit v1.2.3 From 06da8da2b014d6cc98fa86e72b605e525e6d6884 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Apr 2013 17:48:51 +0300 Subject: drm/i915: Use alphabetical names for sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add sprite_name() macro which should be used with the kind of sprites that are fixed to pipes (gen4.5+). Also use dev_priv->num_plane to calculate the sprite index insted assuming two sprites per pipe. This should make it print the right name. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d5dcf7fe1ee9..15d0a3a8f319 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -76,6 +76,8 @@ enum plane { }; #define plane_name(p) ((p) + 'A') +#define sprite_name(p, s) ((p) * dev_priv->num_plane + (s) + 'A') + enum port { PORT_A = 0, PORT_B, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 81ae89b9c794..02faba0263de 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1302,8 +1302,8 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, reg = SPCNTR(pipe, i); val = I915_READ(reg); WARN((val & SP_ENABLE), - "sprite %d assertion failure, should be off on pipe %c but is still active\n", - pipe * 2 + i, pipe_name(pipe)); + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + sprite_name(pipe, i), pipe_name(pipe)); } } @@ -9051,8 +9051,8 @@ void intel_modeset_init(struct drm_device *dev) for (j = 0; j < dev_priv->num_plane; j++) { ret = intel_plane_init(dev, i, j); if (ret) - DRM_DEBUG_KMS("pipe %c plane %d init failed: %d\n", - pipe_name(i), j, ret); + DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n", + pipe_name(i), sprite_name(i, j), ret); } } -- cgit v1.2.3 From 855ba3be12badf6228151ca3ccf54632cfdd463d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 17 Apr 2013 15:54:57 -0700 Subject: drm/i915: VLV GPU frequency to opcode functions When requesting frequency changes or querying status from the Punit, we need to use an opcode that corresponds to the frequency, taking into account the memory frequency. Signed-off-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 15d0a3a8f319..abb065502deb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1887,6 +1887,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); +int vlv_gpu_freq(int ddr_freq, int val); +int vlv_freq_opcode(int ddr_freq, int val); #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 413877d4afea..f802368e8e9d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4620,3 +4620,59 @@ int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) { return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val); } + +int vlv_gpu_freq(int ddr_freq, int val) +{ + int mult, base; + + switch (ddr_freq) { + case 800: + mult = 20; + base = 120; + break; + case 1066: + mult = 22; + base = 133; + break; + case 1333: + mult = 21; + base = 125; + break; + default: + return -1; + } + + return ((val - 0xbd) * mult) + base; +} + +int vlv_freq_opcode(int ddr_freq, int val) +{ + int mult, base; + + switch (ddr_freq) { + case 800: + mult = 20; + base = 120; + break; + case 1066: + mult = 22; + base = 133; + break; + case 1333: + mult = 21; + base = 125; + break; + default: + return -1; + } + + val /= mult; + val -= base / mult; + val += 0xbd; + + if (val > 0xea) + val = 0xea; + + return val; +} + -- cgit v1.2.3 From 0a073b843bcd9a660f76e497182aac97cafddc4c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 17 Apr 2013 15:54:58 -0700 Subject: drm/i915: turbo & RC6 support for VLV v7 Uses slightly different interfaces than other platforms. v2: track actual set freq, not requested (Rohit) fix debug prints in init code (Jesse) v3: don't write sleep reg (Jesse) re-add RC6 wake limit write (Ben) fixup thresholds to match other platforms (Ben) clean up mem freq calculation (Ben) clean up debug prints (Ben) v4: move defines from punit patch (Ville) v5: remove writes to nonexistent regs (Jesse) put RP and RC regs together (Jesse) fix RC6 enable (Jesse) v6: use correct fuse reads from NC (Jesse) split out min/max funcs for use in sysfs (Jesse) add debugfs & sysfs freq controls (Jesse) v7: update with Ben's hw_max changes (Jesse) Signed-off-by: Jesse Barnes Reviewed-by: Ben Widawsky (v6) [danvet: Follow checkpatch sugggestion to use min_t to avoid casting fun.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 58 +++++++++-- drivers/gpu/drm/i915/i915_drv.h | 5 + drivers/gpu/drm/i915/i915_irq.c | 5 +- drivers/gpu/drm/i915/i915_reg.h | 21 ++++ drivers/gpu/drm/i915/i915_sysfs.c | 71 +++++++++---- drivers/gpu/drm/i915/intel_pm.c | 199 ++++++++++++++++++++++++++++++++++-- 6 files changed, 320 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e913d325d5b8..367b534d2260 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -941,7 +941,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) MEMSTAT_VID_SHIFT); seq_printf(m, "Current P-state: %d\n", (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); - } else if (IS_GEN6(dev) || IS_GEN7(dev)) { + } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); @@ -1009,6 +1009,25 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "Max overclocked frequency: %dMHz\n", dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER); + } else if (IS_VALLEYVIEW(dev)) { + u32 freq_sts, val; + + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, + &freq_sts); + seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); + seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); + + valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val); + seq_printf(m, "max GPU freq: %d MHz\n", + vlv_gpu_freq(dev_priv->mem_freq, val)); + + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); + seq_printf(m, "min GPU freq: %d MHz\n", + vlv_gpu_freq(dev_priv->mem_freq, val)); + + seq_printf(m, "current GPU freq: %d MHz\n", + vlv_gpu_freq(dev_priv->mem_freq, + (freq_sts >> 8) & 0xff)); } else { seq_printf(m, "no P-state info available\n"); } @@ -1812,7 +1831,11 @@ i915_max_freq_get(void *data, u64 *val) if (ret) return ret; - *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; + if (IS_VALLEYVIEW(dev)) + *val = vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.max_delay); + else + *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1837,9 +1860,16 @@ i915_max_freq_set(void *data, u64 val) /* * Turbo will still be enabled, but won't go above the set value. */ - do_div(val, GT_FREQUENCY_MULTIPLIER); - dev_priv->rps.max_delay = val; - gen6_set_rps(dev, val); + if (IS_VALLEYVIEW(dev)) { + val = vlv_freq_opcode(dev_priv->mem_freq, val); + dev_priv->rps.max_delay = val; + gen6_set_rps(dev, val); + } else { + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.max_delay = val; + gen6_set_rps(dev, val); + } + mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1863,7 +1893,11 @@ i915_min_freq_get(void *data, u64 *val) if (ret) return ret; - *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; + if (IS_VALLEYVIEW(dev)) + *val = vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.min_delay); + else + *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1888,9 +1922,15 @@ i915_min_freq_set(void *data, u64 val) /* * Turbo will still be enabled, but won't go below the set value. */ - do_div(val, GT_FREQUENCY_MULTIPLIER); - dev_priv->rps.min_delay = val; - gen6_set_rps(dev, val); + if (IS_VALLEYVIEW(dev)) { + val = vlv_freq_opcode(dev_priv->mem_freq, val); + dev_priv->rps.min_delay = val; + valleyview_set_rps(dev, val); + } else { + do_div(val, GT_FREQUENCY_MULTIPLIER); + dev_priv->rps.min_delay = val; + gen6_set_rps(dev, val); + } mutex_unlock(&dev_priv->rps.hw_lock); return 0; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index abb065502deb..bd2d7f17393e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1856,6 +1856,9 @@ extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_init_pch_refclk(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); +extern void valleyview_set_rps(struct drm_device *dev, u8 val); +extern int valleyview_rps_max_freq(struct drm_i915_private *dev_priv); +extern int valleyview_rps_min_freq(struct drm_i915_private *dev_priv); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); extern int intel_enable_rc6(const struct drm_device *dev); @@ -1887,6 +1890,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); +int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); + int vlv_gpu_freq(int ddr_freq, int val); int vlv_freq_opcode(int ddr_freq, int val); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3af983fad67c..932e7f8b6d5c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -482,7 +482,10 @@ static void gen6_pm_rps_work(struct work_struct *work) */ if (!(new_delay > dev_priv->rps.max_delay || new_delay < dev_priv->rps.min_delay)) { - gen6_set_rps(dev_priv->dev, new_delay); + if (IS_VALLEYVIEW(dev_priv->dev)) + valleyview_set_rps(dev_priv->dev, new_delay); + else + gen6_set_rps(dev_priv->dev, new_delay); } mutex_unlock(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 31de7e4b1f3e..66fb8dd28225 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4315,6 +4315,7 @@ #define GEN6_RC_CTL_RC6_ENABLE (1<<18) #define GEN6_RC_CTL_RC1e_ENABLE (1<<20) #define GEN6_RC_CTL_RC7_ENABLE (1<<22) +#define GEN7_RC_CTL_TO_MODE (1<<28) #define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) #define GEN6_RC_CTL_HW_ENABLE (1<<31) #define GEN6_RP_DOWN_TIMEOUT 0xA010 @@ -4406,12 +4407,32 @@ #define IOSF_BAR_SHIFT 1 #define IOSF_SB_BUSY (1<<0) #define IOSF_PORT_PUNIT 0x4 +#define IOSF_PORT_NC 0x11 #define VLV_IOSF_DATA 0x182104 #define VLV_IOSF_ADDR 0x182108 #define PUNIT_OPCODE_REG_READ 6 #define PUNIT_OPCODE_REG_WRITE 7 +#define PUNIT_REG_GPU_LFM 0xd3 +#define PUNIT_REG_GPU_FREQ_REQ 0xd4 +#define PUNIT_REG_GPU_FREQ_STS 0xd8 +#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc + +#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ +#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ + +#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c +#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 +#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 +#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 +#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 +#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 +#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 +#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 + #define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_RCn_MASK 7 diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index d5e1890678f9..ca00df2de07b 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -212,7 +212,10 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, int ret; mutex_lock(&dev_priv->rps.hw_lock); - ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; + if (IS_VALLEYVIEW(dev_priv->dev)) + ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay); + else + ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); @@ -226,7 +229,10 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute int ret; mutex_lock(&dev_priv->rps.hw_lock); - ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; + if (IS_VALLEYVIEW(dev_priv->dev)) + ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay); + else + ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); @@ -246,16 +252,25 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, if (ret) return ret; - val /= GT_FREQUENCY_MULTIPLIER; - mutex_lock(&dev_priv->rps.hw_lock); - rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = dev_priv->rps.hw_max; - non_oc_max = (rp_state_cap & 0xff); - hw_min = ((rp_state_cap & 0xff0000) >> 16); + if (IS_VALLEYVIEW(dev_priv->dev)) { + val = vlv_freq_opcode(dev_priv->mem_freq, val); + + hw_max = valleyview_rps_max_freq(dev_priv); + hw_min = valleyview_rps_min_freq(dev_priv); + non_oc_max = hw_max; + } else { + val /= GT_FREQUENCY_MULTIPLIER; - if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + hw_max = dev_priv->rps.hw_max; + non_oc_max = (rp_state_cap & 0xff); + hw_min = ((rp_state_cap & 0xff0000) >> 16); + } + + if (val < hw_min || val > hw_max || + val < dev_priv->rps.min_delay) { mutex_unlock(&dev_priv->rps.hw_lock); return -EINVAL; } @@ -264,8 +279,12 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, DRM_DEBUG("User requested overclocking to %d\n", val * GT_FREQUENCY_MULTIPLIER); - if (dev_priv->rps.cur_delay > val) - gen6_set_rps(dev_priv->dev, val); + if (dev_priv->rps.cur_delay > val) { + if (IS_VALLEYVIEW(dev_priv->dev)) + valleyview_set_rps(dev_priv->dev, val); + else + gen6_set_rps(dev_priv->dev, val); + } dev_priv->rps.max_delay = val; @@ -282,7 +301,10 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute int ret; mutex_lock(&dev_priv->rps.hw_lock); - ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; + if (IS_VALLEYVIEW(dev_priv->dev)) + ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay); + else + ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); @@ -302,21 +324,32 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, if (ret) return ret; - val /= GT_FREQUENCY_MULTIPLIER; - mutex_lock(&dev_priv->rps.hw_lock); - rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = dev_priv->rps.hw_max; - hw_min = ((rp_state_cap & 0xff0000) >> 16); + if (IS_VALLEYVIEW(dev)) { + val = vlv_freq_opcode(dev_priv->mem_freq, val); + + hw_max = valleyview_rps_max_freq(dev_priv); + hw_min = valleyview_rps_min_freq(dev_priv); + } else { + val /= GT_FREQUENCY_MULTIPLIER; + + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + hw_max = dev_priv->rps.hw_max; + hw_min = ((rp_state_cap & 0xff0000) >> 16); + } if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { mutex_unlock(&dev_priv->rps.hw_lock); return -EINVAL; } - if (dev_priv->rps.cur_delay < val) - gen6_set_rps(dev_priv->dev, val); + if (dev_priv->rps.cur_delay < val) { + if (IS_VALLEYVIEW(dev)) + valleyview_set_rps(dev, val); + else + gen6_set_rps(dev_priv->dev, val); + } dev_priv->rps.min_delay = val; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f802368e8e9d..2557926553b3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2481,6 +2481,52 @@ void gen6_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(val * 50); } +void valleyview_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 limits = gen6_rps_limits(dev_priv, &val); + u32 pval; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + WARN_ON(val > dev_priv->rps.max_delay); + WARN_ON(val < dev_priv->rps.min_delay); + + DRM_DEBUG_DRIVER("gpu freq request from %d to %d\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.cur_delay), + vlv_gpu_freq(dev_priv->mem_freq, val)); + + if (val == dev_priv->rps.cur_delay) + return; + + valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); + + do { + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + if (time_after(jiffies, timeout)) { + DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); + break; + } + udelay(10); + } while (pval & 1); + + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + if ((pval >> 8) != val) + DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n", + val, pval >> 8); + + /* Make sure we continue to get interrupts + * until we hit the minimum or maximum frequencies. + */ + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + + dev_priv->rps.cur_delay = pval >> 8; + + trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); +} + + static void gen6_disable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2742,6 +2788,127 @@ static void gen6_update_ring_freq(struct drm_device *dev) } } +int valleyview_rps_max_freq(struct drm_i915_private *dev_priv) +{ + u32 val, rp0; + + valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val); + + rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT; + /* Clamp to max */ + rp0 = min_t(u32, rp0, 0xea); + + return rp0; +} + +static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv) +{ + u32 val, rpe; + + valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val); + rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT; + valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val); + rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5; + + return rpe; +} + +int valleyview_rps_min_freq(struct drm_i915_private *dev_priv) +{ + u32 val; + + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); + + return val & 0xff; +} + +static void valleyview_enable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + u32 gtfifodbg, val, rpe; + int i; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + if ((gtfifodbg = I915_READ(GTFIFODBG))) { + DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg); + I915_WRITE(GTFIFODBG, gtfifodbg); + } + + gen6_gt_force_wake_get(dev_priv); + + I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400); + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000); + I915_WRITE(GEN6_RP_UP_EI, 66000); + I915_WRITE(GEN6_RP_DOWN_EI, 350000); + + I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); + + I915_WRITE(GEN6_RP_CONTROL, + GEN6_RP_MEDIA_TURBO | + GEN6_RP_MEDIA_HW_NORMAL_MODE | + GEN6_RP_MEDIA_IS_GFX | + GEN6_RP_ENABLE | + GEN6_RP_UP_BUSY_AVG | + GEN6_RP_DOWN_IDLE_CONT); + + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000); + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); + + for_each_ring(ring, dev_priv, i) + I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); + + I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350); + + /* allows RC6 residency counter to work */ + I915_WRITE(0x138104, _MASKED_BIT_ENABLE(0x3)); + I915_WRITE(GEN6_RC_CONTROL, + GEN7_RC_CTL_TO_MODE); + + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val); + dev_priv->mem_freq = 800 + (266 * (val >> 6) & 3); + DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); + + DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); + DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); + + DRM_DEBUG_DRIVER("current GPU freq: %d\n", + vlv_gpu_freq(dev_priv->mem_freq, (val >> 8) & 0xff)); + dev_priv->rps.cur_delay = (val >> 8) & 0xff; + + dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); + dev_priv->rps.hw_max = dev_priv->rps.max_delay; + DRM_DEBUG_DRIVER("max GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.max_delay)); + + rpe = valleyview_rps_rpe_freq(dev_priv); + DRM_DEBUG_DRIVER("RPe GPU freq: %d\n", + vlv_gpu_freq(dev_priv->mem_freq, rpe)); + + val = valleyview_rps_min_freq(dev_priv); + DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, + val)); + dev_priv->rps.min_delay = val; + + DRM_DEBUG_DRIVER("setting GPU freq to %d\n", + vlv_gpu_freq(dev_priv->mem_freq, rpe)); + + valleyview_set_rps(dev_priv->dev, rpe); + + /* requires MSI enabled */ + I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); + spin_lock_irq(&dev_priv->rps.lock); + WARN_ON(dev_priv->rps.pm_iir != 0); + I915_WRITE(GEN6_PMIMR, 0); + spin_unlock_irq(&dev_priv->rps.lock); + /* enable all PM interrupts */ + I915_WRITE(GEN6_PMINTRMSK, 0); + + gen6_gt_force_wake_put(dev_priv); +} + void ironlake_teardown_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3468,7 +3635,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) { ironlake_disable_drps(dev); ironlake_disable_rc6(dev); - } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) { + } else if (INTEL_INFO(dev)->gen >= 6) { cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); mutex_lock(&dev_priv->rps.hw_lock); gen6_disable_rps(dev); @@ -3484,8 +3651,13 @@ static void intel_gen6_powersave_work(struct work_struct *work) struct drm_device *dev = dev_priv->dev; mutex_lock(&dev_priv->rps.hw_lock); - gen6_enable_rps(dev); - gen6_update_ring_freq(dev); + + if (IS_VALLEYVIEW(dev)) { + valleyview_enable_rps(dev); + } else { + gen6_enable_rps(dev); + gen6_update_ring_freq(dev); + } mutex_unlock(&dev_priv->rps.hw_lock); } @@ -3497,7 +3669,7 @@ void intel_enable_gt_powersave(struct drm_device *dev) ironlake_enable_drps(dev); ironlake_enable_rc6(dev); intel_init_emon(dev); - } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { + } else if (IS_GEN6(dev) || IS_GEN7(dev)) { /* * PCU communication is slow and this doesn't need to be * done at any specific time, so do this out of our fast path @@ -4568,14 +4740,13 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) return 0; } -static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, +static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode, u8 addr, u32 *val) { - u32 cmd, devfn, port, be, bar; + u32 cmd, devfn, be, bar; bar = 0; be = 0xf; - port = IOSF_PORT_PUNIT; devfn = PCI_DEVFN(2, 0); cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | @@ -4597,7 +4768,7 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, - 500)) { + 5)) { DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", addr); @@ -4613,12 +4784,20 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode, int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) { - return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_READ, addr, val); + return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ, + addr, val); } int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) { - return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val); + return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE, + addr, &val); +} + +int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +{ + return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ, + addr, val); } int vlv_gpu_freq(int ddr_freq, int val) -- cgit v1.2.3 From 75e539864a133c4d8d6a4aac9f409e0a23d7bc3f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Apr 2013 21:10:43 +0200 Subject: drm/i915: fix VLV limits Magic updates. v2: use 64 bit types and math (Ville) v3: Trim out all the m/n/p calculation changes since they are still under discussion. Instead squash in a fixup for hdmi limits which slipped into a different patch. Signed-off-by: Pallavi G Signed-off-by: Vijay Purushothaman Signed-off-by: Yogesh M Signed-off-by: Gajanan Bhat Signed-off-by: Jesse Barnes (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 02faba0263de..bdbad762134c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -396,15 +396,15 @@ static const intel_limit_t intel_limits_vlv_dac = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, - .p1 = { .min = 2, .max = 3 }, + .p1 = { .min = 1, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, .find_pll = intel_vlv_find_best_pll, }; static const intel_limit_t intel_limits_vlv_hdmi = { - .dot = { .min = 20000, .max = 165000 }, - .vco = { .min = 4000000, .max = 5994000}, + .dot = { .min = 25000, .max = 270000 }, + .vco = { .min = 4000000, .max = 6000000 }, .n = { .min = 1, .max = 7 }, .m = { .min = 60, .max = 300 }, /* guess */ .m1 = { .min = 2, .max = 3 }, @@ -424,7 +424,7 @@ static const intel_limit_t intel_limits_vlv_dp = { .m1 = { .min = 2, .max = 3 }, .m2 = { .min = 11, .max = 156 }, .p = { .min = 10, .max = 30 }, - .p1 = { .min = 2, .max = 3 }, + .p1 = { .min = 1, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, .find_pll = intel_vlv_find_best_pll, -- cgit v1.2.3 From 598fac6bf8299ed7ae1852426660be3c265047a4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Apr 2013 22:01:46 +0200 Subject: drm/i915: magic VLV PLL registers in the dpio sideband Stolen from a patch with the below impressive sob-section. Signed-off-by: Pallavi G Signed-off-by: Vijay Purushothaman Signed-off-by: Gajanan Bhat Signed-off-by: Ben Widawsky Signed-off-by: Jesse Barnes [danvet: Drop everything but the header #defines.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 118 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 66fb8dd28225..fb1a4fa68d55 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -353,6 +353,8 @@ * 0x8100: fast clock controls * * DPIO is VLV only. + * + * Note: digital port B is DDI0, digital pot C is DDI1 */ #define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100) #define DPIO_RID (0<<24) @@ -369,8 +371,20 @@ #define DPIO_SFR_BYPASS (1<<1) #define DPIO_RESET (1<<0) +#define _DPIO_TX3_SWING_CTL4_A 0x690 +#define _DPIO_TX3_SWING_CTL4_B 0x2a90 +#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX_SWING_CTL4_A, \ + _DPIO_TX3_SWING_CTL4_B) + +/* + * Per pipe/PLL DPIO regs + */ #define _DPIO_DIV_A 0x800c #define DPIO_POST_DIV_SHIFT (28) /* 3 bits */ +#define DPIO_POST_DIV_DAC 0 +#define DPIO_POST_DIV_HDMIDP 1 /* DAC 225-400M rate */ +#define DPIO_POST_DIV_LVDS1 2 +#define DPIO_POST_DIV_LVDS2 3 #define DPIO_K_SHIFT (24) /* 4 bits */ #define DPIO_P1_SHIFT (21) /* 3 bits */ #define DPIO_P2_SHIFT (16) /* 5 bits */ @@ -396,14 +410,111 @@ #define _DPIO_CORE_CLK_B 0x803c #define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B) +#define _DPIO_IREF_CTL_A 0x8040 +#define _DPIO_IREF_CTL_B 0x8060 +#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B) + +#define DPIO_IREF_BCAST 0xc044 +#define _DPIO_IREF_A 0x8044 +#define _DPIO_IREF_B 0x8064 +#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B) + +#define _DPIO_PLL_CML_A 0x804c +#define _DPIO_PLL_CML_B 0x806c +#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) + #define _DPIO_LFP_COEFF_A 0x8048 #define _DPIO_LFP_COEFF_B 0x8068 #define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B) +#define DPIO_CALIBRATION 0x80ac + #define DPIO_FASTCLK_DISABLE 0x8100 -#define DPIO_DATA_CHANNEL1 0x8220 -#define DPIO_DATA_CHANNEL2 0x8420 +/* + * Per DDI channel DPIO regs + */ + +#define _DPIO_PCS_TX_0 0x8200 +#define _DPIO_PCS_TX_1 0x8400 +#define DPIO_PCS_TX_LANE2_RESET (1<<16) +#define DPIO_PCS_TX_LANE1_RESET (1<<7) +#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1) + +#define _DPIO_PCS_CLK_0 0x8204 +#define _DPIO_PCS_CLK_1 0x8404 +#define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22) +#define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21) +#define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6) +#define DPIO_PCS_CLK_SOFT_RESET (1<<5) +#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1) + +#define _DPIO_PCS_CTL_OVR1_A 0x8224 +#define _DPIO_PCS_CTL_OVR1_B 0x8424 +#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \ + _DPIO_PCS_CTL_OVR1_B) + +#define _DPIO_PCS_STAGGER0_A 0x822c +#define _DPIO_PCS_STAGGER0_B 0x842c +#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \ + _DPIO_PCS_STAGGER0_B) + +#define _DPIO_PCS_STAGGER1_A 0x8230 +#define _DPIO_PCS_STAGGER1_B 0x8430 +#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \ + _DPIO_PCS_STAGGER1_B) + +#define _DPIO_PCS_CLOCKBUF0_A 0x8238 +#define _DPIO_PCS_CLOCKBUF0_B 0x8438 +#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \ + _DPIO_PCS_CLOCKBUF0_B) + +#define _DPIO_PCS_CLOCKBUF8_A 0x825c +#define _DPIO_PCS_CLOCKBUF8_B 0x845c +#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \ + _DPIO_PCS_CLOCKBUF8_B) + +#define _DPIO_TX_SWING_CTL2_A 0x8288 +#define _DPIO_TX_SWING_CTL2_B 0x8488 +#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \ + _DPIO_TX_SWING_CTL2_B) + +#define _DPIO_TX_SWING_CTL3_A 0x828c +#define _DPIO_TX_SWING_CTL3_B 0x848c +#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \ + _DPIO_TX_SWING_CTL3_B) + +#define _DPIO_TX_SWING_CTL4_A 0x8290 +#define _DPIO_TX_SWING_CTL4_B 0x8490 +#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \ + _DPIO_TX_SWING_CTL4_B) + +#define _DPIO_TX_OCALINIT_0 0x8294 +#define _DPIO_TX_OCALINIT_1 0x8494 +#define DPIO_TX_OCALINIT_EN (1<<31) +#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \ + _DPIO_TX_OCALINIT_1) + +#define _DPIO_TX_CTL_0 0x82ac +#define _DPIO_TX_CTL_1 0x84ac +#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1) + +#define _DPIO_TX_LANE_0 0x82b8 +#define _DPIO_TX_LANE_1 0x84b8 +#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1) + +#define _DPIO_DATA_CHANNEL1 0x8220 +#define _DPIO_DATA_CHANNEL2 0x8420 +#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2) + +#define _DPIO_PORT0_PCS0 0x0220 +#define _DPIO_PORT0_PCS1 0x0420 +#define _DPIO_PORT1_PCS2 0x2620 +#define _DPIO_PORT1_PCS3 0x2820 +#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2) +#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3) +#define DPIO_DATA_CHANNEL1 0x8220 +#define DPIO_DATA_CHANNEL2 0x8420 /* * Fence registers @@ -965,7 +1076,10 @@ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ #define DPLL_LOCK_VLV (1<<15) +#define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14) #define DPLL_INTEGRATED_CLOCK_VLV (1<<13) +#define DPLL_PORTC_READY_MASK (0xf << 4) +#define DPLL_PORTB_READY_MASK (0xf) #define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 /* -- cgit v1.2.3 From e2fa6fba3d2fa03a5efdedf0b6f045fcc3428a80 Mon Sep 17 00:00:00 2001 From: Pallavi G Date: Thu, 18 Apr 2013 14:44:28 -0700 Subject: drm/i915/dp: program VSwing and Preemphasis control settings on VLV v2 Program few Tx buffer Swing control settings through DPIO. v2: fix up codingstyle (Daniel) call from set_signal_levels (Ville, Daniel) use proper port numbers (Jesse) Signed-off-by: Pallavi G Signed-off-by: Yogesh M Signed-off-by: Gajanan Bhat Signed-off-by: Jesse Barnes (v2 changes) [danvet: Reorder if-ladder to avoid two IS_VLV checks.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +- drivers/gpu/drm/i915/intel_dp.c | 128 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 2 + 3 files changed, 128 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bdbad762134c..9ff992aabcd6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -450,8 +450,7 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) return I915_READ(DPIO_DATA); } -static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, - u32 val) +void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 89f89b727900..9e16b0ca8dd8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1461,7 +1461,9 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) + if (IS_VALLEYVIEW(dev)) + return DP_TRAIN_VOLTAGE_SWING_1200; + else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) return DP_TRAIN_VOLTAGE_SWING_800; else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) return DP_TRAIN_VOLTAGE_SWING_1200; @@ -1486,7 +1488,19 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) default: return DP_TRAIN_PRE_EMPHASIS_0; } - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { + } else if (IS_VALLEYVIEW(dev)) { + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + return DP_TRAIN_PRE_EMPHASIS_9_5; + case DP_TRAIN_VOLTAGE_SWING_600: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_800: + return DP_TRAIN_PRE_EMPHASIS_3_5; + case DP_TRAIN_VOLTAGE_SWING_1200: + default: + return DP_TRAIN_PRE_EMPHASIS_0; + } + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_6; @@ -1511,6 +1525,111 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) } } +static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *dport = dp_to_dig_port(intel_dp); + unsigned long demph_reg_value, preemph_reg_value, + uniqtranscale_reg_value; + uint8_t train_set = intel_dp->train_set[0]; + int port; + + if (dport->port == PORT_B) + port = 0; + else if (dport->port == PORT_C) + port = 1; + else + BUG(); + + switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { + case DP_TRAIN_PRE_EMPHASIS_0: + preemph_reg_value = 0x0004000; + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + demph_reg_value = 0x2B405555; + uniqtranscale_reg_value = 0x552AB83A; + break; + case DP_TRAIN_VOLTAGE_SWING_600: + demph_reg_value = 0x2B404040; + uniqtranscale_reg_value = 0x5548B83A; + break; + case DP_TRAIN_VOLTAGE_SWING_800: + demph_reg_value = 0x2B245555; + uniqtranscale_reg_value = 0x5560B83A; + break; + case DP_TRAIN_VOLTAGE_SWING_1200: + demph_reg_value = 0x2B405555; + uniqtranscale_reg_value = 0x5598DA3A; + break; + default: + return 0; + } + break; + case DP_TRAIN_PRE_EMPHASIS_3_5: + preemph_reg_value = 0x0002000; + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + demph_reg_value = 0x2B404040; + uniqtranscale_reg_value = 0x5552B83A; + break; + case DP_TRAIN_VOLTAGE_SWING_600: + demph_reg_value = 0x2B404848; + uniqtranscale_reg_value = 0x5580B83A; + break; + case DP_TRAIN_VOLTAGE_SWING_800: + demph_reg_value = 0x2B404040; + uniqtranscale_reg_value = 0x55ADDA3A; + break; + default: + return 0; + } + break; + case DP_TRAIN_PRE_EMPHASIS_6: + preemph_reg_value = 0x0000000; + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + demph_reg_value = 0x2B305555; + uniqtranscale_reg_value = 0x5570B83A; + break; + case DP_TRAIN_VOLTAGE_SWING_600: + demph_reg_value = 0x2B2B4040; + uniqtranscale_reg_value = 0x55ADDA3A; + break; + default: + return 0; + } + break; + case DP_TRAIN_PRE_EMPHASIS_9_5: + preemph_reg_value = 0x0006000; + switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + demph_reg_value = 0x1B405555; + uniqtranscale_reg_value = 0x55ADDA3A; + break; + default: + return 0; + } + break; + default: + return 0; + } + + /* eDP is only on port C */ + mutex_lock(&dev_priv->dpio_lock); + intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port), + uniqtranscale_reg_value); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port), 0x0C782040); + intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000); + intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value); + intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000); + mutex_unlock(&dev_priv->dpio_lock); + + return 0; +} + static void intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { @@ -1685,7 +1804,10 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) if (HAS_DDI(dev)) { signal_levels = intel_hsw_signal_levels(train_set); mask = DDI_BUF_EMP_MASK; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { + } else if (IS_VALLEYVIEW(dev)) { + signal_levels = intel_vlv_signal_levels(intel_dp); + mask = 0; + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { signal_levels = intel_gen7_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b5b6d19e6dd3..399b18181b45 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -689,6 +689,8 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); +extern void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, + u32 val); /* Power-related functions, located in intel_pm.c */ extern void intel_init_pm(struct drm_device *dev); -- cgit v1.2.3 From 78c9b7e71d90f32ce19d4a575a1a206cfe7c6a00 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 18 Apr 2013 14:44:29 -0700 Subject: drm/i915: drop init_dpio, shouldn't be needed This is a reset feature we don't actually need. Signed-off-by: Jesse Barnes [danvet: Make it compile.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9ff992aabcd6..83465622be33 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -467,17 +467,6 @@ void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) DRM_ERROR("DPIO write wait timed out\n"); } -static void vlv_init_dpio(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Reset the DPIO config */ - I915_WRITE(DPIO_CTL, 0); - POSTING_READ(DPIO_CTL); - I915_WRITE(DPIO_CTL, 1); - POSTING_READ(DPIO_CTL); -} - static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { @@ -9429,9 +9418,6 @@ void intel_modeset_cleanup(struct drm_device *dev) ironlake_teardown_rc6(dev); - if (IS_VALLEYVIEW(dev)) - vlv_init_dpio(dev); - mutex_unlock(&dev->struct_mutex); /* Disable the irq before mode object teardown, for the irq might -- cgit v1.2.3 From 89b667f86a62a99a7b484a7e1b3f8f7a108a7dee Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 18 Apr 2013 14:51:36 -0700 Subject: drm/i915: update VLV PLL and DPIO code v11 In Valleyview voltage swing, pre-emphasis and lane control registers can be programmed only through the h/w side band fabric. Update vlv_update_pll, i9xx_crtc_enable, and intel_enable_pll with the appropriate programming. We need to make sure that the tx lane reset occurs in both the full mode set and DPMS paths, so factor things out to allow that. v2: use different DPIO_DIVISOR values for VGA and DisplayPort v3: Fix update pll logic to use same DPIO_DIVISOR & DPIO_REFSFR values for all display interfaces v4: collapse with various updates v5: squash with crtc enable/pll enable bits v6: split out DP code (jbarnes) put phyready check under IS_VALLEYVIEW (jbarnes) remove unneeded check in 9xx pll div update (Jani) wrap VLV pll update call in IS_VALLEYVIEW (Jani) move port enable back to end of crtc enable (jbarnes) put phyready check under IS_VALLEYVIEW (jbarnes) v7: fix up conflicts against latest drm-intel-next-queued v8: use DPIO reg names, fix pipes (Jani) from mPhy_registers_VLV2_ww20p5 doc v9: update to latest info from driver enabling notes doc driver_vbios_notes_9 v10: fixup a bit of pipe/port confusion to allow eDP and HDMI to work simultaneously (Jesse) v11: use pll/port callbacks for DPIO port activity (Daniel) use separate VLV CRTC enable function (Daniel) move around port ready checks (Jesse) Signed-off-by: Pallavi G Signed-off-by: Vijay Purushothaman Signed-off-by: Gajanan Bhat Signed-off-by: Ben Widawsky Signed-off-by: Jesse Barnes [danvet: Drop pfit changes and add a little comment explaining that vlv has a different enable sequence and so needs it's own crtc_enable callback. Also apply a fixup patch from Wu Fengguang to shut up some compiler warnings.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 237 +++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_dp.c | 69 +++++++++- drivers/gpu/drm/i915/intel_drv.h | 14 +++ drivers/gpu/drm/i915/intel_hdmi.c | 108 ++++++++++++++++ 4 files changed, 370 insertions(+), 58 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83465622be33..3fadd33c772f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1576,6 +1576,20 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, return I915_READ(SBI_DATA); } +void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) +{ + u32 port_mask; + + if (!port) + port_mask = DPLL_PORTB_READY_MASK; + else + port_mask = DPLL_PORTC_READY_MASK; + + if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000)) + WARN(1, "timed out waiting for port %c ready: 0x%08x\n", + 'B' + port, I915_READ(DPLL(0))); +} + /** * ironlake_enable_pch_pll - enable PCH PLL * @dev_priv: i915 private structure @@ -3678,6 +3692,52 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) } } +static void valleyview_crtc_enable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; + int pipe = intel_crtc->pipe; + int plane = intel_crtc->plane; + + WARN_ON(!crtc->enabled); + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + intel_update_watermarks(dev); + + mutex_lock(&dev_priv->dpio_lock); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); + + intel_enable_pll(dev_priv, pipe); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + + /* VLV wants encoder enabling _before_ the pipe is up. */ + for_each_encoder_on_crtc(dev, crtc, encoder) + encoder->enable(encoder); + + intel_enable_pipe(dev_priv, pipe, false); + intel_enable_plane(dev_priv, plane, pipe); + + intel_crtc_load_lut(crtc); + intel_update_fbc(dev); + + /* Give the overlay scaler a chance to enable if it's on this pipe */ + intel_crtc_dpms_overlay(intel_crtc, true); + intel_crtc_update_cursor(crtc, true); + + mutex_unlock(&dev_priv->dpio_lock); +} + static void i9xx_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3766,6 +3826,10 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) i9xx_pfit_disable(intel_crtc); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->post_disable) + encoder->post_disable(encoder); + intel_disable_pll(dev_priv, pipe); intel_crtc->active = false; @@ -4208,6 +4272,34 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, } } +static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv) +{ + u32 reg_val; + + /* + * PLLB opamp always calibrates to max value of 0x3f, force enable it + * and set it to a reasonable value instead. + */ + reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1)); + reg_val &= 0xffffff00; + reg_val |= 0x00000030; + intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val); + + reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION); + reg_val &= 0x8cffffff; + reg_val = 0x8c000000; + intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); + + reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1)); + reg_val &= 0xffffff00; + intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val); + + reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION); + reg_val &= 0x00ffffff; + reg_val |= 0xb0000000; + intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); +} + static void intel_dp_set_m_n(struct intel_crtc *crtc) { if (crtc->config.has_pch_encoder) @@ -4220,24 +4312,18 @@ static void vlv_update_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *adjusted_mode = + &crtc->config.adjusted_mode; + struct intel_encoder *encoder; int pipe = crtc->pipe; - u32 dpll, mdiv, pdiv; + u32 dpll, mdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; - bool is_sdvo; - u32 temp; + bool is_hdmi; + u32 coreclk, reg_val, temp; mutex_lock(&dev_priv->dpio_lock); - is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) || - intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); - - dpll = DPLL_VGA_MODE_DIS; - dpll |= DPLL_EXT_BUFFER_ENABLE_VLV; - dpll |= DPLL_REFA_CLK_ENABLE_VLV; - dpll |= DPLL_INTEGRATED_CLOCK_VLV; - - I915_WRITE(DPLL(pipe), dpll); - POSTING_READ(DPLL(pipe)); + is_hdmi = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI); bestn = crtc->config.dpll.n; bestm1 = crtc->config.dpll.m1; @@ -4245,71 +4331,105 @@ static void vlv_update_pll(struct intel_crtc *crtc) bestp1 = crtc->config.dpll.p1; bestp2 = crtc->config.dpll.p2; - /* - * In Valleyview PLL and program lane counter registers are exposed - * through DPIO interface - */ + /* See eDP HDMI DPIO driver vbios notes doc */ + + /* PLL B needs special handling */ + if (pipe) + vlv_pllb_recal_opamp(dev_priv); + + /* Set up Tx target for periodic Rcomp update */ + intel_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f); + + /* Disable target IRef on PLL */ + reg_val = intel_dpio_read(dev_priv, DPIO_IREF_CTL(pipe)); + reg_val &= 0x00ffffff; + intel_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val); + + /* Disable fast lock */ + intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610); + + /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); mdiv |= ((bestn << DPIO_N_SHIFT)); - mdiv |= (1 << DPIO_POST_DIV_SHIFT); mdiv |= (1 << DPIO_K_SHIFT); - mdiv |= DPIO_ENABLE_CALIBRATION; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) + mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); - intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000); + mdiv |= DPIO_ENABLE_CALIBRATION; + intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); - pdiv = (1 << DPIO_REFSEL_OVERRIDE) | (5 << DPIO_PLL_MODESEL_SHIFT) | - (3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) | - (7 << DPIO_PLL_REFCLK_SEL_SHIFT) | (8 << DPIO_DRIVER_CTL_SHIFT) | - (5 << DPIO_CLK_BIAS_CTL_SHIFT); - intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv); + /* Set HBR and RBR LPF coefficients */ + if (adjusted_mode->clock == 162000 || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) + intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + 0x005f0021); + else + intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + 0x00d0000f); + + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) { + /* Use SSC source */ + if (!pipe) + intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + 0x0df40000); + else + intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + 0x0df70000); + } else { /* HDMI or VGA */ + /* Use bend source */ + if (!pipe) + intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + 0x0df70000); + else + intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + 0x0df40000); + } - intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f003b); + coreclk = intel_dpio_read(dev_priv, DPIO_CORE_CLK(pipe)); + coreclk = (coreclk & 0x0000ff00) | 0x01c00000; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) + coreclk |= 0x01000000; + intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk); - dpll |= DPLL_VCO_ENABLE; - I915_WRITE(DPLL(pipe), dpll); - POSTING_READ(DPLL(pipe)); - if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) - DRM_ERROR("DPLL %d failed to lock\n", pipe); + intel_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000); - intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620); + for_each_encoder_on_crtc(dev, &crtc->base, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); - if (crtc->config.has_dp_encoder) - intel_dp_set_m_n(crtc); + /* Enable DPIO clock input */ + dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | + DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; + if (pipe) + dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; + dpll |= DPLL_VCO_ENABLE; I915_WRITE(DPLL(pipe), dpll); - - /* Wait for the clocks to stabilize. */ POSTING_READ(DPLL(pipe)); udelay(150); - temp = 0; - if (is_sdvo) { + if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) + DRM_ERROR("DPLL %d failed to lock\n", pipe); + + if (is_hdmi) { temp = 0; if (crtc->config.pixel_multiplier > 1) { temp = (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT; } - } - I915_WRITE(DPLL_MD(pipe), temp); - POSTING_READ(DPLL_MD(pipe)); - /* Now program lane control registers */ - if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) - || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) { - temp = 0x1000C4; - if(pipe == 1) - temp |= (1 << 21); - intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp); + I915_WRITE(DPLL_MD(pipe), temp); + POSTING_READ(DPLL_MD(pipe)); } - if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { - temp = 0x1000C4; - if(pipe == 1) - temp |= (1 << 21); - intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp); - } + if (crtc->config.has_dp_encoder) + intel_dp_set_m_n(crtc); mutex_unlock(&dev_priv->dpio_lock); } @@ -4699,7 +4819,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, else i9xx_update_pll(intel_crtc, has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + num_connectors); /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -8753,6 +8873,13 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_disable = ironlake_crtc_disable; dev_priv->display.off = ironlake_crtc_off; dev_priv->display.update_plane = ironlake_update_plane; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.get_pipe_config = i9xx_get_pipe_config; + dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; + dev_priv->display.crtc_enable = valleyview_crtc_enable; + dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display.off = i9xx_crtc_off; + dev_priv->display.update_plane = i9xx_update_plane; } else { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9e16b0ca8dd8..058002659d9b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1390,15 +1390,77 @@ static void intel_enable_dp(struct intel_encoder *encoder) ironlake_edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); ironlake_edp_backlight_on(intel_dp); + + if (IS_VALLEYVIEW(dev)) { + struct intel_digital_port *dport = + enc_to_dig_port(&encoder->base); + int channel = vlv_dport_to_channel(dport); + + vlv_wait_port_ready(dev_priv, channel); + } } static void intel_pre_enable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) ironlake_edp_pll_on(intel_dp); + + if (IS_VALLEYVIEW(dev)) { + struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); + struct intel_crtc *intel_crtc = + to_intel_crtc(encoder->base.crtc); + int port = vlv_dport_to_channel(dport); + int pipe = intel_crtc->pipe; + u32 val; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); + val = 0; + if (pipe) + val |= (1<<21); + else + val &= ~(1<<21); + val |= 0x001000c4; + intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val); + + intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port), + 0x00760018); + intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port), + 0x00400888); + } +} + +static void intel_dp_pre_pll_enable(struct intel_encoder *encoder) +{ + struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int port = vlv_dport_to_channel(dport); + + if (!IS_VALLEYVIEW(dev)) + return; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + /* Program Tx lane resets to default */ + intel_dpio_write(dev_priv, DPIO_PCS_TX(port), + DPIO_PCS_TX_LANE2_RESET | + DPIO_PCS_TX_LANE1_RESET); + intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), + DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | + DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | + (1<dpio_lock)); + switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { case DP_TRAIN_PRE_EMPHASIS_0: preemph_reg_value = 0x0004000; @@ -1615,8 +1679,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) return 0; } - /* eDP is only on port C */ - mutex_lock(&dev_priv->dpio_lock); intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000); intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value); intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port), @@ -1625,7 +1687,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000); intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value); intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000); - mutex_unlock(&dev_priv->dpio_lock); return 0; } @@ -3078,6 +3139,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->disable = intel_disable_dp; intel_encoder->post_disable = intel_post_disable_dp; intel_encoder->get_hw_state = intel_dp_get_hw_state; + if (IS_VALLEYVIEW(dev)) + intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable; intel_dig_port->port = port; intel_dig_port->dp.output_reg = output_reg; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 399b18181b45..63264ed0c9a6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -431,6 +431,19 @@ struct intel_digital_port { struct intel_hdmi hdmi; }; +static inline int +vlv_dport_to_channel(struct intel_digital_port *dport) +{ + switch (dport->port) { + case PORT_B: + return 0; + case PORT_C: + return 1; + default: + BUG(); + } +} + static inline struct drm_crtc * intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) { @@ -606,6 +619,7 @@ intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe); extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); +extern void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port); struct intel_load_detect_pipe { struct drm_framebuffer *release_fb; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 3e6a3ef10d5c..53ce8a57f589 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -697,6 +697,14 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } + + if (IS_VALLEYVIEW(dev)) { + struct intel_digital_port *dport = + enc_to_dig_port(&encoder->base); + int channel = vlv_dport_to_channel(dport); + + vlv_wait_port_ready(dev_priv, channel); + } } static void intel_disable_hdmi(struct intel_encoder *encoder) @@ -947,6 +955,101 @@ done: return 0; } +static void intel_hdmi_pre_enable(struct intel_encoder *encoder) +{ + struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = + to_intel_crtc(encoder->base.crtc); + int port = vlv_dport_to_channel(dport); + int pipe = intel_crtc->pipe; + u32 val; + + if (!IS_VALLEYVIEW(dev)) + return; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + /* Enable clock channels for this port */ + val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); + val = 0; + if (pipe) + val |= (1<<21); + else + val &= ~(1<<21); + val |= 0x001000c4; + intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val); + + /* HDMI 1.0V-2dB */ + intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), + 0x2b245f5f); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port), + 0x5578b83a); + intel_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port), + 0x0c782040); + intel_dpio_write(dev_priv, DPIO_TX3_SWING_CTL4(port), + 0x2b247878); + intel_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000); + intel_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), + 0x00002000); + intel_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), + DPIO_TX_OCALINIT_EN); + + /* Program lane clock */ + intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port), + 0x00760018); + intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port), + 0x00400888); +} + +static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder) +{ + struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int port = vlv_dport_to_channel(dport); + + if (!IS_VALLEYVIEW(dev)) + return; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + /* Program Tx lane resets to default */ + intel_dpio_write(dev_priv, DPIO_PCS_TX(port), + DPIO_PCS_TX_LANE2_RESET | + DPIO_PCS_TX_LANE1_RESET); + intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), + DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | + DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | + (1<base); + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + int port = vlv_dport_to_channel(dport); + + /* Reset lanes to avoid HDMI flicker (VLV w/a) */ + mutex_lock(&dev_priv->dpio_lock); + intel_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000); + intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060); + mutex_unlock(&dev_priv->dpio_lock); +} + static void intel_hdmi_destroy(struct drm_connector *connector) { drm_sysfs_connector_remove(connector); @@ -1086,6 +1189,11 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->enable = intel_enable_hdmi; intel_encoder->disable = intel_disable_hdmi; intel_encoder->get_hw_state = intel_hdmi_get_hw_state; + if (IS_VALLEYVIEW(dev)) { + intel_encoder->pre_enable = intel_hdmi_pre_enable; + intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable; + intel_encoder->post_disable = intel_hdmi_post_disable; + } intel_encoder->type = INTEL_OUTPUT_HDMI; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); -- cgit v1.2.3 From 8664281b64c457705db72fc60143d03827e75ca9 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Apr 2013 17:57:57 -0300 Subject: drm/i915: report Gen5+ CPU and PCH FIFO underruns In this commit we enable both CPU and PCH FIFO underrun reporting and start reporting them. We follow a few rules: - after we receive one of these errors, we mask the interrupt, so we won't get an "interrupt storm" and we also won't flood dmesg; - at each mode set we enable the interrupts again, so we'll see each message at most once per mode set; - in the specific places where we need to ignore the errors, we completely mask the interrupts. The downside of this patch is that since we're completely disabling (masking) the interrupts instead of just not printing error messages, we will mask more than just what we want on IVB/HSW CPU interrupts (due to GEN7_ERR_INT) and on CPT/PPT/LPT PCHs (due to SERR_INT). So when we decide to mask PCH FIFO underruns for pipe A on CPT, we'll also be masking PCH FIFO underruns for pipe B, because both are reported by SERR_INT, which has to be either completely enabled or completely disabled (in othe words, there's no way to disable/enable specific bits of GEN7_ERR_INT and SERR_INT). V2: Rename some functions and variables, downgrade messages to DRM_DEBUG_DRIVER and rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 315 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 13 +- drivers/gpu/drm/i915/intel_display.c | 14 ++ drivers/gpu/drm/i915/intel_drv.h | 11 ++ 4 files changed, 342 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 932e7f8b6d5c..c79793ee868b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -112,6 +112,213 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) } } +static bool ivb_can_enable_err_int(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + enum pipe pipe; + + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + + if (crtc->cpu_fifo_underrun_disabled) + return false; + } + + return true; +} + +static bool cpt_can_enable_serr_int(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *crtc; + + for_each_pipe(pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + + if (crtc->pch_fifo_underrun_disabled) + return false; + } + + return true; +} + +static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN : + DE_PIPEB_FIFO_UNDERRUN; + + if (enable) + ironlake_enable_display_irq(dev_priv, bit); + else + ironlake_disable_display_irq(dev_priv, bit); +} + +static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, + bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (enable) { + if (!ivb_can_enable_err_int(dev)) + return; + + I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A | + ERR_INT_FIFO_UNDERRUN_B | + ERR_INT_FIFO_UNDERRUN_C); + + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + } else { + ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); + } +} + +static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc, + bool enable) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER : + SDE_TRANSB_FIFO_UNDER; + + if (enable) + I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit); + else + I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit); + + POSTING_READ(SDEIMR); +} + +static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, + enum transcoder pch_transcoder, + bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (enable) { + if (!cpt_can_enable_serr_int(dev)) + return; + + I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN | + SERR_INT_TRANS_B_FIFO_UNDERRUN | + SERR_INT_TRANS_C_FIFO_UNDERRUN); + + I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT); + } else { + I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT); + } + + POSTING_READ(SDEIMR); +} + +/** + * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages + * @dev: drm device + * @pipe: pipe + * @enable: true if we want to report FIFO underrun errors, false otherwise + * + * This function makes us disable or enable CPU fifo underruns for a specific + * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun + * reporting for one pipe may also disable all the other CPU error interruts for + * the other pipes, due to the fact that there's just one interrupt mask/enable + * bit for all the pipes. + * + * Returns the previous state of underrun reporting. + */ +bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + unsigned long flags; + bool ret; + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + + ret = !intel_crtc->cpu_fifo_underrun_disabled; + + if (enable == ret) + goto done; + + intel_crtc->cpu_fifo_underrun_disabled = !enable; + + if (IS_GEN5(dev) || IS_GEN6(dev)) + ironlake_set_fifo_underrun_reporting(dev, pipe, enable); + else if (IS_GEN7(dev)) + ivybridge_set_fifo_underrun_reporting(dev, enable); + +done: + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + return ret; +} + +/** + * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages + * @dev: drm device + * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older) + * @enable: true if we want to report FIFO underrun errors, false otherwise + * + * This function makes us disable or enable PCH fifo underruns for a specific + * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO + * underrun reporting for one transcoder may also disable all the other PCH + * error interruts for the other transcoders, due to the fact that there's just + * one interrupt mask/enable bit for all the transcoders. + * + * Returns the previous state of underrun reporting. + */ +bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, + enum transcoder pch_transcoder, + bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe p; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + unsigned long flags; + bool ret; + + if (HAS_PCH_LPT(dev)) { + crtc = NULL; + for_each_pipe(p) { + struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p]; + if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) { + crtc = c; + break; + } + } + if (!crtc) { + DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n"); + return false; + } + } else { + crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder]; + } + intel_crtc = to_intel_crtc(crtc); + + spin_lock_irqsave(&dev_priv->irq_lock, flags); + + ret = !intel_crtc->pch_fifo_underrun_disabled; + + if (enable == ret) + goto done; + + intel_crtc->pch_fifo_underrun_disabled = !enable; + + if (HAS_PCH_IBX(dev)) + ibx_set_fifo_underrun_reporting(intel_crtc, enable); + else + cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable); + +done: + spin_unlock_irqrestore(&dev_priv->irq_lock, flags); + return ret; +} + + void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { @@ -800,10 +1007,58 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR)) DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n"); - if (pch_iir & SDE_TRANSB_FIFO_UNDER) - DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n"); if (pch_iir & SDE_TRANSA_FIFO_UNDER) - DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n"); + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, + false)) + DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); + + if (pch_iir & SDE_TRANSB_FIFO_UNDER) + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, + false)) + DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); +} + +static void ivb_err_int_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 err_int = I915_READ(GEN7_ERR_INT); + + if (err_int & ERR_INT_FIFO_UNDERRUN_A) + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) + DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); + + if (err_int & ERR_INT_FIFO_UNDERRUN_B) + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) + DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); + + if (err_int & ERR_INT_FIFO_UNDERRUN_C) + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false)) + DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n"); + + I915_WRITE(GEN7_ERR_INT, err_int); +} + +static void cpt_serr_int_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 serr_int = I915_READ(SERR_INT); + + if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, + false)) + DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n"); + + if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN) + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B, + false)) + DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n"); + + if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN) + if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C, + false)) + DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n"); + + I915_WRITE(SERR_INT, serr_int); } static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) @@ -841,6 +1096,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", pipe_name(pipe), I915_READ(FDI_RX_IIR(pipe))); + + if (pch_iir & SDE_ERROR_CPT) + cpt_serr_int_handler(dev); } static irqreturn_t ivybridge_irq_handler(int irq, void *arg) @@ -853,6 +1111,14 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) atomic_inc(&dev_priv->irq_received); + /* We get interrupts on unclaimed registers, so check for this before we + * do any I915_{READ,WRITE}. */ + if (IS_HASWELL(dev) && + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { + DRM_ERROR("Unclaimed register before interrupt\n"); + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); + } + /* disable master interrupt before clearing iir */ de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); @@ -868,6 +1134,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) POSTING_READ(SDEIER); } + /* On Haswell, also mask ERR_INT because we don't want to risk + * generating "unclaimed register" interrupts from inside the interrupt + * handler. */ + if (IS_HASWELL(dev)) + ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); + gt_iir = I915_READ(GTIIR); if (gt_iir) { snb_gt_irq_handler(dev, dev_priv, gt_iir); @@ -877,6 +1149,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) de_iir = I915_READ(DEIIR); if (de_iir) { + if (de_iir & DE_ERR_INT_IVB) + ivb_err_int_handler(dev); + if (de_iir & DE_AUX_CHANNEL_A_IVB) dp_aux_irq_handler(dev); @@ -914,6 +1189,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; } + if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); if (!HAS_PCH_NOP(dev)) { @@ -983,6 +1261,14 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (de_iir & DE_PIPEB_VBLANK) drm_handle_vblank(dev, 1); + if (de_iir & DE_PIPEA_FIFO_UNDERRUN) + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) + DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); + + if (de_iir & DE_PIPEB_FIFO_UNDERRUN) + if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false)) + DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n"); + if (de_iir & DE_PLANEA_FLIP_DONE) { intel_prepare_page_flip(dev, 0); intel_finish_page_flip_plane(dev, 0); @@ -2208,10 +2494,14 @@ static void ibx_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 mask; - if (HAS_PCH_IBX(dev)) - mask = SDE_GMBUS | SDE_AUX_MASK; - else - mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + if (HAS_PCH_IBX(dev)) { + mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | + SDE_TRANSA_FIFO_UNDER; + } else { + mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT; + + I915_WRITE(SERR_INT, I915_READ(SERR_INT)); + } if (HAS_PCH_NOP(dev)) return; @@ -2226,7 +2516,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | - DE_AUX_CHANNEL_A; + DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | + DE_PIPEA_FIFO_UNDERRUN; u32 render_irqs; dev_priv->irq_mask = ~display_mask; @@ -2276,12 +2567,14 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PLANEC_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB | DE_PLANEA_FLIP_DONE_IVB | - DE_AUX_CHANNEL_A_IVB; + DE_AUX_CHANNEL_A_IVB | + DE_ERR_INT_IVB; u32 render_irqs; dev_priv->irq_mask = ~display_mask; /* should always can generate irq */ + I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); I915_WRITE(DEIER, @@ -2409,6 +2702,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) I915_WRITE(DEIMR, 0xffffffff); I915_WRITE(DEIER, 0x0); I915_WRITE(DEIIR, I915_READ(DEIIR)); + if (IS_GEN7(dev)) + I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT)); I915_WRITE(GTIMR, 0xffffffff); I915_WRITE(GTIER, 0x0); @@ -2420,6 +2715,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) I915_WRITE(SDEIMR, 0xffffffff); I915_WRITE(SDEIER, 0x0); I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev)) + I915_WRITE(SERR_INT, I915_READ(SERR_INT)); } static void i8xx_irq_preinstall(struct drm_device * dev) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fb1a4fa68d55..32f970d2fd51 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -640,7 +640,10 @@ #define ERROR_GEN6 0x040a0 #define GEN7_ERR_INT 0x44040 -#define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define ERR_INT_MMIO_UNCLAIMED (1<<13) +#define ERR_INT_FIFO_UNDERRUN_C (1<<6) +#define ERR_INT_FIFO_UNDERRUN_B (1<<3) +#define ERR_INT_FIFO_UNDERRUN_A (1<<0) #define FPGA_DBG 0x42300 #define FPGA_DBG_RM_NOCLAIM (1<<31) @@ -3622,7 +3625,7 @@ #define DE_PIPEA_FIFO_UNDERRUN (1 << 0) /* More Ivybridge lolz */ -#define DE_ERR_DEBUG_IVB (1<<30) +#define DE_ERR_INT_IVB (1<<30) #define DE_GSE_IVB (1<<29) #define DE_PCH_EVENT_IVB (1<<28) #define DE_DP_A_HOTPLUG_IVB (1<<27) @@ -3781,6 +3784,7 @@ SDE_PORTC_HOTPLUG_CPT | \ SDE_PORTB_HOTPLUG_CPT) #define SDE_GMBUS_CPT (1 << 17) +#define SDE_ERROR_CPT (1 << 16) #define SDE_AUDIO_CP_REQ_C_CPT (1 << 10) #define SDE_AUDIO_CP_CHG_C_CPT (1 << 9) #define SDE_FDI_RXC_CPT (1 << 8) @@ -3805,6 +3809,11 @@ #define SDEIIR 0xc4008 #define SDEIER 0xc400c +#define SERR_INT 0xc4040 +#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) +#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) +#define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0) + /* digital port hotplug */ #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ #define PORTD_HOTPLUG_ENABLE (1 << 20) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3fadd33c772f..8a96c998ee53 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3346,6 +3346,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) return; intel_crtc->active = true; + + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); + intel_update_watermarks(dev); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { @@ -3437,6 +3441,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) return; intel_crtc->active = true; + + intel_set_cpu_fifo_underrun_reporting(dev, pipe, true); + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); + intel_update_watermarks(dev); if (intel_crtc->config.has_pch_encoder) @@ -3523,6 +3532,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + intel_set_pch_fifo_underrun_reporting(dev, pipe, false); intel_disable_pipe(dev_priv, pipe); /* Disable PF */ @@ -3536,6 +3546,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_disable(crtc); ironlake_disable_pch_transcoder(dev_priv, pipe); + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); if (HAS_PCH_CPT(dev)) { /* disable TRANS_DP_CTL */ @@ -3602,6 +3613,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false); intel_disable_pipe(dev_priv, pipe); intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); @@ -3622,6 +3635,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (intel_crtc->config.has_pch_encoder) { lpt_disable_pch_transcoder(dev_priv); + intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); intel_ddi_fdi_disable(crtc); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 63264ed0c9a6..c20201d948eb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -265,6 +265,10 @@ struct intel_crtc { /* reset counter value when the last flip was submitted */ unsigned int reset_counter; + + /* Access to these should be protected by dev_priv->irq_lock. */ + bool cpu_fifo_underrun_disabled; + bool pch_fifo_underrun_disabled; }; struct intel_plane { @@ -487,6 +491,7 @@ int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); extern void intel_attach_force_audio_property(struct drm_connector *connector); extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); +extern bool intel_pipe_has_type(struct drm_crtc *crtc, int type); extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); @@ -743,5 +748,11 @@ intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); extern void intel_display_handle_reset(struct drm_device *dev); +extern bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, + enum pipe pipe, + bool enable); +extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, + enum transcoder pch_transcoder, + bool enable); #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.3 From de032bf40a52dbbada11e071d150d2c062b5527e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Apr 2013 17:57:58 -0300 Subject: drm/i915: print Gen5+ CPU/PCH poison interrupts This is bad news and shouldn't be happening. V2: Rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 13 +++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c79793ee868b..dae8953d2912 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1023,6 +1023,9 @@ static void ivb_err_int_handler(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 err_int = I915_READ(GEN7_ERR_INT); + if (err_int & ERR_INT_POISON) + DRM_ERROR("Poison interrupt\n"); + if (err_int & ERR_INT_FIFO_UNDERRUN_A) if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); @@ -1043,6 +1046,9 @@ static void cpt_serr_int_handler(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 serr_int = I915_READ(SERR_INT); + if (serr_int & SERR_INT_POISON) + DRM_ERROR("PCH poison interrupt\n"); + if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN) if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false)) @@ -1261,6 +1267,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (de_iir & DE_PIPEB_VBLANK) drm_handle_vblank(dev, 1); + if (de_iir & DE_POISON) + DRM_ERROR("Poison interrupt\n"); + if (de_iir & DE_PIPEA_FIFO_UNDERRUN) if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false)) DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n"); @@ -2496,7 +2505,7 @@ static void ibx_irq_postinstall(struct drm_device *dev) if (HAS_PCH_IBX(dev)) { mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | - SDE_TRANSA_FIFO_UNDER; + SDE_TRANSA_FIFO_UNDER | SDE_POISON; } else { mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT; @@ -2517,7 +2526,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | - DE_PIPEA_FIFO_UNDERRUN; + DE_PIPEA_FIFO_UNDERRUN | DE_POISON; u32 render_irqs; dev_priv->irq_mask = ~display_mask; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 32f970d2fd51..9093d6669560 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -640,6 +640,7 @@ #define ERROR_GEN6 0x040a0 #define GEN7_ERR_INT 0x44040 +#define ERR_INT_POISON (1<<31) #define ERR_INT_MMIO_UNCLAIMED (1<<13) #define ERR_INT_FIFO_UNDERRUN_C (1<<6) #define ERR_INT_FIFO_UNDERRUN_B (1<<3) @@ -3810,6 +3811,7 @@ #define SDEIER 0xc400c #define SERR_INT 0xc4040 +#define SERR_INT_POISON (1<<31) #define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) #define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) #define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0) -- cgit v1.2.3 From 2bfce95075fa58eaf2ead5b0863c50a3f6098bc2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 18 Apr 2013 16:35:40 -0300 Subject: drm/i915: check the power well inside haswell_get_pipe_config This fixes "unclaimed register" messages when booting with eDP only and i915.disable_power_well=1. The error messages were caused by: commit 0e8ffe1bf81b0780cc6229cb38664754dffe8776 Author: Daniel Vetter Date: Thu Mar 28 10:42:00 2013 +0100 drm/i915: add hw state readout/checking for pipe_config Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8a96c998ee53..6f7e4cc35d99 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5978,9 +5978,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; uint32_t tmp; - tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder)); + if (!intel_using_power_well(dev_priv->dev) && + cpu_transcoder != TRANSCODER_EDP) + return false; + + tmp = I915_READ(PIPECONF(cpu_transcoder)); if (!(tmp & PIPECONF_ENABLE)) return false; -- cgit v1.2.3 From f196e6bedb1b8a76f8526798e0feeb7a213e7505 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 18 Apr 2013 16:35:41 -0300 Subject: drm/i915: use cpu_transcoder for TRANS_DDI_FUNC_CTL ... inside haswell_get_pipe_config. Because there's one TRANS_DDI_FUNC_CTL register per CPU transcoder, not per pipe. This solves "unclaimed register" messages when booting with eDP only and using the i915.disable_power_well=1. Also fix a comment and remove an useless empty line. The error messages were caused by: commit 88adfff1ad5019f65b9d0b4e1a4ac900fb065183 Author: Daniel Vetter Date: Thu Mar 28 10:42:01 2013 +0100 drm/i915: hw readout support for ->has_pch_encoders Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6f7e4cc35d99..3c90605ddd45 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5990,16 +5990,15 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, return false; /* - * aswell has only FDI/PCH transcoder A. It is which is connected to + * Haswell has only FDI/PCH transcoder A. It is which is connected to * DDI E. So just check whether this pipe is wired to DDI E and whether * the PCH transcoder is on. */ - tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe)); + tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) pipe_config->has_pch_encoder = true; - return true; } -- cgit v1.2.3 From 29a397ba7a4bded235c79f050753637cad3409ff Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Apr 2013 12:23:02 +0300 Subject: drm/i915: Move the CSC_MODE bits next to the register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shame on me for not putting the bit definitions next to the register definition in the first place. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9093d6669560..60e0e19373b1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4939,6 +4939,9 @@ #define _PIPE_A_CSC_COEFF_RV_GV 0x49020 #define _PIPE_A_CSC_COEFF_BV 0x49024 #define _PIPE_A_CSC_MODE 0x49028 +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) +#define CSC_MODE_YUV_TO_RGB (1 << 0) #define _PIPE_A_CSC_PREOFF_HI 0x49030 #define _PIPE_A_CSC_PREOFF_ME 0x49034 #define _PIPE_A_CSC_PREOFF_LO 0x49038 @@ -4960,10 +4963,6 @@ #define _PIPE_B_CSC_POSTOFF_ME 0x49144 #define _PIPE_B_CSC_POSTOFF_LO 0x49148 -#define CSC_BLACK_SCREEN_OFFSET (1 << 2) -#define CSC_POSITION_BEFORE_GAMMA (1 << 1) -#define CSC_MODE_YUV_TO_RGB (1 << 0) - #define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) #define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) #define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) -- cgit v1.2.3 From bf98a72650c9272e70e7f0e904f85c025c0bb421 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 19 Apr 2013 14:27:31 +0100 Subject: drm/i915: Remove mention of Haswell in DDI code We are trying to have more platform-orthogonal pieces of code. The DDI code shouldn't mention Haswell. v2: Fix the email address Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e14fe5f569ee..eef450b1af44 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -675,7 +675,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, int pipe = intel_crtc->pipe; int type = intel_encoder->type; - DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", + DRM_DEBUG_KMS("Preparing DDI mode on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); intel_crtc->eld_vld = false; -- cgit v1.2.3 From cece5d58d5568e4a7986e43981d21a80ea189a82 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 19 Apr 2013 08:46:35 -0700 Subject: drm/i915: use vlv_dport_to_channel in vlv_signal_levels Minor cleanup. Would be nice to use an enum for channel in the DPIO macros so we don't mix up pipes and channels, but that's for another patch. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 058002659d9b..1ccf853e2df7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1595,14 +1595,7 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) unsigned long demph_reg_value, preemph_reg_value, uniqtranscale_reg_value; uint8_t train_set = intel_dp->train_set[0]; - int port; - - if (dport->port == PORT_B) - port = 0; - else if (dport->port == PORT_C) - port = 1; - else - BUG(); + int port = vlv_dport_to_channel(dport); WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); -- cgit v1.2.3 From 80ad9206c0d863832bc5f6008c4d1868d1df8e70 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 19 Apr 2013 14:36:51 +0300 Subject: drm/i915: Make struct dpll == intel_clock_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows unifying a bunch of the PLL calculations and whatnot. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ------------ drivers/gpu/drm/i915/intel_drv.h | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3c90605ddd45..74156e231fd5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -45,18 +45,6 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); -typedef struct { - /* given values */ - int n; - int m1, m2; - int p1, p2; - /* derived values */ - int dot; - int vco; - int m; - int p; -} intel_clock_t; - typedef struct { int min, max; } intel_range_t; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c20201d948eb..66922f8f1bc5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -177,6 +177,18 @@ struct intel_connector { u8 polled; }; +typedef struct dpll { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +} intel_clock_t; + struct intel_crtc_config { struct drm_display_mode requested_mode; struct drm_display_mode adjusted_mode; @@ -208,11 +220,7 @@ struct intel_crtc_config { /* Settings for the intel dpll used on pretty much everything but * haswell. */ - struct dpll { - unsigned n; - unsigned m1, m2; - unsigned p1, p2; - } dpll; + struct dpll dpll; int pipe_bpp; struct intel_link_m_n dp_m_n; -- cgit v1.2.3 From 2d04befb949744998284d8551ae7cd47059b8a53 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 22 Apr 2013 00:53:49 -0700 Subject: drm/i915: Add PTE encoding function to the gtt/ppgtt vtables. Sandybridge/Ivybridge, Bay Trail, and Haswell all have slightly different page table entry formats. Rather than polluting one function with generation checks, simply use a function pointer and set up the correct PTE encoding function at startup. v2: Move the gen6_gtt_pte_t typedef to i915_drv.h so that the function pointers and implementations have identical signatures. Also remove inline keyword on gen6_pte_encode. Both suggested by Jani Nikula. Signed-off-by: Kenneth Graunke Reviewed-by: Jani Nikula Tested-by: Daniel Leung [v1] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 ++++++++ drivers/gpu/drm/i915/i915_gem_gtt.c | 30 ++++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bd2d7f17393e..d80bced96cea 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -395,6 +395,8 @@ enum i915_cache_level { I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ }; +typedef uint32_t gen6_gtt_pte_t; + /* The Graphics Translation Table is the way in which GEN hardware translates a * Graphics Virtual Address into a Physical Address. In addition to the normal * collateral associated with any va->pa translations GEN hardware also has a @@ -430,6 +432,9 @@ struct i915_gtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); + gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level); }; #define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) @@ -451,6 +456,9 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); + gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level); int (*enable)(struct drm_device *dev); void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 50df194914a6..92e147ff8665 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,8 +28,6 @@ #include "i915_trace.h" #include "intel_drv.h" -typedef uint32_t gen6_gtt_pte_t; - /* PPGTT stuff */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) @@ -44,9 +42,9 @@ typedef uint32_t gen6_gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); @@ -154,9 +152,9 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = gen6_pte_encode(ppgtt->dev, - ppgtt->scratch_page_dma_addr, - I915_CACHE_LLC); + scratch_pte = ppgtt->pte_encode(ppgtt->dev, + ppgtt->scratch_page_dma_addr, + I915_CACHE_LLC); while (num_entries) { last_pte = first_pte + num_entries; @@ -191,8 +189,8 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, dma_addr_t page_addr; page_addr = sg_page_iter_dma_address(&sg_iter); - pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr, - cache_level); + pt_vaddr[act_pte] = ppgtt->pte_encode(ppgtt->dev, page_addr, + cache_level); if (++act_pte == I915_PPGTT_PT_ENTRIES) { kunmap_atomic(pt_vaddr); act_pt++; @@ -236,6 +234,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; + ppgtt->pte_encode = gen6_pte_encode; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->enable = gen6_ppgtt_enable; ppgtt->clear_range = gen6_ppgtt_clear_range; @@ -438,7 +437,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { addr = sg_page_iter_dma_address(&sg_iter); - iowrite32(gen6_pte_encode(dev, addr, level), >t_entries[i]); + iowrite32(dev_priv->gtt.pte_encode(dev, addr, level), + >t_entries[i]); i++; } @@ -450,7 +450,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, */ if (i != 0) WARN_ON(readl(>t_entries[i-1]) - != gen6_pte_encode(dev, addr, level)); + != dev_priv->gtt.pte_encode(dev, addr, level)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -475,8 +475,9 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma, - I915_CACHE_LLC); + scratch_pte = dev_priv->gtt.pte_encode(dev, + dev_priv->gtt.scratch_page_dma, + I915_CACHE_LLC); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); readl(gtt_base); @@ -823,6 +824,7 @@ int i915_gem_gtt_init(struct drm_device *dev) } else { dev_priv->gtt.gtt_probe = gen6_gmch_probe; dev_priv->gtt.gtt_remove = gen6_gmch_remove; + dev_priv->gtt.pte_encode = gen6_pte_encode; } ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, -- cgit v1.2.3 From 93c34e70ebf464a9ee142d93b681c5df094ec654 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 22 Apr 2013 00:53:50 -0700 Subject: drm/i915: Fix page table entries for Bay Trail. On Bay Trail, bit 1 means "writeable by the GPU." Failing to set that means basically anything using the GPU will cause hangs. v2: Drop accidental inline keyword on byt_pte_encode. Signed-off-by: Kenneth Graunke Reviewed-by: Jani Nikula Tested-by: Daniel Leung [v1] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 92e147ff8665..62058dc760ac 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -73,6 +73,27 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, return pte; } +#define BYT_PTE_WRITEABLE (1 << 1) +#define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2) + +static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) +{ + gen6_gtt_pte_t pte = GEN6_PTE_VALID; + pte |= GEN6_PTE_ADDR_ENCODE(addr); + + /* Mark the page as writeable. Other platforms don't have a + * setting for read-only/writable, so this matches that behavior. + */ + pte |= BYT_PTE_WRITEABLE; + + if (level != I915_CACHE_NONE) + pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES; + + return pte; +} + static int gen6_ppgtt_enable(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -234,7 +255,11 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; - ppgtt->pte_encode = gen6_pte_encode; + if (IS_VALLEYVIEW(dev)) { + ppgtt->pte_encode = byt_pte_encode; + } else { + ppgtt->pte_encode = gen6_pte_encode; + } ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; ppgtt->enable = gen6_ppgtt_enable; ppgtt->clear_range = gen6_ppgtt_clear_range; @@ -824,7 +849,11 @@ int i915_gem_gtt_init(struct drm_device *dev) } else { dev_priv->gtt.gtt_probe = gen6_gmch_probe; dev_priv->gtt.gtt_remove = gen6_gmch_remove; - dev_priv->gtt.pte_encode = gen6_pte_encode; + if (IS_VALLEYVIEW(dev)) { + dev_priv->gtt.pte_encode = byt_pte_encode; + } else { + dev_priv->gtt.pte_encode = gen6_pte_encode; + } } ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total, -- cgit v1.2.3 From 9119708cd484923bbc45fa60740bff58b358b848 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 22 Apr 2013 00:53:51 -0700 Subject: drm/i915: Split out Haswell code from gen6_pte_encode. Now that we have function pointers, it's cleaner to just create a new per-platform PTE encoding function. This should be identical in behavior to the previous code. v2: Drop accidental inline keyword on hsw_pte_encode. Signed-off-by: Kenneth Graunke Reviewed-by: Jani Nikula Tested-by: Daniel Leung [v1] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 62058dc760ac..ce024bd18eac 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -51,20 +51,13 @@ static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, switch (level) { case I915_CACHE_LLC_MLC: - /* Haswell doesn't set L3 this way */ - if (IS_HASWELL(dev)) - pte |= GEN6_PTE_CACHE_LLC; - else - pte |= GEN6_PTE_CACHE_LLC_MLC; + pte |= GEN6_PTE_CACHE_LLC_MLC; break; case I915_CACHE_LLC: pte |= GEN6_PTE_CACHE_LLC; break; case I915_CACHE_NONE: - if (IS_HASWELL(dev)) - pte |= HSW_PTE_UNCACHED; - else - pte |= GEN6_PTE_UNCACHED; + pte |= GEN6_PTE_UNCACHED; break; default: BUG(); @@ -94,6 +87,19 @@ static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev, return pte; } +static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) +{ + gen6_gtt_pte_t pte = GEN6_PTE_VALID; + pte |= GEN6_PTE_ADDR_ENCODE(addr); + + if (level != I915_CACHE_NONE) + pte |= GEN6_PTE_CACHE_LLC; + + return pte; +} + static int gen6_ppgtt_enable(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -255,7 +261,9 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; - if (IS_VALLEYVIEW(dev)) { + if (IS_HASWELL(dev)) { + ppgtt->pte_encode = hsw_pte_encode; + } else if (IS_VALLEYVIEW(dev)) { ppgtt->pte_encode = byt_pte_encode; } else { ppgtt->pte_encode = gen6_pte_encode; @@ -849,7 +857,9 @@ int i915_gem_gtt_init(struct drm_device *dev) } else { dev_priv->gtt.gtt_probe = gen6_gmch_probe; dev_priv->gtt.gtt_remove = gen6_gmch_remove; - if (IS_VALLEYVIEW(dev)) { + if (IS_HASWELL(dev)) { + dev_priv->gtt.pte_encode = hsw_pte_encode; + } else if (IS_VALLEYVIEW(dev)) { dev_priv->gtt.pte_encode = byt_pte_encode; } else { dev_priv->gtt.pte_encode = gen6_pte_encode; -- cgit v1.2.3 From 259bd5d4e909a6c07e0da8d6f623d2ab89b7a042 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 22 Apr 2013 15:59:30 -0700 Subject: drm/i915: fix locking around punit access in cur_delayinfo for VLV We need to hold the rps lock around punit access. Reported-by: Kenneth Graunke Signed-off-by: Jesse Barnes Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 367b534d2260..d195d097cbb7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1012,6 +1012,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) } else if (IS_VALLEYVIEW(dev)) { u32 freq_sts, val; + mutex_lock(&dev_priv->rps.hw_lock); valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq_sts); seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); @@ -1028,6 +1029,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "current GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv->mem_freq, (freq_sts >> 8) & 0xff)); + mutex_unlock(&dev_priv->rps.hw_lock); } else { seq_printf(m, "no P-state info available\n"); } -- cgit v1.2.3 From 142e239849c800f9dc23f828762873073f612d3f Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Thu, 11 Apr 2013 15:57:57 +0200 Subject: drm/i915: Add bit field to record which pins have received HPD events (v3) This way it is possible to limit 're'-detect() of displays to connectors which have received an HPD event. v2: Reordered drm_i915_private: Move hpd_event_bits to hpd state tracking. v3: Fixed merge conflicts with previous patches. Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d80bced96cea..9a171dd83dcf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -951,6 +951,7 @@ typedef struct drm_i915_private { HPD_MARK_DISABLED = 2 } hpd_mark; } hpd_stats[HPD_NUM_PINS]; + u32 hpd_event_bits; struct timer_list hotplug_reenable_timer; int num_pch_pll; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dae8953d2912..e37820199b26 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -557,6 +557,7 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_connector *connector; unsigned long irqflags; bool hpd_disabled = false; + u32 hpd_event_bits; /* HPD irq before everything is fully set up. */ if (!dev_priv->enable_hotplug_processing) @@ -566,6 +567,9 @@ static void i915_hotplug_work_func(struct work_struct *work) DRM_DEBUG_KMS("running encoder hotplug functions\n"); spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + + hpd_event_bits = dev_priv->hpd_event_bits; + dev_priv->hpd_event_bits = 0; list_for_each_entry(connector, &mode_config->connector_list, head) { intel_connector = to_intel_connector(connector); intel_encoder = intel_connector->encoder; @@ -580,6 +584,10 @@ static void i915_hotplug_work_func(struct work_struct *work) | DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; } + if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", + drm_get_connector_name(connector), intel_encoder->hpd_pin); + } } /* if there were no outputs to poll, poll was disabled, * therefore make sure it's enabled when disabling HPD on @@ -844,6 +852,7 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev, if (!(hpd[i] & hotplug_trigger) || dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) + dev_priv->hpd_event_bits |= (1 << i); continue; if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, @@ -853,6 +862,7 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev, dev_priv->hpd_stats[i].hpd_cnt = 0; } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; + dev_priv->hpd_event_bits &= ~(1 << i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); ret = true; } else { -- cgit v1.2.3 From 321a1b3026ea194dd084cf3bda1e235b2986b0af Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Thu, 11 Apr 2013 16:00:26 +0200 Subject: drm/i915: Only reprobe display on encoder which has received an HPD event (v2) Instead of calling into the DRM helper layer to poll all connectors for changes in connected displays probe only those connectors which have received a hotplug event. v2: Resolved conflicts with changes in previous commits. Renamed function and and added a WARN_ON() to warn of intel_hpd_irq_event() from being called without mode_config.mutex held - suggested by Jani Nikula. Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e37820199b26..7c81f0fb721a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -541,6 +541,21 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, crtc); } +static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector) +{ + enum drm_connector_status old_status; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + old_status = connector->status; + + connector->status = connector->funcs->detect(connector, false); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + connector->base.id, + drm_get_connector_name(connector), + old_status, connector->status); + return (old_status != connector->status); +} + /* * Handle hotplug events outside the interrupt handler proper. */ @@ -557,6 +572,7 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_connector *connector; unsigned long irqflags; bool hpd_disabled = false; + bool changed = false; u32 hpd_event_bits; /* HPD irq before everything is fully set up. */ @@ -600,14 +616,20 @@ static void i915_hotplug_work_func(struct work_struct *work) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) - if (intel_encoder->hot_plug) - intel_encoder->hot_plug(intel_encoder); - + list_for_each_entry(connector, &mode_config->connector_list, head) { + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + if (intel_encoder->hot_plug) + intel_encoder->hot_plug(intel_encoder); + if (intel_hpd_irq_event(dev, connector)) + changed = true; + } + } mutex_unlock(&mode_config->mutex); - /* Just fire off a uevent and let userspace tell us what to do */ - drm_helper_hpd_irq_event(dev); + if (changed) + drm_kms_helper_hotplug_event(dev); } static void ironlake_handle_rps_change(struct drm_device *dev) -- cgit v1.2.3 From 79fc46dfd0c7cc68442554a428e03a3b7e0d44aa Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 23 Apr 2013 16:37:17 +0100 Subject: drm/i915: Turn DEV_INFO_FLAGS into a foreach style macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DEV_INFO_FOR_FLAG() now takes 2 parameters: • A function to apply to the flag • A separator This will allow us to use the macro twice in the DRM_DEBUG_DRIVER() call of i915_dump_device_info(). v2: Fix a typo in the subject (Jani Nikula) v3: Undef the helper macros (Jani Nikula, Daniel vetter) Reviewed-by: Jani Nikula Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 10 ++++---- drivers/gpu/drm/i915/i915_dma.c | 10 ++++---- drivers/gpu/drm/i915/i915_drv.h | 50 ++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 35 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d195d097cbb7..a55630a80f83 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -61,11 +61,11 @@ static int i915_capabilities(struct seq_file *m, void *data) seq_printf(m, "gen: %d\n", info->gen); seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev)); -#define DEV_INFO_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x)) -#define DEV_INFO_SEP ; - DEV_INFO_FLAGS; -#undef DEV_INFO_FLAG -#undef DEV_INFO_SEP +#define PRINT_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x)) +#define SEP_SEMICOLON ; + DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_SEMICOLON); +#undef PRINT_FLAG +#undef SEP_SEMICOLON return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3b315ba85a3e..cc5fd5f75e4c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1445,15 +1445,15 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) { const struct intel_device_info *info = dev_priv->info; -#define DEV_INFO_FLAG(name) info->name ? #name "," : "" -#define DEV_INFO_SEP , +#define PRINT_FLAG(name) info->name ? #name "," : "" +#define SEP_COMMA , DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags=" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", info->gen, dev_priv->dev->pdev->device, - DEV_INFO_FLAGS); -#undef DEV_INFO_FLAG -#undef DEV_INFO_SEP + DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_COMMA)); +#undef PRINT_FLAG +#undef SEP_COMMA } /** diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9a171dd83dcf..e3df380646e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -333,31 +333,31 @@ struct drm_i915_gt_funcs { void (*force_wake_put)(struct drm_i915_private *dev_priv); }; -#define DEV_INFO_FLAGS \ - DEV_INFO_FLAG(is_mobile) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_i85x) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_i915g) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_i945gm) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_g33) DEV_INFO_SEP \ - DEV_INFO_FLAG(need_gfx_hws) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_g4x) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_pineview) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_broadwater) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_crestline) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_ivybridge) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_valleyview) DEV_INFO_SEP \ - DEV_INFO_FLAG(is_haswell) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_force_wake) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_fbc) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_pipe_cxsr) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_hotplug) DEV_INFO_SEP \ - DEV_INFO_FLAG(cursor_needs_physical) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_overlay) DEV_INFO_SEP \ - DEV_INFO_FLAG(overlay_needs_physical) DEV_INFO_SEP \ - DEV_INFO_FLAG(supports_tv) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_bsd_ring) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_blt_ring) DEV_INFO_SEP \ - DEV_INFO_FLAG(has_llc) +#define DEV_INFO_FOR_EACH_FLAG(func, sep) \ + func(is_mobile) sep \ + func(is_i85x) sep \ + func(is_i915g) sep \ + func(is_i945gm) sep \ + func(is_g33) sep \ + func(need_gfx_hws) sep \ + func(is_g4x) sep \ + func(is_pineview) sep \ + func(is_broadwater) sep \ + func(is_crestline) sep \ + func(is_ivybridge) sep \ + func(is_valleyview) sep \ + func(is_haswell) sep \ + func(has_force_wake) sep \ + func(has_fbc) sep \ + func(has_pipe_cxsr) sep \ + func(has_hotplug) sep \ + func(cursor_needs_physical) sep \ + func(has_overlay) sep \ + func(overlay_needs_physical) sep \ + func(supports_tv) sep \ + func(has_bsd_ring) sep \ + func(has_blt_ring) sep \ + func(has_llc) struct intel_device_info { u32 display_mmio_offset; -- cgit v1.2.3 From e2a5800a14abcf861b9d6565de2a22bd6e9ae0ef Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 23 Apr 2013 16:38:34 +0100 Subject: drm/i915: Replace the line of %s by a DEV_INFO_FOR_EACH_FLAG() invocation This way, when adding a device flag we don't have to manually maintain that list. v2: undefine the helper macros (Jani Nikula, Daniel Vetter) Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cc5fd5f75e4c..cfa1298669ca 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1445,13 +1445,17 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) { const struct intel_device_info *info = dev_priv->info; +#define PRINT_S(name) "%s" +#define SEP_EMPTY #define PRINT_FLAG(name) info->name ? #name "," : "" #define SEP_COMMA , DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags=" - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + DEV_INFO_FOR_EACH_FLAG(PRINT_S, SEP_EMPTY), info->gen, dev_priv->dev->pdev->device, DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_COMMA)); +#undef PRINT_S +#undef SEP_EMPTY #undef PRINT_FLAG #undef SEP_COMMA } -- cgit v1.2.3 From a587f77987295ddec59afb653cea5335b4d1e191 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 22 Apr 2013 18:40:38 +0100 Subject: drm/i915: Use DEV_INFO_FOR_EACH_FLAG() to declare flags as well Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e3df380646e3..ec8eadd179c4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -359,36 +359,19 @@ struct drm_i915_gt_funcs { func(has_blt_ring) sep \ func(has_llc) +#define DEFINE_FLAG(name) u8 name:1 +#define SEP_SEMICOLON ; + struct intel_device_info { u32 display_mmio_offset; u8 num_pipes:3; u8 gen; - u8 is_mobile:1; - u8 is_i85x:1; - u8 is_i915g:1; - u8 is_i945gm:1; - u8 is_g33:1; - u8 need_gfx_hws:1; - u8 is_g4x:1; - u8 is_pineview:1; - u8 is_broadwater:1; - u8 is_crestline:1; - u8 is_ivybridge:1; - u8 is_valleyview:1; - u8 has_force_wake:1; - u8 is_haswell:1; - u8 has_fbc:1; - u8 has_pipe_cxsr:1; - u8 has_hotplug:1; - u8 cursor_needs_physical:1; - u8 has_overlay:1; - u8 overlay_needs_physical:1; - u8 supports_tv:1; - u8 has_bsd_ring:1; - u8 has_blt_ring:1; - u8 has_llc:1; + DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON); }; +#undef DEFINE_FLAG +#undef SEP_SEMICOLON + enum i915_cache_level { I915_CACHE_NONE = 0, I915_CACHE_LLC, -- cgit v1.2.3 From dd93be584099b157039c43c7b48eac56223ac94d Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 22 Apr 2013 18:40:39 +0100 Subject: drm/i915: Turn HAS_DDI() into a device_info flag Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9ebe895c17d6..564d4c65e25b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -308,12 +308,14 @@ static const struct intel_device_info intel_valleyview_d_info = { static const struct intel_device_info intel_haswell_d_info = { GEN7_FEATURES, .is_haswell = 1, + .has_ddi = 1, }; static const struct intel_device_info intel_haswell_m_info = { GEN7_FEATURES, .is_haswell = 1, .is_mobile = 1, + .has_ddi = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ec8eadd179c4..5407714dee8b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -357,7 +357,8 @@ struct drm_i915_gt_funcs { func(supports_tv) sep \ func(has_bsd_ring) sep \ func(has_blt_ring) sep \ - func(has_llc) + func(has_llc) sep \ + func(has_ddi) #define DEFINE_FLAG(name) u8 name:1 #define SEP_SEMICOLON ; @@ -1367,7 +1368,7 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) -#define HAS_DDI(dev) (IS_HASWELL(dev)) +#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 -- cgit v1.2.3 From e76ebff887e9cc4a8448a0fc6abbb1925291f38b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 22 Apr 2013 18:40:40 +0100 Subject: drm/i915: Introduce HAS_FPGA_DBG_UNCLAIMED() Let's introduce one more of those orthogonal feature macros. This should hopefully make the code more readable and make things easier for new platform enabling. This time, HAS_FPGA_DBG_UNCLAIMED() is true for platforms that have bit 31 of FPGA_DBG able to signal unclaimed writes. Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index cfa1298669ca..13a72e63b4e9 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1472,7 +1472,7 @@ static void intel_early_sanitize_regs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_HASWELL(dev)) + if (HAS_FPGA_DBG_UNCLAIMED(dev)) I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 564d4c65e25b..896b90430ba9 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1205,7 +1205,7 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) static void hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) { - if (IS_HASWELL(dev_priv->dev) && + if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); @@ -1216,7 +1216,7 @@ hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) static void hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) { - if (IS_HASWELL(dev_priv->dev) && + if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { DRM_ERROR("Unclaimed write to %x\n", reg); I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5407714dee8b..ffd325c70407 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1370,6 +1370,7 @@ struct drm_i915_file_private { #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) +#define HAS_FPGA_DBG_UNCLAIMED(dev) (IS_HASWELL(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -- cgit v1.2.3 From 30568c45d9fc4ee0bb9e1da90e185692fcd67e38 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 22 Apr 2013 18:40:41 +0100 Subject: drm/i915: Turn HAS_FPGA_DBG_UNCLAIMED into a device_info flag Signed-off-by: Damien Lespiau Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 896b90430ba9..624cdfcc1ba3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -309,6 +309,7 @@ static const struct intel_device_info intel_haswell_d_info = { GEN7_FEATURES, .is_haswell = 1, .has_ddi = 1, + .has_fpga_dbg = 1, }; static const struct intel_device_info intel_haswell_m_info = { @@ -316,6 +317,7 @@ static const struct intel_device_info intel_haswell_m_info = { .is_haswell = 1, .is_mobile = 1, .has_ddi = 1, + .has_fpga_dbg = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ffd325c70407..a4234a837032 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -358,7 +358,8 @@ struct drm_i915_gt_funcs { func(has_bsd_ring) sep \ func(has_blt_ring) sep \ func(has_llc) sep \ - func(has_ddi) + func(has_ddi) sep \ + func(has_fpga_dbg) #define DEFINE_FLAG(name) u8 name:1 #define SEP_SEMICOLON ; @@ -1370,7 +1371,7 @@ struct drm_i915_file_private { #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) -#define HAS_FPGA_DBG_UNCLAIMED(dev) (IS_HASWELL(dev)) +#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -- cgit v1.2.3 From 52ceb908018d3ac3c19cea85d5e407705f0a79c3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 23 Apr 2013 10:09:26 -0700 Subject: drm/i915: make sure GPU freq drops to minimum after entering RC6 v4 On VLV, the Punit doesn't automatically drop the GPU to it's minimum voltage level when entering RC6, so we arm a timer to do it for us from the RPS interrupt handler. It'll generally only fire when we go idle (or if for some reason there's a long delay between RPS interrupts), but won't be re-armed again until the next RPS event, so shouldn't affect power consumption after we go idle and it triggers. v2: use delayed work instead of timer + work queue combo (Ville) v3: fix up delayed work cancel (must be outside lock) (Daniel) fix up delayed work handling func for delayed work (Jesse) v4: cancel delayed work before RPS shutdown (Jani) pass delay not absolute time to mod_delayed_work (Jani) Signed-off-by: Jesse Barnes Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_pm.c | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a4234a837032..95a3cc367d50 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -653,6 +653,7 @@ struct i915_suspend_saved_registers { struct intel_gen6_power_mgmt { struct work_struct work; + struct delayed_work vlv_work; u32 pm_iir; /* lock - irqsave spinlock that protectects the work_struct and * pm_iir. */ @@ -663,6 +664,7 @@ struct intel_gen6_power_mgmt { u8 cur_delay; u8 min_delay; u8 max_delay; + u8 rpe_delay; u8 hw_max; struct delayed_work delayed_resume_work; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7c81f0fb721a..3cf646cdab1a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -725,6 +725,17 @@ static void gen6_pm_rps_work(struct work_struct *work) gen6_set_rps(dev_priv->dev, new_delay); } + if (IS_VALLEYVIEW(dev_priv->dev)) { + /* + * On VLV, when we enter RC6 we may not be at the minimum + * voltage level, so arm a timer to check. It should only + * fire when there's activity or once after we've entered + * RC6, and then won't be re-armed until the next RPS interrupt. + */ + mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work, + msecs_to_jiffies(100)); + } + mutex_unlock(&dev_priv->rps.hw_lock); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2557926553b3..93b01e197f42 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2822,6 +2822,23 @@ int valleyview_rps_min_freq(struct drm_i915_private *dev_priv) return val & 0xff; } +static void vlv_rps_timer_work(struct work_struct *work) +{ + drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, + rps.vlv_work.work); + + /* + * Timer fired, we must be idle. Drop to min voltage state. + * Note: we use RPe here since it should match the + * Vmin we were shooting for. That should give us better + * perf when we come back out of RC6 than if we used the + * min freq available. + */ + mutex_lock(&dev_priv->rps.hw_lock); + valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); + mutex_unlock(&dev_priv->rps.hw_lock); +} + static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2886,6 +2903,7 @@ static void valleyview_enable_rps(struct drm_device *dev) rpe = valleyview_rps_rpe_freq(dev_priv); DRM_DEBUG_DRIVER("RPe GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, rpe)); + dev_priv->rps.rpe_delay = rpe; val = valleyview_rps_min_freq(dev_priv); DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, @@ -2895,6 +2913,8 @@ static void valleyview_enable_rps(struct drm_device *dev) DRM_DEBUG_DRIVER("setting GPU freq to %d\n", vlv_gpu_freq(dev_priv->mem_freq, rpe)); + INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work); + valleyview_set_rps(dev_priv->dev, rpe); /* requires MSI enabled */ @@ -3637,6 +3657,8 @@ void intel_disable_gt_powersave(struct drm_device *dev) ironlake_disable_rc6(dev); } else if (INTEL_INFO(dev)->gen >= 6) { cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); + if (IS_VALLEYVIEW(dev)) + cancel_delayed_work_sync(&dev_priv->rps.vlv_work); mutex_lock(&dev_priv->rps.hw_lock); gen6_disable_rps(dev); mutex_unlock(&dev_priv->rps.hw_lock); -- cgit v1.2.3 From 250848ca04b734c91f491b7c9b6045d2198a208c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 23 Apr 2013 10:09:27 -0700 Subject: drm/i915: cancel RPS work before disabling RPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville noticed this while doing another review; we may as well cancel this work just to make sure we don't try anything fancy after disabling the RPS interfaces. Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 93b01e197f42..72ad817b6bf4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3657,6 +3657,7 @@ void intel_disable_gt_powersave(struct drm_device *dev) ironlake_disable_rc6(dev); } else if (INTEL_INFO(dev)->gen >= 6) { cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); + cancel_work_sync(&dev_priv->rps.work); if (IS_VALLEYVIEW(dev)) cancel_delayed_work_sync(&dev_priv->rps.vlv_work); mutex_lock(&dev_priv->rps.hw_lock); -- cgit v1.2.3 From d20d4f0ca343c0b76567d46fcc343c165e8d7c43 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 23 Apr 2013 10:09:28 -0700 Subject: drm/i915: create spearate VLV disable_rps function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't want to write reserved regs here, and may want to do other bits in the future, so split it out. Reported-by: Ville Syrjälä Signed-off-by: Jesse Barnes Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 72ad817b6bf4..8b7f050decdd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2547,6 +2547,25 @@ static void gen6_disable_rps(struct drm_device *dev) I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); } +static void valleyview_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RC_CONTROL, 0); + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0); + /* Complete PM interrupt masking here doesn't race with the rps work + * item again unmasking PM interrupts because that is using a different + * register (PMIMR) to mask PM interrupts. The only risk is in leaving + * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ + + spin_lock_irq(&dev_priv->rps.lock); + dev_priv->rps.pm_iir = 0; + spin_unlock_irq(&dev_priv->rps.lock); + + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); +} + int intel_enable_rc6(const struct drm_device *dev) { /* Respect the kernel parameter if it is set */ @@ -3661,7 +3680,10 @@ void intel_disable_gt_powersave(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) cancel_delayed_work_sync(&dev_priv->rps.vlv_work); mutex_lock(&dev_priv->rps.hw_lock); - gen6_disable_rps(dev); + if (IS_VALLEYVIEW(dev)) + valleyview_disable_rps(dev); + else + gen6_disable_rps(dev); mutex_unlock(&dev_priv->rps.hw_lock); } } -- cgit v1.2.3 From fd0c06420d39958032655a04cfd194d5a7b38f83 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 24 Apr 2013 11:13:35 +0200 Subject: drm/i915: disable interrupts earlier in the driver unload code Our rps code relies on the interrupts being off to prevent re-arming of the work items at inopportune moments. Also drop the redundant cancel_work for the main rps work, disable_gt_powersave already takes care of that. Finally add a WARN_ON to ensure we obey that piece of ordering constraint. Long term I want to lock down the setup/teardown code in a similar way to how we painstakingly check modeset sequence constraints already. v2: Disable polling after hpd handling is shut down - since Egbert's hpd irq storm handling the hotplug work can re-arm the polling handler. Spotted by Jani Nikula. Cc: Jesse Barnes Cc: Jani Nikula Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++++------- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 74156e231fd5..988e543ec45b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9530,12 +9530,23 @@ void intel_modeset_cleanup(struct drm_device *dev) struct drm_crtc *crtc; struct intel_crtc *intel_crtc; + /* + * Interrupts and polling as the first thing to avoid creating havoc. + * Too much stuff here (turning of rps, connectors, ...) would + * experience fancy races otherwise. + */ + drm_irq_uninstall(dev); + cancel_work_sync(&dev_priv->hotplug_work); + /* + * Due to the hpd irq storm handling the hotplug work can re-arm the + * poll handlers. Hence disable polling after hpd handling is shut down. + */ drm_kms_helper_poll_fini(dev); + mutex_lock(&dev->struct_mutex); intel_unregister_dsm_handler(); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ if (!crtc->fb) @@ -9553,12 +9564,6 @@ void intel_modeset_cleanup(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); - /* Disable the irq before mode object teardown, for the irq might - * enqueue unpin/hotplug work. */ - drm_irq_uninstall(dev); - cancel_work_sync(&dev_priv->hotplug_work); - cancel_work_sync(&dev_priv->rps.work); - /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8b7f050decdd..bb45122173dd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3671,6 +3671,9 @@ void intel_disable_gt_powersave(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + /* Interrupts should be disabled already to avoid re-arming. */ + WARN_ON(dev->irq_enabled); + if (IS_IRONLAKE_M(dev)) { ironlake_disable_drps(dev); ironlake_disable_rc6(dev); -- cgit v1.2.3 From 996a2239f93b03c5972923f04b097f65565c5bed Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:34 +0200 Subject: drm/i915: Disable high-bpc on pre-1.4 EDID screens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevents black screens when using 30bpp framebuffers on my HDMI screens here. The DP input on the same screen though reports a 1.4 EDID with the correct 8bpc limit set. v2: Actually check for the right thing! Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 988e543ec45b..15ce99125c64 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7694,6 +7694,13 @@ pipe_config_set_bpp(struct drm_crtc *crtc, bpp, connector->display_info.bpc*3); pipe_config->pipe_bpp = connector->display_info.bpc*3; } + + /* Clamp bpp to 8 on screens without EDID 1.4 */ + if (connector->display_info.bpc == 0 && bpp > 24) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", + bpp); + pipe_config->pipe_bpp = 24; + } } return bpp; -- cgit v1.2.3 From 2a7aceecf15a463ba6bfa83b6579e75bb4703cd9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:39 +0200 Subject: drm/i915: Fixup non-24bpp support for VGA screens on Haswell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LPT PCH only supports 8bpc, so we need to force the pipe bpp to the right value. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c063b9f0dd51..991e53047e1d 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -214,6 +214,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev)) pipe_config->has_pch_encoder = true; + /* LPT FDI RX only supports 8bpc. */ + if (HAS_PCH_LPT(dev)) + pipe_config->pipe_bpp = 24; + return true; } -- cgit v1.2.3 From d65406327345e5a5e0f697a3ffe3e53bc9b5d7c6 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:18:36 +0300 Subject: drm/i915: keep max backlight internal to intel_panel.c In preparation of adding locking to backlight, make max backlight value (the modulation frequency the PWM duty cycle value must not exceed) internal to intel_panel.c. Have intel_panel_set_backlight() accept a caller defined range for level, and scale input to max backlight value internally. Clean up intel_panel_get_max_backlight() and usage internally. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 4 +-- drivers/gpu/drm/i915/intel_opregion.c | 4 +-- drivers/gpu/drm/i915/intel_panel.c | 51 ++++++++++++++++++++--------------- 3 files changed, 32 insertions(+), 27 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 66922f8f1bc5..3595c8204649 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -553,8 +553,8 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, int fitting_mode, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); -extern u32 intel_panel_get_max_backlight(struct drm_device *dev); -extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); +extern void intel_panel_set_backlight(struct drm_device *dev, + u32 level, u32 max); extern int intel_panel_setup_backlight(struct drm_connector *connector); extern void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 4d338740f2cb..42faa5885f5a 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -152,7 +152,6 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; struct opregion_asle __iomem *asle = dev_priv->opregion.asle; - u32 max; DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); @@ -163,8 +162,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) if (bclp > 255) return ASLE_BACKLIGHT_FAILED; - max = intel_panel_get_max_backlight(dev); - intel_panel_set_backlight(dev, bclp * max / 255); + intel_panel_set_backlight(dev, bclp, 255); iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv); return 0; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index eb5e6e95f3c7..63a7c36a7603 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -130,6 +130,9 @@ static int is_backlight_combination_mode(struct drm_device *dev) return 0; } +/* XXX: query mode clock or hardware clock and program max PWM appropriately + * when it's 0. + */ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -164,7 +167,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) return val; } -static u32 _intel_panel_get_max_backlight(struct drm_device *dev) +static u32 intel_panel_get_max_backlight(struct drm_device *dev) { u32 max; @@ -182,23 +185,8 @@ static u32 _intel_panel_get_max_backlight(struct drm_device *dev) max *= 0xff; } - return max; -} - -u32 intel_panel_get_max_backlight(struct drm_device *dev) -{ - u32 max; - - max = _intel_panel_get_max_backlight(dev); - if (max == 0) { - /* XXX add code here to query mode clock or hardware clock - * and program max PWM appropriately. - */ - pr_warn_once("fixme: max PWM is zero\n"); - return 1; - } - DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); + return max; } @@ -217,8 +205,11 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) return val; if (i915_panel_invert_brightness > 0 || - dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) - return intel_panel_get_max_backlight(dev) - val; + dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { + u32 max = intel_panel_get_max_backlight(dev); + if (max) + return max - val; + } return val; } @@ -270,6 +261,10 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level u32 max = intel_panel_get_max_backlight(dev); u8 lbpc; + /* we're screwed, but keep behaviour backwards compatible */ + if (!max) + max = 1; + lbpc = level * 0xfe / max + 1; level /= lbpc; pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); @@ -282,9 +277,20 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level I915_WRITE(BLC_PWM_CTL, tmp | level); } -void intel_panel_set_backlight(struct drm_device *dev, u32 level) +/* set backlight brightness to level in range [0..max] */ +void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 freq; + + freq = intel_panel_get_max_backlight(dev); + if (!freq) { + /* we are screwed, bail out */ + return; + } + + /* scale to hardware */ + level = level * freq / max; dev_priv->backlight.level = level; if (dev_priv->backlight.device) @@ -405,7 +411,8 @@ intel_panel_detect(struct drm_device *dev) static int intel_panel_update_status(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); - intel_panel_set_backlight(dev, bd->props.brightness); + intel_panel_set_backlight(dev, bd->props.brightness, + bd->props.max_brightness); return 0; } @@ -434,7 +441,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = dev_priv->backlight.level; - props.max_brightness = _intel_panel_get_max_backlight(dev); + props.max_brightness = intel_panel_get_max_backlight(dev); if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; -- cgit v1.2.3 From 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:18:37 +0300 Subject: drm/i915: protect backlight registers and data with a spinlock Backlight data and registers are fiddled through LVDS/eDP modeset enable/disable hooks, backlight sysfs files, asle interrupts, and register save/restore. Protect the backlight related registers and driver private fields using a spinlock. The locking in register save/restore covers a little more than is strictly necessary, including non-modeset case, for simplicity. v2: Cover register access, save/restore, i915_read_blc_pwm_ctl() and code paths leading there. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_panel.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 13a72e63b4e9..a1648eb3a8b1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1633,6 +1633,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); spin_lock_init(&dev_priv->rps.lock); + spin_lock_init(&dev_priv->backlight.lock); mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 95a3cc367d50..f6f4839484d1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -960,6 +960,7 @@ typedef struct drm_i915_private { struct { int level; bool enabled; + spinlock_t lock; /* bl registers and the above bl fields */ struct backlight_device *device; } backlight; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 41f0fdecfbdc..88b9a663944f 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_device *dev) static void i915_save_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; /* Display arbitration control */ if (INTEL_INFO(dev)->gen <= 4) @@ -202,6 +203,8 @@ static void i915_save_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_save_display_reg(dev); + spin_lock_irqsave(&dev_priv->backlight.lock, flags); + /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); @@ -222,6 +225,8 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.saveLVDS = I915_READ(LVDS); } + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); @@ -257,6 +262,7 @@ static void i915_restore_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 mask = 0xffffffff; + unsigned long flags; /* Display arbitration */ if (INTEL_INFO(dev)->gen <= 4) @@ -265,6 +271,8 @@ static void i915_restore_display(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_restore_display_reg(dev); + spin_lock_irqsave(&dev_priv->backlight.lock, flags); + /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); @@ -304,6 +312,8 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); if (I915_HAS_FBC(dev)) { diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 63a7c36a7603..5d3e9d7d51a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 val; + WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); + /* Restore the CTL value if it lost, e.g. GPU reset */ if (HAS_PCH_SPLIT(dev_priv->dev)) { @@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 val; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); if (HAS_PCH_SPLIT(dev)) { val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; @@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) } val = intel_panel_compute_brightness(dev, val); + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); return val; } @@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) { struct drm_i915_private *dev_priv = dev->dev_private; u32 freq; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); freq = intel_panel_get_max_backlight(dev); if (!freq) { /* we are screwed, bail out */ - return; + goto out; } /* scale to hardware */ @@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) if (dev_priv->backlight.enabled) intel_panel_actually_set_backlight(dev, level); +out: + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } void intel_panel_disable_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); dev_priv->backlight.enabled = false; intel_panel_actually_set_backlight(dev, 0); @@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) I915_WRITE(BLC_PWM_PCH_CTL1, tmp); } } + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); if (dev_priv->backlight.level == 0) { dev_priv->backlight.level = intel_panel_get_max_backlight(dev); @@ -375,6 +396,8 @@ set_level: */ dev_priv->backlight.enabled = true; intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); + + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); } static void intel_panel_init_backlight(struct drm_device *dev) @@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct backlight_properties props; + unsigned long flags; intel_panel_init_backlight(dev); @@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector) memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = dev_priv->backlight.level; + + spin_lock_irqsave(&dev_priv->backlight.lock, flags); props.max_brightness = intel_panel_get_max_backlight(dev); + spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); + if (props.max_brightness == 0) { DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); return -ENODEV; -- cgit v1.2.3 From 1767afa4d0a6409e24fd9421a7c2df0490a0da4a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:20:56 +0300 Subject: drm/i915: don't pretend we support ASLE ALS, PFIT, or PFMB In theory, this should prevent the BIOS from requesting them from us, and this should be the right thing. In practice, this is not always the case, and might surprise the BIOS. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 42faa5885f5a..1ed433186762 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -280,9 +280,7 @@ void intel_opregion_enable_asle(struct drm_device *dev) if (IS_MOBILE(dev)) intel_enable_asle(dev); - iowrite32(ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | - ASLE_PFMB_EN, - &asle->tche); + iowrite32(ASLE_BLC_EN, &asle->tche); iowrite32(1, &asle->ardy); } } -- cgit v1.2.3 From e93d440b352a1ba9e99cc17f3d46b1841caef3cd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:20:57 +0300 Subject: drm/i915/opregion: don't pretend we did something when we didn't In theory, the BIOS should not even request these from us now that we aren't claiming we support these, but when it does anyway, don't pretend it succeeded. It should be the right thing to do, but might confuse the BIOS. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 1ed433186762..6f7cdfa935d7 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -172,29 +172,22 @@ static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) { /* alsi is the current ALS reading in lux. 0 indicates below sensor range, 0xffff indicates above sensor range. 1-0xfffe are valid */ - return 0; + DRM_DEBUG_DRIVER("Illum is not supported\n"); + return ASLE_ALS_ILLUM_FAILED; } static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (pfmb & ASLE_PFMB_PWM_VALID) { - u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); - u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; - blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; - pwm = pwm >> 9; - /* FIXME - what do we do with the PWM? */ - } - return 0; + DRM_DEBUG_DRIVER("PWM freq is not supported\n"); + return ASLE_PWM_FREQ_FAILED; } static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) { /* Panel fitting is currently controlled by the X code, so this is a noop until modesetting support works fully */ - if (!(pfit & ASLE_PFIT_VALID)) - return ASLE_PFIT_FAILED; - return 0; + DRM_DEBUG_DRIVER("Pfit is not supported\n"); + return ASLE_PFIT_FAILED; } void intel_opregion_asle_intr(struct drm_device *dev) -- cgit v1.2.3 From 81a078092ed25b1017d1351c68837b750a09933a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 24 Apr 2013 22:18:44 +0300 Subject: drm/i915: drop code duplication in favor of asle interrupt handler With the previous work asle and gse interrupt handlers should now be functionally the same. Drop the duplicated code. v2: Drop intel_opregion_gse_intr() also in the !CONFIG_ACPI path. (Damien) Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- drivers/gpu/drm/i915/intel_opregion.c | 37 ----------------------------------- 3 files changed, 2 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f6f4839484d1..8a257a9114c2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1821,13 +1821,11 @@ extern int intel_opregion_setup(struct drm_device *dev); extern void intel_opregion_init(struct drm_device *dev); extern void intel_opregion_fini(struct drm_device *dev); extern void intel_opregion_asle_intr(struct drm_device *dev); -extern void intel_opregion_gse_intr(struct drm_device *dev); extern void intel_opregion_enable_asle(struct drm_device *dev); #else static inline void intel_opregion_init(struct drm_device *dev) { return; } static inline void intel_opregion_fini(struct drm_device *dev) { return; } static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } -static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; } static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; } #endif diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 3cf646cdab1a..125b45a6780d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1205,7 +1205,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) dp_aux_irq_handler(dev); if (de_iir & DE_GSE_IVB) - intel_opregion_gse_intr(dev); + intel_opregion_asle_intr(dev); for (i = 0; i < 3; i++) { if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i))) @@ -1302,7 +1302,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) dp_aux_irq_handler(dev); if (de_iir & DE_GSE) - intel_opregion_gse_intr(dev); + intel_opregion_asle_intr(dev); if (de_iir & DE_PIPEA_VBLANK) drm_handle_vblank(dev, 0); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6f7cdfa935d7..dda182833209 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -222,43 +222,6 @@ void intel_opregion_asle_intr(struct drm_device *dev) iowrite32(asle_stat, &asle->aslc); } -void intel_opregion_gse_intr(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle __iomem *asle = dev_priv->opregion.asle; - u32 asle_stat = 0; - u32 asle_req; - - if (!asle) - return; - - asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK; - - if (!asle_req) { - DRM_DEBUG_DRIVER("non asle set request??\n"); - return; - } - - if (asle_req & ASLE_SET_ALS_ILLUM) { - DRM_DEBUG_DRIVER("Illum is not supported\n"); - asle_stat |= ASLE_ALS_ILLUM_FAILED; - } - - if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp)); - - if (asle_req & ASLE_SET_PFIT) { - DRM_DEBUG_DRIVER("Pfit is not supported\n"); - asle_stat |= ASLE_PFIT_FAILED; - } - - if (asle_req & ASLE_SET_PWM_FREQ) { - DRM_DEBUG_DRIVER("PWM freq is not supported\n"); - asle_stat |= ASLE_PWM_FREQ_FAILED; - } - - iowrite32(asle_stat, &asle->aslc); -} #define ASLE_ALS_EN (1<<0) #define ASLE_BLC_EN (1<<1) #define ASLE_PFIT_EN (1<<2) -- cgit v1.2.3 From 35ffda4883a8d3f75632d7389dc96a25640033f0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 25 Apr 2013 16:49:25 +0300 Subject: drm/i915: hsw backlight registers need transcoder instead of pipe v2: Make TRANSCODER_EDP handling more explicit. (Imre) Signed-off-by: Jani Nikula Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_panel.c | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 60e0e19373b1..e79669fa9fe2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2087,6 +2087,10 @@ #define BLM_PIPE_A (0 << 29) #define BLM_PIPE_B (1 << 29) #define BLM_PIPE_C (2 << 29) /* ivb + */ +#define BLM_TRANSCODER_A BLM_PIPE_A /* hsw */ +#define BLM_TRANSCODER_B BLM_PIPE_B +#define BLM_TRANSCODER_C BLM_PIPE_C +#define BLM_TRANSCODER_EDP (3 << 29) #define BLM_PIPE(pipe) ((pipe) << 29) #define BLM_POLARITY_I965 (1 << 28) /* gen4 only */ #define BLM_PHASE_IN_INTERUPT_STATUS (1 << 26) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 5d3e9d7d51a7..7f6141d9a06d 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -344,6 +344,8 @@ void intel_panel_enable_backlight(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = + intel_pipe_to_cpu_transcoder(dev_priv, pipe); unsigned long flags; spin_lock_irqsave(&dev_priv->backlight.lock, flags); @@ -374,7 +376,10 @@ void intel_panel_enable_backlight(struct drm_device *dev, else tmp &= ~BLM_PIPE_SELECT; - tmp |= BLM_PIPE(pipe); + if (cpu_transcoder == TRANSCODER_EDP) + tmp |= BLM_TRANSCODER_EDP; + else + tmp |= BLM_PIPE(cpu_transcoder); tmp &= ~BLM_PWM_ENABLE; I915_WRITE(reg, tmp); -- cgit v1.2.3 From d49f70915c07c1a313e459d23fad61ddbeeb1bae Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 25 Apr 2013 15:15:00 +0100 Subject: drm/i915: Ivybridge is the odd one when it comes to pipe scalers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Between ivb, hsw and vlv, only Ivybridge has sprites with scaling capabilities. Also make max_downscale coherent with that. v2: Rebase on top of the recent ivb/vlv/hsw sprite scaling fixes. Signed-off-by: Damien Lespiau (v1) Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index c7d25c5dd4e6..18993ad93540 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -918,13 +918,15 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) break; case 7: - if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev)) - intel_plane->can_scale = false; - else + if (IS_IVYBRIDGE(dev)) { intel_plane->can_scale = true; + intel_plane->max_downscale = 2; + } else { + intel_plane->can_scale = false; + intel_plane->max_downscale = 1; + } if (IS_VALLEYVIEW(dev)) { - intel_plane->max_downscale = 1; intel_plane->update_plane = vlv_update_plane; intel_plane->disable_plane = vlv_disable_plane; intel_plane->update_colorkey = vlv_update_colorkey; @@ -933,7 +935,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) plane_formats = vlv_plane_formats; num_plane_formats = ARRAY_SIZE(vlv_plane_formats); } else { - intel_plane->max_downscale = 2; intel_plane->update_plane = ivb_update_plane; intel_plane->disable_plane = ivb_disable_plane; intel_plane->update_colorkey = ivb_update_colorkey; -- cgit v1.2.3 From cbbab5bdea0df4e85ac7fbc0b3e1d7dee71cb708 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:14:31 +0200 Subject: drm/i915: consolidate pch pll computations a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need the dpll/fp/fp2 values only when we need a pch pll. So move them together with the code to acquire such a pll. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 15ce99125c64..8e8ac366e75e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5704,7 +5704,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int num_connectors = 0; intel_clock_t clock, reduced_clock; - u32 dpll, fp = 0, fp2 = 0; + u32 dpll = 0, fp = 0, fp2 = 0; bool ok, has_reduced_clock = false; bool is_lvds = false; struct intel_encoder *encoder; @@ -5749,14 +5749,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (is_lvds && dev_priv->lvds_dither) dither = true; - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; - - dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock, - has_reduced_clock ? &fp2 : NULL); - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); @@ -5764,6 +5756,15 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) { struct intel_pch_pll *pll; + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + if (has_reduced_clock) + fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | + reduced_clock.m2; + + dpll = ironlake_compute_dpll(intel_crtc, &clock, + &fp, &reduced_clock, + has_reduced_clock ? &fp2 : NULL); + pll = intel_get_pch_pll(intel_crtc, dpll, fp); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", -- cgit v1.2.3 From 7429e9d4bfcfd08a00ed7b760386bd81a60e91d6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 20 Apr 2013 17:19:46 +0200 Subject: drm/i915: shovel compute clock into crtc->config.dpll on ilk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was somehow lost in the pipe_config->dpll introduction in commit f47709a9502f3715cc488b788ca91cf0c142b1b1 Author: Daniel Vetter Date: Thu Mar 28 10:42:02 2013 +0100 drm/i915: create pipe_config->dpll for clock state While at it, extract a few small helpers for common computations. v2: Use the newly added helpers more thanks to Ville's trick to typedef the legacy intel_clock_t as the new-world struct dpll. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 50 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8e8ac366e75e..f079fcd95dc2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -549,13 +549,18 @@ static void pineview_clock(int refclk, intel_clock_t *clock) clock->dot = clock->vco / clock->p; } +static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) +{ + return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); +} + static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock) { if (IS_PINEVIEW(dev)) { pineview_clock(refclk, clock); return; } - clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; clock->vco = refclk * clock->m / (clock->n + 2); clock->dot = clock->vco / clock->p; @@ -4241,6 +4246,16 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc) crtc->config.clock_set = true; } +static uint32_t pnv_dpll_compute_fp(struct dpll *dpll) +{ + return (1 << dpll->n) << 16 | dpll->m1 << 8 | dpll->m2; +} + +static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll) +{ + return dpll->n << 16 | dpll->m1 << 8 | dpll->m2; +} + static void i9xx_update_pll_dividers(struct intel_crtc *crtc, intel_clock_t *reduced_clock) { @@ -4248,18 +4263,15 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; int pipe = crtc->pipe; u32 fp, fp2 = 0; - struct dpll *clock = &crtc->config.dpll; if (IS_PINEVIEW(dev)) { - fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2; + fp = pnv_dpll_compute_fp(&crtc->config.dpll); if (reduced_clock) - fp2 = (1 << reduced_clock->n) << 16 | - reduced_clock->m1 << 8 | reduced_clock->m2; + fp2 = pnv_dpll_compute_fp(reduced_clock); } else { - fp = clock->n << 16 | clock->m1 << 8 | clock->m2; + fp = i9xx_dpll_compute_fp(&crtc->config.dpll); if (reduced_clock) - fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 | - reduced_clock->m2; + fp2 = i9xx_dpll_compute_fp(reduced_clock); } I915_WRITE(FP0(pipe), fp); @@ -5592,8 +5604,13 @@ static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) intel_cpu_transcoder_set_m_n(intel_crtc, &m_n); } +static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) +{ + return i9xx_dpll_compute_m(dpll) < factor * dpll->n; +} + static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, - intel_clock_t *clock, u32 *fp, + u32 *fp, intel_clock_t *reduced_clock, u32 *fp2) { struct drm_crtc *crtc = &intel_crtc->base; @@ -5633,7 +5650,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock->m < factor * clock->n) + if (ironlake_needs_fb_cb_tune(&intel_crtc->config.dpll, factor)) *fp |= FP_CB_TUNE; if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) @@ -5657,11 +5674,11 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ - dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; /* also FPA1 */ - dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; - switch (clock->p2) { + switch (intel_crtc->config.dpll.p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; break; @@ -5756,12 +5773,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) { struct intel_pch_pll *pll; - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll); if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; + fp2 = i9xx_dpll_compute_fp(&reduced_clock); - dpll = ironlake_compute_dpll(intel_crtc, &clock, + dpll = ironlake_compute_dpll(intel_crtc, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); -- cgit v1.2.3 From c6bb353815c30c3f8a33b436314926706f4b6360 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:14:33 +0200 Subject: drm/i915: move dp clock computations to encoder->compute_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the exception of hsw, which has dedicated DP clocks which run at the fixed frequency already, and vlv, which doesn't have optmized pre-defined dp clock parameters (yet). v2: Ville asked me to elaborate a bit more on the longer-term goals wrt dpll settings computation: So ultimately my idea is that in the compute config stage first the crtc code puts the default platform pll limits into the pipe_config. Then encoders can either overwrite that limit structure with their own special stuff (mostly for lvds madness). Or they can pick some or all of the parameters (e.g. just the p2 switchover on hdmi, or all the clock parameters for dp/sdvo tv). Once that's done then the generic crtc code can fill out any missing bits (using the find_best_pll code) and then try to assign which pll to use (if it's a platform with shared plls). In the end the modeset could should simply write the computed stuff into registers and never be able to fail. Of course there's still a lot of data to be moved into pipe_config to make this all happen, hence some of the temporary ugliness. Reviewed-by: Jesse Barnes (v1) Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 97 +----------------------------------- drivers/gpu/drm/i915/intel_dp.c | 45 +++++++++++++++++ 2 files changed, 46 insertions(+), 96 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f079fcd95dc2..26acc421f0c6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -101,15 +101,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock); -static bool -intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); -static bool -intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); - static bool intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, @@ -242,20 +233,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { .find_pll = intel_g4x_find_best_PLL, }; -static const intel_limit_t intel_limits_g4x_display_port = { - .dot = { .min = 161670, .max = 227000 }, - .vco = { .min = 1750000, .max = 3500000}, - .n = { .min = 1, .max = 2 }, - .m = { .min = 97, .max = 108 }, - .m1 = { .min = 0x10, .max = 0x12 }, - .m2 = { .min = 0x05, .max = 0x06 }, - .p = { .min = 10, .max = 20 }, - .p1 = { .min = 1, .max = 2}, - .p2 = { .dot_limit = 0, - .p2_slow = 10, .p2_fast = 10 }, - .find_pll = intel_find_pll_g4x_dp, -}; - static const intel_limit_t intel_limits_pineview_sdvo = { .dot = { .min = 20000, .max = 400000}, .vco = { .min = 1700000, .max = 3500000 }, @@ -362,20 +339,6 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { .find_pll = intel_g4x_find_best_PLL, }; -static const intel_limit_t intel_limits_ironlake_display_port = { - .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 1760000, .max = 3510000}, - .n = { .min = 1, .max = 2 }, - .m = { .min = 81, .max = 90 }, - .m1 = { .min = 12, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, - .p = { .min = 10, .max = 20 }, - .p1 = { .min = 1, .max = 2}, - .p2 = { .dot_limit = 0, - .p2_slow = 10, .p2_fast = 10 }, - .find_pll = intel_find_pll_ironlake_dp, -}; - static const intel_limit_t intel_limits_vlv_dac = { .dot = { .min = 25000, .max = 270000 }, .vco = { .min = 4000000, .max = 6000000 }, @@ -473,10 +436,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, else limit = &intel_limits_ironlake_single_lvds; } - } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) - limit = &intel_limits_ironlake_display_port; - else + } else limit = &intel_limits_ironlake_dac; return limit; @@ -497,8 +457,6 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) limit = &intel_limits_g4x_hdmi; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { limit = &intel_limits_g4x_sdvo; - } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { - limit = &intel_limits_g4x_display_port; } else /* The option is for other outputs */ limit = &intel_limits_i9xx_sdvo; @@ -745,59 +703,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, return found; } -static bool -intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) -{ - struct drm_device *dev = crtc->dev; - intel_clock_t clock; - - if (target < 200000) { - clock.n = 1; - clock.p1 = 2; - clock.p2 = 10; - clock.m1 = 12; - clock.m2 = 9; - } else { - clock.n = 2; - clock.p1 = 1; - clock.p2 = 10; - clock.m1 = 14; - clock.m2 = 8; - } - intel_clock(dev, refclk, &clock); - memcpy(best_clock, &clock, sizeof(intel_clock_t)); - return true; -} - -/* DisplayPort has only two frequencies, 162MHz and 270MHz */ -static bool -intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) -{ - intel_clock_t clock; - if (target < 200000) { - clock.p1 = 2; - clock.p2 = 10; - clock.n = 2; - clock.m1 = 23; - clock.m2 = 8; - } else { - clock.p1 = 1; - clock.p2 = 10; - clock.n = 1; - clock.m1 = 14; - clock.m2 = 2; - } - clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2); - clock.p = (clock.p1 * clock.p2); - clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p; - clock.vco = 0; - memcpy(best_clock, &clock, sizeof(intel_clock_t)); - return true; -} static bool intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1ccf853e2df7..f63973ad33cb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -660,6 +660,49 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, return ret; } +static void +intel_dp_set_clock(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config, int link_bw) +{ + struct drm_device *dev = encoder->base.dev; + + if (IS_G4X(dev)) { + if (link_bw == DP_LINK_BW_1_62) { + pipe_config->dpll.p1 = 2; + pipe_config->dpll.p2 = 10; + pipe_config->dpll.n = 2; + pipe_config->dpll.m1 = 23; + pipe_config->dpll.m2 = 8; + } else { + pipe_config->dpll.p1 = 1; + pipe_config->dpll.p2 = 10; + pipe_config->dpll.n = 1; + pipe_config->dpll.m1 = 14; + pipe_config->dpll.m2 = 2; + } + pipe_config->clock_set = true; + } else if (IS_HASWELL(dev)) { + /* Haswell has special-purpose DP DDI clocks. */ + } else if (HAS_PCH_SPLIT(dev)) { + if (link_bw == DP_LINK_BW_1_62) { + pipe_config->dpll.n = 1; + pipe_config->dpll.p1 = 2; + pipe_config->dpll.p2 = 10; + pipe_config->dpll.m1 = 12; + pipe_config->dpll.m2 = 9; + } else { + pipe_config->dpll.n = 2; + pipe_config->dpll.p1 = 1; + pipe_config->dpll.p2 = 10; + pipe_config->dpll.m1 = 14; + pipe_config->dpll.m2 = 8; + } + pipe_config->clock_set = true; + } else if (IS_VALLEYVIEW(dev)) { + /* FIXME: Need to figure out optimized DP clocks for vlv. */ + } +} + bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) @@ -765,6 +808,8 @@ found: } pipe_config->pipe_bpp = bpp; + intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); + return true; } -- cgit v1.2.3 From d8b322474941fa565ba5c58292ccc54be92cca41 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 17:54:44 +0200 Subject: drm/i915: use pipe_config for lvds dithering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now we've relied on the bios to get this right for us. Let's try out whether our code has improved a bit, since we should dither always when the output bpp doesn't match the plane bpp. - gen5+ should be fine, since we only use the bios hint as an upgrade. - gen4 changes, since here dithering is still controlled in the lvds register. - gen2/3 has implicit dithering depeding upon whether you use 2 or 3 lvds pairs (which makes sense, since it only supports 8bpc pipe outpu configurations). - hsw doesn't support lvds. v2: Remove redudant dither setting. v3: Completly drop reliance on dev_priv->lvds_dither. v4: Enable dithering on gen2/3 only when we have a 18bpp panel, since up-dithering to a 24bpp panel is not supported by the hw. Spotted by Ville. v5: Also only enable lvds port dithering on gen4 for 18bpp modes. In practice this only excludes dithering a 10bpc plane down for a 24bpp lvds panel. Not something we truly care about. Again noticed by Ville. v6: Actually git add. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 +++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_lvds.c | 15 ++++++++++----- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 26acc421f0c6..38465f0e9710 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5146,8 +5146,7 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) } static void ironlake_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, - bool dither) + struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5176,7 +5175,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, } val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); - if (dither) + if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK; @@ -5259,8 +5258,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc) } static void haswell_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, - bool dither) + struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5270,7 +5268,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, val = I915_READ(PIPECONF(cpu_transcoder)); val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); - if (dither) + if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK_HSW; @@ -5631,7 +5629,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool is_lvds = false; struct intel_encoder *encoder; int ret; - bool dither, fdi_config_ok; + bool fdi_config_ok; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -5666,11 +5664,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - /* determine panel color depth */ - dither = intel_crtc->config.dither; - if (is_lvds && dev_priv->lvds_dither) - dither = true; - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); @@ -5737,7 +5730,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); - ironlake_set_pipeconf(crtc, adjusted_mode, dither); + ironlake_set_pipeconf(crtc, adjusted_mode); /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); @@ -5814,7 +5807,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, bool is_cpu_edp = false; struct intel_encoder *encoder; int ret; - bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -5850,9 +5842,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - /* determine panel color depth */ - dither = intel_crtc->config.dither; - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); drm_mode_debug_printmodeline(mode); @@ -5866,7 +5855,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) ironlake_fdi_set_m_n(crtc); - haswell_set_pipeconf(crtc, adjusted_mode, dither); + haswell_set_pipeconf(crtc, adjusted_mode); intel_set_pipe_csc(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3595c8204649..a5fe976364e1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -213,6 +213,11 @@ struct intel_crtc_config { /* DP has a bunch of special case unfortunately, so mark the pipe * accordingly. */ bool has_dp_encoder; + + /* + * Enable dithering, used when the selected pipe bpp doesn't match the + * plane bpp. + */ bool dither; /* Controls for the clock computation, to override various stages. */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 563f5052fcfc..84085454b104 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -136,7 +136,10 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) * special lvds dither control bit on pch-split platforms, dithering is * only controlled through the PIPECONF reg. */ if (INTEL_INFO(dev)->gen == 4) { - if (dev_priv->lvds_dither) + /* Bspec wording suggests that LVDS port dithering only exists + * for 18bpp panels. */ + if (intel_crtc->config.dither && + intel_crtc->config.pipe_bpp == 18) temp |= LVDS_ENABLE_DITHER; else temp &= ~LVDS_ENABLE_DITHER; @@ -335,7 +338,13 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && lvds_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + } + /* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, @@ -470,10 +479,6 @@ out: pfit_pgm_ratios = 0; } - /* Make sure pre-965 set dither correctly */ - if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != lvds_encoder->pfit_control || pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { lvds_encoder->pfit_control = pfit_control; -- cgit v1.2.3 From 4f4134ace04fd5b0e8734b65f4046e7aa2e39393 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:14:35 +0200 Subject: drm/i915: don't force matching p1 for g4x/ilk+ reduced pll settings g4x dplls and ilk+ pch plls have a separate field for the reduced p1 setting, so this restriction does not apply. Only older platforms have the restriction that the p1 divisors must match. This unnecessary restriction has been introduced in commit cec2f356d59d9e070413e5966a3c5a1af136d948 Author: Sean Paul Date: Tue Jan 10 15:09:36 2012 -0800 drm/i915: Only look for matching clocks for LVDS downcloc Note that with lvds the p2 divisors _always_ match for LVDS, and we don't support auto-downclocking anywhere else. On eDP downclocking works with separate data m/n settings, using the same link clock. Cc: Sean Paul Reviewed-by: Sean Paul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 38465f0e9710..fa9af52ba5a4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -685,9 +685,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, if (!intel_PLL_is_valid(dev, limit, &clock)) continue; - if (match_clock && - clock.p != match_clock->p) - continue; this_err = abs(clock.dot - target); if (this_err < err_most) { -- cgit v1.2.3 From 9566e9af524856a27f3c6b00821e74ff9ae04732 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:14:36 +0200 Subject: drm/i915: remove redundant has_pch_encoder check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we compute the pch pll state, we _have_ a pch encoder. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fa9af52ba5a4..a9013fda1c3a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5569,8 +5569,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, } dpll |= DPLL_DVO_HIGH_SPEED; } - if (intel_crtc->config.has_dp_encoder && - intel_crtc->config.has_pch_encoder) + if (intel_crtc->config.has_dp_encoder) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ -- cgit v1.2.3 From 198a037f02666eeaab5ba07974fa37467b1f6bd8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:14:37 +0200 Subject: drm/i915: simplify config->pixel_multiplier handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only ever check whether it's strictly bigger than one, so all the is_sdvo/is_hdmi checks are redundant. Flatten the code a bit. Also, s/temp/dpll_md/ Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 58 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a9013fda1c3a..2e83dbe5ecc0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4235,7 +4235,7 @@ static void vlv_update_pll(struct intel_crtc *crtc) u32 dpll, mdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; bool is_hdmi; - u32 coreclk, reg_val, temp; + u32 coreclk, reg_val, dpll_md; mutex_lock(&dev_priv->dpio_lock); @@ -4333,16 +4333,13 @@ static void vlv_update_pll(struct intel_crtc *crtc) if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("DPLL %d failed to lock\n", pipe); - if (is_hdmi) { - temp = 0; - if (crtc->config.pixel_multiplier > 1) { - temp = (crtc->config.pixel_multiplier - 1) - << DPLL_MD_UDI_MULTIPLIER_SHIFT; - } - - I915_WRITE(DPLL_MD(pipe), temp); - POSTING_READ(DPLL_MD(pipe)); + dpll_md = 0; + if (crtc->config.pixel_multiplier > 1) { + dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; } + I915_WRITE(DPLL_MD(pipe), dpll_md); + POSTING_READ(DPLL_MD(pipe)); if (crtc->config.has_dp_encoder) intel_dp_set_m_n(crtc); @@ -4374,14 +4371,15 @@ static void i9xx_update_pll(struct intel_crtc *crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; - if (is_sdvo) { - if ((crtc->config.pixel_multiplier > 1) && - (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) { - dpll |= (crtc->config.pixel_multiplier - 1) - << SDVO_MULTIPLIER_SHIFT_HIRES; - } - dpll |= DPLL_DVO_HIGH_SPEED; + if ((crtc->config.pixel_multiplier > 1) && + (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) { + dpll |= (crtc->config.pixel_multiplier - 1) + << SDVO_MULTIPLIER_SHIFT_HIRES; } + + if (is_sdvo) + dpll |= DPLL_DVO_HIGH_SPEED; + if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) dpll |= DPLL_DVO_HIGH_SPEED; @@ -4441,15 +4439,12 @@ static void i9xx_update_pll(struct intel_crtc *crtc, udelay(150); if (INTEL_INFO(dev)->gen >= 4) { - u32 temp = 0; - if (is_sdvo) { - temp = 0; - if (crtc->config.pixel_multiplier > 1) { - temp = (crtc->config.pixel_multiplier - 1) - << DPLL_MD_UDI_MULTIPLIER_SHIFT; - } + u32 dpll_md = 0; + if (crtc->config.pixel_multiplier > 1) { + dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; } - I915_WRITE(DPLL_MD(pipe), temp); + I915_WRITE(DPLL_MD(pipe), dpll_md); } else { /* The pixel multiplier can only be updated once the * DPLL is enabled and the clocks are stable. @@ -5562,13 +5557,14 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, dpll |= DPLLB_MODE_LVDS; else dpll |= DPLLB_MODE_DAC_SERIAL; - if (is_sdvo) { - if (intel_crtc->config.pixel_multiplier > 1) { - dpll |= (intel_crtc->config.pixel_multiplier - 1) - << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; - } - dpll |= DPLL_DVO_HIGH_SPEED; + + if (intel_crtc->config.pixel_multiplier > 1) { + dpll |= (intel_crtc->config.pixel_multiplier - 1) + << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } + + if (is_sdvo) + dpll |= DPLL_DVO_HIGH_SPEED; if (intel_crtc->config.has_dp_encoder) dpll |= DPLL_DVO_HIGH_SPEED; -- cgit v1.2.3 From 2dd24552cab40ea829ba3fda890eeafd2c4816d8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:01 -0700 Subject: drm/i915: factor out GMCH panel fitting code and use for eDP v3 This gets the panel fitter working on eDP on VLV, and should also apply to eDP panels on G4x chipsets (if we ever detect and mark an all-in-one panel as eDP anyway). A few cleanups are still possible on top of this, for example the LVDS border control could be placed in the LVDS encoder structure and updated based on the result of the panel fitter calculation. Multi-pipe fitting isn't handled correctly either if we ever get a config that wants to try the panel fitter on more than one output at a time. v2: use pipe_config for storing pfit values (Daniel) add i9xx_pfit_enable function for use by 9xx and VLV (Daniel) v3: fixup conflicts and lvds_dither check Reviewed-by: Mika Kuoppala Signed-off-by: Jesse Barnes [danvet: fix up botched conflict resolution from Jesse: - border = LVDS_BORDER_ENABLE was lost for CENTER scaling - comment about gen2/3 panel fitter scaling was lost - dev_priv->lvds_dither reintroduced.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 33 ++++++ drivers/gpu/drm/i915/intel_dp.c | 11 +- drivers/gpu/drm/i915/intel_drv.h | 6 + drivers/gpu/drm/i915/intel_lvds.c | 209 +---------------------------------- drivers/gpu/drm/i915/intel_panel.c | 191 ++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 209 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e83dbe5ecc0..fc6f76837437 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3601,6 +3601,33 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe) } } +static void i9xx_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc_config *pipe_config = &crtc->config; + + if (!(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))) + return; + + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, crtc->pipe); + + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + pipe_config->pfit_control, + pipe_config->pfit_pgm_ratios); + + I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control); +} + static void valleyview_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3634,6 +3661,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); + /* Enable panel fitting for eDP */ + i9xx_pfit_enable(intel_crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); @@ -3670,6 +3700,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_enable) encoder->pre_enable(encoder); + /* Enable panel fitting for LVDS */ + i9xx_pfit_enable(intel_crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); if (IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f63973ad33cb..9c834bc15ab7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -712,6 +712,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct intel_crtc *intel_crtc = encoder->new_crtc; struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd); @@ -728,9 +729,13 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { intel_fixed_panel_mode(intel_connector->panel.fixed_mode, adjusted_mode); - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + if (!HAS_PCH_SPLIT(dev)) + intel_gmch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); + else + intel_pch_panel_fitting(dev, + intel_connector->panel.fitting_mode, + mode, adjusted_mode); } /* We need to take the panel's fixed mode into account. */ target_clock = adjusted_mode->clock; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a5fe976364e1..9f3f71bc2f22 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -237,6 +237,9 @@ struct intel_crtc_config { int pixel_target_clock; /* Used by SDVO (and if we ever fix it, HDMI). */ unsigned pixel_multiplier; + + /* Panel fitter controls for gen2-gen4 + VLV */ + u32 pfit_control, pfit_pgm_ratios; }; struct intel_crtc { @@ -558,6 +561,9 @@ extern void intel_pch_panel_fitting(struct drm_device *dev, int fitting_mode, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern void intel_gmch_panel_fitting(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode); extern void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max); extern int intel_panel_setup_backlight(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 84085454b104..7d418818c7a8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -49,8 +49,6 @@ struct intel_lvds_connector { struct intel_lvds_encoder { struct intel_encoder base; - u32 pfit_control; - u32 pfit_pgm_ratios; bool is_dual_link; u32 reg; @@ -153,32 +151,6 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) I915_WRITE(lvds_encoder->reg, temp); } -static void intel_pre_enable_lvds(struct intel_encoder *encoder) -{ - struct drm_device *dev = encoder->base.dev; - struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); - struct drm_i915_private *dev_priv = dev->dev_private; - - if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) - return; - - WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); - assert_pipe_disabled(dev_priv, to_intel_crtc(encoder->base.crtc)->pipe); - - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - enc->pfit_control, - enc->pfit_pgm_ratios); - - I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, enc->pfit_control); -} - /** * Sets the power state for the panel. */ @@ -247,62 +219,6 @@ static int intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static void -centre_horizontally(struct drm_display_mode *mode, - int width) -{ - u32 border, sync_pos, blank_width, sync_width; - - /* keep the hsync and hblank widths constant */ - sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; - blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; - sync_pos = (blank_width - sync_width + 1) / 2; - - border = (mode->hdisplay - width + 1) / 2; - border += border & 1; /* make the border even */ - - mode->crtc_hdisplay = width; - mode->crtc_hblank_start = width + border; - mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; - - mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; - mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; -} - -static void -centre_vertically(struct drm_display_mode *mode, - int height) -{ - u32 border, sync_pos, blank_width, sync_width; - - /* keep the vsync and vblank widths constant */ - sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; - blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; - sync_pos = (blank_width - sync_width + 1) / 2; - - border = (mode->vdisplay - height + 1) / 2; - - mode->crtc_vdisplay = height; - mode->crtc_vblank_start = height + border; - mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; - - mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; - mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; -} - -static inline u32 panel_fitter_scaling(u32 source, u32 target) -{ - /* - * Floating point operation is not supported. So the FACTOR - * is defined, which can avoid the floating point computation - * when calculating the panel ratio. - */ -#define ACCURACY 12 -#define FACTOR (1 << ACCURACY) - u32 ratio = source * FACTOR / target; - return (FACTOR * ratio + FACTOR/2) / FACTOR; -} - static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct intel_crtc_config *pipe_config) { @@ -315,7 +231,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; - u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; unsigned int lvds_bpp; int pipe; @@ -338,11 +253,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; - - /* Make sure pre-965 set dither correctly for 18bpp panels. */ - if (INTEL_INFO(dev)->gen < 4 && lvds_bpp == 18) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - } /* @@ -361,18 +271,11 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, intel_connector->panel.fitting_mode, mode, adjusted_mode); return true; + } else { + intel_gmch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); } - /* Native modes don't need fitting */ - if (adjusted_mode->hdisplay == mode->hdisplay && - adjusted_mode->vdisplay == mode->vdisplay) - goto out; - - /* 965+ wants fuzzy fitting */ - if (INTEL_INFO(dev)->gen >= 4) - pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | - PFIT_FILTER_FUZZY); - /* * Enable automatic panel scaling for non-native modes so that they fill * the screen. Should be enabled before the pipe is enabled, according @@ -385,107 +288,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, drm_mode_set_crtcinfo(adjusted_mode, 0); pipe_config->timings_set = true; - switch (intel_connector->panel.fitting_mode) { - case DRM_MODE_SCALE_CENTER: - /* - * For centered modes, we have to calculate border widths & - * heights and modify the values programmed into the CRTC. - */ - centre_horizontally(adjusted_mode, mode->hdisplay); - centre_vertically(adjusted_mode, mode->vdisplay); - border = LVDS_BORDER_ENABLE; - break; - - case DRM_MODE_SCALE_ASPECT: - /* Scale but preserve the aspect ratio */ - if (INTEL_INFO(dev)->gen >= 4) { - u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; - u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; - - /* 965+ is easy, it does everything in hw */ - if (scaled_width > scaled_height) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR; - else if (scaled_width < scaled_height) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER; - else if (adjusted_mode->hdisplay != mode->hdisplay) - pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; - } else { - u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; - u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; - /* - * For earlier chips we have to calculate the scaling - * ratio by hand and program it into the - * PFIT_PGM_RATIO register - */ - if (scaled_width > scaled_height) { /* pillar */ - centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay); - - border = LVDS_BORDER_ENABLE; - if (mode->vdisplay != adjusted_mode->vdisplay) { - u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); - pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | - bits << PFIT_VERT_SCALE_SHIFT); - pfit_control |= (PFIT_ENABLE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - } else if (scaled_width < scaled_height) { /* letter */ - centre_vertically(adjusted_mode, scaled_width / mode->hdisplay); - - border = LVDS_BORDER_ENABLE; - if (mode->hdisplay != adjusted_mode->hdisplay) { - u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); - pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | - bits << PFIT_VERT_SCALE_SHIFT); - pfit_control |= (PFIT_ENABLE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - } else - /* Aspects match, Let hw scale both directions */ - pfit_control |= (PFIT_ENABLE | - VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - } - break; - - case DRM_MODE_SCALE_FULLSCREEN: - /* - * Full scaling, even if it changes the aspect ratio. - * Fortunately this is all done for us in hw. - */ - if (mode->vdisplay != adjusted_mode->vdisplay || - mode->hdisplay != adjusted_mode->hdisplay) { - pfit_control |= PFIT_ENABLE; - if (INTEL_INFO(dev)->gen >= 4) - pfit_control |= PFIT_SCALING_AUTO; - else - pfit_control |= (VERT_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_AUTO_SCALE | - HORIZ_INTERP_BILINEAR); - } - break; - - default: - break; - } - -out: - /* If not enabling scaling, be consistent and always use 0. */ - if ((pfit_control & PFIT_ENABLE) == 0) { - pfit_control = 0; - pfit_pgm_ratios = 0; - } - - if (pfit_control != lvds_encoder->pfit_control || - pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { - lvds_encoder->pfit_control = pfit_control; - lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; - } - dev_priv->lvds_border_bits = border; - /* * XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the @@ -1115,10 +917,6 @@ bool intel_lvds_init(struct drm_device *dev) lvds_encoder->attached_connector = lvds_connector; - if (!HAS_PCH_SPLIT(dev)) { - lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL); - } - intel_encoder = &lvds_encoder->base; encoder = &intel_encoder->base; intel_connector = &lvds_connector->base; @@ -1130,7 +928,6 @@ bool intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; - intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; intel_encoder->compute_config = intel_lvds_compute_config; intel_encoder->disable = intel_disable_lvds; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7f6141d9a06d..0f32f6498ad3 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -117,6 +117,197 @@ done: dev_priv->pch_pf_size = (width << 16) | height; } +static void +centre_horizontally(struct drm_display_mode *mode, + int width) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the hsync and hblank widths constant */ + sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; + blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->hdisplay - width + 1) / 2; + border += border & 1; /* make the border even */ + + mode->crtc_hdisplay = width; + mode->crtc_hblank_start = width + border; + mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; + + mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; + mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; +} + +static void +centre_vertically(struct drm_display_mode *mode, + int height) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the vsync and vblank widths constant */ + sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; + blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->vdisplay - height + 1) / 2; + + mode->crtc_vdisplay = height; + mode->crtc_vblank_start = height + border; + mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; + + mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; + mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; +} + +static inline u32 panel_fitter_scaling(u32 source, u32 target) +{ + /* + * Floating point operation is not supported. So the FACTOR + * is defined, which can avoid the floating point computation + * when calculating the panel ratio. + */ +#define ACCURACY 12 +#define FACTOR (1 << ACCURACY) + u32 ratio = source * FACTOR / target; + return (FACTOR * ratio + FACTOR/2) / FACTOR; +} + +void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; + struct drm_display_mode *mode, *adjusted_mode; + + mode = &pipe_config->requested_mode; + adjusted_mode = &pipe_config->adjusted_mode; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == mode->hdisplay && + adjusted_mode->vdisplay == mode->vdisplay) + goto out; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + /* + * For centered modes, we have to calculate border widths & + * heights and modify the values programmed into the CRTC. + */ + centre_horizontally(adjusted_mode, mode->hdisplay); + centre_vertically(adjusted_mode, mode->vdisplay); + border = LVDS_BORDER_ENABLE; + break; + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + if (INTEL_INFO(dev)->gen >= 4) { + u32 scaled_width = adjusted_mode->hdisplay * + mode->vdisplay; + u32 scaled_height = mode->hdisplay * + adjusted_mode->vdisplay; + + /* 965+ is easy, it does everything in hw */ + if (scaled_width > scaled_height) + pfit_control |= PFIT_ENABLE | + PFIT_SCALING_PILLAR; + else if (scaled_width < scaled_height) + pfit_control |= PFIT_ENABLE | + PFIT_SCALING_LETTER; + else if (adjusted_mode->hdisplay != mode->hdisplay) + pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; + } else { + u32 scaled_width = adjusted_mode->hdisplay * + mode->vdisplay; + u32 scaled_height = mode->hdisplay * + adjusted_mode->vdisplay; + /* + * For earlier chips we have to calculate the scaling + * ratio by hand and program it into the + * PFIT_PGM_RATIO register + */ + if (scaled_width > scaled_height) { /* pillar */ + centre_horizontally(adjusted_mode, + scaled_height / + mode->vdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->vdisplay != adjusted_mode->vdisplay) { + u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else if (scaled_width < scaled_height) { /* letter */ + centre_vertically(adjusted_mode, + scaled_width / + mode->hdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->hdisplay != adjusted_mode->hdisplay) { + u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else { + /* Aspects match, Let hw scale both directions */ + pfit_control |= (PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } + break; + default: + case DRM_MODE_SCALE_FULLSCREEN: + /* + * Full scaling, even if it changes the aspect ratio. + * Fortunately this is all done for us in hw. + */ + if (mode->vdisplay != adjusted_mode->vdisplay || + mode->hdisplay != adjusted_mode->hdisplay) { + pfit_control |= PFIT_ENABLE; + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= PFIT_SCALING_AUTO; + else + pfit_control |= (VERT_AUTO_SCALE | + VERT_INTERP_BILINEAR | + HORIZ_AUTO_SCALE | + HORIZ_INTERP_BILINEAR); + } + break; + } + + /* 965+ wants fuzzy fitting */ + /* FIXME: handle multiple panels by failing gracefully */ + if (INTEL_INFO(dev)->gen >= 4) + pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | + PFIT_FILTER_FUZZY); + +out: + if ((pfit_control & PFIT_ENABLE) == 0) { + pfit_control = 0; + pfit_pgm_ratios = 0; + } + + /* Make sure pre-965 set dither correctly for 18bpp panels. */ + if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + + if (pfit_control != pipe_config->pfit_control || + pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) { + pipe_config->pfit_control = pfit_control; + pipe_config->pfit_pgm_ratios = pfit_pgm_ratios; + } + dev_priv->lvds_border_bits = border; +} + static int is_backlight_combination_mode(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.2.3 From b074cec8c652f2d273907a4b35239b4766c894ac Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:02 -0700 Subject: drm/i915: move PCH pfit controls into pipe_config And put the pfit stuff into substructs while we're at it. Signed-off-by: Jesse Barnes Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 65 +++++++++++++++++------------------- drivers/gpu/drm/i915/intel_dp.c | 6 ++-- drivers/gpu/drm/i915/intel_drv.h | 18 +++++++--- drivers/gpu/drm/i915/intel_lvds.c | 6 ++-- drivers/gpu/drm/i915/intel_panel.c | 25 ++++++++------ 7 files changed, 63 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8a257a9114c2..14156f2b8d76 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1021,8 +1021,6 @@ typedef struct drm_i915_private { struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ unsigned int lvds_border_bits; - /* Panel fitter placement and size for Ironlake+ */ - u32 pch_pf_pos, pch_pf_size; struct drm_crtc *plane_to_crtc_mapping[3]; struct drm_crtc *pipe_to_crtc_mapping[3]; diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index eef450b1af44..0d7cf317b73f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -995,7 +995,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) /* Can only use the always-on power well for eDP when * not using the panel fitter, and when not using motion * blur mitigation (which we don't support). */ - if (dev_priv->pch_pf_size) + if (intel_crtc->config.pch_pfit.size) temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; else temp |= TRANS_DDI_EDP_INPUT_A_ON; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fc6f76837437..dacfc6c90550 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3225,6 +3225,28 @@ void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) } } +static void ironlake_pfit_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + if (crtc->config.pch_pfit.size && + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | + PF_PIPE_SEL_IVB(pipe)); + else + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos); + I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size); + } +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3269,21 +3291,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) encoder->pre_enable(encoder); /* Enable panel fitting for LVDS */ - if (dev_priv->pch_pf_size && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - if (IS_IVYBRIDGE(dev)) - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | - PF_PIPE_SEL_IVB(pipe)); - else - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); - I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); - I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); - } + ironlake_pfit_enable(intel_crtc); /* * On ILK+ LUT must be loaded before the pipe is running but with @@ -3353,17 +3361,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_clock(intel_crtc); /* Enable panel fitting for eDP */ - if (dev_priv->pch_pf_size && - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 | - PF_PIPE_SEL_IVB(pipe)); - I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); - I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); - } + ironlake_pfit_enable(intel_crtc); /* * On ILK+ LUT must be loaded before the pipe is running but with @@ -3621,11 +3619,11 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) * register description and PRM. */ DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - pipe_config->pfit_control, - pipe_config->pfit_pgm_ratios); + pipe_config->gmch_pfit.control, + pipe_config->gmch_pfit.pgm_ratios); - I915_WRITE(PFIT_PGM_RATIOS, pipe_config->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, pipe_config->pfit_control); + I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); + I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -5800,6 +5798,9 @@ static void haswell_modeset_global_resources(struct drm_device *dev) /* XXX: Should check for edp transcoder here, but thanks to init * sequence that's not yet available. Just in case desktop eDP * on PORT D is possible on haswell, too. */ + /* Even the eDP panel fitter is outside the always-on well. */ + if (I915_READ(PF_WIN_SZ(crtc->pipe))) + enable = true; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, @@ -5809,10 +5810,6 @@ static void haswell_modeset_global_resources(struct drm_device *dev) enable = true; } - /* Even the eDP panel fitter is outside the always-on well. */ - if (dev_priv->pch_pf_size) - enable = true; - intel_set_power_well(dev, enable); } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9c834bc15ab7..9ac034ee0ddd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -710,7 +710,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_crtc *intel_crtc = encoder->new_crtc; struct intel_connector *intel_connector = intel_dp->attached_connector; @@ -733,9 +732,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_gmch_panel_fitting(intel_crtc, pipe_config, intel_connector->panel.fitting_mode); else - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + intel_pch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); } /* We need to take the panel's fixed mode into account. */ target_clock = adjusted_mode->clock; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9f3f71bc2f22..a8c696014967 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -239,7 +239,16 @@ struct intel_crtc_config { unsigned pixel_multiplier; /* Panel fitter controls for gen2-gen4 + VLV */ - u32 pfit_control, pfit_pgm_ratios; + struct { + u32 control; + u32 pgm_ratios; + } gmch_pfit; + + /* Panel fitter placement and size for Ironlake+ */ + struct { + u32 pos; + u32 size; + } pch_pfit; }; struct intel_crtc { @@ -557,10 +566,9 @@ extern void intel_panel_fini(struct intel_panel *panel); extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode); -extern void intel_pch_panel_fitting(struct drm_device *dev, - int fitting_mode, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); +extern void intel_pch_panel_fitting(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode); extern void intel_gmch_panel_fitting(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config, int fitting_mode); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 7d418818c7a8..3e29499b2e9a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -229,7 +229,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct intel_connector *intel_connector = &lvds_encoder->attached_connector->base; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - struct drm_display_mode *mode = &pipe_config->requested_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; unsigned int lvds_bpp; int pipe; @@ -267,9 +266,8 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, if (HAS_PCH_SPLIT(dev)) { pipe_config->has_pch_encoder = true; - intel_pch_panel_fitting(dev, - intel_connector->panel.fitting_mode, - mode, adjusted_mode); + intel_pch_panel_fitting(intel_crtc, pipe_config, + intel_connector->panel.fitting_mode); return true; } else { intel_gmch_panel_fitting(intel_crtc, pipe_config, diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 0f32f6498ad3..00f31f7336f2 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -54,14 +54,17 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, /* adjusted_mode has been preset to be the panel's fixed mode */ void -intel_pch_panel_fitting(struct drm_device *dev, - int fitting_mode, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +intel_pch_panel_fitting(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config, + int fitting_mode) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct drm_display_mode *mode, *adjusted_mode; int x, y, width, height; + mode = &pipe_config->requested_mode; + adjusted_mode = &pipe_config->adjusted_mode; + x = y = width = height = 0; /* Native modes don't need fitting */ @@ -113,8 +116,8 @@ intel_pch_panel_fitting(struct drm_device *dev, } done: - dev_priv->pch_pf_pos = (x << 16) | y; - dev_priv->pch_pf_size = (width << 16) | height; + pipe_config->pch_pfit.pos = (x << 16) | y; + pipe_config->pch_pfit.size = (width << 16) | height; } static void @@ -300,10 +303,10 @@ out: if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != pipe_config->pfit_control || - pfit_pgm_ratios != pipe_config->pfit_pgm_ratios) { - pipe_config->pfit_control = pfit_control; - pipe_config->pfit_pgm_ratios = pfit_pgm_ratios; + if (pfit_control != pipe_config->gmch_pfit.control || + pfit_pgm_ratios != pipe_config->gmch_pfit.pgm_ratios) { + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; } dev_priv->lvds_border_bits = border; } -- cgit v1.2.3 From ab3e67f43a299b064ccd8cd230d4a006a05c8a4c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 25 Apr 2013 12:55:03 -0700 Subject: drm/i915: warn about invalid pfit modes We prevent invalid ones from getting here in the first place, but it doesn't hurt to have an extra sanity check. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 00f31f7336f2..2526326efd81 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -58,7 +58,6 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, struct intel_crtc_config *pipe_config, int fitting_mode) { - struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; struct drm_display_mode *mode, *adjusted_mode; int x, y, width, height; @@ -107,12 +106,15 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc, } break; - default: case DRM_MODE_SCALE_FULLSCREEN: x = y = 0; width = adjusted_mode->hdisplay; height = adjusted_mode->vdisplay; break; + + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; } done: @@ -267,7 +269,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, } } break; - default: case DRM_MODE_SCALE_FULLSCREEN: /* * Full scaling, even if it changes the aspect ratio. @@ -285,6 +286,9 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, HORIZ_INTERP_BILINEAR); } break; + default: + WARN(1, "bad panel fit mode: %d\n", fitting_mode); + return; } /* 965+ wants fuzzy fitting */ -- cgit v1.2.3 From 2ce12e3dffe005f96e3b3ff1f761bbb0bf570fda Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 1 Mar 2013 14:08:33 -0800 Subject: drm/i915: remove VLV MSI IRQ hack Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 125b45a6780d..b0dbf4cd0e07 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2657,7 +2657,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) u32 enable_mask; u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; u32 render_irqs; - u16 msid; enable_mask = I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | @@ -2673,13 +2672,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT; - /* Hack for broken MSIs on VLV */ - pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000); - pci_read_config_word(dev->pdev, 0x98, &msid); - msid &= 0xff; /* mask out delivery bits */ - msid |= (1<<14); - pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); - I915_WRITE(PORT_HOTPLUG_EN, 0); POSTING_READ(PORT_HOTPLUG_EN); -- cgit v1.2.3 From d8241785c24d4508ecc26fb91b28b39a0dd26070 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 27 Apr 2013 12:44:16 +0100 Subject: drm/i915: Only print the info message about incresing stolen size for FBC once Instead of repeatedly bombarding the user with a request to reboot and increase the stolen size with every fb refresh, just inform them the first time only. v2: Rearrange code so the hint to increase the amount of memory stolen by the BIOS is only emitted if we fail to find sufficient stolen memory for FBC. Signed-off-by: Chris Wilson [danvet: Fixup formatting code mismatch that gcc spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 1 + drivers/gpu/drm/i915/intel_pm.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 130d1db27e28..67d3510cafed 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -136,6 +136,7 @@ static int i915_setup_compression(struct drm_device *dev, int size) err_fb: drm_mm_put_block(compressed_fb); err: + pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); return -ENOSPC; } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bb45122173dd..0f4b46e94932 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -481,8 +481,6 @@ void intel_update_fbc(struct drm_device *dev) goto out_disable; if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) { - DRM_INFO("not enough stolen space for compressed buffer (need %zd bytes), disabling\n", intel_fb->obj->base.size); - DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; goto out_disable; -- cgit v1.2.3 From 60c4ae101fdebdd1451e93f08161af3d78725cff Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 29 Apr 2013 18:29:19 +0200 Subject: drm/i915: put the right cpu_transcoder into pipe_config for hw state readout This hack is getting a bit messy, but this plugs the leak for now until we have the cpu_transcoder properly pipe_config'ed. Cc: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dacfc6c90550..90bed0ab0fe2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7981,6 +7981,7 @@ intel_modeset_check_state(struct drm_device *dev) "(expected %i, found %i)\n", enabled, crtc->base.enabled); memset(&pipe_config, 0, sizeof(pipe_config)); + pipe_config.cpu_transcoder = crtc->config.cpu_transcoder; active = dev_priv->display.get_pipe_config(crtc, &pipe_config); WARN(crtc->active != active, -- cgit v1.2.3 From af13188a1a6623fc8b4b6c42178046fb80f8b1d0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 19 Feb 2013 17:45:00 +0100 Subject: drm/i915: force bpp for eDP panels We've had our fair share of woes already which showed that we can't rely on the bpc limits in the EDID for eDP panels without risking black screens. So now we limit the depth by what the BIOS recommends in the VBT: commit 2f4f649a69a9eb51f6e98130e19dd90a260a4145 Author: Jani Nikula Date: Mon Nov 12 14:33:44 2012 +0200 drm/i915: do not ignore eDP bpc settings from vbt But that's not enough, since at least the panel on my ASUS Zenbook Prime here is also unhappy if the bpc is too low. Hence just take the firmware value and dither to get what flimsy panels want. Like before we ensure that we don't change the bpp if the firmware doesn't provide a value, see commit 9a30a61f3516871c5c638fd7c025fbaa11ddf7fe Author: Jani Nikula Date: Mon Nov 12 14:33:45 2012 +0200 drm/i915: do not default to 18 bpp for eDP if missing from VBT v2: Apparently there are some horribly broken eDP panels around which only work if the DP link is set up as if we want to driver a 24bpp mode, but still only work if the data is feed at 18bpp. See commit 57c219633275c7e7413f8bc7be250dc092887458 Author: Daniel Vetter Date: Thu Apr 4 17:19:37 2013 +0200 drm/i915: revert eDP bpp clamping code changes for the gory details. Adjust the patch accordingly and update all the relevant comments. v3: Give up on the cargo-culting v2 attempt and just enfore the edp bpp value if it's there. Broken panels be damned! Cc: Jani Nikula Cc: Paulo Zanoni Reviewed-by: Jani Nikula Tested-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9ac034ee0ddd..82cd9ac16c4a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -748,6 +748,18 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ bpp = min_t(int, 8*3, pipe_config->pipe_bpp); + + /* + * eDP panels are really fickle, try to enfore the bpp the firmware + * recomments. This means we'll up-dither 16bpp framebuffers on + * high-depth panels. + */ + if (is_edp(intel_dp) && dev_priv->edp.bpp) { + DRM_DEBUG_KMS("forcing bpp for eDP panel to BIOS-provided %i\n", + dev_priv->edp.bpp); + bpp = dev_priv->edp.bpp; + } + for (; bpp >= 6*3; bpp -= 2*3) { mode_rate = intel_dp_link_required(target_clock, bpp); @@ -797,18 +809,6 @@ found: target_clock, adjusted_mode->clock, &pipe_config->dp_m_n); - /* - * XXX: We have a strange regression where using the vbt edp bpp value - * for the link bw computation results in black screens, the panel only - * works when we do the computation at the usual 24bpp (but still - * requires us to use 18bpp). Until that's fully debugged, stay - * bug-for-bug compatible with the old code. - */ - if (is_edp(intel_dp) && dev_priv->edp.bpp) { - DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", - bpp, dev_priv->edp.bpp); - bpp = min_t(int, bpp, dev_priv->edp.bpp); - } pipe_config->pipe_bpp = bpp; intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); -- cgit v1.2.3 From 6ff93609b1cf77121ec61e8fe197d683b1702cd9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:36 +0200 Subject: drm/i915: drop adjusted_mode from *_set_pipeconf functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They can get at the adjusted mode through intel_crtc->config. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 90bed0ab0fe2..adc56bd4828e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5168,8 +5168,7 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) return 120000; } -static void ironlake_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode) +static void ironlake_set_pipeconf(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5202,7 +5201,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK; - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) val |= PIPECONF_INTERLACED_ILK; else val |= PIPECONF_PROGRESSIVE; @@ -5280,8 +5279,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc) } } -static void haswell_set_pipeconf(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode) +static void haswell_set_pipeconf(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -5295,7 +5293,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); val &= ~PIPECONF_INTERLACE_MASK_HSW; - if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) val |= PIPECONF_INTERLACED_ILK; else val |= PIPECONF_PROGRESSIVE; @@ -5753,7 +5751,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); - ironlake_set_pipeconf(crtc, adjusted_mode); + ironlake_set_pipeconf(crtc); /* Set up the display plane register */ I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); @@ -5877,7 +5875,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) ironlake_fdi_set_m_n(crtc); - haswell_set_pipeconf(crtc, adjusted_mode); + haswell_set_pipeconf(crtc); intel_set_pipe_csc(crtc); -- cgit v1.2.3 From ff9ce46ed6878d6be08660f7d75897d500a4fe9e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 24 Apr 2013 14:57:17 +0200 Subject: drm/i915: implement high-bpc + pipeconf-dither support for g4x/vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code is rather ... ugly. The only thing it managed to pull off is getting 6bpc on DP working on g4x. Then someone added another custom hack for 6bpc eDP on vlv. Fix up this entire mess by properly implementing the PIPECONF-based dither/bpc controls on g4x/vlv. Note that compared to pch based platforms g4x/vlv don't support 12bpc modes. g4x is already caught, extend the check for vlv. The other fixup is to restrict the lvds-specific dithering to early gen4 devices - g4x should use the pipeconf dither controls. Note that on gen2/3 the dither control is in the panel fitter even. v2: Don't enable dithering when the pipe is in 10 bpc mode. Quoting from Bspec "PIPEACONF - Pipe A Configuration Register, bit 4": "Programming note: Dithering should only be enabled for 8 bpc or 6 bpc." v3: Actually drop the old ugly dither code. v4: Explain in a short comment why g4x/vlv shouldn't dither for 30 bpp pipes (Jesse). v5: Also clear the dither type correctly as spotted by Ville. v6: As Ville pointed out we need to indeed set the dithering both in the pipeconf register (for DP outputs) and in the LVDS port register (for LVDS ouputs). Otherwise LVDS panel will not get properly dithered. The old patch got away with this since it forgot to clear the LVDS dither bit ... v7: Remove redundant BPC_MASK clearing, spotted by Ville. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index adc56bd4828e..983822e10533 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4622,22 +4622,29 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) pipeconf &= ~PIPECONF_DOUBLE_WIDE; } - /* default to 8bpc */ - pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); - if (intel_crtc->config.has_dp_encoder) { - if (intel_crtc->config.dither) { - pipeconf |= PIPECONF_6BPC | - PIPECONF_DITHER_EN | + /* only g4x and later have fancy bpc/dither controls */ + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + pipeconf &= ~(PIPECONF_BPC_MASK | + PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); + + /* Bspec claims that we can't use dithering for 30bpp pipes. */ + if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30) + pipeconf |= PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP; - } - } - if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base, - INTEL_OUTPUT_EDP)) { - if (intel_crtc->config.dither) { - pipeconf |= PIPECONF_6BPC | - PIPECONF_ENABLE | - I965_PIPECONF_ACTIVE; + switch (intel_crtc->config.pipe_bpp) { + case 18: + pipeconf |= PIPECONF_6BPC; + break; + case 24: + pipeconf |= PIPECONF_8BPC; + break; + case 30: + pipeconf |= PIPECONF_10BPC; + break; + default: + /* Case prevented by intel_choose_pipe_bpp_dither. */ + BUG(); } } -- cgit v1.2.3 From 52541e30339d932382ab9c0c1d1bacc8dacc541e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:38 +0200 Subject: drm/i915: allow high-bpc modes on DP Totally untested due to lack of screens supporting more than 8bpc. But now we should have closed all holes in our bpp handling, so this should be safe. The last missing piece was 10bpc support for g4x/vlv, since we directly use the pipe bpp to feed the display link (and anyway, only the cpt has any means to have a pipe bpp != the display link bpp). Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 82cd9ac16c4a..7840b4d22774 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -747,7 +747,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ - bpp = min_t(int, 8*3, pipe_config->pipe_bpp); + bpp = pipe_config->pipe_bpp; /* * eDP panels are really fickle, try to enfore the bpp the firmware -- cgit v1.2.3 From 33d29b145305641f2c693b759cac468e0c87ab4d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 13 Feb 2013 18:04:45 +0100 Subject: drm/i915: move intel_crtc->fdi_lanes to pipe_config We need this for two reasons: - Correct handling of shared fdi lanes on ivb with fastboot. - Handling fdi link bw limits when we only have two fdi lanes by dithering down a bit. Just search&replace in this patch, no functional change at all. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 7 ++++--- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 4 +++- 3 files changed, 25 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0d7cf317b73f..c9c4741020df 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -181,7 +181,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) /* Enable the PCH Receiver FDI PLL */ rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | - FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19); + FDI_RX_PLL_ENABLE | + ((intel_crtc->config.fdi_lanes - 1) << 19); I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); udelay(220); @@ -209,7 +210,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) * port reversal bit */ I915_WRITE(DDI_BUF_CTL(PORT_E), DDI_BUF_CTL_ENABLE | - ((intel_crtc->fdi_lanes - 1) << 1) | + ((intel_crtc->config.fdi_lanes - 1) << 1) | hsw_ddi_buf_ctl_values[i / 2]); POSTING_READ(DDI_BUF_CTL(PORT_E)); @@ -1022,7 +1023,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) } else if (type == INTEL_OUTPUT_ANALOG) { temp |= TRANS_DDI_MODE_SELECT_FDI; - temp |= (intel_crtc->fdi_lanes - 1) << 1; + temp |= (intel_crtc->config.fdi_lanes - 1) << 1; } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 983822e10533..a3799779d46f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2420,7 +2420,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); temp &= ~(7 << 19); - temp |= (intel_crtc->fdi_lanes - 1) << 19; + temp |= (intel_crtc->config.fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; I915_WRITE(reg, temp | FDI_TX_ENABLE); @@ -2518,7 +2518,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); temp &= ~(7 << 19); - temp |= (intel_crtc->fdi_lanes - 1) << 19; + temp |= (intel_crtc->config.fdi_lanes - 1) << 19; temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; @@ -2653,7 +2653,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); temp &= ~(7 << 19); - temp |= (intel_crtc->fdi_lanes - 1) << 19; + temp |= (intel_crtc->config.fdi_lanes - 1) << 19; temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB); temp |= FDI_LINK_TRAIN_PATTERN_1_IVB; temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; @@ -2755,7 +2755,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); temp &= ~((0x7 << 19) | (0x7 << 16)); - temp |= (intel_crtc->fdi_lanes - 1) << 19; + temp |= (intel_crtc->config.fdi_lanes - 1) << 19; temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); @@ -5398,12 +5398,12 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n", - pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); - if (intel_crtc->fdi_lanes > 4) { + pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); + if (intel_crtc->config.fdi_lanes > 4) { DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); + pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->fdi_lanes = 4; + intel_crtc->config.fdi_lanes = 4; return false; } @@ -5416,28 +5416,28 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) return true; case PIPE_B: if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && - intel_crtc->fdi_lanes > 2) { + intel_crtc->config.fdi_lanes > 2) { DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); + pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->fdi_lanes = 2; + intel_crtc->config.fdi_lanes = 2; return false; } - if (intel_crtc->fdi_lanes > 2) + if (intel_crtc->config.fdi_lanes > 2) WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); else cpt_enable_fdi_bc_bifurcation(dev); return true; case PIPE_C: - if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) { - if (intel_crtc->fdi_lanes > 2) { + if (!pipe_B_crtc->base.enabled || pipe_B_crtc->config.fdi_lanes <= 2) { + if (intel_crtc->config.fdi_lanes > 2) { DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->fdi_lanes); + pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->fdi_lanes = 2; + intel_crtc->config.fdi_lanes = 2; return false; } @@ -5525,7 +5525,7 @@ static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) lane = ironlake_get_lanes_required(target_clock, link_bw, intel_crtc->config.pipe_bpp); - intel_crtc->fdi_lanes = lane; + intel_crtc->config.fdi_lanes = lane; if (intel_crtc->config.pixel_multiplier > 1) link_bw *= intel_crtc->config.pixel_multiplier; @@ -5752,7 +5752,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Note, this also computes intel_crtc->fdi_lanes which is used below in * ironlake_check_fdi_lanes. */ - intel_crtc->fdi_lanes = 0; + intel_crtc->config.fdi_lanes = 0; if (intel_crtc->config.has_pch_encoder) ironlake_fdi_set_m_n(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a8c696014967..cc075a312ea3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -249,6 +249,9 @@ struct intel_crtc_config { u32 pos; u32 size; } pch_pfit; + + /* FDI lanes used, only valid if has_pch_encoder is set. */ + int fdi_lanes; }; struct intel_crtc { @@ -267,7 +270,6 @@ struct intel_crtc { bool lowfreq_avail; struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; - int fdi_lanes; atomic_t unpin_work_count; -- cgit v1.2.3 From 627eb5a318a6caca2145d3c7195b084c59b291d9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 29 Apr 2013 19:33:42 +0200 Subject: drm/i915: hw state readout support for pipe_config->fdi_lanes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: Introduce some nice #defines for the FDI lane width fields and put them to good use. Suggested by Ville. v3: Fixup the mask vs. shift copy&pasta fail Imre Deak spotted, and use the shift #define also in the mask. Cc: Imre Deak Cc: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 +++-------- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++---------- 3 files changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e79669fa9fe2..2d27960d6dc1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4146,10 +4146,9 @@ #define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22) #define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22) #define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22) -#define FDI_DP_PORT_WIDTH_X1 (0<<19) -#define FDI_DP_PORT_WIDTH_X2 (1<<19) -#define FDI_DP_PORT_WIDTH_X3 (2<<19) -#define FDI_DP_PORT_WIDTH_X4 (3<<19) +#define FDI_DP_PORT_WIDTH_SHIFT 19 +#define FDI_DP_PORT_WIDTH_MASK (7 << FDI_DP_PORT_WIDTH_SHIFT) +#define FDI_DP_PORT_WIDTH(width) (((width) - 1) << FDI_DP_PORT_WIDTH_SHIFT) #define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) /* Ironlake: hardwired to 1 */ #define FDI_TX_PLL_ENABLE (1<<14) @@ -4174,7 +4173,6 @@ /* train, dp width same as FDI_TX */ #define FDI_FS_ERRC_ENABLE (1<<27) #define FDI_FE_ERRC_ENABLE (1<<26) -#define FDI_DP_PORT_WIDTH_X8 (7<<19) #define FDI_RX_POLARITY_REVERSED_LPT (1<<16) #define FDI_8BPC (0<<16) #define FDI_10BPC (1<<16) @@ -4196,9 +4194,6 @@ #define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) #define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) #define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) -/* LPT */ -#define FDI_PORT_WIDTH_2X_LPT (1<<19) -#define FDI_PORT_WIDTH_1X_LPT (0<<19) #define _FDI_RXA_MISC 0xf0010 #define _FDI_RXB_MISC 0xf1010 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c9c4741020df..72941f94c830 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -182,7 +182,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) /* Enable the PCH Receiver FDI PLL */ rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | FDI_RX_PLL_ENABLE | - ((intel_crtc->config.fdi_lanes - 1) << 19); + FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); POSTING_READ(_FDI_RXA_CTL); udelay(220); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a3799779d46f..63975c7f9668 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2419,8 +2419,8 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) /* enable CPU FDI TX and PCH FDI RX */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); - temp &= ~(7 << 19); - temp |= (intel_crtc->config.fdi_lanes - 1) << 19; + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; I915_WRITE(reg, temp | FDI_TX_ENABLE); @@ -2517,8 +2517,8 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) /* enable CPU FDI TX and PCH FDI RX */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); - temp &= ~(7 << 19); - temp |= (intel_crtc->config.fdi_lanes - 1) << 19; + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); temp &= ~FDI_LINK_TRAIN_NONE; temp |= FDI_LINK_TRAIN_PATTERN_1; temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; @@ -2652,8 +2652,8 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) /* enable CPU FDI TX and PCH FDI RX */ reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); - temp &= ~(7 << 19); - temp |= (intel_crtc->config.fdi_lanes - 1) << 19; + temp &= ~FDI_DP_PORT_WIDTH_MASK; + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB); temp |= FDI_LINK_TRAIN_PATTERN_1_IVB; temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; @@ -2754,8 +2754,8 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); - temp &= ~((0x7 << 19) | (0x7 << 16)); - temp |= (intel_crtc->config.fdi_lanes - 1) << 19; + temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16)); + temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes); temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); @@ -5784,9 +5784,14 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, if (!(tmp & PIPECONF_ENABLE)) return false; - if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) + if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { pipe_config->has_pch_encoder = true; + tmp = I915_READ(FDI_RX_CTL(crtc->pipe)); + pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> + FDI_DP_PORT_WIDTH_SHIFT) + 1; + } + return true; } @@ -5922,9 +5927,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, */ tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && - I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) + I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) { pipe_config->has_pch_encoder = true; + tmp = I915_READ(FDI_RX_CTL(PIPE_A)); + pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> + FDI_DP_PORT_WIDTH_SHIFT) + 1; + } + return true; } @@ -7886,6 +7896,14 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, return false; } + if (current_config->fdi_lanes != pipe_config->fdi_lanes) { + DRM_ERROR("mismatch in fdi_lanes " + "(expected %i, found %i)\n", + current_config->fdi_lanes, + pipe_config->fdi_lanes); + return false; + } + return true; } -- cgit v1.2.3 From ca3a0ff80faa7ee043fd615c9d9394757e2acb09 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 14 Feb 2013 16:54:22 +0100 Subject: drm/i915: split up fdi_set_m_n into computation and hw setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And also move the computed m_n values into the pipe_config. This is a prep step to move the fdi state computation completely into the prepare phase of the modeset sequence. Which will allow us to handle fdi link bw constraints in a better way. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 26 +++++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 63975c7f9668..0f1e17a7b757 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5499,13 +5499,11 @@ void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, } } -static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) +static void ironlake_fdi_compute_config(struct intel_crtc *intel_crtc) { - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &intel_crtc->config.adjusted_mode; - struct intel_link_m_n m_n = {0}; int target_clock, lane, link_bw; /* FDI is a binary signal running at ~2.7GHz, encoding @@ -5530,9 +5528,7 @@ static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) if (intel_crtc->config.pixel_multiplier > 1) link_bw *= intel_crtc->config.pixel_multiplier; intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock, - link_bw, &m_n); - - intel_cpu_transcoder_set_m_n(intel_crtc, &m_n); + link_bw, &intel_crtc->config.fdi_m_n); } static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) @@ -5753,8 +5749,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Note, this also computes intel_crtc->fdi_lanes which is used below in * ironlake_check_fdi_lanes. */ intel_crtc->config.fdi_lanes = 0; - if (intel_crtc->config.has_pch_encoder) - ironlake_fdi_set_m_n(crtc); + if (intel_crtc->config.has_pch_encoder) { + ironlake_fdi_compute_config(intel_crtc); + + intel_cpu_transcoder_set_m_n(intel_crtc, + &intel_crtc->config.fdi_m_n); + } fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); @@ -5884,8 +5884,12 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); - if (intel_crtc->config.has_pch_encoder) - ironlake_fdi_set_m_n(crtc); + if (intel_crtc->config.has_pch_encoder) { + ironlake_fdi_compute_config(intel_crtc); + + intel_cpu_transcoder_set_m_n(intel_crtc, + &intel_crtc->config.fdi_m_n); + } haswell_set_pipeconf(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cc075a312ea3..48f309eaf7aa 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -250,8 +250,9 @@ struct intel_crtc_config { u32 size; } pch_pfit; - /* FDI lanes used, only valid if has_pch_encoder is set. */ + /* FDI configuration, only valid if has_pch_encoder is set. */ int fdi_lanes; + struct intel_link_m_n fdi_m_n; }; struct intel_crtc { -- cgit v1.2.3 From 877d48d5f7d4f90d3bd5fb5422e1a88d39e1d3b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:43 +0200 Subject: drm/i915: compute fdi lane config earlier Now that it's split up, we can easily move it around and precompute the fdi lane configuration. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 71 +++++++++++++++++------------------- 1 file changed, 34 insertions(+), 37 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f1e17a7b757..a7674c313e03 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3974,6 +3974,37 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) return encoder->get_hw_state(encoder, &pipe); } +static void ironlake_fdi_compute_config(struct drm_device *dev, + struct intel_crtc_config *pipe_config) +{ + struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + int target_clock, lane, link_bw; + + /* FDI is a binary signal running at ~2.7GHz, encoding + * each output octet as 10 bits. The actual frequency + * is stored as a divider into a 100MHz clock, and the + * mode pixel clock is stored in units of 1KHz. + * Hence the bw of each lane in terms of the mode signal + * is: + */ + link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; + + if (pipe_config->pixel_target_clock) + target_clock = pipe_config->pixel_target_clock; + else + target_clock = adjusted_mode->clock; + + lane = ironlake_get_lanes_required(target_clock, link_bw, + pipe_config->pipe_bpp); + + pipe_config->fdi_lanes = lane; + + if (pipe_config->pixel_multiplier > 1) + link_bw *= pipe_config->pixel_multiplier; + intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, + link_bw, &pipe_config->fdi_m_n); +} + static bool intel_crtc_compute_config(struct drm_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -4008,6 +4039,9 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, pipe_config->pipe_bpp = 8*3; } + if (pipe_config->has_pch_encoder) + ironlake_fdi_compute_config(dev, pipe_config); + return true; } @@ -5499,38 +5533,6 @@ void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, } } -static void ironlake_fdi_compute_config(struct intel_crtc *intel_crtc) -{ - struct drm_device *dev = intel_crtc->base.dev; - struct drm_display_mode *adjusted_mode = - &intel_crtc->config.adjusted_mode; - int target_clock, lane, link_bw; - - /* FDI is a binary signal running at ~2.7GHz, encoding - * each output octet as 10 bits. The actual frequency - * is stored as a divider into a 100MHz clock, and the - * mode pixel clock is stored in units of 1KHz. - * Hence the bw of each lane in terms of the mode signal - * is: - */ - link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; - - if (intel_crtc->config.pixel_target_clock) - target_clock = intel_crtc->config.pixel_target_clock; - else - target_clock = adjusted_mode->clock; - - lane = ironlake_get_lanes_required(target_clock, link_bw, - intel_crtc->config.pipe_bpp); - - intel_crtc->config.fdi_lanes = lane; - - if (intel_crtc->config.pixel_multiplier > 1) - link_bw *= intel_crtc->config.pixel_multiplier; - intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock, - link_bw, &intel_crtc->config.fdi_m_n); -} - static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) { return i9xx_dpll_compute_m(dpll) < factor * dpll->n; @@ -5748,10 +5750,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Note, this also computes intel_crtc->fdi_lanes which is used below in * ironlake_check_fdi_lanes. */ - intel_crtc->config.fdi_lanes = 0; if (intel_crtc->config.has_pch_encoder) { - ironlake_fdi_compute_config(intel_crtc); - intel_cpu_transcoder_set_m_n(intel_crtc, &intel_crtc->config.fdi_m_n); } @@ -5885,8 +5884,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); if (intel_crtc->config.has_pch_encoder) { - ironlake_fdi_compute_config(intel_crtc); - intel_cpu_transcoder_set_m_n(intel_crtc, &intel_crtc->config.fdi_m_n); } -- cgit v1.2.3 From ebfd86fda69bbe4d7b15e0c31e86a3069cf69085 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:44 +0200 Subject: drm/i915: Split up ironlake_check_fdi_lanes Again in preparation to move the configuration checks into the pipe_config computation stage of the modeset sequence. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7674c313e03..1a3fdba4e74d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5459,11 +5459,6 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) return false; } - if (intel_crtc->config.fdi_lanes > 2) - WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); - else - cpt_enable_fdi_bc_bifurcation(dev); - return true; case PIPE_C: if (!pipe_B_crtc->base.enabled || pipe_B_crtc->config.fdi_lanes <= 2) { @@ -5480,9 +5475,31 @@ static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) return false; } + return true; + default: + BUG(); + } +} + +static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + switch (intel_crtc->pipe) { + case PIPE_A: + break; + case PIPE_B: + if (intel_crtc->config.fdi_lanes > 2) + WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); + else + cpt_enable_fdi_bc_bifurcation(dev); + + break; + case PIPE_C: cpt_enable_fdi_bc_bifurcation(dev); - return true; + break; default: BUG(); } @@ -5756,6 +5773,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); + if (IS_IVYBRIDGE(dev)) + ivybridge_update_fdi_bc_bifurcation(intel_crtc); ironlake_set_pipeconf(crtc); -- cgit v1.2.3 From 1857e1daa0695d45b2639ac9e3cfcdaede4a7f8a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 29 Apr 2013 19:34:16 +0200 Subject: drm/i915: move fdi lane configuration checks ahead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This nicely allows us to drop some hacks which have only been used to work around modeset failures due to lack of fdi lanes. v2: Implement proper checking for Haswell platforms - the fdi link to the LPT PCH has only 2 lanes. Note that we already filter out impossible modes in intel_crt_mode_valid. Unfortunately LPT does not support 6bpc on the fdi rx, so we can't pull clever tricks to squeeze in a few more modes. v2: Rebased on top of Ben Widawsky's num_pipes reorg. v3: Rebase on top of Ville's pipe debug output ocd rampage. v4: Fixup rebase fail spotted by Ville. v5: Fixup rebase fail spotted by Imre Deak. I suck. Cc: Imre Deak Cc: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 129 ++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 64 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1a3fdba4e74d..1d157978f10b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3974,9 +3974,68 @@ bool intel_connector_get_hw_state(struct intel_connector *connector) return encoder->get_hw_state(encoder, &pipe); } -static void ironlake_fdi_compute_config(struct drm_device *dev, +static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *pipe_B_crtc = + to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); + + DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n", + pipe_name(pipe), pipe_config->fdi_lanes); + if (pipe_config->fdi_lanes > 4) { + DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + + if (IS_HASWELL(dev)) { + if (pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n", + pipe_config->fdi_lanes); + return false; + } else { + return true; + } + } + + if (INTEL_INFO(dev)->num_pipes == 2) + return true; + + /* Ivybridge 3 pipe is really complicated */ + switch (pipe) { + case PIPE_A: + return true; + case PIPE_B: + if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && + pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + return true; + case PIPE_C: + if (!pipe_B_crtc->base.enabled || + pipe_B_crtc->config.fdi_lanes <= 2) { + if (pipe_config->fdi_lanes > 2) { + DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", + pipe_name(pipe), pipe_config->fdi_lanes); + return false; + } + } else { + DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n"); + return false; + } + return true; + default: + BUG(); + } +} + +static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, struct intel_crtc_config *pipe_config) { + struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int target_clock, lane, link_bw; @@ -4003,6 +4062,9 @@ static void ironlake_fdi_compute_config(struct drm_device *dev, link_bw *= pipe_config->pixel_multiplier; intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, link_bw, &pipe_config->fdi_m_n); + + return ironlake_check_fdi_lanes(intel_crtc->base.dev, + intel_crtc->pipe, pipe_config); } static bool intel_crtc_compute_config(struct drm_crtc *crtc, @@ -4040,7 +4102,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, } if (pipe_config->has_pch_encoder) - ironlake_fdi_compute_config(dev, pipe_config); + return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); return true; } @@ -5424,63 +5486,6 @@ static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) POSTING_READ(SOUTH_CHICKEN1); } -static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc) -{ - struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *pipe_B_crtc = - to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]); - - DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n", - pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); - if (intel_crtc->config.fdi_lanes > 4) { - DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); - /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->config.fdi_lanes = 4; - - return false; - } - - if (INTEL_INFO(dev)->num_pipes == 2) - return true; - - switch (intel_crtc->pipe) { - case PIPE_A: - return true; - case PIPE_B: - if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled && - intel_crtc->config.fdi_lanes > 2) { - DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); - /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->config.fdi_lanes = 2; - - return false; - } - - return true; - case PIPE_C: - if (!pipe_B_crtc->base.enabled || pipe_B_crtc->config.fdi_lanes <= 2) { - if (intel_crtc->config.fdi_lanes > 2) { - DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", - pipe_name(intel_crtc->pipe), intel_crtc->config.fdi_lanes); - /* Clamp lanes to avoid programming the hw with bogus values. */ - intel_crtc->config.fdi_lanes = 2; - - return false; - } - } else { - DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n"); - return false; - } - - return true; - default: - BUG(); - } -} - static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; @@ -5672,7 +5677,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool is_lvds = false; struct intel_encoder *encoder; int ret; - bool fdi_config_ok; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { @@ -5765,14 +5769,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); - /* Note, this also computes intel_crtc->fdi_lanes which is used below in - * ironlake_check_fdi_lanes. */ if (intel_crtc->config.has_pch_encoder) { intel_cpu_transcoder_set_m_n(intel_crtc, &intel_crtc->config.fdi_m_n); } - fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); if (IS_IVYBRIDGE(dev)) ivybridge_update_fdi_bc_bifurcation(intel_crtc); @@ -5788,7 +5789,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_update_linetime_watermarks(dev, pipe, adjusted_mode); - return fdi_config_ok ? ret : -EINVAL; + return ret; } static bool ironlake_get_pipe_config(struct intel_crtc *crtc, -- cgit v1.2.3 From 1e833f40eb38b033ea185687daa72c073f1acc15 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 19 Feb 2013 22:31:57 +0100 Subject: drm/i915: don't count cpu ports for fdi B/C lane sharing This allows us to use all 4 fdi lanes on fdi B when the cpu eDP is running on pipe C. Yay! v2: Encapsulate test into a little helper function, as suggested by Chris Wilson. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d157978f10b..1ef44b2a6952 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2369,6 +2369,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } +static bool pipe_has_enabled_pch(struct intel_crtc *intel_crtc) +{ + return intel_crtc->base.enabled && intel_crtc->config.has_pch_encoder; +} + static void ivb_modeset_global_resources(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2378,10 +2383,13 @@ static void ivb_modeset_global_resources(struct drm_device *dev) to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]); uint32_t temp; - /* When everything is off disable fdi C so that we could enable fdi B - * with all lanes. XXX: This misses the case where a pipe is not using - * any pch resources and so doesn't need any fdi lanes. */ - if (!pipe_B_crtc->base.enabled && !pipe_C_crtc->base.enabled) { + /* + * When everything is off disable fdi C so that we could enable fdi B + * with all lanes. Note that we don't care about enabled pipes without + * an enabled pch encoder. + */ + if (!pipe_has_enabled_pch(pipe_B_crtc) && + !pipe_has_enabled_pch(pipe_C_crtc)) { WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); @@ -4015,7 +4023,7 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, } return true; case PIPE_C: - if (!pipe_B_crtc->base.enabled || + if (!pipe_has_enabled_pch(pipe_B_crtc) || pipe_B_crtc->config.fdi_lanes <= 2) { if (pipe_config->fdi_lanes > 2) { DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n", -- cgit v1.2.3 From 325b9d048810f7689ec644595061c0b700e64bce Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:24:33 +0200 Subject: drm/i915: fixup 12bpc hdmi dotclock handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to multiply the hdmi port dotclock by 1.5x since it's not really a dotclock, but the 10/8 encoding bitclock divided by 10. Also add correct limit checks for the dotclock and reject modes which don't fit. HDMI 1.4 would allow more, but our hw doesn't support that unfortunately :( Somehow I suspect 12bpc hdmi output never really worked - we really need an i-g-t testcase to check all the different pixel modes and outputs. v2: Fixup the adjusted port clock handling - we need to make sure that the fdi link code still gets the real pixelclock. v3: g4x/vlv don't support 12bpc hdmi output so drop the bogus comment. Acked-by: Ville Syrjälä [danvet: Switch dotclock limit check to <= as suggested by Ville.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 53ce8a57f589..21302db7f76d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -783,6 +783,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; if (intel_hdmi->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ @@ -802,16 +803,28 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, /* * HDMI is either 12 or 8, so if the display lets 10bpc sneak * through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi - * outputs. + * outputs. We also need to check that the higher clock still fits + * within limits. */ - if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) { + if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 + && HAS_PCH_SPLIT(dev)) { DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); pipe_config->pipe_bpp = 12*3; + + /* Need to adjust the port link by 1.5x for 12bpc. */ + adjusted_mode->clock = clock_12bpc; + pipe_config->pixel_target_clock = + pipe_config->requested_mode.clock; } else { DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); pipe_config->pipe_bpp = 8*3; } + if (adjusted_mode->clock > 225000) { + DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); + return false; + } + return true; } -- cgit v1.2.3 From e29c22c0c4fefeb48a0157811930f7e9df0bb3f3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 21 Feb 2013 00:00:16 +0100 Subject: drm/i915: implement fdi auto-dithering So on a bunch of setups we only have 2 fdi lanes available, e.g. hsw VGA or 3 pipes on ivb. And seemingly a lot of modes don't quite fit into this, among them the default 1080p mode. The solution is to dither down the pipe a bit so that everything fits, which this patch implements. But ports compute their state under the assumption that the bpp they pick will be the one selected, e.g. the display port bw computations won't work otherwise. Now we could adjust our code to again up-dither to the computed DP link parameters, but that's pointless. So instead when the pipe needs to adjust parameters we need to retry the pipe_config computation at the encoder stage. Furthermore we need to inform encoders that they should not increase bandwidth requirements if possible. This is required for the hdmi code, which prefers the pipe to up-dither to either of the two possible hdmi bpc values. LVDS has a similar requirement, although that's probably only theoretical in nature: It's unlikely that we'll ever see an 8bpc high-res lvds panel (which is required to hit the 2 fdi lane limit). eDP is the only thing which could increase the pipe_bpp setting again, even when in the retry-loop. This could hit the WARN. Two reasons for not bothering: - On many eDP panels we'll get a black screen if the bpp settings don't match vbt. So failing the modeset is the right thing to do. But since that also means it's the only way to light up the panel, it should work. So we shouldn't be able to hit this WARN. - There are still opens around the eDP panel handling, and maybe we need additional tricks. Before that happens it's imo no use trying to be too clever. Worst case we just need to kill that WARN or maybe fail the compute config stage if the eDP connector can't get the bpp setting it wants. And since this can only happen with an fdi link in between and so for pch eDP panels it's rather unlikely to blow up, if ever. v2: Rebased on top of a bikeshed from Paulo. v3: Improve commit message around eDP handling with the stuff things with Imre. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 56 ++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 7 +++++ drivers/gpu/drm/i915/intel_hdmi.c | 14 ++++++--- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 4 files changed, 62 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ef44b2a6952..f40a28589eea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4040,13 +4040,16 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe, } } -static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, - struct intel_crtc_config *pipe_config) +#define RETRY 1 +static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int target_clock, lane, link_bw; + bool setup_ok, needs_recompute = false; +retry: /* FDI is a binary signal running at ~2.7GHz, encoding * each output octet as 10 bits. The actual frequency * is stored as a divider into a 100MHz clock, and the @@ -4071,12 +4074,26 @@ static bool ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, link_bw, &pipe_config->fdi_m_n); - return ironlake_check_fdi_lanes(intel_crtc->base.dev, - intel_crtc->pipe, pipe_config); + setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, + intel_crtc->pipe, pipe_config); + if (!setup_ok && pipe_config->pipe_bpp > 6*3) { + pipe_config->pipe_bpp -= 2*3; + DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n", + pipe_config->pipe_bpp); + needs_recompute = true; + pipe_config->bw_constrained = true; + + goto retry; + } + + if (needs_recompute) + return RETRY; + + return setup_ok ? 0 : -EINVAL; } -static bool intel_crtc_compute_config(struct drm_crtc *crtc, - struct intel_crtc_config *pipe_config) +static int intel_crtc_compute_config(struct drm_crtc *crtc, + struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; @@ -4085,7 +4102,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, /* FDI link clock is fixed at 2.7G */ if (pipe_config->requested_mode.clock * 3 > IRONLAKE_FDI_FREQ * 4) - return false; + return -EINVAL; } /* All interlaced capable intel hw wants timings in frames. Note though @@ -4099,7 +4116,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, */ if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && adjusted_mode->hsync_start == adjusted_mode->hdisplay) - return false; + return -EINVAL; if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ @@ -4112,7 +4129,7 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, if (pipe_config->has_pch_encoder) return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); - return true; + return 0; } static int valleyview_get_display_clock_speed(struct drm_device *dev) @@ -7692,7 +7709,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_encoder_helper_funcs *encoder_funcs; struct intel_encoder *encoder; struct intel_crtc_config *pipe_config; - int plane_bpp; + int plane_bpp, ret = -EINVAL; + bool retry = true; pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); if (!pipe_config) @@ -7705,6 +7723,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, if (plane_bpp < 0) goto fail; +encoder_retry: /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. @@ -7733,10 +7752,23 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, } } - if (!(intel_crtc_compute_config(crtc, pipe_config))) { + ret = intel_crtc_compute_config(crtc, pipe_config); + if (ret < 0) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto fail; } + + if (ret == RETRY) { + if (WARN(!retry, "loop in pipe configuration computation\n")) { + ret = -EINVAL; + goto fail; + } + + DRM_DEBUG_KMS("CRTC bw constrained, retrying\n"); + retry = false; + goto encoder_retry; + } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; @@ -7746,7 +7778,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return pipe_config; fail: kfree(pipe_config); - return ERR_PTR(-EINVAL); + return ERR_PTR(ret); } /* Computes which crtcs are affected and sets the relevant bits in the mask. For diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 48f309eaf7aa..766afcf39ee9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -223,6 +223,13 @@ struct intel_crtc_config { /* Controls for the clock computation, to override various stages. */ bool clock_set; + /* + * crtc bandwidth limit, don't increase pipe bpp or clock if not really + * required. This is set in the 2nd loop of calling encoder's + * ->compute_config if the first pick doesn't work out. + */ + bool bw_constrained; + /* Settings for the intel dpll used on pretty much everything but * haswell. */ struct dpll dpll; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 21302db7f76d..93de5ff77912 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -784,6 +784,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2; + int desired_bpp; if (intel_hdmi->color_range_auto) { /* See CEA-861-E - 5.1 Default Encoding Parameters */ @@ -808,16 +809,21 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, */ if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000 && HAS_PCH_SPLIT(dev)) { - DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); - pipe_config->pipe_bpp = 12*3; + DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); + desired_bpp = 12*3; /* Need to adjust the port link by 1.5x for 12bpc. */ adjusted_mode->clock = clock_12bpc; pipe_config->pixel_target_clock = pipe_config->requested_mode.clock; } else { - DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); - pipe_config->pipe_bpp = 8*3; + DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); + desired_bpp = 8*3; + } + + if (!pipe_config->bw_constrained) { + DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp); + pipe_config->pipe_bpp = desired_bpp; } if (adjusted_mode->clock > 225000) { diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3e29499b2e9a..8d65baf043ea 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -248,7 +248,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, else lvds_bpp = 6*3; - if (lvds_bpp != pipe_config->pipe_bpp) { + if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) { DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n", pipe_config->pipe_bpp, lvds_bpp); pipe_config->pipe_bpp = lvds_bpp; -- cgit v1.2.3 From 0973f18f8a764d869add12728887c2d1cc281ffb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:25:33 +0200 Subject: drm/i915: stop for_each_intel_crtc_masked macro from leaking Spotted while changing related code. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f40a28589eea..467c77bc7cb9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7943,7 +7943,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) list_for_each_entry((intel_crtc), \ &(dev)->mode_config.crtc_list, \ base.head) \ - if (mask & (1 <<(intel_crtc)->pipe)) \ + if (mask & (1 <<(intel_crtc)->pipe)) static bool intel_pipe_config_compare(struct intel_crtc_config *current_config, -- cgit v1.2.3 From 08a24034a84866e3abb7fdb35ed0e479b240c205 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Apr 2013 11:25:34 +0200 Subject: drm/i915: introduce macros to check pipe config properties This code will get _really_ repetive, and we'll end up with tons more of this kind. So extract the common patterns. This should also help when we add a lazy pipe_config compare mode for fastboot. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 467c77bc7cb9..2c3cbec75b4e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7949,21 +7949,19 @@ static bool intel_pipe_config_compare(struct intel_crtc_config *current_config, struct intel_crtc_config *pipe_config) { - if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) { - DRM_ERROR("mismatch in has_pch_encoder " - "(expected %i, found %i)\n", - current_config->has_pch_encoder, - pipe_config->has_pch_encoder); - return false; +#define PIPE_CONF_CHECK_I(name) \ + if (current_config->name != pipe_config->name) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected %i, found %i)\n", \ + current_config->name, \ + pipe_config->name); \ + return false; \ } - if (current_config->fdi_lanes != pipe_config->fdi_lanes) { - DRM_ERROR("mismatch in fdi_lanes " - "(expected %i, found %i)\n", - current_config->fdi_lanes, - pipe_config->fdi_lanes); - return false; - } + PIPE_CONF_CHECK_I(has_pch_encoder); + PIPE_CONF_CHECK_I(fdi_lanes); + +#undef PIPE_CONF_CHECK_I return true; } -- cgit v1.2.3 From 72419203cab9acf173956f5564639b0012cd2604 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Apr 2013 13:28:53 +0200 Subject: drm/i915: hw state readout support for fdi m/n We want to use the fdi m/n values to easily compute the adjusted mode dotclock on pch ports. Hence make sure the values stored in the pipe config are always reliable. v2: Fixup FDI TU readout. v3: Rebase on top of moved cpu_transcoder. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2d27960d6dc1..76896baa621c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2776,6 +2776,7 @@ /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ #define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) #define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 +#define TU_SIZE_SHIFT 25 #define PIPE_GMCH_DATA_M_MASK (0xffffff) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2c3cbec75b4e..f442e0bc8e9f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5817,6 +5817,22 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder transcoder = pipe_config->cpu_transcoder; + + pipe_config->fdi_m_n.link_m = I915_READ(PIPE_LINK_M1(transcoder)); + pipe_config->fdi_m_n.link_n = I915_READ(PIPE_LINK_N1(transcoder)); + pipe_config->fdi_m_n.gmch_m = I915_READ(PIPE_DATA_M1(transcoder)) + & ~TU_SIZE_MASK; + pipe_config->fdi_m_n.gmch_n = I915_READ(PIPE_DATA_N1(transcoder)); + pipe_config->fdi_m_n.tu = ((I915_READ(PIPE_DATA_M1(transcoder)) + & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; +} + static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -5834,6 +5850,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, tmp = I915_READ(FDI_RX_CTL(crtc->pipe)); pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> FDI_DP_PORT_WIDTH_SHIFT) + 1; + + ironlake_get_fdi_m_n_config(crtc, pipe_config); } return true; @@ -5979,6 +5997,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, tmp = I915_READ(FDI_RX_CTL(PIPE_A)); pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >> FDI_DP_PORT_WIDTH_SHIFT) + 1; + + ironlake_get_fdi_m_n_config(crtc, pipe_config); } return true; @@ -7960,6 +7980,11 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, PIPE_CONF_CHECK_I(has_pch_encoder); PIPE_CONF_CHECK_I(fdi_lanes); + PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); + PIPE_CONF_CHECK_I(fdi_m_n.gmch_n); + PIPE_CONF_CHECK_I(fdi_m_n.link_m); + PIPE_CONF_CHECK_I(fdi_m_n.link_n); + PIPE_CONF_CHECK_I(fdi_m_n.tu); #undef PIPE_CONF_CHECK_I -- cgit v1.2.3 From 1bd1bd806037af04dd1d7bdd39b2b04090c10d2c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 29 Apr 2013 21:56:12 +0200 Subject: drm/i915: hw state readout support for pipe timings This does duplicate the logic in intel_crtc_mode_get a bit, but the issue is that we also should handle interlace modes and other insanity correctly. Hence I've opted for a sligthly more elaborate route where we first read out the crtc timings for the adjusted mode, and then optionally (not sure if we really need it) compute the modeline from that. v2: Also read out the pipe source dimensions into the requested mode. v3: Rebase on top of the moved cpu_transcoder. v4: Simplify CHECK_FLAGS logic as suggested by Chris Wilson. Also properly #undef that macro again. Reviewed-by: Mika Kuoppala (v3) [danvet: Use the existing mask for interlaced bits, spotted by Mika.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 75 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 76896baa621c..b5d87bd457bd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2842,6 +2842,7 @@ #define PIPECONF_INTERLACED_ILK (3 << 21) #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ +#define PIPECONF_INTERLACE_MODE_MASK (7 << 21) #define PIPECONF_CXSR_DOWNCLOCK (1<<16) #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) #define PIPECONF_BPC_MASK (0x7 << 5) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f442e0bc8e9f..9b0d6b03aa1c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4721,6 +4721,45 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); } +static void intel_get_pipe_timings(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; + uint32_t tmp; + + tmp = I915_READ(HTOTAL(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(HBLANK(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(HSYNC(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1; + + tmp = I915_READ(VTOTAL(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(VBLANK(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1; + tmp = I915_READ(VSYNC(cpu_transcoder)); + pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1; + pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1; + + if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) { + pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE; + pipe_config->adjusted_mode.crtc_vtotal += 1; + pipe_config->adjusted_mode.crtc_vblank_end += 1; + } + + tmp = I915_READ(PIPESRC(crtc->pipe)); + pipe_config->requested_mode.vdisplay = (tmp & 0xffff) + 1; + pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1; +} + static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; @@ -4937,6 +4976,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, if (!(tmp & PIPECONF_ENABLE)) return false; + intel_get_pipe_timings(crtc, pipe_config); + return true; } @@ -5854,6 +5895,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, ironlake_get_fdi_m_n_config(crtc, pipe_config); } + intel_get_pipe_timings(crtc, pipe_config); + return true; } @@ -6001,6 +6044,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, ironlake_get_fdi_m_n_config(crtc, pipe_config); } + intel_get_pipe_timings(crtc, pipe_config); + return true; } @@ -7978,6 +8023,15 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, return false; \ } +#define PIPE_CONF_CHECK_FLAGS(name, mask) \ + if ((current_config->name ^ pipe_config->name) & (mask)) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected %i, found %i)\n", \ + current_config->name & (mask), \ + pipe_config->name & (mask)); \ + return false; \ + } + PIPE_CONF_CHECK_I(has_pch_encoder); PIPE_CONF_CHECK_I(fdi_lanes); PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); @@ -7986,7 +8040,28 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, PIPE_CONF_CHECK_I(fdi_m_n.link_n); PIPE_CONF_CHECK_I(fdi_m_n.tu); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end); + + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start); + PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end); + + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_INTERLACE); + + PIPE_CONF_CHECK_I(requested_mode.hdisplay); + PIPE_CONF_CHECK_I(requested_mode.vdisplay); + #undef PIPE_CONF_CHECK_I +#undef PIPE_CONF_CHECK_FLAGS return true; } -- cgit v1.2.3 From f599cc2917a1beb1a619d70e3ee7b9bc4dc17bb9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Apr 2013 13:02:50 +0300 Subject: drm/i915: cleanup opregion technology enabled indicator defines Move near other defines, add TCHE in the name. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index dda182833209..75062e0e8e3a 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -123,6 +123,12 @@ struct opregion_asle { #define ASLE_PFIT_FAILED (1<<14) #define ASLE_PWM_FREQ_FAILED (1<<16) +/* Technology enabled indicator */ +#define ASLE_TCHE_ALS_EN (1 << 0) +#define ASLE_TCHE_BLC_EN (1 << 1) +#define ASLE_TCHE_PFIT_EN (1 << 2) +#define ASLE_TCHE_PFMB_EN (1 << 3) + /* ASLE backlight brightness to set */ #define ASLE_BCLP_VALID (1<<31) #define ASLE_BCLP_MSK (~(1<<31)) @@ -222,11 +228,6 @@ void intel_opregion_asle_intr(struct drm_device *dev) iowrite32(asle_stat, &asle->aslc); } -#define ASLE_ALS_EN (1<<0) -#define ASLE_BLC_EN (1<<1) -#define ASLE_PFIT_EN (1<<2) -#define ASLE_PFMB_EN (1<<3) - void intel_opregion_enable_asle(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -236,7 +237,7 @@ void intel_opregion_enable_asle(struct drm_device *dev) if (IS_MOBILE(dev)) intel_enable_asle(dev); - iowrite32(ASLE_BLC_EN, &asle->tche); + iowrite32(ASLE_TCHE_BLC_EN, &asle->tche); iowrite32(1, &asle->ardy); } } -- cgit v1.2.3 From 68bca4b0c5553c0137d13df37f18a4b059d6e795 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Apr 2013 13:02:51 +0300 Subject: drm/i915: manage opregion asle driver readiness properly Only set ASLE driver readiness (ARDY) and technology enabled indicator (TCHE) once per opregion init. There should be no need to do that at irq postinstall time. Also clear driver readiness at fini. While at it, add defines for driver readiness. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 75062e0e8e3a..5b6d202ec76d 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -110,6 +110,10 @@ struct opregion_asle { u8 rsvd[102]; } __attribute__((packed)); +/* Driver readiness indicator */ +#define ASLE_ARDY_READY (1 << 0) +#define ASLE_ARDY_NOT_READY (0 << 0) + /* ASLE irq request bits */ #define ASLE_SET_ALS_ILLUM (1 << 0) #define ASLE_SET_BACKLIGHT (1 << 1) @@ -236,9 +240,6 @@ void intel_opregion_enable_asle(struct drm_device *dev) if (asle) { if (IS_MOBILE(dev)) intel_enable_asle(dev); - - iowrite32(ASLE_TCHE_BLC_EN, &asle->tche); - iowrite32(1, &asle->ardy); } } @@ -425,8 +426,12 @@ void intel_opregion_init(struct drm_device *dev) register_acpi_notifier(&intel_opregion_notifier); } - if (opregion->asle) + if (opregion->asle) { intel_opregion_enable_asle(dev); + + iowrite32(ASLE_TCHE_BLC_EN, &opregion->asle->tche); + iowrite32(ASLE_ARDY_READY, &opregion->asle->ardy); + } } void intel_opregion_fini(struct drm_device *dev) @@ -437,6 +442,9 @@ void intel_opregion_fini(struct drm_device *dev) if (!opregion->header) return; + if (opregion->asle) + iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy); + if (opregion->acpi) { iowrite32(0, &opregion->acpi->drdy); @@ -499,6 +507,8 @@ int intel_opregion_setup(struct drm_device *dev) if (mboxes & MBOX_ASLE) { DRM_DEBUG_DRIVER("ASLE supported\n"); opregion->asle = base + OPREGION_ASLE_OFFSET; + + iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy); } return 0; -- cgit v1.2.3 From 2cc7aa29143b1276db3e87d2a2d50d3625b77d60 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Apr 2013 13:02:52 +0300 Subject: drm/i915: untie opregion init and asle irq/pipestat enable Stop calling intel_opregion_enable_asle() and consequently intel_enable_asle() on opregion init. It should not be necessary for these reasons: 1) On PCH split platforms, it only enables GSE interrupt, which is enabled in irq postinstall anyway. Moreover, the irq enable uses the wrong bit on IVB+. 2) On gen 2, it would enable a reserved pipestat bit. If there were gen 2 systems with opregion asle support, that is. And the gen 2 irq handler won't handle it anyway. 3) On gen 3-4, the irq postinstall will call intel_opregion_enable_asle() to enable the pipestat. In short, move the asle irq/pipestat enable responsibility to irq postinstall, which already happens to be in place. This should not cause any functional changes, but only do the one line change here for easier bisectability, just in case, and leave all the cleanups this allows to followup patches. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 5b6d202ec76d..4e697993a3f2 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -427,8 +427,6 @@ void intel_opregion_init(struct drm_device *dev) } if (opregion->asle) { - intel_opregion_enable_asle(dev); - iowrite32(ASLE_TCHE_BLC_EN, &opregion->asle->tche); iowrite32(ASLE_ARDY_READY, &opregion->asle->ardy); } -- cgit v1.2.3 From f898780ba020696e50c04abf2a55790df37ce384 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Apr 2013 13:02:53 +0300 Subject: drm/i915: cleanup redundant checks from intel_enable_asle Realize that intel_enable_asle() is never called on PCH-split platforms or on VLV. Rip out the GSE irq enable for PCH-split platforms, which also happens to be incorrect for IVB+. This should not cause any functional changes. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b0dbf4cd0e07..1783ebe4cd99 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -356,21 +356,11 @@ void intel_enable_asle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; - /* FIXME: opregion/asle for VLV */ - if (IS_VALLEYVIEW(dev)) - return; - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - if (HAS_PCH_SPLIT(dev)) - ironlake_enable_display_irq(dev_priv, DE_GSE); - else { - i915_enable_pipestat(dev_priv, 1, - PIPE_LEGACY_BLC_EVENT_ENABLE); - if (INTEL_INFO(dev)->gen >= 4) - i915_enable_pipestat(dev_priv, 0, - PIPE_LEGACY_BLC_EVENT_ENABLE); - } + i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); + if (INTEL_INFO(dev)->gen >= 4) + i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -- cgit v1.2.3 From f49e38dd23d28d4fceea1e84ae444b4c25fc0407 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 29 Apr 2013 13:02:54 +0300 Subject: drm/i915: cleanup opregion asle pipestat enable Both intel_opregion_enable_asle() and intel_enable_asle() have shrunk considerably. Merge them together into a static function in i915_irq.c, and rename to better reflect the purpose and the related platforms. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ---- drivers/gpu/drm/i915/i915_irq.c | 11 +++++++---- drivers/gpu/drm/i915/intel_opregion.c | 11 ----------- 3 files changed, 7 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 14156f2b8d76..c34103d42c11 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1484,8 +1484,6 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); -void intel_enable_asle(struct drm_device *dev); - #ifdef CONFIG_DEBUG_FS extern void i915_destroy_error_state(struct drm_device *dev); #else @@ -1819,12 +1817,10 @@ extern int intel_opregion_setup(struct drm_device *dev); extern void intel_opregion_init(struct drm_device *dev); extern void intel_opregion_fini(struct drm_device *dev); extern void intel_opregion_asle_intr(struct drm_device *dev); -extern void intel_opregion_enable_asle(struct drm_device *dev); #else static inline void intel_opregion_init(struct drm_device *dev) { return; } static inline void intel_opregion_fini(struct drm_device *dev) { return; } static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } -static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; } #endif /* intel_acpi.c */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1783ebe4cd99..03a31befa8fd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,13 +349,16 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) } /** - * intel_enable_asle - enable ASLE interrupt for OpRegion + * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion */ -void intel_enable_asle(struct drm_device *dev) +static void i915_enable_asle_pipestat(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; + if (!dev_priv->opregion.asle || !IS_MOBILE(dev)) + return; + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE); @@ -2964,7 +2967,7 @@ static int i915_irq_postinstall(struct drm_device *dev) I915_WRITE(IER, enable_mask); POSTING_READ(IER); - intel_opregion_enable_asle(dev); + i915_enable_asle_pipestat(dev); return 0; } @@ -3198,7 +3201,7 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_EN, 0); POSTING_READ(PORT_HOTPLUG_EN); - intel_opregion_enable_asle(dev); + i915_enable_asle_pipestat(dev); return 0; } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 4e697993a3f2..62b64e4877b8 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -232,17 +232,6 @@ void intel_opregion_asle_intr(struct drm_device *dev) iowrite32(asle_stat, &asle->aslc); } -void intel_opregion_enable_asle(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct opregion_asle __iomem *asle = dev_priv->opregion.asle; - - if (asle) { - if (IS_MOBILE(dev)) - intel_enable_asle(dev); - } -} - #define ACPI_EV_DISPLAY_SWITCH (1<<0) #define ACPI_EV_LID (1<<1) #define ACPI_EV_DOCK (1<<2) -- cgit v1.2.3 From 68fc874289e58e62bd0820db0d52150ce6d9fe03 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:16 +0200 Subject: drm/i915: move lvds_border_bits to pipe_config pipe_config is the new dev_priv! More seriously, this is actually better since a pipe_config can be thrown away if the modeset compute config stage fails. Whereas any state stored in dev_prive needs to be painstakingly restored, since otherwise a dpms off/on will wreak massive havoc. Yes, that even applies to state only used in ->mode_set callbacks, since we need to call those even for dpms on when the Haswell power well cleared everything out. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_panel.c | 3 +-- 4 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c34103d42c11..8890b0ba66c3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1019,8 +1019,6 @@ typedef struct drm_i915_private { /* Kernel Modesetting */ struct sdvo_device_mapping sdvo_mappings[2]; - /* indicate whether the LVDS_BORDER should be enabled or not */ - unsigned int lvds_border_bits; struct drm_crtc *plane_to_crtc_mapping[3]; struct drm_crtc *pipe_to_crtc_mapping[3]; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 766afcf39ee9..dfcf546790bc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -249,6 +249,7 @@ struct intel_crtc_config { struct { u32 control; u32 pgm_ratios; + u32 lvds_border_bits; } gmch_pfit; /* Panel fitter placement and size for Ironlake+ */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 8d65baf043ea..47f47ea64f59 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -116,7 +116,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) } /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; + temp |= intel_crtc->config.gmch_pfit.lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. */ diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 2526326efd81..4bf1e18f74cc 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -183,7 +183,6 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, int fitting_mode) { struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; struct drm_display_mode *mode, *adjusted_mode; @@ -312,7 +311,7 @@ out: pipe_config->gmch_pfit.control = pfit_control; pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; } - dev_priv->lvds_border_bits = border; + pipe_config->gmch_pfit.lvds_border_bits = border; } static int is_backlight_combination_mode(struct drm_device *dev) -- cgit v1.2.3 From 2deefda541edb0c73e57e988ccaac4cd014da0d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:17 +0200 Subject: drm/i915: rip out indirection for pfit pipe_config assignment This was still required a bit (on the cargo-cult side though) when the state was stored in dev_priv, and when the enable/disable sequence was botched a bit (to avoid too many updates). But with pipeconfig we always get a clean slate, so this is pointless. Rip it out. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 4bf1e18f74cc..56f17b2382fc 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -306,11 +306,8 @@ out: if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) pfit_control |= PANEL_8TO6_DITHER_ENABLE; - if (pfit_control != pipe_config->gmch_pfit.control || - pfit_pgm_ratios != pipe_config->gmch_pfit.pgm_ratios) { - pipe_config->gmch_pfit.control = pfit_control; - pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; - } + pipe_config->gmch_pfit.control = pfit_control; + pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; pipe_config->gmch_pfit.lvds_border_bits = border; } -- cgit v1.2.3 From 5a80c45c5297a025c2615624042ea8b6840a5376 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 25 Apr 2013 22:52:18 +0200 Subject: drm/i915: move border color writes to pfit_enable Writing hw registers from compute_config? Just say no! In this case not too horrible since we write a constant 0, and only debugging would put something else in there. But while checking that code I've noticed that this register disappeared on pch platforms, so fix that up, too. And adjust the comment a bit, it's outdated. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ drivers/gpu/drm/i915/intel_lvds.c | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9b0d6b03aa1c..650433790813 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3632,6 +3632,10 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); + + /* Border color in case we don't scale up to the full screen. Black by + * default, change to something else for debugging. */ + I915_WRITE(BCLRPAT(crtc->pipe), 0); } static void valleyview_crtc_enable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 47f47ea64f59..d256fe454a9d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -231,7 +231,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; unsigned int lvds_bpp; - int pipe; /* Should never happen!! */ if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) { @@ -274,15 +273,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, intel_connector->panel.fitting_mode); } - /* - * Enable automatic panel scaling for non-native modes so that they fill - * the screen. Should be enabled before the pipe is enabled, according - * to register description and PRM. - * Change the value here to see the borders for debugging - */ - for_each_pipe(pipe) - I915_WRITE(BCLRPAT(pipe), 0); - drm_mode_set_crtcinfo(adjusted_mode, 0); pipe_config->timings_set = true; -- cgit v1.2.3 From 1731693a5a372869d017e601a23b1ce2eb3135ed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Apr 2013 18:52:38 +0300 Subject: drm/i915: Implement proper clipping for video sprites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly clip the source when the destination gets clipped by the pipe dimensions. Sadly the video sprite hardware is rather limited so it can't do proper sub-pixel postitioning. Resort to truncating the source coordinates to (macro)pixel boundary. The scaling checks are done using the strict drm_region functions. Which means that an error is returned when the min/max scaling ratios are exceeded. Also do some additional checking against various hardware limits. v2: Truncate src coords instead of rounding to avoid increasing src viewport size, and adapt to changes in drm_calc_{h,v}scale(). v3: Adapt to drm_region->drm_rect rename. Fix misaligned crtc_w for packed YUV formats when scaling isn't supported. v4: Use stricter scaling checks, use drm_rect_equals() v5: If sprite is below min size, make it invisible instead returning an error. Use WARN_ON() instead if BUG_ON(), and add one to sanity check the src viewport size. v6: Add comments to remind about src and dst coordinate types Reviewed-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 196 +++++++++++++++++++++++++++--------- 1 file changed, 149 insertions(+), 47 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 18993ad93540..87fe3b625c4b 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "intel_drv.h" #include #include "i915_drv.h" @@ -583,6 +584,20 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) key->flags = I915_SET_COLORKEY_NONE; } +static bool +format_is_yuv(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_YUYV: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YVYU: + return true; + default: + return false; + } +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -600,9 +615,29 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); int ret = 0; - int x = src_x >> 16, y = src_y >> 16; - int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay; bool disable_primary = false; + bool visible; + int hscale, vscale; + int max_scale, min_scale; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + struct drm_rect src = { + /* sample coordinates in 16.16 fixed point */ + .x1 = src_x, + .x2 = src_x + src_w, + .y1 = src_y, + .y2 = src_y + src_h, + }; + struct drm_rect dst = { + /* integer pixels */ + .x1 = crtc_x, + .x2 = crtc_x + crtc_w, + .y1 = crtc_y, + .y2 = crtc_y + crtc_h, + }; + const struct drm_rect clip = { + .x2 = crtc->mode.hdisplay, + .y2 = crtc->mode.vdisplay, + }; intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; @@ -618,19 +653,23 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_plane->src_w = src_w; intel_plane->src_h = src_h; - src_w = src_w >> 16; - src_h = src_h >> 16; - /* Pipe must be running... */ - if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) + if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) { + DRM_DEBUG_KMS("Pipe disabled\n"); return -EINVAL; + } - if (crtc_x >= primary_w || crtc_y >= primary_h) + /* Don't modify another pipe's plane */ + if (intel_plane->pipe != intel_crtc->pipe) { + DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); return -EINVAL; + } - /* Don't modify another pipe's plane */ - if (intel_plane->pipe != intel_crtc->pipe) + /* FIXME check all gen limits */ + if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) { + DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); return -EINVAL; + } /* Sprite planes can be linear or x-tiled surfaces */ switch (obj->tiling_mode) { @@ -638,55 +677,115 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, case I915_TILING_X: break; default: + DRM_DEBUG_KMS("Unsupported tiling mode\n"); return -EINVAL; } - /* - * Clamp the width & height into the visible area. Note we don't - * try to scale the source if part of the visible region is offscreen. - * The caller must handle that by adjusting source offset and size. - */ - if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) { - crtc_w += crtc_x; - crtc_x = 0; + max_scale = intel_plane->max_downscale << 16; + min_scale = intel_plane->can_scale ? 1 : (1 << 16); + + hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); + if (hscale < 0) { + DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); + drm_rect_debug_print(&src, true); + drm_rect_debug_print(&dst, false); + + return hscale; } - if ((crtc_x + crtc_w) <= 0) /* Nothing to display */ - goto out; - if ((crtc_x + crtc_w) > primary_w) - crtc_w = primary_w - crtc_x; - if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) { - crtc_h += crtc_y; - crtc_y = 0; + vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); + if (vscale < 0) { + DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); + drm_rect_debug_print(&src, true); + drm_rect_debug_print(&dst, false); + + return vscale; } - if ((crtc_y + crtc_h) <= 0) /* Nothing to display */ - goto out; - if (crtc_y + crtc_h > primary_h) - crtc_h = primary_h - crtc_y; - if (!crtc_w || !crtc_h) /* Again, nothing to display */ - goto out; + visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale); - /* - * We may not have a scaler, eg. HSW does not have it any more - */ - if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h)) - return -EINVAL; + crtc_x = dst.x1; + crtc_y = dst.y1; + crtc_w = drm_rect_width(&dst); + crtc_h = drm_rect_height(&dst); - /* - * We can take a larger source and scale it down, but - * only so much... 16x is the max on SNB. - */ - if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale) - return -EINVAL; + if (visible) { + /* Make the source viewport size an exact multiple of the scaling factors. */ + drm_rect_adjust_size(&src, + drm_rect_width(&dst) * hscale - drm_rect_width(&src), + drm_rect_height(&dst) * vscale - drm_rect_height(&src)); + + /* sanity check to make sure the src viewport wasn't enlarged */ + WARN_ON(src.x1 < (int) src_x || + src.y1 < (int) src_y || + src.x2 > (int) (src_x + src_w) || + src.y2 > (int) (src_y + src_h)); + + /* + * Hardware doesn't handle subpixel coordinates. + * Adjust to (macro)pixel boundary, but be careful not to + * increase the source viewport size, because that could + * push the downscaling factor out of bounds. + * + * FIXME Should we be really strict and reject the + * config if it results in non (macro)pixel aligned + * coords? + */ + src_x = src.x1 >> 16; + src_w = drm_rect_width(&src) >> 16; + src_y = src.y1 >> 16; + src_h = drm_rect_height(&src) >> 16; + + if (format_is_yuv(fb->pixel_format)) { + src_x &= ~1; + src_w &= ~1; + + /* + * Must keep src and dst the + * same if we can't scale. + */ + if (!intel_plane->can_scale) + crtc_w &= ~1; + + if (crtc_w == 0) + visible = false; + } + } + + /* Check size restrictions when scaling */ + if (visible && (src_w != crtc_w || src_h != crtc_h)) { + unsigned int width_bytes; + + WARN_ON(!intel_plane->can_scale); + + /* FIXME interlacing min height is 6 */ + + if (crtc_w < 3 || crtc_h < 3) + visible = false; + + if (src_w < 3 || src_h < 3) + visible = false; + + width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; + + if (src_w > 2048 || src_h > 2048 || + width_bytes > 4096 || fb->pitches[0] > 4096) { + DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); + return -EINVAL; + } + } + + dst.x1 = crtc_x; + dst.x2 = crtc_x + crtc_w; + dst.y1 = crtc_y; + dst.y2 = crtc_y + crtc_h; /* * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - if ((crtc_x == 0) && (crtc_y == 0) && - (crtc_w == primary_w) && (crtc_h == primary_h)) - disable_primary = true; + disable_primary = drm_rect_equals(&dst, &clip); + WARN_ON(disable_primary && !visible); mutex_lock(&dev->struct_mutex); @@ -708,8 +807,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (!disable_primary) intel_enable_primary(crtc); - intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y, - crtc_w, crtc_h, x, y, src_w, src_h); + if (visible) + intel_plane->update_plane(plane, fb, obj, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + else + intel_plane->disable_plane(plane); if (disable_primary) intel_disable_primary(crtc); @@ -732,7 +835,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, out_unlock: mutex_unlock(&dev->struct_mutex); -out: return ret; } -- cgit v1.2.3 From 3c3686cd9700efefcfc24ab5910b3e5fffd0b069 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Apr 2013 18:52:39 +0300 Subject: drm/i915: Relax the sprite scaling limits checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce the size of the the src/dst viewport to keep the scalign ratios in check. v2: Below min size sprite handling squashed to previous patch Reviewed-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 48 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 87fe3b625c4b..19b9cb961b5a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -681,26 +681,19 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return -EINVAL; } + /* + * FIXME the following code does a bunch of fuzzy adjustments to the + * coordinates and sizes. We probably need some way to decide whether + * more strict checking should be done instead. + */ max_scale = intel_plane->max_downscale << 16; min_scale = intel_plane->can_scale ? 1 : (1 << 16); - hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); - if (hscale < 0) { - DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); - drm_rect_debug_print(&src, true); - drm_rect_debug_print(&dst, false); - - return hscale; - } - - vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); - if (vscale < 0) { - DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); - drm_rect_debug_print(&src, true); - drm_rect_debug_print(&dst, false); + hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale); + BUG_ON(hscale < 0); - return vscale; - } + vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale); + BUG_ON(vscale < 0); visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale); @@ -710,6 +703,25 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, crtc_h = drm_rect_height(&dst); if (visible) { + /* check again in case clipping clamped the results */ + hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale); + if (hscale < 0) { + DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); + drm_rect_debug_print(&src, true); + drm_rect_debug_print(&dst, false); + + return hscale; + } + + vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale); + if (vscale < 0) { + DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); + drm_rect_debug_print(&src, true); + drm_rect_debug_print(&dst, false); + + return vscale; + } + /* Make the source viewport size an exact multiple of the scaling factors. */ drm_rect_adjust_size(&src, drm_rect_width(&dst) * hscale - drm_rect_width(&src), @@ -726,10 +738,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * Adjust to (macro)pixel boundary, but be careful not to * increase the source viewport size, because that could * push the downscaling factor out of bounds. - * - * FIXME Should we be really strict and reject the - * config if it results in non (macro)pixel aligned - * coords? */ src_x = src.x1 >> 16; src_w = drm_rect_width(&src) >> 16; -- cgit v1.2.3 From dce3271b1ee05ca01ebdde50d613d7b33ef178a9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Apr 2013 13:30:33 +0300 Subject: drm/i915: reference count for i915_hw_contexts Enabling PPGTT and also the need to track which context was guilty of gpu hang (arb robustness enabling) have put pressure for struct i915_hw_context to be more than just a placeholder for hw context state. In order to track object lifetime properly in a multi peer usage, add reference counting for i915_hw_context. v2: track i915_hw_context pointers instead of using ctx_ids (from Chris Wilson) v3 (Ben): Get rid of do_release() and handle refcounting more compactly. (recommended by Chis) v4: kref_* put inside static inlines (Daniel Vetter) remove code duplication on freeing context (Chris Wilson) v5: idr_remove and ctx->file_priv = NULL in destroy ioctl (Chris) This actually will cause a problem if one destroys a context and later refers to the idea of the context (multiple contexts may have the same id, but only 1 will exist in the idr). v6: Strip out the request related stuff. Reworded commit message. Got rid of do_destroy and introduced i915_gem_context_release_handle, suggested by Chris Wilson. v7: idr_remove can't be called inside idr_for_each (Chris Wilson) Signed-off-by: Ben Widawsky (v5) Signed-off-by: Mika Kuoppala (v7) Reviewed-by: Ben Widawsky Reviewed-by: Chris Wilson [danvet: Squash sob lines, the patch ping-ponged between Ben and Mika a bit ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 12 ++++++++++++ drivers/gpu/drm/i915/i915_gem_context.c | 28 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8890b0ba66c3..3ac71db78e9e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -452,6 +452,7 @@ struct i915_hw_ppgtt { /* This must match up with the value previously used for execbuf2.rsvd1. */ #define DEFAULT_CONTEXT_ID 0 struct i915_hw_context { + struct kref ref; int id; bool is_initialized; struct drm_i915_file_private *file_priv; @@ -1697,6 +1698,17 @@ void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, struct drm_file *file, int to_id); +void i915_gem_context_free(struct kref *ctx_ref); +static inline void i915_gem_context_reference(struct i915_hw_context *ctx) +{ + kref_get(&ctx->ref); +} + +static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) +{ + kref_put(&ctx->ref, i915_gem_context_free); +} + int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a1e8ecb6adf6..9e8c68510e1b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -124,10 +124,10 @@ static int get_context_size(struct drm_device *dev) return ret; } -static void do_destroy(struct i915_hw_context *ctx) +void i915_gem_context_free(struct kref *ctx_ref) { - if (ctx->file_priv) - idr_remove(&ctx->file_priv->context_idr, ctx->id); + struct i915_hw_context *ctx = container_of(ctx_ref, + typeof(*ctx), ref); drm_gem_object_unreference(&ctx->obj->base); kfree(ctx); @@ -145,6 +145,7 @@ create_hw_context(struct drm_device *dev, if (ctx == NULL) return ERR_PTR(-ENOMEM); + kref_init(&ctx->ref); ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); if (ctx->obj == NULL) { kfree(ctx); @@ -169,18 +170,18 @@ create_hw_context(struct drm_device *dev, if (file_priv == NULL) return ctx; - ctx->file_priv = file_priv; - ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0, GFP_KERNEL); if (ret < 0) goto err_out; + + ctx->file_priv = file_priv; ctx->id = ret; return ctx; err_out: - do_destroy(ctx); + i915_gem_context_unreference(ctx); return ERR_PTR(ret); } @@ -226,7 +227,7 @@ static int create_default_context(struct drm_i915_private *dev_priv) err_unpin: i915_gem_object_unpin(ctx->obj); err_destroy: - do_destroy(ctx); + i915_gem_context_unreference(ctx); return ret; } @@ -262,6 +263,7 @@ void i915_gem_context_init(struct drm_device *dev) void i915_gem_context_fini(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; if (dev_priv->hw_contexts_disabled) return; @@ -271,9 +273,8 @@ void i915_gem_context_fini(struct drm_device *dev) * other code, leading to spurious errors. */ intel_gpu_reset(dev); - i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj); - - do_destroy(dev_priv->ring[RCS].default_context); + i915_gem_object_unpin(dctx->obj); + i915_gem_context_unreference(dctx); } static int context_idr_cleanup(int id, void *p, void *data) @@ -282,8 +283,7 @@ static int context_idr_cleanup(int id, void *p, void *data) BUG_ON(id == DEFAULT_CONTEXT_ID); - do_destroy(ctx); - + i915_gem_context_unreference(ctx); return 0; } @@ -512,8 +512,8 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, return -ENOENT; } - do_destroy(ctx); - + idr_remove(&ctx->file_priv->context_idr, ctx->id); + i915_gem_context_unreference(ctx); mutex_unlock(&dev->struct_mutex); DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id); -- cgit v1.2.3 From 17aa6be9579eb204b426eeae146a43bf3dd05078 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:40 +0200 Subject: drm/i915: simplify DP/DDI port width macros If we ever leak a non-DP compliant port width through here, we have a pretty serious issue. So just rip out all these WARNs - if we need them it's probably better to have them at a central place where we compute the dp lane count. Also use the new DDI width macro for FDI mode. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni [danvet: fixup the embarrassing s/intel_dp->DP/temp/ mistake Paulo spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 ++--------- drivers/gpu/drm/i915/intel_ddi.c | 34 ++-------------------------------- drivers/gpu/drm/i915/intel_dp.c | 12 +----------- 3 files changed, 5 insertions(+), 52 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b5d87bd457bd..aec569f13186 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2664,9 +2664,7 @@ #define DP_PRE_EMPHASIS_SHIFT 22 /* How many wires to use. I guess 3 was too hard */ -#define DP_PORT_WIDTH_1 (0 << 19) -#define DP_PORT_WIDTH_2 (1 << 19) -#define DP_PORT_WIDTH_4 (3 << 19) +#define DP_PORT_WIDTH(width) (((width) - 1) << 19) #define DP_PORT_WIDTH_MASK (7 << 19) /* Mystic DPCD version 1.1 special mode */ @@ -4755,9 +4753,6 @@ #define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12) #define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) #define TRANS_DDI_BFI_ENABLE (1<<4) -#define TRANS_DDI_PORT_WIDTH_X1 (0<<1) -#define TRANS_DDI_PORT_WIDTH_X2 (1<<1) -#define TRANS_DDI_PORT_WIDTH_X4 (3<<1) /* DisplayPort Transport Control */ #define DP_TP_CTL_A 0x64040 @@ -4801,9 +4796,7 @@ #define DDI_BUF_PORT_REVERSAL (1<<16) #define DDI_BUF_IS_IDLE (1<<7) #define DDI_A_4_LANES (1<<4) -#define DDI_PORT_WIDTH_X1 (0<<1) -#define DDI_PORT_WIDTH_X2 (1<<1) -#define DDI_PORT_WIDTH_X4 (3<<1) +#define DDI_PORT_WIDTH(width) (((width) - 1) << 1) #define DDI_INIT_DISPLAY_DETECTED (1<<0) /* DDI Buffer Translations */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 72941f94c830..3ff4de6c6009 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -687,22 +687,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, intel_dp->DP = intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW; - switch (intel_dp->lane_count) { - case 1: - intel_dp->DP |= DDI_PORT_WIDTH_X1; - break; - case 2: - intel_dp->DP |= DDI_PORT_WIDTH_X2; - break; - case 4: - intel_dp->DP |= DDI_PORT_WIDTH_X4; - break; - default: - intel_dp->DP |= DDI_PORT_WIDTH_X4; - WARN(1, "Unexpected DP lane count %d\n", - intel_dp->lane_count); - break; - } + intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count); if (intel_dp->has_audio) { DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n", @@ -1031,22 +1016,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) temp |= TRANS_DDI_MODE_SELECT_DP_SST; - switch (intel_dp->lane_count) { - case 1: - temp |= TRANS_DDI_PORT_WIDTH_X1; - break; - case 2: - temp |= TRANS_DDI_PORT_WIDTH_X2; - break; - case 4: - temp |= TRANS_DDI_PORT_WIDTH_X4; - break; - default: - temp |= TRANS_DDI_PORT_WIDTH_X4; - WARN(1, "Unsupported lane count %d\n", - intel_dp->lane_count); - } - + temp |= DDI_PORT_WIDTH(intel_dp->lane_count); } else { WARN(1, "Invalid encoder type %d for pipe %c\n", intel_encoder->type, pipe_name(pipe)); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7840b4d22774..a2935234ac03 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -891,18 +891,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* Handle DP bits in common between all three register formats */ intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; + intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count); - switch (intel_dp->lane_count) { - case 1: - intel_dp->DP |= DP_PORT_WIDTH_1; - break; - case 2: - intel_dp->DP |= DP_PORT_WIDTH_2; - break; - case 4: - intel_dp->DP |= DP_PORT_WIDTH_4; - break; - } if (intel_dp->has_audio) { DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", pipe_name(intel_crtc->pipe)); -- cgit v1.2.3 From 168f83660211b9e059e3bc0638daaa01e9ea0b71 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 May 2013 16:29:08 +0300 Subject: drm/i915: unreference default context on module unload Before module unload is called, gpu_idle() will switch to default context. This will increment ref count of base object as the default context is 'running' on module unload time. Unreference the drm object so that when context is freed, base object is freed as well. v2: added comment to explain the refcounts (Ben Widawsky) Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9e8c68510e1b..280617ef4996 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -274,6 +274,14 @@ void i915_gem_context_fini(struct drm_device *dev) intel_gpu_reset(dev); i915_gem_object_unpin(dctx->obj); + + /* When default context is created and switched to, base object refcount + * will be 2 (+1 from object creation and +1 from do_switch()). + * i915_gem_context_fini() will be called after gpu_idle() has switched + * to default context. So we need to unreference the base object once + * to offset the do_switch part, so that i915_gem_context_unreference() + * can then free the base object correctly. */ + drm_gem_object_unreference(&dctx->obj->base); i915_gem_context_unreference(dctx); } -- cgit v1.2.3 From 2b87f3b1bab1df814057ff551f4fc49c22a7fde9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 2 May 2013 15:30:47 -0700 Subject: drm/i915: fix Haswell pfit power well check v2 We can't read the pfit regs if the power well is off, so use the cached value. v2: re-add lost comment (Jesse) make sure the crtc using the fitter is actually enabled (Jesse) Signed-off-by: Jesse Barnes [danvet: Drop now unused dev_priv, as spotted by Mika.] Reviewed-by: Mika Kuoppala Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 650433790813..de8be7595a62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5906,7 +5906,6 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, static void haswell_modeset_global_resources(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; bool enable = false; struct intel_crtc *crtc; struct intel_encoder *encoder; @@ -5918,7 +5917,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev) * sequence that's not yet available. Just in case desktop eDP * on PORT D is possible on haswell, too. */ /* Even the eDP panel fitter is outside the always-on well. */ - if (I915_READ(PF_WIN_SZ(crtc->pipe))) + if (crtc->config.pch_pfit.size && crtc->base.enabled) enable = true; } -- cgit v1.2.3 From 21a8e6a4853b2ed39fa4c5188a710f2cf1b92026 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 10 Apr 2013 23:28:35 +0200 Subject: drm/i915: don't setup hdmi for port D edp in ddi_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dp_init_connector adjusts the encoder type if it is a eDP panel. Use that to decide whether we should set up a hdmi connector or not. To do so reorder the hdmi connector setup sequence in ddi_init a bit. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3ff4de6c6009..d7a33856a61a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1484,16 +1484,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) return; } - if (port != PORT_A) { - hdmi_connector = kzalloc(sizeof(struct intel_connector), - GFP_KERNEL); - if (!hdmi_connector) { - kfree(dp_connector); - kfree(intel_dig_port); - return; - } - } - intel_encoder = &intel_dig_port->base; encoder = &intel_encoder->base; @@ -1511,8 +1501,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_dig_port->port = port; intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & DDI_BUF_PORT_REVERSAL; - if (hdmi_connector) - intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); intel_encoder->type = INTEL_OUTPUT_UNKNOWN; @@ -1520,7 +1508,16 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_ddi_hot_plug; - if (hdmi_connector) - intel_hdmi_init_connector(intel_dig_port, hdmi_connector); intel_dp_init_connector(intel_dig_port, dp_connector); + + if (intel_encoder->type != INTEL_OUTPUT_EDP) { + hdmi_connector = kzalloc(sizeof(struct intel_connector), + GFP_KERNEL); + if (!hdmi_connector) { + return; + } + + intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port); + intel_hdmi_init_connector(intel_dig_port, hdmi_connector); + } } -- cgit v1.2.3 From 112522f6789581824903f6f72082b5b841a7f0f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 2 May 2013 16:48:07 +0300 Subject: drm/i915: put context upon switching In order to be notified of when the context and all of its associated objects is idle (for if the context maps to a ppgtt) we need a callback from the retire handler. We can arrange this by using the kref_get/put of the context for request tracking and by inserting a request to demarque the switch away from the old context. [Ben: fixed minor error to patch compile, AND s/last_context/from/] Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 37 +++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 280617ef4996..efa0ede5c679 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -361,13 +361,13 @@ mi_set_context(struct intel_ring_buffer *ring, static int do_switch(struct i915_hw_context *to) { struct intel_ring_buffer *ring = to->ring; - struct drm_i915_gem_object *from_obj = ring->last_context_obj; + struct i915_hw_context *from = ring->last_context; u32 hw_flags = 0; int ret; - BUG_ON(from_obj != NULL && from_obj->pin_count == 0); + BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0); - if (from_obj == to->obj) + if (from == to) return 0; ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false); @@ -390,7 +390,7 @@ static int do_switch(struct i915_hw_context *to) if (!to->is_initialized || is_default_context(to)) hw_flags |= MI_RESTORE_INHIBIT; - else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */ + else if (WARN_ON_ONCE(from == to)) /* not yet expected */ hw_flags |= MI_FORCE_RESTORE; ret = mi_set_context(ring, to, hw_flags); @@ -405,9 +405,9 @@ static int do_switch(struct i915_hw_context *to) * is a bit suboptimal because the retiring can occur simply after the * MI_SET_CONTEXT instead of when the next seqno has completed. */ - if (from_obj != NULL) { - from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; - i915_gem_object_move_to_active(from_obj, ring); + if (from != NULL) { + from->obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; + i915_gem_object_move_to_active(from->obj, ring); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the * whole damn pipeline, we don't need to explicitly mark the * object dirty. The only exception is that the context must be @@ -415,15 +415,26 @@ static int do_switch(struct i915_hw_context *to) * able to defer doing this until we know the object would be * swapped, but there is no way to do that yet. */ - from_obj->dirty = 1; - BUG_ON(from_obj->ring != ring); - i915_gem_object_unpin(from_obj); + from->obj->dirty = 1; + BUG_ON(from->obj->ring != ring); + + ret = i915_add_request(ring, NULL, NULL); + if (ret) { + /* Too late, we've already scheduled a context switch. + * Try to undo the change so that the hw state is + * consistent with out tracking. In case of emergency, + * scream. + */ + WARN_ON(mi_set_context(ring, from, MI_RESTORE_INHIBIT)); + return ret; + } - drm_gem_object_unreference(&from_obj->base); + i915_gem_object_unpin(from->obj); + i915_gem_context_unreference(from); } - drm_gem_object_reference(&to->obj->base); - ring->last_context_obj = to->obj; + i915_gem_context_reference(to); + ring->last_context = to; to->is_initialized = true; return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d66208c2c48b..dac1614a1bca 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -135,7 +135,7 @@ struct intel_ring_buffer { */ bool itlb_before_ctx_switch; struct i915_hw_context *default_context; - struct drm_i915_gem_object *last_context_obj; + struct i915_hw_context *last_context; void *private; }; -- cgit v1.2.3 From 0e50e96bf2d89c3415cb68aead301f485938f1ca Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 2 May 2013 16:48:08 +0300 Subject: drm/i915: add context into request struct Storing context reference into request struct allows us to inspect context and its associated objects when requests are retired. Both ppgtt and arb robustness work will need this. Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem.c | 24 ++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3ac71db78e9e..ca0b0ce6e276 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1270,6 +1270,9 @@ struct drm_i915_gem_request { /** Postion in the ringbuffer of the end of the request */ u32 tail; + /** Context related to this request */ + struct i915_hw_context *ctx; + /** Time at which this request was emitted, in jiffies. */ unsigned long emitted_jiffies; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6be940effefd..8a81d1a21050 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2042,6 +2042,11 @@ i915_add_request(struct intel_ring_buffer *ring, request->seqno = intel_ring_get_seqno(ring); request->ring = ring; request->tail = request_ring_position; + request->ctx = ring->last_context; + + if (request->ctx) + i915_gem_context_reference(request->ctx); + request->emitted_jiffies = jiffies; was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); @@ -2094,6 +2099,17 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) spin_unlock(&file_priv->mm.lock); } +static void i915_gem_free_request(struct drm_i915_gem_request *request) +{ + list_del(&request->list); + i915_gem_request_remove_from_client(request); + + if (request->ctx) + i915_gem_context_unreference(request->ctx); + + kfree(request); +} + static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct intel_ring_buffer *ring) { @@ -2104,9 +2120,7 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct drm_i915_gem_request, list); - list_del(&request->list); - i915_gem_request_remove_from_client(request); - kfree(request); + i915_gem_free_request(request); } while (!list_empty(&ring->active_list)) { @@ -2198,9 +2212,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) */ ring->last_retired_head = request->tail; - list_del(&request->list); - i915_gem_request_remove_from_client(request); - kfree(request); + i915_gem_free_request(request); } /* Move any buffers on the active list that are no longer referenced -- cgit v1.2.3 From 4d8a62eac3caad710ef030aab25248d56693a8f1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:51 +0200 Subject: drm/i915: fix up adjusted_mode tracking for interlaced modes With the hw state readout&check code it's important that the values we keep around are the canonical ones. Unfortunately when adding the pipe timings readout support I've missed that the write side adjusts the timings in the pipe config. Fix this up and so prevent the unsightly WARN noise in dmesg. This regression has been introduced in commit 1bd1bd806037af04dd1d7bdd39b2b04090c10d2c Author: Daniel Vetter Date: Mon Apr 29 21:56:12 2013 +0200 drm/i915: hw state readout support for pipe timings Reported-by: Paulo Zanoni Cc: Mika Kuoppala Reviewed-by: Paulo Zanoni Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index de8be7595a62..3a691a13f9e6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4675,12 +4675,17 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; - uint32_t vsyncshift; + uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end; + + /* We need to be careful not to changed the adjusted mode, for otherwise + * the hw state checker will get angry at the mismatch. */ + crtc_vtotal = adjusted_mode->crtc_vtotal; + crtc_vblank_end = adjusted_mode->crtc_vblank_end; if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { /* the chip adds 2 halflines automatically */ - adjusted_mode->crtc_vtotal -= 1; - adjusted_mode->crtc_vblank_end -= 1; + crtc_vtotal -= 1; + crtc_vblank_end -= 1; vsyncshift = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_htotal / 2; } else { @@ -4702,10 +4707,10 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, I915_WRITE(VTOTAL(cpu_transcoder), (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); + ((crtc_vtotal - 1) << 16)); I915_WRITE(VBLANK(cpu_transcoder), (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); + ((crtc_vblank_end - 1) << 16)); I915_WRITE(VSYNC(cpu_transcoder), (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); -- cgit v1.2.3 From ab9412ba06484cdfd82bdb748689024efe2221fe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:46 +0200 Subject: drm/i915: s/TRANSCONF/PCH_TRANSCONF/ Every time I read hsw code I get completely confused about this. So call it what it is more explicitly. Also, add an LPT_TRANSCONF for the pch transcoder A and use it in lpt-only code, to really unconfuse me. v2: s/plane/pipe/ in the TRANSCONF #define (Paulo). Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 ++++--- drivers/gpu/drm/i915/i915_ums.c | 8 ++++---- drivers/gpu/drm/i915/intel_display.c | 30 +++++++++++++++--------------- 3 files changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aec569f13186..fd5601998982 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4060,9 +4060,10 @@ #define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2) #define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2) -#define _TRANSACONF 0xf0008 -#define _TRANSBCONF 0xf1008 -#define TRANSCONF(plane) _PIPE(plane, _TRANSACONF, _TRANSBCONF) +#define _PCH_TRANSACONF 0xf0008 +#define _PCH_TRANSBCONF 0xf1008 +#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF) +#define LPT_TRANSCONF _PCH_TRANSACONF /* lpt has only one transcoder */ #define TRANS_DISABLE (0<<31) #define TRANS_ENABLE (1<<31) #define TRANS_STATE_MASK (1<<30) diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 985a09716237..75960dd81b5a 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -148,7 +148,7 @@ void i915_save_display_reg(struct drm_device *dev) dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); - dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF); + dev_priv->regfile.saveTRANSACONF = I915_READ(_PCH_TRANSACONF); dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); @@ -205,7 +205,7 @@ void i915_save_display_reg(struct drm_device *dev) dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); - dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF); + dev_priv->regfile.saveTRANSBCONF = I915_READ(_PCH_TRANSBCONF); dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); @@ -379,7 +379,7 @@ void i915_restore_display_reg(struct drm_device *dev) I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ); I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); - I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF); + I915_WRITE(_PCH_TRANSACONF, dev_priv->regfile.saveTRANSACONF); I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); @@ -448,7 +448,7 @@ void i915_restore_display_reg(struct drm_device *dev) I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ); I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); - I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); + I915_WRITE(_PCH_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3a691a13f9e6..d2dfe90213af 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1206,14 +1206,14 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); } -static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe) +static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) { int reg; u32 val; bool enabled; - reg = TRANSCONF(pipe); + reg = PCH_TRANSCONF(pipe); val = I915_READ(reg); enabled = !!(val & TRANS_ENABLE); WARN(enabled, @@ -1565,7 +1565,7 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); /* Make sure transcoder isn't still depending on us */ - assert_transcoder_disabled(dev_priv, intel_crtc->pipe); + assert_pch_transcoder_disabled(dev_priv, intel_crtc->pipe); reg = pll->pll_reg; val = I915_READ(reg); @@ -1605,7 +1605,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, I915_WRITE(reg, val); } - reg = TRANSCONF(pipe); + reg = PCH_TRANSCONF(pipe); val = I915_READ(reg); pipeconf_val = I915_READ(PIPECONF(pipe)); @@ -1659,8 +1659,8 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, else val |= TRANS_PROGRESSIVE; - I915_WRITE(TRANSCONF(TRANSCODER_A), val); - if (wait_for(I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE, 100)) + I915_WRITE(LPT_TRANSCONF, val); + if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100)) DRM_ERROR("Failed to enable PCH transcoder\n"); } @@ -1677,7 +1677,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, /* Ports must be off as well */ assert_pch_ports_disabled(dev_priv, pipe); - reg = TRANSCONF(pipe); + reg = PCH_TRANSCONF(pipe); val = I915_READ(reg); val &= ~TRANS_ENABLE; I915_WRITE(reg, val); @@ -1698,11 +1698,11 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv) { u32 val; - val = I915_READ(_TRANSACONF); + val = I915_READ(LPT_TRANSCONF); val &= ~TRANS_ENABLE; - I915_WRITE(_TRANSACONF, val); + I915_WRITE(LPT_TRANSCONF, val); /* wait for PCH transcoder off, transcoder state */ - if (wait_for((I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE) == 0, 50)) + if (wait_for((I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE) == 0, 50)) DRM_ERROR("Failed to disable PCH transcoder\n"); /* Workaround: clear timing override bit. */ @@ -3011,7 +3011,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - assert_transcoder_disabled(dev_priv, pipe); + assert_pch_transcoder_disabled(dev_priv, pipe); /* Write the TU size bits before fdi link training, so that error * detection works. */ @@ -3115,7 +3115,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; - assert_transcoder_disabled(dev_priv, TRANSCODER_A); + assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A); lpt_program_iclkip(crtc); @@ -5894,7 +5894,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, if (!(tmp & PIPECONF_ENABLE)) return false; - if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { + if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { pipe_config->has_pch_encoder = true; tmp = I915_READ(FDI_RX_CTL(crtc->pipe)); @@ -6042,7 +6042,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, */ tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && - I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) { + I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) { pipe_config->has_pch_encoder = true; tmp = I915_READ(FDI_RX_CTL(PIPE_A)); -- cgit v1.2.3 From 275f01b2694a52d13c32358d17d594ec9aba55e3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:47 +0200 Subject: drm/i915: PCH_ prefix for transcoder timings While at it, also extract a common helper to copy the timings from the cpu transcoder to the pch transcoder. That way it's really explicit how the lpt transcoder is hardcoded. v2: - Re-align #defines properly (Paulo). - Use cpu_transcoder when copying pipe timings (Paulo). - s/intel_pch_transcoder_enable/intel_pch_transcoder_set_timings/ since we already have a pch transcoder enable function, and this is clearer, too. - Fixup 80 char line overflow in intel_display.c. I've opted to ignore this in i915_reg.h and i915_ums.c since meh. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 70 ++++++++++++++++++------------------ drivers/gpu/drm/i915/i915_ums.c | 48 ++++++++++++------------- drivers/gpu/drm/i915/intel_display.c | 42 +++++++++++++--------- 3 files changed, 85 insertions(+), 75 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fd5601998982..e888fcca6ee6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3929,25 +3929,25 @@ /* transcoder */ -#define _TRANS_HTOTAL_A 0xe0000 -#define TRANS_HTOTAL_SHIFT 16 -#define TRANS_HACTIVE_SHIFT 0 -#define _TRANS_HBLANK_A 0xe0004 -#define TRANS_HBLANK_END_SHIFT 16 -#define TRANS_HBLANK_START_SHIFT 0 -#define _TRANS_HSYNC_A 0xe0008 -#define TRANS_HSYNC_END_SHIFT 16 -#define TRANS_HSYNC_START_SHIFT 0 -#define _TRANS_VTOTAL_A 0xe000c -#define TRANS_VTOTAL_SHIFT 16 -#define TRANS_VACTIVE_SHIFT 0 -#define _TRANS_VBLANK_A 0xe0010 -#define TRANS_VBLANK_END_SHIFT 16 -#define TRANS_VBLANK_START_SHIFT 0 -#define _TRANS_VSYNC_A 0xe0014 -#define TRANS_VSYNC_END_SHIFT 16 -#define TRANS_VSYNC_START_SHIFT 0 -#define _TRANS_VSYNCSHIFT_A 0xe0028 +#define _PCH_TRANS_HTOTAL_A 0xe0000 +#define TRANS_HTOTAL_SHIFT 16 +#define TRANS_HACTIVE_SHIFT 0 +#define _PCH_TRANS_HBLANK_A 0xe0004 +#define TRANS_HBLANK_END_SHIFT 16 +#define TRANS_HBLANK_START_SHIFT 0 +#define _PCH_TRANS_HSYNC_A 0xe0008 +#define TRANS_HSYNC_END_SHIFT 16 +#define TRANS_HSYNC_START_SHIFT 0 +#define _PCH_TRANS_VTOTAL_A 0xe000c +#define TRANS_VTOTAL_SHIFT 16 +#define TRANS_VACTIVE_SHIFT 0 +#define _PCH_TRANS_VBLANK_A 0xe0010 +#define TRANS_VBLANK_END_SHIFT 16 +#define TRANS_VBLANK_START_SHIFT 0 +#define _PCH_TRANS_VSYNC_A 0xe0014 +#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_START_SHIFT 0 +#define _PCH_TRANS_VSYNCSHIFT_A 0xe0028 #define _TRANSA_DATA_M1 0xe0030 #define _TRANSA_DATA_N1 0xe0034 @@ -4025,22 +4025,22 @@ #define HSW_TVIDEO_DIP_VSC_DATA(trans) \ _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B) -#define _TRANS_HTOTAL_B 0xe1000 -#define _TRANS_HBLANK_B 0xe1004 -#define _TRANS_HSYNC_B 0xe1008 -#define _TRANS_VTOTAL_B 0xe100c -#define _TRANS_VBLANK_B 0xe1010 -#define _TRANS_VSYNC_B 0xe1014 -#define _TRANS_VSYNCSHIFT_B 0xe1028 - -#define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B) -#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B) -#define TRANS_HSYNC(pipe) _PIPE(pipe, _TRANS_HSYNC_A, _TRANS_HSYNC_B) -#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B) -#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B) -#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B) -#define TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _TRANS_VSYNCSHIFT_A, \ - _TRANS_VSYNCSHIFT_B) +#define _PCH_TRANS_HTOTAL_B 0xe1000 +#define _PCH_TRANS_HBLANK_B 0xe1004 +#define _PCH_TRANS_HSYNC_B 0xe1008 +#define _PCH_TRANS_VTOTAL_B 0xe100c +#define _PCH_TRANS_VBLANK_B 0xe1010 +#define _PCH_TRANS_VSYNC_B 0xe1014 +#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028 + +#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B) +#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B) +#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B) +#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B) +#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B) +#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B) +#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \ + _PCH_TRANS_VSYNCSHIFT_B) #define _TRANSB_DATA_M1 0xe1030 #define _TRANSB_DATA_N1 0xe1034 diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 75960dd81b5a..4168d2b6b4f1 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -149,12 +149,12 @@ void i915_save_display_reg(struct drm_device *dev) dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); dev_priv->regfile.saveTRANSACONF = I915_READ(_PCH_TRANSACONF); - dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); - dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); - dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); - dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); - dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); - dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); + dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_PCH_TRANS_HTOTAL_A); + dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_PCH_TRANS_HBLANK_A); + dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_PCH_TRANS_HSYNC_A); + dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_PCH_TRANS_VTOTAL_A); + dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_PCH_TRANS_VBLANK_A); + dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_PCH_TRANS_VSYNC_A); } dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR); @@ -206,12 +206,12 @@ void i915_save_display_reg(struct drm_device *dev) dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); dev_priv->regfile.saveTRANSBCONF = I915_READ(_PCH_TRANSBCONF); - dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); - dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); - dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); - dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); - dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); - dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); + dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_PCH_TRANS_HTOTAL_B); + dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_PCH_TRANS_HBLANK_B); + dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_PCH_TRANS_HSYNC_B); + dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_PCH_TRANS_VTOTAL_B); + dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_PCH_TRANS_VBLANK_B); + dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_PCH_TRANS_VSYNC_B); } dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR); @@ -380,12 +380,12 @@ void i915_restore_display_reg(struct drm_device *dev) I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); I915_WRITE(_PCH_TRANSACONF, dev_priv->regfile.saveTRANSACONF); - I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); - I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); - I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); - I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); - I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); - I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); + I915_WRITE(_PCH_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); + I915_WRITE(_PCH_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); + I915_WRITE(_PCH_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); + I915_WRITE(_PCH_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); + I915_WRITE(_PCH_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); + I915_WRITE(_PCH_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); } /* Restore plane info */ @@ -449,12 +449,12 @@ void i915_restore_display_reg(struct drm_device *dev) I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); I915_WRITE(_PCH_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); - I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); - I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); - I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); - I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); - I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); - I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); + I915_WRITE(_PCH_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); + I915_WRITE(_PCH_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); + I915_WRITE(_PCH_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); + I915_WRITE(_PCH_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); + I915_WRITE(_PCH_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); + I915_WRITE(_PCH_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); } /* Restore plane info */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d2dfe90213af..9f755fd5cd1c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2995,6 +2995,30 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) mutex_unlock(&dev_priv->dpio_lock); } +static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, + enum pipe pch_transcoder) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; + + I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder), + I915_READ(HTOTAL(cpu_transcoder))); + I915_WRITE(PCH_TRANS_HBLANK(pch_transcoder), + I915_READ(HBLANK(cpu_transcoder))); + I915_WRITE(PCH_TRANS_HSYNC(pch_transcoder), + I915_READ(HSYNC(cpu_transcoder))); + + I915_WRITE(PCH_TRANS_VTOTAL(pch_transcoder), + I915_READ(VTOTAL(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VBLANK(pch_transcoder), + I915_READ(VBLANK(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VSYNC(pch_transcoder), + I915_READ(VSYNC(cpu_transcoder))); + I915_WRITE(PCH_TRANS_VSYNCSHIFT(pch_transcoder), + I915_READ(VSYNCSHIFT(cpu_transcoder))); +} + /* * Enable PCH resources required for PCH ports: * - PCH PLLs @@ -3058,14 +3082,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) /* set transcoder timing, panel must allow it */ assert_panel_unlocked(dev_priv, pipe); - I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe))); - I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe))); - I915_WRITE(TRANS_HSYNC(pipe), I915_READ(HSYNC(pipe))); - - I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe))); - I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe))); - I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe))); - I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe))); + ironlake_pch_transcoder_set_timings(intel_crtc, pipe); intel_fdi_normal_train(crtc); @@ -3120,14 +3137,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc) lpt_program_iclkip(crtc); /* Set transcoder timing. */ - I915_WRITE(_TRANS_HTOTAL_A, I915_READ(HTOTAL(cpu_transcoder))); - I915_WRITE(_TRANS_HBLANK_A, I915_READ(HBLANK(cpu_transcoder))); - I915_WRITE(_TRANS_HSYNC_A, I915_READ(HSYNC(cpu_transcoder))); - - I915_WRITE(_TRANS_VTOTAL_A, I915_READ(VTOTAL(cpu_transcoder))); - I915_WRITE(_TRANS_VBLANK_A, I915_READ(VBLANK(cpu_transcoder))); - I915_WRITE(_TRANS_VSYNC_A, I915_READ(VSYNC(cpu_transcoder))); - I915_WRITE(_TRANS_VSYNCSHIFT_A, I915_READ(VSYNCSHIFT(cpu_transcoder))); + ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A); lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } -- cgit v1.2.3 From b551842d4d92cd337cc2af27947cc53e09fe34ab Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:48 +0200 Subject: drm/i915: make set_m_n functions static This is possible thanks to moving the m/n stuff into pipe_config. Unfortunately we need to move them a bit to avoid forward declarations. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 68 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 4 --- 2 files changed, 34 insertions(+), 38 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9f755fd5cd1c..4f74a7f55183 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4382,6 +4382,40 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv) intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); } +static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n); + I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m); + I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n); +} + +static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, + struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + enum transcoder transcoder = crtc->config.cpu_transcoder; + + if (INTEL_INFO(dev)->gen >= 5) { + I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); + I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); + } else { + I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n); + I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m); + I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n); + } +} + static void intel_dp_set_m_n(struct intel_crtc *crtc) { if (crtc->config.has_pch_encoder) @@ -5606,40 +5640,6 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) return bps / (link_bw * 8) + 1; } -void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe = crtc->pipe; - - I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n); - I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m); - I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n); -} - -void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe = crtc->pipe; - enum transcoder transcoder = crtc->config.cpu_transcoder; - - if (INTEL_INFO(dev)->gen >= 5) { - I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n); - I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); - I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); - } else { - I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n); - I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m); - I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n); - } -} - static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor) { return i9xx_dpll_compute_m(dpll) < factor * dpll->n; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index dfcf546790bc..88890a30f356 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -719,10 +719,6 @@ extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); -extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n); -extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, - struct intel_link_m_n *m_n); extern void intel_prepare_ddi(struct drm_device *dev); extern void hsw_fdi_link_train(struct drm_crtc *crtc); extern void intel_ddi_init(struct drm_device *dev, enum port port); -- cgit v1.2.3 From e3b95f1eb5b9a7ecc7241a27499ae8754b845926 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:49 +0200 Subject: drm/i915: Apply OCD to data/link m/n register #defines - PCH_ prefix for pch registers on ibx/cpt/ppt. - Drop the DP_ from the link defines, redundant. - Drop the GMCH from the data defines and instead give the special g4x registers a consistent _G4X postfix. v2: - Realign #defines and use tabs (Paulo). Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 74 ++++++++++++++++++------------------ drivers/gpu/drm/i915/i915_ums.c | 32 ++++++++-------- drivers/gpu/drm/i915/intel_display.c | 16 ++++---- 3 files changed, 61 insertions(+), 61 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e888fcca6ee6..a47010331e72 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2768,8 +2768,8 @@ * which is after the LUTs, so we want the bytes for our color format. * For our current usage, this is always 3, one byte for R, G and B. */ -#define _PIPEA_GMCH_DATA_M 0x70050 -#define _PIPEB_GMCH_DATA_M 0x71050 +#define _PIPEA_DATA_M_G4X 0x70050 +#define _PIPEB_DATA_M_G4X 0x71050 /* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ #define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) @@ -2778,8 +2778,8 @@ #define PIPE_GMCH_DATA_M_MASK (0xffffff) -#define _PIPEA_GMCH_DATA_N 0x70054 -#define _PIPEB_GMCH_DATA_N 0x71054 +#define _PIPEA_DATA_N_G4X 0x70054 +#define _PIPEB_DATA_N_G4X 0x71054 #define PIPE_GMCH_DATA_N_MASK (0xffffff) /* @@ -2793,18 +2793,18 @@ * Attributes and VB-ID. */ -#define _PIPEA_DP_LINK_M 0x70060 -#define _PIPEB_DP_LINK_M 0x71060 +#define _PIPEA_LINK_M_G4X 0x70060 +#define _PIPEB_LINK_M_G4X 0x71060 #define PIPEA_DP_LINK_M_MASK (0xffffff) -#define _PIPEA_DP_LINK_N 0x70064 -#define _PIPEB_DP_LINK_N 0x71064 +#define _PIPEA_LINK_N_G4X 0x70064 +#define _PIPEB_LINK_N_G4X 0x71064 #define PIPEA_DP_LINK_N_MASK (0xffffff) -#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) -#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) -#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M) -#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N) +#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X) +#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X) +#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X) +#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X) /* Display & cursor control */ @@ -3949,14 +3949,14 @@ #define TRANS_VSYNC_START_SHIFT 0 #define _PCH_TRANS_VSYNCSHIFT_A 0xe0028 -#define _TRANSA_DATA_M1 0xe0030 -#define _TRANSA_DATA_N1 0xe0034 -#define _TRANSA_DATA_M2 0xe0038 -#define _TRANSA_DATA_N2 0xe003c -#define _TRANSA_DP_LINK_M1 0xe0040 -#define _TRANSA_DP_LINK_N1 0xe0044 -#define _TRANSA_DP_LINK_M2 0xe0048 -#define _TRANSA_DP_LINK_N2 0xe004c +#define _PCH_TRANSA_DATA_M1 0xe0030 +#define _PCH_TRANSA_DATA_N1 0xe0034 +#define _PCH_TRANSA_DATA_M2 0xe0038 +#define _PCH_TRANSA_DATA_N2 0xe003c +#define _PCH_TRANSA_LINK_M1 0xe0040 +#define _PCH_TRANSA_LINK_N1 0xe0044 +#define _PCH_TRANSA_LINK_M2 0xe0048 +#define _PCH_TRANSA_LINK_N2 0xe004c /* Per-transcoder DIP controls */ @@ -4042,23 +4042,23 @@ #define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \ _PCH_TRANS_VSYNCSHIFT_B) -#define _TRANSB_DATA_M1 0xe1030 -#define _TRANSB_DATA_N1 0xe1034 -#define _TRANSB_DATA_M2 0xe1038 -#define _TRANSB_DATA_N2 0xe103c -#define _TRANSB_DP_LINK_M1 0xe1040 -#define _TRANSB_DP_LINK_N1 0xe1044 -#define _TRANSB_DP_LINK_M2 0xe1048 -#define _TRANSB_DP_LINK_N2 0xe104c - -#define TRANSDATA_M1(pipe) _PIPE(pipe, _TRANSA_DATA_M1, _TRANSB_DATA_M1) -#define TRANSDATA_N1(pipe) _PIPE(pipe, _TRANSA_DATA_N1, _TRANSB_DATA_N1) -#define TRANSDATA_M2(pipe) _PIPE(pipe, _TRANSA_DATA_M2, _TRANSB_DATA_M2) -#define TRANSDATA_N2(pipe) _PIPE(pipe, _TRANSA_DATA_N2, _TRANSB_DATA_N2) -#define TRANSDPLINK_M1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M1, _TRANSB_DP_LINK_M1) -#define TRANSDPLINK_N1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N1, _TRANSB_DP_LINK_N1) -#define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2) -#define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2) +#define _PCH_TRANSB_DATA_M1 0xe1030 +#define _PCH_TRANSB_DATA_N1 0xe1034 +#define _PCH_TRANSB_DATA_M2 0xe1038 +#define _PCH_TRANSB_DATA_N2 0xe103c +#define _PCH_TRANSB_LINK_M1 0xe1040 +#define _PCH_TRANSB_LINK_N1 0xe1044 +#define _PCH_TRANSB_LINK_M2 0xe1048 +#define _PCH_TRANSB_LINK_N2 0xe104c + +#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1) +#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1) +#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2) +#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2) +#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1) +#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1) +#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2) +#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2) #define _PCH_TRANSACONF 0xf0008 #define _PCH_TRANSBCONF 0xf1008 diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 4168d2b6b4f1..5ef30b2e6bc6 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -259,14 +259,14 @@ void i915_save_display_reg(struct drm_device *dev) dev_priv->regfile.saveDP_B = I915_READ(DP_B); dev_priv->regfile.saveDP_C = I915_READ(DP_C); dev_priv->regfile.saveDP_D = I915_READ(DP_D); - dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); - dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); - dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); - dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); - dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); - dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); - dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); - dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); + dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_DATA_M_G4X); + dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_DATA_M_G4X); + dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_DATA_N_G4X); + dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_DATA_N_G4X); + dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_LINK_M_G4X); + dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_LINK_M_G4X); + dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_LINK_N_G4X); + dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_LINK_N_G4X); } /* FIXME: regfile.save TV & SDVO state */ @@ -282,14 +282,14 @@ void i915_restore_display_reg(struct drm_device *dev) /* Display port ratios (must be done before clock is set) */ if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); + I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_DATA_M_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_DATA_N_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_DATA_N_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_LINK_M_G4X, dev_priv->regfile.savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_LINK_M_G4X, dev_priv->regfile.savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_LINK_N_G4X, dev_priv->regfile.savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_LINK_N_G4X, dev_priv->regfile.savePIPEB_DP_LINK_N); } /* Fences */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4f74a7f55183..c48bb76c055c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4389,10 +4389,10 @@ static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; int pipe = crtc->pipe; - I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n); - I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m); - I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n); + I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n); + I915_WRITE(PCH_TRANS_LINK_M1(pipe), m_n->link_m); + I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n); } static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, @@ -4409,10 +4409,10 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m); I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n); } else { - I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); - I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n); - I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m); - I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n); + I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M_G4X(pipe), m_n->link_m); + I915_WRITE(PIPE_LINK_N_G4X(pipe), m_n->link_n); } } -- cgit v1.2.3 From a1520318a51d6c21b1d9229a9c35b4fcb890b175 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 May 2013 11:49:50 +0200 Subject: drm/i915: make intel_cpt_verify_modeset static Only one caller. Also drop the intel_ prefix as is now customary for platform specific and static functions. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c48bb76c055c..d50994a22966 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3229,7 +3229,7 @@ prepare: /* separate function? */ return pll; } -void intel_cpt_verify_modeset(struct drm_device *dev, int pipe) +static void cpt_verify_modeset(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; int dslreg = PIPEDSL(pipe); @@ -3334,7 +3334,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) encoder->enable(encoder); if (HAS_PCH_CPT(dev)) - intel_cpt_verify_modeset(dev, intel_crtc->pipe); + cpt_verify_modeset(dev, intel_crtc->pipe); /* * There seems to be a race in PCH platform hw (at least on some diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 88890a30f356..e3108c0966c3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -718,7 +718,6 @@ extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); -extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); extern void intel_prepare_ddi(struct drm_device *dev); extern void hsw_fdi_link_train(struct drm_crtc *crtc); extern void intel_ddi_init(struct drm_device *dev, enum port port); -- cgit v1.2.3 From 186507e9e8e89d5920305fdffd8cbba6366da795 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 23 Apr 2013 23:15:29 -0700 Subject: drm/i915: Assert mutex_is_locked on context lookup Because our context refcounting doesn't grab a ref at lookup time, it is unsafe to do so without the lock. NOTE: We don't have an easy way to put the assertion in the lookup function which is where this really belongs. Context switching is good enough because it actually asserts even more correctness by protecting the default_context. Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes [danvet: s/BUG/WARN/] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index efa0ede5c679..c81ae52c8c2e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -463,6 +463,8 @@ int i915_switch_context(struct intel_ring_buffer *ring, if (dev_priv->hw_contexts_disabled) return 0; + WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + if (ring != &dev_priv->ring[RCS]) return 0; -- cgit v1.2.3 From 0a73287060cdd8fc2b50ecd216c918c2d097de59 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 23 Apr 2013 23:15:30 -0700 Subject: drm/i915: BUG_ON bad PPGTT offset Because PPGTT PDEs within the GTT are calculated in cachelines (HW guys consistency ftw) we do a divide which will wreak havoc if this is wrong, and I know that from experience). If/when we move to multiple PPGTTs this will have to become a WARN, and return an error. For now however it should always be considered fatal, and only a developer could hit it. Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes [danvet: s/BUG/WARN] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ce024bd18eac..a4f0f9519503 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -110,6 +110,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev) uint32_t pd_entry; int i; + WARN_ON(ppgtt->pd_offset & 0x3f); + pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { -- cgit v1.2.3 From 3e302542055617703b260489ec1ff6fc6f1e68cd Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 23 Apr 2013 23:15:32 -0700 Subject: drm/i915: Extract PDE writes It also makes some sense IMO to have these two functions separate irrespective of the number of callers. Only the single caller for now, but that will change as we add more PPGTTs. Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes [danvet: Resolve conflict.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a4f0f9519503..85b3d5d4deec 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -100,18 +100,14 @@ static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev, return pte; } -static int gen6_ppgtt_enable(struct drm_device *dev) +static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) { - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t pd_offset; - struct intel_ring_buffer *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + struct drm_i915_private *dev_priv = ppgtt->dev->dev_private; gen6_gtt_pte_t __iomem *pd_addr; uint32_t pd_entry; int i; WARN_ON(ppgtt->pd_offset & 0x3f); - pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { @@ -124,6 +120,19 @@ static int gen6_ppgtt_enable(struct drm_device *dev) writel(pd_entry, pd_addr + i); } readl(pd_addr); +} + +static int gen6_ppgtt_enable(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t pd_offset; + struct intel_ring_buffer *ring; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + int i; + + BUG_ON(ppgtt->pd_offset & 0x3f); + + gen6_write_pdes(ppgtt); pd_offset = ppgtt->pd_offset; pd_offset /= 64; /* in cachelines, */ -- cgit v1.2.3 From 8f375e10ee47b9d7b9b3aefcf67854c6e92708be Mon Sep 17 00:00:00 2001 From: Jan-Simon Möller Date: Mon, 6 May 2013 14:52:08 +0200 Subject: drm/i915: Fix declaration of intel_gmbus_{is_forced_bit/is_port_falid} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description: intel_gmbus_is_forced_bit is no extern as its body is right below. Likewise for intel_gmbus_is_port_valid. This fixes a compilation issue with clang. An initial version of this patch was developed by PaX Team . This is respin of this patch. 20130509: v2: (re-)add inline upon request. Signed-off-by: Jan-Simon Möller CC: pageexec@freemail.hu CC: daniel.vetter@ffwll.ch CC: airlied@linux.ie CC: intel-gfx@lists.freedesktop.org CC: dri-devel@lists.freedesktop.org CC: linux-kernel@vger.kernel.org [danvet: Bikeshed commit message.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ca0b0ce6e276..729f5b67f53c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1809,7 +1809,7 @@ void i915_teardown_sysfs(struct drm_device *dev_priv); /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); -extern inline bool intel_gmbus_is_port_valid(unsigned port) +static inline bool intel_gmbus_is_port_valid(unsigned port) { return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD); } @@ -1818,7 +1818,7 @@ extern struct i2c_adapter *intel_gmbus_get_adapter( struct drm_i915_private *dev_priv, unsigned port); extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed); extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit); -extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) +static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) { return container_of(adapter, struct intel_gmbus, adapter)->force_bit; } -- cgit v1.2.3 From 177006a10b33c9bd729cd60be0a37b41a23e4df3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 2 May 2013 10:48:07 -0700 Subject: drm/i915: read current freq from Punit on VLV Instead of returning the cached value, which is just what the kernel requested. Reviewed-by: Kenneth Graunke Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index ca00df2de07b..c0d7875b475c 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -212,10 +212,13 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, int ret; mutex_lock(&dev_priv->rps.hw_lock); - if (IS_VALLEYVIEW(dev_priv->dev)) - ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay); - else + if (IS_VALLEYVIEW(dev_priv->dev)) { + u32 freq; + valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq); + ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff); + } else { ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; + } mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); -- cgit v1.2.3 From 2445966ee80837116498bd83084ad6d28272320c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 2 May 2013 10:48:08 -0700 Subject: drm/i915: go back to switch for VLV mem freq detection v2 Both the docs and the existing code were wrong. So fix both and use a switch statement like we do elsewhere to make things simple & clear. Signed-off-by: Jesse Barnes Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0f4b46e94932..556b9892bb92 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2902,7 +2902,18 @@ static void valleyview_enable_rps(struct drm_device *dev) GEN7_RC_CTL_TO_MODE); valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val); - dev_priv->mem_freq = 800 + (266 * (val >> 6) & 3); + switch ((val >> 6) & 3) { + case 0: + case 1: + dev_priv->mem_freq = 800; + break; + case 2: + dev_priv->mem_freq = 1066; + break; + case 3: + dev_priv->mem_freq = 1333; + break; + } DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq); DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); -- cgit v1.2.3 From 0ef37f3f5e33eae7d6c388a7b374397794beca39 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 3 May 2013 13:26:37 -0700 Subject: drm/i915: fix panel fitting on LVDS on ILK+ v2 This regression was introduced in: commit b074cec8c652f2d273907a4b35239b4766c894ac Author: Jesse Barnes Date: Thu Apr 25 12:55:02 2013 -0700 drm/i915: move PCH pfit controls into pipe_config In refactoring this, it was only applied to eDP, which is incorrect. In fact, if we ever use the panel fitter to deal with overscan on HDMI, we'll need to extend it again, so just drop the conditional altogether. v2: drop check for eDP since we can use the fitter in any config (Daniel) Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d50994a22966..5491a58e5b37 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3249,8 +3249,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; int pipe = crtc->pipe; - if (crtc->config.pch_pfit.size && - intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) { + if (crtc->config.pch_pfit.size) { /* Force use of hard-coded filter coefficients * as some pre-programmed values are broken, * e.g. x201. -- cgit v1.2.3 From 7df5080bc7f3e3fba9cddac71133ed52864c40be Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 2 May 2013 10:48:09 -0700 Subject: drm/i915: set proper DPIO post divider for VGA on VLV v4 Supposedly we should use the DAC divider for <300MHz pixel clocks, but as that doesn't actually work as well as the high freq divider here in practice, just use the high freq divider all the time. v2: remove unconditional write (Jesse) check for pixel rate properly (Jesse) v3: give up, the DAC divider apparently doesn't work, and low res modes work ok (Jesse) remove debug msg (Jesse) Signed-off-by: Jesse Barnes Tested-by: Kenneth Graunke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5491a58e5b37..b9d5711c595c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4468,10 +4468,13 @@ static void vlv_update_pll(struct intel_crtc *crtc) mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); mdiv |= ((bestn << DPIO_N_SHIFT)); mdiv |= (1 << DPIO_K_SHIFT); - if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI) || - intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || - intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) - mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); + + /* + * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, + * but we don't support that). + * Note: don't use the DAC post divider as it seems unstable. + */ + mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; -- cgit v1.2.3 From b97186f0d94808ce94cd9b77b40e78f2fbd6e6b2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 12:15:36 -0300 Subject: drm/i915: add intel_display_power_enabled This should replace intel_using_power_well. The idea is that we're adding the requested power domain as an argument, so this might enable the code to look less platform-specific and also allows us to easily add new domains in case we need. v2: Add more domains to enum intel_display_power_domain v3: Even more domains requested Requested-by: Daniel Vetter Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 18 ++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 11 ++++++----- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_pm.c | 24 ++++++++++++++++++++---- 4 files changed, 46 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 729f5b67f53c..c81100c54e24 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -88,6 +88,24 @@ enum port { }; #define port_name(p) ((p) + 'A') +enum intel_display_power_domain { + POWER_DOMAIN_PIPE_A, + POWER_DOMAIN_PIPE_B, + POWER_DOMAIN_PIPE_C, + POWER_DOMAIN_PIPE_A_PANEL_FITTER, + POWER_DOMAIN_PIPE_B_PANEL_FITTER, + POWER_DOMAIN_PIPE_C_PANEL_FITTER, + POWER_DOMAIN_TRANSCODER_A, + POWER_DOMAIN_TRANSCODER_B, + POWER_DOMAIN_TRANSCODER_C, + POWER_DOMAIN_TRANSCODER_EDP = POWER_DOMAIN_TRANSCODER_A + 0xF, +}; + +#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A) +#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \ + ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER) +#define POWER_DOMAIN_TRANSCODER(tran) ((tran) + POWER_DOMAIN_TRANSCODER_A) + enum hpd_pin { HPD_NONE = 0, HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b9d5711c595c..c46f40d88d8e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1110,8 +1110,8 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - if (!intel_using_power_well(dev_priv->dev) && - cpu_transcoder != TRANSCODER_EDP) { + if (!intel_display_power_enabled(dev_priv->dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder))) { cur_state = false; } else { reg = PIPECONF(cpu_transcoder); @@ -3532,7 +3532,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) /* XXX: Once we have proper panel fitter state tracking implemented with * hardware state read/check support we should switch to only disable * the panel fitter when we know it's used. */ - if (intel_using_power_well(dev)) { + if (intel_display_power_enabled(dev, + POWER_DOMAIN_PIPE_PANEL_FITTER(pipe))) { I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); } @@ -6039,8 +6040,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; uint32_t tmp; - if (!intel_using_power_well(dev_priv->dev) && - cpu_transcoder != TRANSCODER_EDP) + if (!intel_display_power_enabled(dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder))) return false; tmp = I915_READ(PIPECONF(cpu_transcoder)); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e3108c0966c3..be9ad392b0e8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -754,7 +754,8 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); -extern bool intel_using_power_well(struct drm_device *dev); +extern bool intel_display_power_enabled(struct drm_device *dev, + enum intel_display_power_domain domain); extern void intel_init_power_well(struct drm_device *dev); extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 556b9892bb92..9b3e90e10ed7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4344,15 +4344,31 @@ void intel_init_clock_gating(struct drm_device *dev) * enable it, so check if it's enabled and also check if we've requested it to * be enabled. */ -bool intel_using_power_well(struct drm_device *dev) +bool intel_display_power_enabled(struct drm_device *dev, + enum intel_display_power_domain domain) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_HASWELL(dev)) + if (!HAS_POWER_WELL(dev)) + return true; + + switch (domain) { + case POWER_DOMAIN_PIPE_A: + case POWER_DOMAIN_TRANSCODER_EDP: + return true; + case POWER_DOMAIN_PIPE_B: + case POWER_DOMAIN_PIPE_C: + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + case POWER_DOMAIN_TRANSCODER_A: + case POWER_DOMAIN_TRANSCODER_B: + case POWER_DOMAIN_TRANSCODER_C: return I915_READ(HSW_PWR_WELL_DRIVER) == (HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE); - else - return true; + default: + BUG(); + } } void intel_set_power_well(struct drm_device *dev, bool enable) -- cgit v1.2.3 From ff57f1b095e7c3ad0720193cd341d8ac1c781156 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 12:15:37 -0300 Subject: drm/i915: add power well and cpu transcoder info to the error state We need to dump these registers if we want to properly interpret the others. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c46f40d88d8e..260545cc5049 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9756,6 +9756,9 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state) #include struct intel_display_error_state { + + u32 power_well_driver; + struct intel_cursor_error_state { u32 control; u32 position; @@ -9764,6 +9767,7 @@ struct intel_display_error_state { } cursor[I915_MAX_PIPES]; struct intel_pipe_error_state { + enum transcoder cpu_transcoder; u32 conf; u32 source; @@ -9798,8 +9802,12 @@ intel_display_capture_error_state(struct drm_device *dev) if (error == NULL) return NULL; + if (HAS_POWER_WELL(dev)) + error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); + for_each_pipe(i) { cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); + error->pipe[i].cpu_transcoder = cpu_transcoder; if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { error->cursor[i].control = I915_READ(CURCNTR(i)); @@ -9845,8 +9853,13 @@ intel_display_print_error_state(struct seq_file *m, int i; seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); + if (HAS_POWER_WELL(dev)) + seq_printf(m, "PWR_WELL_CTL2: %08x\n", + error->power_well_driver); for_each_pipe(i) { seq_printf(m, "Pipe [%d]:\n", i); + seq_printf(m, " CPU transcoder: %c\n", + transcoder_name(error->pipe[i].cpu_transcoder)); seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); seq_printf(m, " SRC: %08x\n", error->pipe[i].source); seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); -- cgit v1.2.3 From 12d217c795071bfee483158e1397c57e8dc3cb76 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 12:15:38 -0300 Subject: drm/i915: clear FPGA_DBG_RM_NOCLAIM when capturing error state In the error state function we read the registers without checking if the power well is on, so after doing this we have to clear the FPGA_DBG_RM_NOCLAIM bit to prevent the next I915_WRITE from detecting it and printing an error message. The first version of this patch was checking for the power well state and then avoiding reading registers that were off, but the reviewers requested to just read the registers any way and then later clear the FPGA_DBG_RM_NOCLAIM bit. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 260545cc5049..544d766f6ef3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9842,6 +9842,13 @@ intel_display_capture_error_state(struct drm_device *dev) error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder)); } + /* In the code above we read the registers without checking if the power + * well was on, so here we have to clear the FPGA_DBG_RM_NOCLAIM bit to + * prevent the next I915_WRITE from detecting it and printing an error + * message. */ + if (HAS_POWER_WELL(dev)) + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); + return error; } -- cgit v1.2.3 From 71f8ba6b7e44fc525fb15a60997c0c5064c160e6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 12:15:39 -0300 Subject: drm/i915: check the power well on i915_pipe_enabled This fixes "unclaimed register" messages when the power well is disabled and there's a GPU hang. v2: Use the new intel_display_power_enabled(). v3: Use the new domains for intel_display_power_enabled(). Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 03a31befa8fd..161101f42717 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -384,6 +384,10 @@ i915_pipe_enabled(struct drm_device *dev, int pipe) enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); + if (!intel_display_power_enabled(dev, + POWER_DOMAIN_TRANSCODER(cpu_transcoder))) + return false; + return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE; } -- cgit v1.2.3 From c77bf5659deb9405ef61080c148e47d2c8ee31e5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 12:15:40 -0300 Subject: drm/i915: only disable DDI sound if intel_crtc->eld_vld We already have the same check on intel_enable_ddi. This patch prevents "unclaimed register" messages when the power well is disabled. V2: Reset intel_crtc->eld_vld to false after the mode_set function. V3: Add both "type != INTEL_OUTPUT_EDP" requested. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 11 +++++++---- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index d7a33856a61a..3e946d3cd196 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1300,7 +1300,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) ironlake_edp_backlight_on(intel_dp); } - if (intel_crtc->eld_vld) { + if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); @@ -1318,9 +1318,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; - tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); - tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); - I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << + (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 544d766f6ef3..d0c5ecff6948 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3864,8 +3864,8 @@ static void intel_crtc_disable(struct drm_crtc *crtc) /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); - intel_crtc->eld_vld = false; dev_priv->display.crtc_disable(crtc); + intel_crtc->eld_vld = false; intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); -- cgit v1.2.3 From ecdb4eb71b8f76db2bf58c86af907e7b8ee056b0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 3 May 2013 18:48:10 +0100 Subject: drm/i915: Add platform information to implemented workarounds Signed-off-by: Damien Lespiau Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 ++-- drivers/gpu/drm/i915/intel_pm.c | 77 +++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 624cdfcc1ba3..40b57871a0bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1198,9 +1198,9 @@ MODULE_LICENSE("GPL and additional rights"); static void ilk_dummy_write(struct drm_i915_private *dev_priv) { - /* WaIssueDummyWriteToWakeupFromRC6: Issue a dummy write to wake up the - * chip from rc6 before touching it for real. MI_MODE is masked, hence - * harmless to write 0 into. */ + /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up + * the chip from rc6 before touching it for real. MI_MODE is masked, + * hence harmless to write 0 into. */ I915_WRITE_NOTRACE(MI_MODE, 0); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9b3e90e10ed7..f95b97cf4a0d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3808,7 +3808,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev) _3D_CHICKEN2_WM_READ_PIPELINED << 16 | _3D_CHICKEN2_WM_READ_PIPELINED); - /* WaDisableRenderCachePipelinedFlush */ + /* WaDisableRenderCachePipelinedFlush:ilk */ I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); @@ -3875,11 +3875,11 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_READ(ILK_DISPLAY_CHICKEN2) | ILK_ELPIN_409_SELECT); - /* WaDisableHiZPlanesWhenMSAAEnabled */ + /* WaDisableHiZPlanesWhenMSAAEnabled:snb */ I915_WRITE(_3D_CHICKEN, _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB)); - /* WaSetupGtModeTdRowDispatch */ + /* WaSetupGtModeTdRowDispatch:snb */ if (IS_SNB_GT1(dev)) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE)); @@ -3906,8 +3906,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) * According to the spec, bit 11 (RCCUNIT) must also be set, * but we didn't debug actual testcases to find it out. * - * Also apply WaDisableVDSUnitClockGating and - * WaDisableRCPBUnitClockGating. + * Also apply WaDisableVDSUnitClockGating:snb and + * WaDisableRCPBUnitClockGating:snb. */ I915_WRITE(GEN6_UCGCTL2, GEN7_VDSUNIT_CLOCK_GATE_DISABLE | @@ -3938,7 +3938,7 @@ static void gen6_init_clock_gating(struct drm_device *dev) ILK_DPARBUNIT_CLOCK_GATE_ENABLE | ILK_DPFDUNIT_CLOCK_GATE_ENABLE); - /* WaMbcDriverBootEnable */ + /* WaMbcDriverBootEnable:snb */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); @@ -3968,7 +3968,6 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; - /* WaVSRefCountFullforceMissDisable */ if (IS_HASWELL(dev_priv->dev)) reg &= ~GEN7_FF_VS_REF_CNT_FFME; @@ -3999,21 +3998,21 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_WRITE(WM1_LP_ILK, 0); /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. + * This implements the WaDisableRCZUnitClockGating:hsw workaround. */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + /* Apply the WaDisableRHWOOptimizationForRenderHang:hsw workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + /* WaApplyL3ControlAndL3ChickenMode:hsw */ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); - /* This is required by WaCatErrorRejectionIssue */ + /* This is required by WaCatErrorRejectionIssue:hsw */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); @@ -4025,17 +4024,18 @@ static void haswell_init_clock_gating(struct drm_device *dev) intel_flush_display_plane(dev_priv, pipe); } + /* WaVSRefCountFullforceMissDisable:hsw */ gen7_setup_fixed_func_scheduler(dev_priv); - /* WaDisable4x2SubspanOptimization */ + /* WaDisable4x2SubspanOptimization:hsw */ I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); - /* WaMbcDriverBootEnable */ + /* WaMbcDriverBootEnable:hsw */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); - /* WaSwitchSolVfFArbitrationPriority */ + /* WaSwitchSolVfFArbitrationPriority:hsw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); /* XXX: This is a workaround for early silicon revisions and should be @@ -4062,16 +4062,16 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); - /* WaDisableEarlyCull */ + /* WaDisableEarlyCull:ivb */ I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); - /* WaDisableBackToBackFlipFix */ + /* WaDisableBackToBackFlipFix:ivb */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); - /* WaDisablePSDDualDispatchEnable */ + /* WaDisablePSDDualDispatchEnable:ivb */ if (IS_IVB_GT1(dev)) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); @@ -4079,11 +4079,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2, _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + /* WaApplyL3ControlAndL3ChickenMode:ivb */ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, @@ -4096,7 +4096,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - /* WaForceL3Serialization */ + /* WaForceL3Serialization:ivb */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); @@ -4111,13 +4111,13 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) * but we didn't debug actual testcases to find it out. * * According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. + * This implements the WaDisableRCZUnitClockGating:ivb workaround. */ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE | GEN6_RCCUNIT_CLOCK_GATE_DISABLE); - /* This is required by WaCatErrorRejectionIssue */ + /* This is required by WaCatErrorRejectionIssue:ivb */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); @@ -4129,13 +4129,14 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) intel_flush_display_plane(dev_priv, pipe); } - /* WaMbcDriverBootEnable */ + /* WaMbcDriverBootEnable:ivb */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); + /* WaVSRefCountFullforceMissDisable:ivb */ gen7_setup_fixed_func_scheduler(dev_priv); - /* WaDisable4x2SubspanOptimization */ + /* WaDisable4x2SubspanOptimization:ivb */ I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); @@ -4161,46 +4162,46 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); - /* WaDisableEarlyCull */ + /* WaDisableEarlyCull:vlv */ I915_WRITE(_3D_CHICKEN3, _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL)); - /* WaDisableBackToBackFlipFix */ + /* WaDisableBackToBackFlipFix:vlv */ I915_WRITE(IVB_CHICKEN3, CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | CHICKEN3_DGMG_DONE_FIX_DISABLE); - /* WaDisablePSDDualDispatchEnable */ + /* WaDisablePSDDualDispatchEnable:vlv */ I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP | GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE)); - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + /* Apply the WaDisableRHWOOptimizationForRenderHang:vlv workaround. */ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + /* WaApplyL3ControlAndL3ChickenMode:vlv */ I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS); I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); - /* WaForceL3Serialization */ + /* WaForceL3Serialization:vlv */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); - /* WaDisableDopClockGating */ + /* WaDisableDopClockGating:vlv */ I915_WRITE(GEN7_ROW_CHICKEN2, _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - /* WaForceL3Serialization */ + /* WaForceL3Serialization:vlv */ I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & ~L3SQ_URB_READ_CAM_MATCH_DISABLE); - /* This is required by WaCatErrorRejectionIssue */ + /* This is required by WaCatErrorRejectionIssue:vlv */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - /* WaMbcDriverBootEnable */ + /* WaMbcDriverBootEnable:vlv */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); @@ -4216,10 +4217,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev) * but we didn't debug actual testcases to find it out. * * According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. + * This implements the WaDisableRCZUnitClockGating:vlv workaround. * - * Also apply WaDisableVDSUnitClockGating and - * WaDisableRCPBUnitClockGating. + * Also apply WaDisableVDSUnitClockGating:vlv and + * WaDisableRCPBUnitClockGating:vlv. */ I915_WRITE(GEN6_UCGCTL2, GEN7_VDSUNIT_CLOCK_GATE_DISABLE | @@ -4241,7 +4242,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); /* - * WaDisableVLVClockGating_VBIIssue + * WaDisableVLVClockGating_VBIIssue:vlv * Disable clock gating on th GCFG unit to prevent a delay * in the reporting of vblank events. */ -- cgit v1.2.3 From 8693a824873a0a97be77c1d5f1e98777f06f7305 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 3 May 2013 18:48:11 +0100 Subject: drm/i915: Add references to some workaround we implement We did not mention the workaround name when implementing those. This should help us track what we already implement. Signed-off-by: Damien Lespiau Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 1 + drivers/gpu/drm/i915/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_pm.c | 3 +++ drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index c81ae52c8c2e..64cb1909a0ce 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -333,6 +333,7 @@ mi_set_context(struct intel_ring_buffer *ring, if (ret) return ret; + /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw */ if (IS_GEN7(ring->dev)) intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE); else diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3e946d3cd196..146893288e53 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -174,6 +174,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) * mode set "sequence for CRT port" document: * - TP1 to TP2 time with the default value * - FDI delay to 90h + * + * WaFDIAutoLinkSetTimingOverrride:hsw */ I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d0c5ecff6948..f5523a80efc9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4125,8 +4125,8 @@ static int intel_crtc_compute_config(struct drm_crtc *crtc, if (!pipe_config->timings_set) drm_mode_set_crtcinfo(adjusted_mode, 0); - /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes - * with a hsync front porch of 0. + /* Cantiga+ cannot handle modes with a hsync front porch of 0. + * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. */ if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) && adjusted_mode->hsync_start == adjusted_mode->hdisplay) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f95b97cf4a0d..5093b8612bc4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4586,6 +4586,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); + /* WaRsForcewakeWaitTC0:snb */ __gen6_gt_wait_for_thread_c0(dev_priv); } @@ -4617,6 +4618,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); + /* WaRsForcewakeWaitTC0:ivb,hsw */ __gen6_gt_wait_for_thread_c0(dev_priv); } @@ -4720,6 +4722,7 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) FORCEWAKE_ACK_TIMEOUT_MS)) DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); + /* WaRsForcewakeWaitTC0:vlv */ __gen6_gt_wait_for_thread_c0(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1d5d613eb6be..3d2c236e15ab 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -515,6 +515,8 @@ static int init_render_ring(struct intel_ring_buffer *ring) /* We need to disable the AsyncFlip performance optimisations in order * to use MI_WAIT_FOR_EVENT within the CS. It should already be * programmed to '1' on all products. + * + * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv */ if (INTEL_INFO(dev)->gen >= 6) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); -- cgit v1.2.3 From bc5ead8c09b51e85d110132495a9bfa58dc39dab Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 7 May 2013 15:10:29 +0300 Subject: drm/i915: fix hotplug event bit tracking commit 142e239849c800f9dc23f828762873073f612d3f Author: Egbert Eich Date: Thu Apr 11 15:57:57 2013 +0200 drm/i915: Add bit field to record which pins have received HPD events (v3) added a bit field for hotplug event tracking. There ended up being three different v3 of the patch: [1], [2], and [3]. Apparently [1] was the correct one, but some frankenstein combination of the three got committed, which reversed the logic for setting the hotplug bits and misplaced a continue statement, skipping the hotplug irq storm handling altogether. This lead to broken hotplug detection, bisected to commit 321a1b3026ea194dd084cf3bda1e235b2986b0af Author: Egbert Eich Date: Thu Apr 11 16:00:26 2013 +0200 drm/i915: Only reprobe display on encoder which has received an HPD event (v2) which uses the incorrectly set hotplug event bits. Fix the mess. [1] http://mid.gmane.org/1366112220-7638-6-git-send-email-eich@suse.de [2] http://mid.gmane.org/1365688677-13682-1-git-send-email-eich@suse.de [3] http://mid.gmane.org/1365688996-13874-1-git-send-email-eich@suse.de Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 161101f42717..879c4ccb00db 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -882,9 +882,9 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev, if (!(hpd[i] & hotplug_trigger) || dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) - dev_priv->hpd_event_bits |= (1 << i); continue; + dev_priv->hpd_event_bits |= (1 << i); if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { -- cgit v1.2.3 From 7d708ee40a6b9ca1112a322e554c887df105b025 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 17 Apr 2013 14:04:50 +0300 Subject: drm/i915: HSW: allow PCH clock gating for suspend For the device to enter D3 we should enable PCH clock gating. v2: - use HAS_PCH_LPT instead of IS_HASWELL (Ville, Paolo) - rename lpt_allow_clock_gating to lpt_suspend_hw (Paolo) Signed-off-by: Imre Deak Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 5 +++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 18 ++++++++++++++++++ 5 files changed, 27 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 40b57871a0bf..707a56ec389d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -529,6 +529,8 @@ static int i915_drm_freeze(struct drm_device *dev) */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) dev_priv->display.crtc_disable(crtc); + + intel_modeset_suspend_hw(dev); } i915_save_state(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c81100c54e24..0ef9b4c6b4e5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1865,6 +1865,7 @@ static inline void intel_unregister_dsm_handler(void) { return; } /* modesetting */ extern void intel_modeset_init_hw(struct drm_device *dev); +extern void intel_modeset_suspend_hw(struct drm_device *dev); extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f5523a80efc9..b89072252b6c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9271,6 +9271,11 @@ void intel_modeset_init_hw(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } +void intel_modeset_suspend_hw(struct drm_device *dev) +{ + intel_suspend_hw(dev); +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index be9ad392b0e8..6096871c4806 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -716,6 +716,7 @@ extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) extern void intel_init_clock_gating(struct drm_device *dev); +extern void intel_suspend_hw(struct drm_device *dev); extern void intel_write_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); extern void intel_prepare_ddi(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5093b8612bc4..22e3af68b136 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3988,6 +3988,18 @@ static void lpt_init_clock_gating(struct drm_device *dev) PCH_LP_PARTITION_LEVEL_DISABLE); } +static void lpt_suspend_hw(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { + uint32_t val = I915_READ(SOUTH_DSPCLK_GATE_D); + + val &= ~PCH_LP_PARTITION_LEVEL_DISABLE; + I915_WRITE(SOUTH_DSPCLK_GATE_D, val); + } +} + static void haswell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4340,6 +4352,12 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } +void intel_suspend_hw(struct drm_device *dev) +{ + if (HAS_PCH_LPT(dev)) + lpt_suspend_hw(dev); +} + /** * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to -- cgit v1.2.3 From 615aaa5f96e40971039e01105c09808a3dead7d5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Apr 2013 21:09:10 +0300 Subject: drm/i915: Re-enable FBC WM if the watermark is good on gen6+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the calculated FBC watermark is no good, we simply disable FBC watermarks. But we fail to re-enable them later if the calculated watermark becomes good again. Fix that, but remember to leave FBC watermarks disabled on ILK since that's required by some workarounds. v2: Fix checkpatch complaint Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 22e3af68b136..7d35f4301155 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1631,6 +1631,10 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level, I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); return false; + } else if (INTEL_INFO(dev)->gen >= 6) { + /* enable FBC WM (except on ILK, where it must remain off) */ + I915_WRITE(DISP_ARB_CTL, + I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS); } if (display_wm > display->max_wm) { -- cgit v1.2.3 From c9cddffc669408a361c62353a36dd40b469dd9c2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 May 2013 10:45:13 -0700 Subject: drm/i915: BIOS and power context stolen mem handling for VLV v7 But we need to get the right stolen base and make pre-allocated objects for BIOS stuff so we don't clobber it. If the BIOS hasn't allocated a power context, we allocate one here too, from stolen space as required by the docs. v2: fix stolen to phys if ladder (Ben) keep BIOS reserved space out of allocator altogether (Ben) v3: fix mask of stolen base (Ben) v4: clean up preallocated object on unload (Ben) don't zero reg on unload (Jesse) fix mask harder (Jesse) v5: use unref for freeing stolen bits (Chris) move alloc/free to intel_pm.c (Chris) v6: NULL pctx at disable time so error paths work (Ben) v7: use correct PCI device for config read (Jesse) Reviewed-by: Ben Widawsky Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem_stolen.c | 12 +++++++-- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 49 ++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0ef9b4c6b4e5..eeec0be671b7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1073,6 +1073,8 @@ typedef struct drm_i915_private { struct i915_gpu_error gpu_error; + struct drm_i915_gem_object *vlv_pctx; + /* list of fbdev register on this device */ struct intel_fbdev *fbdev; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 67d3510cafed..913994cd0a3a 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -62,7 +62,10 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) * its value of TOLUD. */ base = 0; - if (INTEL_INFO(dev)->gen >= 6) { + if (IS_VALLEYVIEW(dev)) { + pci_read_config_dword(dev->pdev, 0x5c, &base); + base &= ~((1<<20) - 1); + } else if (INTEL_INFO(dev)->gen >= 6) { /* Read Base Data of Stolen Memory Register (BDSM) directly. * Note that there is also a MCHBAR miror at 0x1080c0 or * we could use device 2:0x5c instead. @@ -183,6 +186,7 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) int i915_gem_init_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int bios_reserved = 0; dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); if (dev_priv->mm.stolen_base == 0) @@ -191,8 +195,12 @@ int i915_gem_init_stolen(struct drm_device *dev) DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); + if (IS_VALLEYVIEW(dev)) + bios_reserved = 1024*1024; /* top 1M on VLV/BYT */ + /* Basic memrange allocator for stolen space */ - drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size); + drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size - + bios_reserved); return 0; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a47010331e72..a809a5633b28 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -700,6 +700,7 @@ #define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) #define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) #define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) +#define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7d35f4301155..67294f4cd3a5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2566,6 +2566,11 @@ static void valleyview_disable_rps(struct drm_device *dev) spin_unlock_irq(&dev_priv->rps.lock); I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); + + if (dev_priv->vlv_pctx) { + drm_gem_object_unreference(&dev_priv->vlv_pctx->base); + dev_priv->vlv_pctx = NULL; + } } int intel_enable_rc6(const struct drm_device *dev) @@ -2860,6 +2865,48 @@ static void vlv_rps_timer_work(struct work_struct *work) mutex_unlock(&dev_priv->rps.hw_lock); } +static void valleyview_setup_pctx(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *pctx; + unsigned long pctx_paddr; + u32 pcbr; + int pctx_size = 24*1024; + + pcbr = I915_READ(VLV_PCBR); + if (pcbr) { + /* BIOS set it up already, grab the pre-alloc'd space */ + int pcbr_offset; + + pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base; + pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev, + pcbr_offset, + pcbr_offset, + pctx_size); + goto out; + } + + /* + * From the Gunit register HAS: + * The Gfx driver is expected to program this register and ensure + * proper allocation within Gfx stolen memory. For example, this + * register should be programmed such than the PCBR range does not + * overlap with other ranges, such as the frame buffer, protected + * memory, or any other relevant ranges. + */ + pctx = i915_gem_object_create_stolen(dev, pctx_size); + if (!pctx) { + DRM_DEBUG("not enough stolen space for PCTX, disabling\n"); + return; + } + + pctx_paddr = dev_priv->mm.stolen_base + pctx->stolen->start; + I915_WRITE(VLV_PCBR, pctx_paddr); + +out: + dev_priv->vlv_pctx = pctx; +} + static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2874,6 +2921,8 @@ static void valleyview_enable_rps(struct drm_device *dev) I915_WRITE(GTFIFODBG, gtfifodbg); } + valleyview_setup_pctx(dev); + gen6_gt_force_wake_get(dev_priv); I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400); -- cgit v1.2.3 From 3727d55e4d85836aa6cb759a965daaef88074150 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 May 2013 10:45:14 -0700 Subject: drm/i915: allow stolen, pre-allocated objects to avoid GTT allocation v2 In some cases, we may not need GTT address space allocated to a stolen object, so allow passing -1 to the preallocated function to indicate as much. v2: remove BUG_ON(gtt_offset & 4095) now that -1 is allowed (Ville) Reviewed-by: Chris Wilson Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 5 ++++- drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 913994cd0a3a..89cbfab9570e 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -339,7 +339,6 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, /* KISS and expect everything to be page-aligned */ BUG_ON(stolen_offset & 4095); - BUG_ON(gtt_offset & 4095); BUG_ON(size & 4095); if (WARN_ON(size == 0)) @@ -360,6 +359,10 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, return NULL; } + /* Some objects just need physical mem from stolen space */ + if (gtt_offset == -1) + return obj; + /* To simplify the initialisation sequence between KMS and GTT, * we allow construction of the stolen object prior to * setting up the GTT space. The actual reservation will occur diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 67294f4cd3a5..6df886e06b64 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2881,7 +2881,7 @@ static void valleyview_setup_pctx(struct drm_device *dev) pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base; pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev, pcbr_offset, - pcbr_offset, + -1, pctx_size); goto out; } -- cgit v1.2.3 From 590e4df8c82e6c2707ae12ba6672ab6fb9cd4b89 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 8 May 2013 10:45:15 -0700 Subject: drm/i915: VLV support is no longer preliminary Works pretty well actually. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 707a56ec389d..3cb27fa842ee 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -966,12 +966,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct intel_device_info *intel_info = (struct intel_device_info *) ent->driver_data; - if (intel_info->is_valleyview) - if(!i915_preliminary_hw_support) { - DRM_ERROR("Preliminary hardware support disabled\n"); - return -ENODEV; - } - /* Only bind to function 0 of the device. Early generations * used function 1 as a placeholder for multi-head. This causes * us confusion instead, especially on the systems where both -- cgit v1.2.3 From 9ff8c9bac2d78634f34d9b6e43e04bf316a7f456 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:02 +0300 Subject: drm/i915: use enc_to_intel_dp() instead of opencoding the same Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6096871c4806..b1f50b15c6f3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -620,19 +620,17 @@ static inline struct intel_encoder *intel_attached_encoder(struct drm_connector return to_intel_connector(connector)->encoder; } -static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) -{ - struct intel_digital_port *intel_dig_port = - container_of(encoder, struct intel_digital_port, base.base); - return &intel_dig_port->dp; -} - static inline struct intel_digital_port * enc_to_dig_port(struct drm_encoder *encoder) { return container_of(encoder, struct intel_digital_port, base.base); } +static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) +{ + return &enc_to_dig_port(encoder)->dp; +} + static inline struct intel_digital_port * dp_to_dig_port(struct intel_dp *intel_dp) { -- cgit v1.2.3 From d8e8b582b4e685a0e2a95ca0f4862582d465c649 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:03 +0300 Subject: drm/i915: hsw: replace !is_pch_edp() with port==PORT_A On HSW the CPU side eDP is always on port-A, the PCH side eDP is always on port-D. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b89072252b6c..157a68f48060 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5969,7 +5969,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { case INTEL_OUTPUT_EDP: - if (!intel_encoder_is_pch_edp(&encoder->base)) + if (enc_to_dig_port(&encoder->base)->port == PORT_A) is_cpu_edp = true; break; } -- cgit v1.2.3 From 2de6905f0a30c8fbe293e1e3ecdb766bbf5f7760 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:04 +0300 Subject: drm/i915: ilk-ivb: replace !is_pch_edp() with port==PORT_A On ILK-IVB the CPU side eDP is always on port-A. Also reduce somewhat the debug verbosity. v2: - reduce debug verbosity Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 157a68f48060..4ca2a3d885a0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5045,7 +5045,6 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) u32 val, final; bool has_lvds = false; bool has_cpu_edp = false; - bool has_pch_edp = false; bool has_panel = false; bool has_ck505 = false; bool can_ssc = false; @@ -5060,9 +5059,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) break; case INTEL_OUTPUT_EDP: has_panel = true; - if (intel_encoder_is_pch_edp(&encoder->base)) - has_pch_edp = true; - else + if (enc_to_dig_port(&encoder->base)->port == PORT_A) has_cpu_edp = true; break; } @@ -5076,9 +5073,8 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) can_ssc = true; } - DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n", - has_panel, has_lvds, has_pch_edp, has_cpu_edp, - has_ck505); + DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n", + has_panel, has_lvds, has_ck505); /* Ironlake: try to setup display ref clock before DPLL * enabling. This is only under driver's control after -- cgit v1.2.3 From f7d24902e197824eee717e4c3f406eb8623e67e0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:05 +0300 Subject: drm/i915: stop using is_pch_edp() in intel_dp_init_connector() is_pch_edp() will be removed in a follow-up patch, so replace it with a check for the port and VBT info (for port-D eDP). Also make things a bit clearer by using a switch on the ports. v2: - make the comment about not setting the conder type for DP clearer (Ville) Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a2935234ac03..6f3a9e8f7078 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2980,24 +2980,35 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, if (intel_dpd_is_edp(dev)) intel_dp->is_pch_edp = true; + type = DRM_MODE_CONNECTOR_DisplayPort; /* * FIXME : We need to initialize built-in panels before external panels. * For X0, DP_C is fixed as eDP. Revisit this as part of VLV eDP cleanup */ - if (IS_VALLEYVIEW(dev) && port == PORT_C) { - type = DRM_MODE_CONNECTOR_eDP; - intel_encoder->type = INTEL_OUTPUT_EDP; - } else if (port == PORT_A || is_pch_edp(intel_dp)) { + switch (port) { + case PORT_A: type = DRM_MODE_CONNECTOR_eDP; - intel_encoder->type = INTEL_OUTPUT_EDP; - } else { - /* The intel_encoder->type value may be INTEL_OUTPUT_UNKNOWN for - * DDI or INTEL_OUTPUT_DISPLAYPORT for the older gens, so don't - * rewrite it. - */ - type = DRM_MODE_CONNECTOR_DisplayPort; + break; + case PORT_C: + if (IS_VALLEYVIEW(dev)) + type = DRM_MODE_CONNECTOR_eDP; + break; + case PORT_D: + if (HAS_PCH_SPLIT(dev) && intel_dpd_is_edp(dev)) + type = DRM_MODE_CONNECTOR_eDP; + break; + default: /* silence GCC warning */ + break; } + /* + * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but + * for DP the encoder type can be set by the caller to + * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it. + */ + if (type == DRM_MODE_CONNECTOR_eDP) + intel_encoder->type = INTEL_OUTPUT_EDP; + drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); -- cgit v1.2.3 From 68b4d8247033b425ae948f02885c2aed5ae823f3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:06 +0300 Subject: drm/i915: stop using is_pch_edp() in is_cpu_edp() is_pch_edp() will be removed by the next patch, so replace it by a check for the port and device type. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6f3a9e8f7078..3ab683af5256 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -65,6 +65,13 @@ static bool is_pch_edp(struct intel_dp *intel_dp) return intel_dp->is_pch_edp; } +static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + + return intel_dig_port->base.base.dev; +} + /** * is_cpu_edp - is the port on the CPU and attached to an eDP panel? * @intel_dp: DP struct @@ -73,14 +80,12 @@ static bool is_pch_edp(struct intel_dp *intel_dp) */ static bool is_cpu_edp(struct intel_dp *intel_dp) { - return is_edp(intel_dp) && !is_pch_edp(intel_dp); -} - -static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) -{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + enum port port = intel_dig_port->port; - return intel_dig_port->base.base.dev; + return is_edp(intel_dp) && + (port == PORT_A || (port == PORT_C && IS_VALLEYVIEW(dev))); } static struct intel_dp *intel_attached_dp(struct drm_connector *connector) -- cgit v1.2.3 From 15e6bf74b660c2e7aecc200ac77eb19eb6628240 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:07 +0300 Subject: drm/i915: remove is_pch_edp() helpers and state variable There are no more users for these, so remove them. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 36 ------------------------------------ drivers/gpu/drm/i915/intel_drv.h | 2 -- 2 files changed, 38 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3ab683af5256..fa7e66b4adc6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -52,19 +52,6 @@ static bool is_edp(struct intel_dp *intel_dp) return intel_dig_port->base.type == INTEL_OUTPUT_EDP; } -/** - * is_pch_edp - is the port on the PCH and attached to an eDP panel? - * @intel_dp: DP struct - * - * Returns true if the given DP struct corresponds to a PCH DP port attached - * to an eDP panel, false otherwise. Helpful for determining whether we - * may need FDI resources for a given DP output or not. - */ -static bool is_pch_edp(struct intel_dp *intel_dp) -{ - return intel_dp->is_pch_edp; -} - static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -93,25 +80,6 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector) return enc_to_intel_dp(&intel_attached_encoder(connector)->base); } -/** - * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP? - * @encoder: DRM encoder - * - * Return true if @encoder corresponds to a PCH attached eDP panel. Needed - * by intel_display.c. - */ -bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) -{ - struct intel_dp *intel_dp; - - if (!encoder) - return false; - - intel_dp = enc_to_intel_dp(encoder); - - return is_pch_edp(intel_dp); -} - static void intel_dp_link_down(struct intel_dp *intel_dp); static int @@ -2981,10 +2949,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp->DP = I915_READ(intel_dp->output_reg); intel_dp->attached_connector = intel_connector; - if (HAS_PCH_SPLIT(dev) && port == PORT_D) - if (intel_dpd_is_edp(dev)) - intel_dp->is_pch_edp = true; - type = DRM_MODE_CONNECTOR_DisplayPort; /* * FIXME : We need to initialize built-in panels before external panels. diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b1f50b15c6f3..118e1bfcbe85 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -451,7 +451,6 @@ struct intel_dp { uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; - bool is_pch_edp; uint8_t train_set[4]; int panel_power_up_delay; int panel_power_down_delay; @@ -565,7 +564,6 @@ extern void ironlake_edp_panel_on(struct intel_dp *intel_dp); extern void ironlake_edp_panel_off(struct intel_dp *intel_dp); extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); -extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane); -- cgit v1.2.3 From e7281eab0bb4a5265593866d6f7acea2812fe0ec Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 May 2013 13:14:08 +0300 Subject: drm/i915: print DP init debug messages from a single place Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++--------- drivers/gpu/drm/i915/intel_dp.c | 4 ++++ 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4ca2a3d885a0..0dab9f64b35d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8821,10 +8821,8 @@ static void intel_setup_outputs(struct drm_device *dev) intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); } - if (!found && SUPPORTS_INTEGRATED_DP(dev)) { - DRM_DEBUG_KMS("probing DP_B\n"); + if (!found && SUPPORTS_INTEGRATED_DP(dev)) intel_dp_init(dev, DP_B, PORT_B); - } } /* Before G4X SDVOC doesn't have its own detect register */ @@ -8840,17 +8838,13 @@ static void intel_setup_outputs(struct drm_device *dev) DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); } - if (SUPPORTS_INTEGRATED_DP(dev)) { - DRM_DEBUG_KMS("probing DP_C\n"); + if (SUPPORTS_INTEGRATED_DP(dev)) intel_dp_init(dev, DP_C, PORT_C); - } } if (SUPPORTS_INTEGRATED_DP(dev) && - (I915_READ(DP_D) & DP_DETECTED)) { - DRM_DEBUG_KMS("probing DP_D\n"); + (I915_READ(DP_D) & DP_DETECTED)) intel_dp_init(dev, DP_D, PORT_D); - } } else if (IS_GEN2(dev)) intel_dvo_init(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fa7e66b4adc6..0291b28ec872 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2978,6 +2978,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, if (type == DRM_MODE_CONNECTOR_eDP) intel_encoder->type = INTEL_OUTPUT_EDP; + DRM_DEBUG_KMS("Adding %s connector on port %c\n", + type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP", + port_name(port)); + drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); -- cgit v1.2.3 From 70484559296623d49e559a3a10fa32fd2bc5dcc3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:41 +0200 Subject: drm/i915: move sdvo TV clock computation to intel_sdvo.c We have a very nice infrastructure for this now! Note that the multifunction sdvo support is pretty neatly broken: We completely ignore userspace's request for which connector to wire up with the encoder and just use whatever the last detect callback has seen. Not something I'll fix in this patch, but unfortunately something which is also broken in the DDI code ... v2: Don't call sdvo_tv_clock twice. Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 30 ------------------------------ drivers/gpu/drm/i915/intel_sdvo.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0dab9f64b35d..9365c5aa16bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4290,30 +4290,6 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) return refclk; } -static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc) -{ - unsigned dotclock = crtc->config.adjusted_mode.clock; - struct dpll *clock = &crtc->config.dpll; - - /* SDVO TV has fixed PLL values depend on its clock range, - this mirrors vbios setting. */ - if (dotclock >= 100000 && dotclock < 140500) { - clock->p1 = 2; - clock->p2 = 10; - clock->n = 3; - clock->m1 = 16; - clock->m2 = 8; - } else if (dotclock >= 140500 && dotclock <= 200000) { - clock->p1 = 1; - clock->p2 = 10; - clock->n = 6; - clock->m1 = 12; - clock->m2 = 8; - } - - crtc->config.clock_set = true; -} - static uint32_t pnv_dpll_compute_fp(struct dpll *dpll) { return (1 << dpll->n) << 16 | dpll->m1 << 8 | dpll->m2; @@ -4972,9 +4948,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, intel_crtc->config.dpll.p2 = clock.p2; } - if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(intel_crtc); - if (IS_GEN2(dev)) i8xx_update_pll(intel_crtc, adjusted_mode, has_reduced_clock ? &reduced_clock : NULL, @@ -5580,9 +5553,6 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, reduced_clock); } - if (is_sdvo && is_tv) - i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc)); - return true; } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a618a6a45a77..0fc6fc2d6a30 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1041,6 +1041,32 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, return true; } +static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config) +{ + unsigned dotclock = pipe_config->adjusted_mode.clock; + struct dpll *clock = &pipe_config->dpll; + + /* SDVO TV has fixed PLL values depend on its clock range, + this mirrors vbios setting. */ + if (dotclock >= 100000 && dotclock < 140500) { + clock->p1 = 2; + clock->p2 = 10; + clock->n = 3; + clock->m1 = 16; + clock->m2 = 8; + } else if (dotclock >= 140500 && dotclock <= 200000) { + clock->p1 = 1; + clock->p2 = 10; + clock->n = 6; + clock->m1 = 12; + clock->m2 = 8; + } else { + WARN(1, "SDVO TV clock out of range: %i\n", dotclock); + } + + pipe_config->clock_set = true; +} + static bool intel_sdvo_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { @@ -1097,6 +1123,10 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, if (intel_sdvo->color_range) pipe_config->limited_color_range = true; + /* Clock computation needs to happen after pixel multiplier. */ + if (intel_sdvo->is_tv) + i9xx_adjust_sdvo_tv_clock(pipe_config); + return true; } -- cgit v1.2.3 From b4c09f3bbda97ec685afd604d8a3a08c72465910 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:42 +0200 Subject: drm/i915: drop TVclock special casing on ilk+ TV-out uses the same reference clock as everyone else. The only difference seems to be in the slightly different CB tuning limit. Note that PLL_REF_INPUT_TVCLKINBC is a reserved value on ilk+. Also strictly speaking we don't support native TV-out on ilk+, hence all that code is dead. But Bspec still contains some residual mentions of native TV-out on some pch-split platforms, so I've figured it doesn't hurt to keep the code around a bit longer (e.g. in the cb tune function). v2: Improve the commit message as Jani suggested in his review. Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9365c5aa16bb..5fcd5b09ff56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5637,9 +5637,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (intel_encoder->needs_tv_clock) is_tv = true; break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; } num_connectors++; @@ -5698,13 +5695,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, break; } - if (is_sdvo && is_tv) - dpll |= PLL_REF_INPUT_TVCLKINBC; - else if (is_tv) - /* XXX: just matching BIOS for now */ - /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ - dpll |= 3; - else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) + if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; else dpll |= PLL_REF_INPUT_DREFCLK; -- cgit v1.2.3 From fec32900cc8f4ec8ad6b3007d2035e598f128f24 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:43 +0200 Subject: drm/i915: rip out TV-out lore ... This seems to be an impressive piece of copy&pasta lore. I've checked all docs and on most platforms these bits are all MBZ, with the exception of the SDVO pixel multiplier on gen3. On gen4 that moved to a special DPLL_MD registers. No indication whatsoever that we actually need this for native TV-out support. I suspect this started as a hack when we didn't yet have proper pixel multiplier support in place for SDVO TV, but then got stuck in a life of its own. Just rip it out. Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5fcd5b09ff56..97a29c4c27f7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4589,10 +4589,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc, if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) dpll |= PLL_REF_INPUT_TVCLKINBC; - else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) - /* XXX: just matching BIOS for now */ - /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ - dpll |= 3; else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; -- cgit v1.2.3 From a16af721e83466b965c7e53d5350e16abf9691e4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:44 +0200 Subject: drm/i915: rip out now unused is_foo tracking from crtc code More ugly stuff gone for good! The big special case left now is lvds (which is indeed really special). Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 97a29c4c27f7..df81f1648400 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4879,8 +4879,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, int refclk, num_connectors = 0; intel_clock_t clock, reduced_clock; u32 dspcntr; - bool ok, has_reduced_clock = false, is_sdvo = false; - bool is_lvds = false, is_tv = false; + bool ok, has_reduced_clock = false; + bool is_lvds = false; struct intel_encoder *encoder; const intel_limit_t *limit; int ret; @@ -4890,15 +4890,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, case INTEL_OUTPUT_LVDS: is_lvds = true; break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; } num_connectors++; @@ -5333,7 +5324,6 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; - struct intel_encoder *edp_encoder = NULL; int num_connectors = 0; bool is_lvds = false; @@ -5342,9 +5332,6 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) case INTEL_OUTPUT_LVDS: is_lvds = true; break; - case INTEL_OUTPUT_EDP: - edp_encoder = encoder; - break; } num_connectors++; } @@ -5503,22 +5490,13 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, struct intel_encoder *intel_encoder; int refclk; const intel_limit_t *limit; - bool ret, is_sdvo = false, is_tv = false, is_lvds = false; + bool ret, is_lvds = false; for_each_encoder_on_crtc(dev, crtc, intel_encoder) { switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; break; - case INTEL_OUTPUT_SDVO: - case INTEL_OUTPUT_HDMI: - is_sdvo = true; - if (intel_encoder->needs_tv_clock) - is_tv = true; - break; - case INTEL_OUTPUT_TVOUT: - is_tv = true; - break; } } -- cgit v1.2.3 From 09ede5414f0215461c933032630bf9c3a61a8ba3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:45 +0200 Subject: drm/i915: make SDVO TV-out work for multifunction devices We need to track this correctly. While at it shovel the boolean to track whether the sdvo is in tv mode or not into pipe_config. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36997 Tested-by: Pierre Assal Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=63609 Tested-by: cancan,feng Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++----- drivers/gpu/drm/i915/intel_drv.h | 5 ++++- drivers/gpu/drm/i915/intel_sdvo.c | 8 ++------ 3 files changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df81f1648400..e75e54680321 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4587,7 +4587,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); - if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT)) + if (crtc->config.sdvo_tv_clock) dpll |= PLL_REF_INPUT_TVCLKINBC; else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) @@ -5598,7 +5598,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, struct intel_encoder *intel_encoder; uint32_t dpll; int factor, num_connectors = 0; - bool is_lvds = false, is_sdvo = false, is_tv = false; + bool is_lvds = false, is_sdvo = false; for_each_encoder_on_crtc(dev, crtc, intel_encoder) { switch (intel_encoder->type) { @@ -5608,8 +5608,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, case INTEL_OUTPUT_SDVO: case INTEL_OUTPUT_HDMI: is_sdvo = true; - if (intel_encoder->needs_tv_clock) - is_tv = true; break; } @@ -5623,7 +5621,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, dev_priv->lvds_ssc_freq == 100) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; - } else if (is_sdvo && is_tv) + } else if (intel_crtc->config.sdvo_tv_clock) factor = 20; if (ironlake_needs_fb_cb_tune(&intel_crtc->config.dpll, factor)) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 118e1bfcbe85..0f3554592719 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -120,7 +120,6 @@ struct intel_encoder { struct intel_crtc *new_crtc; int type; - bool needs_tv_clock; /* * Intel hw has only one MUX where encoders could be clone, hence a * simple flag is enough to compute the possible_clones mask. @@ -223,6 +222,10 @@ struct intel_crtc_config { /* Controls for the clock computation, to override various stages. */ bool clock_set; + /* SDVO TV has a bunch of special case. To make multifunction encoders + * work correctly, we need to track this at runtime.*/ + bool sdvo_tv_clock; + /* * crtc bandwidth limit, don't increase pipe bpp or clock if not really * required. This is set in the 2nd loop of calling encoder's diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 0fc6fc2d6a30..015f9f4263fe 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1092,6 +1092,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, mode, adjusted_mode); + pipe_config->sdvo_tv_clock = true; } else if (intel_sdvo->is_lvds) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, intel_sdvo->sdvo_lvds_fixed_mode)) @@ -1655,12 +1656,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (ret == connector_status_connected) { intel_sdvo->is_tv = false; intel_sdvo->is_lvds = false; - intel_sdvo->base.needs_tv_clock = false; - if (response & SDVO_TV_MASK) { + if (response & SDVO_TV_MASK) intel_sdvo->is_tv = true; - intel_sdvo->base.needs_tv_clock = true; - } if (response & SDVO_LVDS_MASK) intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL; } @@ -2349,7 +2347,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo_connector->output_flag = type; intel_sdvo->is_tv = true; - intel_sdvo->base.needs_tv_clock = true; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); @@ -2437,7 +2434,6 @@ static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) { intel_sdvo->is_tv = false; - intel_sdvo->base.needs_tv_clock = false; intel_sdvo->is_lvds = false; /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ -- cgit v1.2.3 From 41aa344866e3ba1d117a798355c35d44d7cc6318 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 May 2013 20:03:18 -0300 Subject: drm/i915: Organize VBT stuff inside drm_i915_private drm_i915_private is getting bigger and bigger when adding new vbt stuff. So, the better way of getting drm_i915_private organized is to create a special structure for vbt stuff. v2: Basically conflicts fixes Reviewed-by: Jani Nikula Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 +-- drivers/gpu/drm/i915/i915_drv.h | 57 +++++++++++--------- drivers/gpu/drm/i915/intel_bios.c | 100 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_crt.c | 4 +- drivers/gpu/drm/i915/intel_display.c | 12 ++--- drivers/gpu/drm/i915/intel_dp.c | 18 +++---- drivers/gpu/drm/i915/intel_lvds.c | 16 +++--- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_sdvo.c | 6 +-- drivers/gpu/drm/i915/intel_tv.c | 8 +-- 10 files changed, 119 insertions(+), 112 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a1648eb3a8b1..f5addac7c154 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1742,10 +1742,10 @@ int i915_driver_unload(struct drm_device *dev) * free the memory space allocated for the child device * config parsed from VBT */ - if (dev_priv->child_dev && dev_priv->child_dev_num) { - kfree(dev_priv->child_dev); - dev_priv->child_dev = NULL; - dev_priv->child_dev_num = 0; + if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) { + kfree(dev_priv->vbt.child_dev); + dev_priv->vbt.child_dev = NULL; + dev_priv->vbt.child_dev_num = 0; } vga_switcheroo_unregister_client(dev->pdev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eeec0be671b7..14817de37405 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -891,6 +891,37 @@ enum modeset_restore { MODESET_SUSPENDED, }; +struct intel_vbt_data { + struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ + struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ + + /* Feature bits */ + unsigned int int_tv_support:1; + unsigned int lvds_dither:1; + unsigned int lvds_vbt:1; + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; + int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + + /* eDP */ + int edp_rate; + int edp_lanes; + int edp_preemphasis; + int edp_vswing; + bool edp_initialized; + bool edp_support; + int edp_bpp; + struct edp_power_seq edp_pps; + + int crt_ddc_pin; + + int child_dev_num; + struct child_device_config *child_dev; +}; + typedef struct drm_i915_private { struct drm_device *dev; struct kmem_cache *slab; @@ -970,6 +1001,7 @@ typedef struct drm_i915_private { struct intel_fbc_work *fbc_work; struct intel_opregion opregion; + struct intel_vbt_data vbt; /* overlay */ struct intel_overlay *overlay; @@ -986,31 +1018,8 @@ typedef struct drm_i915_private { /* LVDS info */ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ - - /* Feature bits from the VBIOS */ - unsigned int int_tv_support:1; - unsigned int lvds_dither:1; - unsigned int lvds_vbt:1; - unsigned int int_crt_support:1; - unsigned int lvds_use_ssc:1; - unsigned int display_clock_mode:1; - unsigned int fdi_rx_polarity_inverted:1; - int lvds_ssc_freq; - unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ - struct { - int rate; - int lanes; - int preemphasis; - int vswing; - - bool initialized; - bool support; - int bpp; - struct edp_power_seq pps; - } edp; bool no_aux_handshake; - int crt_ddc_pin; struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ @@ -1052,8 +1061,6 @@ typedef struct drm_i915_private { /* indicates the reduced downclock for LVDS*/ int lvds_downclock; u16 orig_clock; - int child_dev_num; - struct child_device_config *child_dev; bool mchbar_need_disable; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 95070b2124c6..53f2bed8bc5f 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -212,7 +212,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_options) return; - dev_priv->lvds_dither = lvds_options->pixel_dither; + dev_priv->vbt.lvds_dither = lvds_options->pixel_dither; if (lvds_options->panel_type == 0xff) return; @@ -226,7 +226,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, if (!lvds_lfp_data_ptrs) return; - dev_priv->lvds_vbt = 1; + dev_priv->vbt.lvds_vbt = 1; panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, lvds_lfp_data_ptrs, @@ -238,7 +238,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); - dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; + dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); @@ -274,9 +274,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, /* check the resolution, just to be sure */ if (fp_timing->x_res == panel_fixed_mode->hdisplay && fp_timing->y_res == panel_fixed_mode->vdisplay) { - dev_priv->bios_lvds_val = fp_timing->lvds_reg_val; + dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val; DRM_DEBUG_KMS("VBT initial LVDS value %x\n", - dev_priv->bios_lvds_val); + dev_priv->vbt.bios_lvds_val); } } } @@ -316,7 +316,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); - dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; + dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); @@ -345,20 +345,20 @@ parse_general_features(struct drm_i915_private *dev_priv, general = find_section(bdb, BDB_GENERAL_FEATURES); if (general) { - dev_priv->int_tv_support = general->int_tv_support; - dev_priv->int_crt_support = general->int_crt_support; - dev_priv->lvds_use_ssc = general->enable_ssc; - dev_priv->lvds_ssc_freq = + dev_priv->vbt.int_tv_support = general->int_tv_support; + dev_priv->vbt.int_crt_support = general->int_crt_support; + dev_priv->vbt.lvds_use_ssc = general->enable_ssc; + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, general->ssc_freq); - dev_priv->display_clock_mode = general->display_clock_mode; - dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + dev_priv->vbt.display_clock_mode = general->display_clock_mode; + dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", - dev_priv->int_tv_support, - dev_priv->int_crt_support, - dev_priv->lvds_use_ssc, - dev_priv->lvds_ssc_freq, - dev_priv->display_clock_mode, - dev_priv->fdi_rx_polarity_inverted); + dev_priv->vbt.int_tv_support, + dev_priv->vbt.int_crt_support, + dev_priv->vbt.lvds_use_ssc, + dev_priv->vbt.lvds_ssc_freq, + dev_priv->vbt.display_clock_mode, + dev_priv->vbt.fdi_rx_polarity_inverted); } } @@ -375,7 +375,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv, int bus_pin = general->crt_ddc_gmbus_pin; DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin); if (intel_gmbus_is_port_valid(bus_pin)) - dev_priv->crt_ddc_pin = bus_pin; + dev_priv->vbt.crt_ddc_pin = bus_pin; } else { DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n", block_size); @@ -486,7 +486,7 @@ parse_driver_features(struct drm_i915_private *dev_priv, if (SUPPORTS_EDP(dev) && driver->lvds_config == BDB_DRIVER_FEATURE_EDP) - dev_priv->edp.support = 1; + dev_priv->vbt.edp_support = 1; if (driver->dual_frequency) dev_priv->render_reclock_avail = true; @@ -501,20 +501,20 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp = find_section(bdb, BDB_EDP); if (!edp) { - if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->vbt.edp_support) DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); return; } switch ((edp->color_depth >> (panel_type * 2)) & 3) { case EDP_18BPP: - dev_priv->edp.bpp = 18; + dev_priv->vbt.edp_bpp = 18; break; case EDP_24BPP: - dev_priv->edp.bpp = 24; + dev_priv->vbt.edp_bpp = 24; break; case EDP_30BPP: - dev_priv->edp.bpp = 30; + dev_priv->vbt.edp_bpp = 30; break; } @@ -522,48 +522,48 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp_pps = &edp->power_seqs[panel_type]; edp_link_params = &edp->link_params[panel_type]; - dev_priv->edp.pps = *edp_pps; + dev_priv->vbt.edp_pps = *edp_pps; - dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 : + dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 : DP_LINK_BW_1_62; switch (edp_link_params->lanes) { case 0: - dev_priv->edp.lanes = 1; + dev_priv->vbt.edp_lanes = 1; break; case 1: - dev_priv->edp.lanes = 2; + dev_priv->vbt.edp_lanes = 2; break; case 3: default: - dev_priv->edp.lanes = 4; + dev_priv->vbt.edp_lanes = 4; break; } switch (edp_link_params->preemphasis) { case 0: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0; break; case 1: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5; break; case 2: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6; break; case 3: - dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; + dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5; break; } switch (edp_link_params->vswing) { case 0: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400; break; case 1: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600; break; case 2: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800; break; case 3: - dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200; + dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200; break; } } @@ -611,13 +611,13 @@ parse_device_mapping(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("no child dev is parsed from VBT\n"); return; } - dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); - if (!dev_priv->child_dev) { + dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL); + if (!dev_priv->vbt.child_dev) { DRM_DEBUG_KMS("No memory space for child device\n"); return; } - dev_priv->child_dev_num = count; + dev_priv->vbt.child_dev_num = count; count = 0; for (i = 0; i < child_device_num; i++) { p_child = &(p_defs->devices[i]); @@ -625,7 +625,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, /* skip the device block if device type is invalid */ continue; } - child_dev_ptr = dev_priv->child_dev + count; + child_dev_ptr = dev_priv->vbt.child_dev + count; count++; memcpy((void *)child_dev_ptr, (void *)p_child, sizeof(*p_child)); @@ -638,23 +638,23 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; + dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; /* LFP panel data */ - dev_priv->lvds_dither = 1; - dev_priv->lvds_vbt = 0; + dev_priv->vbt.lvds_dither = 1; + dev_priv->vbt.lvds_vbt = 0; /* SDVO panel data */ - dev_priv->sdvo_lvds_vbt_mode = NULL; + dev_priv->vbt.sdvo_lvds_vbt_mode = NULL; /* general features */ - dev_priv->int_tv_support = 1; - dev_priv->int_crt_support = 1; + dev_priv->vbt.int_tv_support = 1; + dev_priv->vbt.int_crt_support = 1; /* Default to using SSC */ - dev_priv->lvds_use_ssc = 1; - dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); - DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); + dev_priv->vbt.lvds_use_ssc = 1; + dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); + DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); } static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 991e53047e1d..cc414f1a0b92 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -442,7 +442,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG); - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); edid = intel_crt_get_edid(connector, i2c); if (edid) { @@ -648,7 +648,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) int ret; struct i2c_adapter *i2c; - i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin); + i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); ret = intel_crt_ddc_get_modes(connector, i2c); if (ret || !IS_G4X(dev)) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e75e54680321..a14fec3a6740 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4242,7 +4242,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { if (i915_panel_use_ssc >= 0) return i915_panel_use_ssc != 0; - return dev_priv->lvds_use_ssc + return dev_priv->vbt.lvds_use_ssc && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE); } @@ -4278,7 +4278,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) refclk = vlv_get_refclk(crtc); } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - refclk = dev_priv->lvds_ssc_freq * 1000; + refclk = dev_priv->vbt.lvds_ssc_freq * 1000; DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", refclk / 1000); } else if (!IS_GEN2(dev)) { @@ -5026,7 +5026,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev) } if (HAS_PCH_IBX(dev)) { - has_ck505 = dev_priv->display_clock_mode; + has_ck505 = dev_priv->vbt.display_clock_mode; can_ssc = has_ck505; } else { has_ck505 = false; @@ -5338,8 +5338,8 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - dev_priv->lvds_ssc_freq); - return dev_priv->lvds_ssc_freq * 1000; + dev_priv->vbt.lvds_ssc_freq); + return dev_priv->vbt.lvds_ssc_freq * 1000; } return 120000; @@ -5618,7 +5618,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 21; if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && - dev_priv->lvds_ssc_freq == 100) || + dev_priv->vbt.lvds_ssc_freq == 100) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (intel_crtc->config.sdvo_tv_clock) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0291b28ec872..2bb4009b7a60 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -727,10 +727,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, * recomments. This means we'll up-dither 16bpp framebuffers on * high-depth panels. */ - if (is_edp(intel_dp) && dev_priv->edp.bpp) { + if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp) { DRM_DEBUG_KMS("forcing bpp for eDP panel to BIOS-provided %i\n", - dev_priv->edp.bpp); - bpp = dev_priv->edp.bpp; + dev_priv->vbt.edp_bpp); + bpp = dev_priv->vbt.edp_bpp; } for (; bpp >= 6*3; bpp -= 2*3) { @@ -2745,11 +2745,11 @@ bool intel_dpd_is_edp(struct drm_device *dev) struct child_device_config *p_child; int i; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return false; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + p_child = dev_priv->vbt.child_dev + i; if (p_child->dvo_port == PORT_IDPD && p_child->device_type == DEVICE_TYPE_eDP) @@ -2827,7 +2827,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); - vbt = dev_priv->edp.pps; + vbt = dev_priv->vbt.edp_pps; /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of * our hw here, which are all in 100usec. */ @@ -3097,8 +3097,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, } /* fallback to VBT if available for eDP */ - if (!fixed_mode && dev_priv->lfp_lvds_vbt_mode) { - fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { + fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); if (fixed_mode) fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index d256fe454a9d..e34e290c29eb 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -735,11 +735,11 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return true; - for (i = 0; i < dev_priv->child_dev_num; i++) { - struct child_device_config *child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + struct child_device_config *child = dev_priv->vbt.child_dev + i; /* If the device type is not LFP, continue. * We have to check both the new identifiers as well as the @@ -827,7 +827,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) */ val = I915_READ(lvds_encoder->reg); if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) - val = dev_priv->bios_lvds_val; + val = dev_priv->vbt.bios_lvds_val; return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; } @@ -887,7 +887,7 @@ bool intel_lvds_init(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return false; - if (dev_priv->edp.support) { + if (dev_priv->vbt.edp_support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); return false; } @@ -1005,11 +1005,11 @@ bool intel_lvds_init(struct drm_device *dev) } /* Failed to get EDID, what about VBT? */ - if (dev_priv->lfp_lvds_vbt_mode) { + if (dev_priv->vbt.lfp_lvds_vbt_mode) { DRM_DEBUG_KMS("using mode from VBT: "); - drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode); + drm_mode_debug_printmodeline(dev_priv->vbt.lfp_lvds_vbt_mode); - fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); if (fixed_mode) { fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; goto out; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6df886e06b64..5a22ce2b8244 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3889,7 +3889,7 @@ static void cpt_init_clock_gating(struct drm_device *dev) val = I915_READ(TRANS_CHICKEN2(pipe)); val |= TRANS_CHICKEN2_TIMING_OVERRIDE; val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; - if (dev_priv->fdi_rx_polarity_inverted) + if (dev_priv->vbt.fdi_rx_polarity_inverted) val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 015f9f4263fe..2f54dc3dc5df 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1526,7 +1526,7 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector) return drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, - dev_priv->crt_ddc_pin)); + dev_priv->vbt.crt_ddc_pin)); } static enum drm_connector_status @@ -1809,9 +1809,9 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) goto end; /* Fetch modes from VBT */ - if (dev_priv->sdvo_lvds_vbt_mode != NULL) { + if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) { newmode = drm_mode_duplicate(connector->dev, - dev_priv->sdvo_lvds_vbt_mode); + dev_priv->vbt.sdvo_lvds_vbt_mode); if (newmode != NULL) { /* Guarantee the mode is preferred */ newmode->type = (DRM_MODE_TYPE_PREFERRED | diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index b945bc54207a..7d11a5adc985 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1521,12 +1521,12 @@ static int tv_is_present_in_vbt(struct drm_device *dev) struct child_device_config *p_child; int i, ret; - if (!dev_priv->child_dev_num) + if (!dev_priv->vbt.child_dev_num) return 1; ret = 0; - for (i = 0; i < dev_priv->child_dev_num; i++) { - p_child = dev_priv->child_dev + i; + for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { + p_child = dev_priv->vbt.child_dev + i; /* * If the device type is not TV, continue. */ @@ -1564,7 +1564,7 @@ intel_tv_init(struct drm_device *dev) return; } /* Even if we have an encoder we may not have a connector */ - if (!dev_priv->int_tv_support) + if (!dev_priv->vbt.int_tv_support) return; /* -- cgit v1.2.3 From abe959c7e06f62f064432a2aa00c199f1f672c81 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 6 May 2013 19:37:33 -0300 Subject: drm/i915: Add support for FBC on Ivybridge. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduce Frame Buffer Compression (FBC) support for IVB, without enabling it by default. It adds a new function gen7_enable_fbc to avoid getting ironlake_enable_fbc messed with many IS_IVYBRIDGE checks. v2: Fixes from Ville. * Fix Plane. FBC is tied to primary plane A in HSW * Fix DPFC initial write to avoid let trash on the register. v3: Checking for bad plane on intel_update_fbc() as Chris suggested. v4: Ville pointed out that according to BSpec FBC_CTL bits 0:3 must be 0. v5: Up to v4 this work was entirely focused on Haswell. However Ville noticed I could reuse the FBC work done for HSW and get FBC for free at Ivybridge. So it makes more sense enable FBC for IVB first. FBC for HSW comming on next patches. We are just not enabling it by default on IVB. v6: Fix confused commit name (by Matt Turner). v7: Remove gtt_offset shift since it is page aligned byte offset (by Ville). Cc: Matt Turner Cc: Chris Wilson Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ drivers/gpu/drm/i915/intel_pm.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3cb27fa842ee..cd84f774aace 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -280,6 +280,7 @@ static const struct intel_device_info intel_ivybridge_m_info = { GEN7_FEATURES, .is_ivybridge = 1, .is_mobile = 1, + .has_fbc = 1, }; static const struct intel_device_info intel_ivybridge_q_info = { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a809a5633b28..a7fc13d28b5c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -925,7 +925,9 @@ #define DPFC_CTL_EN (1<<31) #define DPFC_CTL_PLANEA (0<<30) #define DPFC_CTL_PLANEB (1<<30) +#define IVB_DPFC_CTL_PLANE_SHIFT (29) #define DPFC_CTL_FENCE_EN (1<<29) +#define IVB_DPFC_CTL_FENCE_EN (1<<28) #define DPFC_CTL_PERSISTENT_MODE (1<<25) #define DPFC_SR_EN (1<<10) #define DPFC_CTL_LIMIT_1X (0<<6) @@ -958,6 +960,7 @@ #define ILK_DPFC_CHICKEN 0x43224 #define ILK_FBC_RT_BASE 0x2128 #define ILK_FBC_RT_VALID (1<<0) +#define SNB_FBC_FRONT_BUFFER (1<<1) #define ILK_DISPLAY_CHICKEN1 0x42000 #define ILK_FBCQ_DIS (1<<22) @@ -973,6 +976,9 @@ #define SNB_CPU_FENCE_ENABLE (1<<29) #define DPFC_CPU_FENCE_OFFSET 0x100104 +/* Framebuffer compression for Ivybridge */ +#define IVB_FBC_RT_BASE 0x7020 + /* * GPIO regs diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5a22ce2b8244..e398963797a6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -253,6 +253,30 @@ static bool ironlake_fbc_enabled(struct drm_device *dev) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } +static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); + + I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | + IVB_DPFC_CTL_FENCE_EN | + intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); + + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | obj->fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + + sandybridge_blit_fbc_update(dev); + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + bool intel_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -439,7 +463,7 @@ void intel_update_fbc(struct drm_device *dev) if (enable_fbc < 0) { DRM_DEBUG_KMS("fbc set to per-chip default\n"); enable_fbc = 1; - if (INTEL_INFO(dev)->gen <= 6) + if (INTEL_INFO(dev)->gen <= 7) enable_fbc = 0; } if (!enable_fbc) { @@ -4507,7 +4531,12 @@ void intel_init_pm(struct drm_device *dev) if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - dev_priv->display.enable_fbc = ironlake_enable_fbc; + if (IS_IVYBRIDGE(dev)) + dev_priv->display.enable_fbc = + gen7_enable_fbc; + else + dev_priv->display.enable_fbc = + ironlake_enable_fbc; dev_priv->display.disable_fbc = ironlake_disable_fbc; } else if (IS_GM45(dev)) { dev_priv->display.fbc_enabled = g4x_fbc_enabled; -- cgit v1.2.3 From 30ca7c6f97e266d122b03261f75f530d5c83608b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 6 May 2013 19:37:34 -0300 Subject: drm/i915: IVB FBC WaFbcAsynchFlipDisableFbcQueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display register 42000h bit 22 must be set to 1b for the entire time that Frame Buffer Compression is enabled. Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e398963797a6..48283167c195 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -268,6 +268,8 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) IVB_DPFC_CTL_FENCE_EN | intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); + /* WaFbcAsynchFlipDisableFbcQueue */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); -- cgit v1.2.3 From b74ea102b746a1e5157d6b0c83f486ad3c6235d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 May 2013 14:08:38 -0300 Subject: drm/i915: IVB FBC WaFbcDisableDpfcClockGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display register 42020h bit 9 must be set to 1b for the entire time that Frame Buffer Compression is enabled. v2: RMW to preserve other bits (by Ville) v3: Fix from Ville: sed &/| at RMW v4: Too far on sed. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 48283167c195..fdc2839448a0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -242,6 +242,12 @@ static void ironlake_disable_fbc(struct drm_device *dev) dpfc_ctl &= ~DPFC_CTL_EN; I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + if (IS_IVYBRIDGE(dev)) + /* WaFbcDisableDpfcClockGating */ + I915_WRITE(ILK_DSPCLK_GATE_D, + I915_READ(ILK_DSPCLK_GATE_D) & + ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + DRM_DEBUG_KMS("disabled FBC\n"); } } @@ -270,6 +276,11 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* WaFbcAsynchFlipDisableFbcQueue */ I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); + /* WaFbcDisableDpfcClockGating */ + I915_WRITE(ILK_DSPCLK_GATE_D, + I915_READ(ILK_DSPCLK_GATE_D) | + ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); -- cgit v1.2.3 From 891348b2bf08d8946e0621bec49802897b28c1c4 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 6 May 2013 19:37:36 -0300 Subject: drm/i915: Enable FBC at Haswell. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduce Frame Buffer Compression (FBC) support for HSW. FBC is tied to primary plane A in HSW. v2: Ville pointed out docs say FBC must be disabled before disabling the plane on HSW. v3: Really enabling it by default at HSW. Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 1 + drivers/gpu/drm/i915/intel_display.c | 5 +++-- drivers/gpu/drm/i915/intel_pm.c | 21 ++++++++++++--------- 3 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cd84f774aace..a1a936fd34e0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -319,6 +319,7 @@ static const struct intel_device_info intel_haswell_m_info = { .is_mobile = 1, .has_ddi = 1, .has_fpga_dbg = 1, + .has_fbc = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a14fec3a6740..50814ce84a9f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3518,11 +3518,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); - intel_disable_plane(dev_priv, plane, pipe); - + /* FBC must be disabled before disabling the plane on HSW. */ if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + intel_disable_plane(dev_priv, plane, pipe); + if (intel_crtc->config.has_pch_encoder) intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false); intel_disable_pipe(dev_priv, pipe); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fdc2839448a0..10f788b62fa8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -274,12 +274,14 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) IVB_DPFC_CTL_FENCE_EN | intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); - /* WaFbcAsynchFlipDisableFbcQueue */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); - /* WaFbcDisableDpfcClockGating */ - I915_WRITE(ILK_DSPCLK_GATE_D, - I915_READ(ILK_DSPCLK_GATE_D) | - ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + if (IS_IVYBRIDGE(dev)) { + /* WaFbcAsynchFlipDisableFbcQueue */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); + /* WaFbcDisableDpfcClockGating */ + I915_WRITE(ILK_DSPCLK_GATE_D, + I915_READ(ILK_DSPCLK_GATE_D) | + ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + } I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); @@ -476,7 +478,7 @@ void intel_update_fbc(struct drm_device *dev) if (enable_fbc < 0) { DRM_DEBUG_KMS("fbc set to per-chip default\n"); enable_fbc = 1; - if (INTEL_INFO(dev)->gen <= 7) + if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) enable_fbc = 0; } if (!enable_fbc) { @@ -497,7 +499,8 @@ void intel_update_fbc(struct drm_device *dev) dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; goto out_disable; } - if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { + if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) && + intel_crtc->plane != 0) { DRM_DEBUG_KMS("plane not 0, disabling compression\n"); dev_priv->no_fbc_reason = FBC_BAD_PLANE; goto out_disable; @@ -4544,7 +4547,7 @@ void intel_init_pm(struct drm_device *dev) if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - if (IS_IVYBRIDGE(dev)) + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->display.enable_fbc = gen7_enable_fbc; else -- cgit v1.2.3 From 285541647a816e00348916ba7387eeacea30eba9 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 6 May 2013 19:37:37 -0300 Subject: drm/i915: HSW FBC WaFbcAsynchFlipDisableFbcQueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display register 420B0h bit 22 must be set to 1b for the entire time that Frame Buffer Compression is enabled. Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 +++++++ drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a7fc13d28b5c..d48558678e87 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -980,6 +980,13 @@ #define IVB_FBC_RT_BASE 0x7020 +#define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 +#define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 +#define HSW_BYPASS_FBC_QUEUE (1<<22) +#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \ + _HSW_PIPE_SLICE_CHICKEN_1_A, + \ + _HSW_PIPE_SLICE_CHICKEN_1_B) + /* * GPIO regs */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 10f788b62fa8..4e678bad46d3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -281,6 +281,10 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) I915_WRITE(ILK_DSPCLK_GATE_D, I915_READ(ILK_DSPCLK_GATE_D) | ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + } else { + /* WaFbcAsynchFlipDisableFbcQueue */ + I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe), + HSW_BYPASS_FBC_QUEUE); } I915_WRITE(SNB_DPFC_CTL_SA, -- cgit v1.2.3 From d89f2071461d5682b897c73278daaf25fd11aff5 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 May 2013 14:20:50 -0300 Subject: drm/i915: HSW FBC WaFbcDisableDpfcClockGating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display register 46500h bit 23 must be set to 1b for the entire time that Frame Buffer Compression is enabled. v2: Ville suggested to enable it back when disabling fbc to avoid wasting power. v3: RMW to preserve other bits (by Ville) v4: Fix from Ville: sed &/| at RMW v5: Too far on sed. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Rodrigo Vivi [danvet: Insert missing space that checkpatch spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 10 ++++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d48558678e87..7af7ae66b338 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -987,6 +987,9 @@ _HSW_PIPE_SLICE_CHICKEN_1_A, + \ _HSW_PIPE_SLICE_CHICKEN_1_B) +#define HSW_CLKGATE_DISABLE_PART_1 0x46500 +#define HSW_DPFC_GATING_DISABLE (1<<23) + /* * GPIO regs */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4e678bad46d3..d806448f84fa 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -248,6 +248,12 @@ static void ironlake_disable_fbc(struct drm_device *dev) I915_READ(ILK_DSPCLK_GATE_D) & ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE); + if (IS_HASWELL(dev)) + /* WaFbcDisableDpfcClockGating */ + I915_WRITE(HSW_CLKGATE_DISABLE_PART_1, + I915_READ(HSW_CLKGATE_DISABLE_PART_1) & + ~HSW_DPFC_GATING_DISABLE); + DRM_DEBUG_KMS("disabled FBC\n"); } } @@ -285,6 +291,10 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) /* WaFbcAsynchFlipDisableFbcQueue */ I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe), HSW_BYPASS_FBC_QUEUE); + /* WaFbcDisableDpfcClockGating */ + I915_WRITE(HSW_CLKGATE_DISABLE_PART_1, + I915_READ(HSW_CLKGATE_DISABLE_PART_1) | + HSW_DPFC_GATING_DISABLE); } I915_WRITE(SNB_DPFC_CTL_SA, -- cgit v1.2.3 From 1c0b85c566b7a5a5cdabb767a39b445ce271a4fa Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 10 May 2013 14:01:51 +0100 Subject: drm/i915: Compute WR PLL dividers dynamically Up to now, we were using a static table to match the clock frequency with a (r2,n2,p) triplet. Despite this table being big, it's by no mean comprehensive and we had to fall back to the closest frequency when the requested TMDS clock wasn't in the table. This patch computes (r2,n2,p) dynamically and get rid of The Big Table. v2: Replace the floating point constant 1e6 by 1000000 Bugzilla: http://bugs.freedesktop.org/show_bug.cgi?id=58497 Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni (v1) Tested-by: Paulo Zanoni (v1) [danvet: s/ /^T/] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 617 ++++++++++++++------------------------- 1 file changed, 214 insertions(+), 403 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 146893288e53..cddcf4af7a5a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -281,392 +281,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DRM_ERROR("FDI link training failed!\n"); } -/* WRPLL clock dividers */ -struct wrpll_tmds_clock { - u32 clock; - u16 p; /* Post divider */ - u16 n2; /* Feedback divider */ - u16 r2; /* Reference divider */ -}; - -/* Table of matching values for WRPLL clocks programming for each frequency. - * The code assumes this table is sorted. */ -static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { - {19750, 38, 25, 18}, - {20000, 48, 32, 18}, - {21000, 36, 21, 15}, - {21912, 42, 29, 17}, - {22000, 36, 22, 15}, - {23000, 36, 23, 15}, - {23500, 40, 40, 23}, - {23750, 26, 16, 14}, - {24000, 36, 24, 15}, - {25000, 36, 25, 15}, - {25175, 26, 40, 33}, - {25200, 30, 21, 15}, - {26000, 36, 26, 15}, - {27000, 30, 21, 14}, - {27027, 18, 100, 111}, - {27500, 30, 29, 19}, - {28000, 34, 30, 17}, - {28320, 26, 30, 22}, - {28322, 32, 42, 25}, - {28750, 24, 23, 18}, - {29000, 30, 29, 18}, - {29750, 32, 30, 17}, - {30000, 30, 25, 15}, - {30750, 30, 41, 24}, - {31000, 30, 31, 18}, - {31500, 30, 28, 16}, - {32000, 30, 32, 18}, - {32500, 28, 32, 19}, - {33000, 24, 22, 15}, - {34000, 28, 30, 17}, - {35000, 26, 32, 19}, - {35500, 24, 30, 19}, - {36000, 26, 26, 15}, - {36750, 26, 46, 26}, - {37000, 24, 23, 14}, - {37762, 22, 40, 26}, - {37800, 20, 21, 15}, - {38000, 24, 27, 16}, - {38250, 24, 34, 20}, - {39000, 24, 26, 15}, - {40000, 24, 32, 18}, - {40500, 20, 21, 14}, - {40541, 22, 147, 89}, - {40750, 18, 19, 14}, - {41000, 16, 17, 14}, - {41500, 22, 44, 26}, - {41540, 22, 44, 26}, - {42000, 18, 21, 15}, - {42500, 22, 45, 26}, - {43000, 20, 43, 27}, - {43163, 20, 24, 15}, - {44000, 18, 22, 15}, - {44900, 20, 108, 65}, - {45000, 20, 25, 15}, - {45250, 20, 52, 31}, - {46000, 18, 23, 15}, - {46750, 20, 45, 26}, - {47000, 20, 40, 23}, - {48000, 18, 24, 15}, - {49000, 18, 49, 30}, - {49500, 16, 22, 15}, - {50000, 18, 25, 15}, - {50500, 18, 32, 19}, - {51000, 18, 34, 20}, - {52000, 18, 26, 15}, - {52406, 14, 34, 25}, - {53000, 16, 22, 14}, - {54000, 16, 24, 15}, - {54054, 16, 173, 108}, - {54500, 14, 24, 17}, - {55000, 12, 22, 18}, - {56000, 14, 45, 31}, - {56250, 16, 25, 15}, - {56750, 14, 25, 17}, - {57000, 16, 27, 16}, - {58000, 16, 43, 25}, - {58250, 16, 38, 22}, - {58750, 16, 40, 23}, - {59000, 14, 26, 17}, - {59341, 14, 40, 26}, - {59400, 16, 44, 25}, - {60000, 16, 32, 18}, - {60500, 12, 39, 29}, - {61000, 14, 49, 31}, - {62000, 14, 37, 23}, - {62250, 14, 42, 26}, - {63000, 12, 21, 15}, - {63500, 14, 28, 17}, - {64000, 12, 27, 19}, - {65000, 14, 32, 19}, - {65250, 12, 29, 20}, - {65500, 12, 32, 22}, - {66000, 12, 22, 15}, - {66667, 14, 38, 22}, - {66750, 10, 21, 17}, - {67000, 14, 33, 19}, - {67750, 14, 58, 33}, - {68000, 14, 30, 17}, - {68179, 14, 46, 26}, - {68250, 14, 46, 26}, - {69000, 12, 23, 15}, - {70000, 12, 28, 18}, - {71000, 12, 30, 19}, - {72000, 12, 24, 15}, - {73000, 10, 23, 17}, - {74000, 12, 23, 14}, - {74176, 8, 100, 91}, - {74250, 10, 22, 16}, - {74481, 12, 43, 26}, - {74500, 10, 29, 21}, - {75000, 12, 25, 15}, - {75250, 10, 39, 28}, - {76000, 12, 27, 16}, - {77000, 12, 53, 31}, - {78000, 12, 26, 15}, - {78750, 12, 28, 16}, - {79000, 10, 38, 26}, - {79500, 10, 28, 19}, - {80000, 12, 32, 18}, - {81000, 10, 21, 14}, - {81081, 6, 100, 111}, - {81624, 8, 29, 24}, - {82000, 8, 17, 14}, - {83000, 10, 40, 26}, - {83950, 10, 28, 18}, - {84000, 10, 28, 18}, - {84750, 6, 16, 17}, - {85000, 6, 17, 18}, - {85250, 10, 30, 19}, - {85750, 10, 27, 17}, - {86000, 10, 43, 27}, - {87000, 10, 29, 18}, - {88000, 10, 44, 27}, - {88500, 10, 41, 25}, - {89000, 10, 28, 17}, - {89012, 6, 90, 91}, - {89100, 10, 33, 20}, - {90000, 10, 25, 15}, - {91000, 10, 32, 19}, - {92000, 10, 46, 27}, - {93000, 10, 31, 18}, - {94000, 10, 40, 23}, - {94500, 10, 28, 16}, - {95000, 10, 44, 25}, - {95654, 10, 39, 22}, - {95750, 10, 39, 22}, - {96000, 10, 32, 18}, - {97000, 8, 23, 16}, - {97750, 8, 42, 29}, - {98000, 8, 45, 31}, - {99000, 8, 22, 15}, - {99750, 8, 34, 23}, - {100000, 6, 20, 18}, - {100500, 6, 19, 17}, - {101000, 6, 37, 33}, - {101250, 8, 21, 14}, - {102000, 6, 17, 15}, - {102250, 6, 25, 22}, - {103000, 8, 29, 19}, - {104000, 8, 37, 24}, - {105000, 8, 28, 18}, - {106000, 8, 22, 14}, - {107000, 8, 46, 29}, - {107214, 8, 27, 17}, - {108000, 8, 24, 15}, - {108108, 8, 173, 108}, - {109000, 6, 23, 19}, - {110000, 6, 22, 18}, - {110013, 6, 22, 18}, - {110250, 8, 49, 30}, - {110500, 8, 36, 22}, - {111000, 8, 23, 14}, - {111264, 8, 150, 91}, - {111375, 8, 33, 20}, - {112000, 8, 63, 38}, - {112500, 8, 25, 15}, - {113100, 8, 57, 34}, - {113309, 8, 42, 25}, - {114000, 8, 27, 16}, - {115000, 6, 23, 18}, - {116000, 8, 43, 25}, - {117000, 8, 26, 15}, - {117500, 8, 40, 23}, - {118000, 6, 38, 29}, - {119000, 8, 30, 17}, - {119500, 8, 46, 26}, - {119651, 8, 39, 22}, - {120000, 8, 32, 18}, - {121000, 6, 39, 29}, - {121250, 6, 31, 23}, - {121750, 6, 23, 17}, - {122000, 6, 42, 31}, - {122614, 6, 30, 22}, - {123000, 6, 41, 30}, - {123379, 6, 37, 27}, - {124000, 6, 51, 37}, - {125000, 6, 25, 18}, - {125250, 4, 13, 14}, - {125750, 4, 27, 29}, - {126000, 6, 21, 15}, - {127000, 6, 24, 17}, - {127250, 6, 41, 29}, - {128000, 6, 27, 19}, - {129000, 6, 43, 30}, - {129859, 4, 25, 26}, - {130000, 6, 26, 18}, - {130250, 6, 42, 29}, - {131000, 6, 32, 22}, - {131500, 6, 38, 26}, - {131850, 6, 41, 28}, - {132000, 6, 22, 15}, - {132750, 6, 28, 19}, - {133000, 6, 34, 23}, - {133330, 6, 37, 25}, - {134000, 6, 61, 41}, - {135000, 6, 21, 14}, - {135250, 6, 167, 111}, - {136000, 6, 62, 41}, - {137000, 6, 35, 23}, - {138000, 6, 23, 15}, - {138500, 6, 40, 26}, - {138750, 6, 37, 24}, - {139000, 6, 34, 22}, - {139050, 6, 34, 22}, - {139054, 6, 34, 22}, - {140000, 6, 28, 18}, - {141000, 6, 36, 23}, - {141500, 6, 22, 14}, - {142000, 6, 30, 19}, - {143000, 6, 27, 17}, - {143472, 4, 17, 16}, - {144000, 6, 24, 15}, - {145000, 6, 29, 18}, - {146000, 6, 47, 29}, - {146250, 6, 26, 16}, - {147000, 6, 49, 30}, - {147891, 6, 23, 14}, - {148000, 6, 23, 14}, - {148250, 6, 28, 17}, - {148352, 4, 100, 91}, - {148500, 6, 33, 20}, - {149000, 6, 48, 29}, - {150000, 6, 25, 15}, - {151000, 4, 19, 17}, - {152000, 6, 27, 16}, - {152280, 6, 44, 26}, - {153000, 6, 34, 20}, - {154000, 6, 53, 31}, - {155000, 6, 31, 18}, - {155250, 6, 50, 29}, - {155750, 6, 45, 26}, - {156000, 6, 26, 15}, - {157000, 6, 61, 35}, - {157500, 6, 28, 16}, - {158000, 6, 65, 37}, - {158250, 6, 44, 25}, - {159000, 6, 53, 30}, - {159500, 6, 39, 22}, - {160000, 6, 32, 18}, - {161000, 4, 31, 26}, - {162000, 4, 18, 15}, - {162162, 4, 131, 109}, - {162500, 4, 53, 44}, - {163000, 4, 29, 24}, - {164000, 4, 17, 14}, - {165000, 4, 22, 18}, - {166000, 4, 32, 26}, - {167000, 4, 26, 21}, - {168000, 4, 46, 37}, - {169000, 4, 104, 83}, - {169128, 4, 64, 51}, - {169500, 4, 39, 31}, - {170000, 4, 34, 27}, - {171000, 4, 19, 15}, - {172000, 4, 51, 40}, - {172750, 4, 32, 25}, - {172800, 4, 32, 25}, - {173000, 4, 41, 32}, - {174000, 4, 49, 38}, - {174787, 4, 22, 17}, - {175000, 4, 35, 27}, - {176000, 4, 30, 23}, - {177000, 4, 38, 29}, - {178000, 4, 29, 22}, - {178500, 4, 37, 28}, - {179000, 4, 53, 40}, - {179500, 4, 73, 55}, - {180000, 4, 20, 15}, - {181000, 4, 55, 41}, - {182000, 4, 31, 23}, - {183000, 4, 42, 31}, - {184000, 4, 30, 22}, - {184750, 4, 26, 19}, - {185000, 4, 37, 27}, - {186000, 4, 51, 37}, - {187000, 4, 36, 26}, - {188000, 4, 32, 23}, - {189000, 4, 21, 15}, - {190000, 4, 38, 27}, - {190960, 4, 41, 29}, - {191000, 4, 41, 29}, - {192000, 4, 27, 19}, - {192250, 4, 37, 26}, - {193000, 4, 20, 14}, - {193250, 4, 53, 37}, - {194000, 4, 23, 16}, - {194208, 4, 23, 16}, - {195000, 4, 26, 18}, - {196000, 4, 45, 31}, - {197000, 4, 35, 24}, - {197750, 4, 41, 28}, - {198000, 4, 22, 15}, - {198500, 4, 25, 17}, - {199000, 4, 28, 19}, - {200000, 4, 37, 25}, - {201000, 4, 61, 41}, - {202000, 4, 112, 75}, - {202500, 4, 21, 14}, - {203000, 4, 146, 97}, - {204000, 4, 62, 41}, - {204750, 4, 44, 29}, - {205000, 4, 38, 25}, - {206000, 4, 29, 19}, - {207000, 4, 23, 15}, - {207500, 4, 40, 26}, - {208000, 4, 37, 24}, - {208900, 4, 48, 31}, - {209000, 4, 48, 31}, - {209250, 4, 31, 20}, - {210000, 4, 28, 18}, - {211000, 4, 25, 16}, - {212000, 4, 22, 14}, - {213000, 4, 30, 19}, - {213750, 4, 38, 24}, - {214000, 4, 46, 29}, - {214750, 4, 35, 22}, - {215000, 4, 43, 27}, - {216000, 4, 24, 15}, - {217000, 4, 37, 23}, - {218000, 4, 42, 26}, - {218250, 4, 42, 26}, - {218750, 4, 34, 21}, - {219000, 4, 47, 29}, - {220000, 4, 44, 27}, - {220640, 4, 49, 30}, - {220750, 4, 36, 22}, - {221000, 4, 36, 22}, - {222000, 4, 23, 14}, - {222525, 4, 28, 17}, - {222750, 4, 33, 20}, - {227000, 4, 37, 22}, - {230250, 4, 29, 17}, - {233500, 4, 38, 22}, - {235000, 4, 40, 23}, - {238000, 4, 30, 17}, - {241500, 2, 17, 19}, - {245250, 2, 20, 22}, - {247750, 2, 22, 24}, - {253250, 2, 15, 16}, - {256250, 2, 18, 19}, - {262500, 2, 31, 32}, - {267250, 2, 66, 67}, - {268500, 2, 94, 95}, - {270000, 2, 14, 14}, - {272500, 2, 77, 76}, - {273750, 2, 57, 56}, - {280750, 2, 24, 23}, - {281250, 2, 23, 22}, - {286000, 2, 17, 16}, - {291750, 2, 26, 24}, - {296703, 2, 56, 51}, - {297000, 2, 22, 20}, - {298000, 2, 21, 19}, -}; - static void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -790,27 +404,224 @@ void intel_ddi_put_crtc_pll(struct drm_crtc *crtc) intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE; } -static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2) +#define LC_FREQ 2700 +#define LC_FREQ_2K (LC_FREQ * 2000) + +#define P_MIN 2 +#define P_MAX 64 +#define P_INC 2 + +/* Constraints for PLL good behavior */ +#define REF_MIN 48 +#define REF_MAX 400 +#define VCO_MIN 2400 +#define VCO_MAX 4800 + +#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a)) + +struct wrpll_rnp { + unsigned p, n2, r2; +}; + +static unsigned wrpll_get_budget_for_freq(int clock) +{ + unsigned budget; + + switch (clock) { + case 25175000: + case 25200000: + case 27000000: + case 27027000: + case 37762500: + case 37800000: + case 40500000: + case 40541000: + case 54000000: + case 54054000: + case 59341000: + case 59400000: + case 72000000: + case 74176000: + case 74250000: + case 81000000: + case 81081000: + case 89012000: + case 89100000: + case 108000000: + case 108108000: + case 111264000: + case 111375000: + case 148352000: + case 148500000: + case 162000000: + case 162162000: + case 222525000: + case 222750000: + case 296703000: + case 297000000: + budget = 0; + break; + case 233500000: + case 245250000: + case 247750000: + case 253250000: + case 298000000: + budget = 1500; + break; + case 169128000: + case 169500000: + case 179500000: + case 202000000: + budget = 2000; + break; + case 256250000: + case 262500000: + case 270000000: + case 272500000: + case 273750000: + case 280750000: + case 281250000: + case 286000000: + case 291750000: + budget = 4000; + break; + case 267250000: + case 268500000: + budget = 5000; + break; + default: + budget = 1000; + break; + } + + return budget; +} + +static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, + unsigned r2, unsigned n2, unsigned p, + struct wrpll_rnp *best) { - u32 i; + uint64_t a, b, c, d, diff, diff_best; - for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) - if (clock <= wrpll_tmds_clock_table[i].clock) - break; + /* No best (r,n,p) yet */ + if (best->p == 0) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + return; + } + + /* + * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to + * freq2k. + * + * delta = 1e6 * + * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) / + * freq2k; + * + * and we would like delta <= budget. + * + * If the discrepancy is above the PPM-based budget, always prefer to + * improve upon the previous solution. However, if you're within the + * budget, try to maximize Ref * VCO, that is N / (P * R^2). + */ + a = freq2k * budget * p * r2; + b = freq2k * budget * best->p * best->r2; + diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2)); + diff_best = ABS_DIFF((freq2k * best->p * best->r2), + (LC_FREQ_2K * best->n2)); + c = 1000000 * diff; + d = 1000000 * diff_best; + + if (a < c && b < d) { + /* If both are above the budget, pick the closer */ + if (best->p * best->r2 * diff < p * r2 * diff_best) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + } + } else if (a >= c && b < d) { + /* If A is below the threshold but B is above it? Update. */ + best->p = p; + best->n2 = n2; + best->r2 = r2; + } else if (a >= c && b >= d) { + /* Both are below the limit, so pick the higher n2/(r2*r2) */ + if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) { + best->p = p; + best->n2 = n2; + best->r2 = r2; + } + } + /* Otherwise a < c && b >= d, do nothing */ +} + +static void +intel_ddi_calculate_wrpll(int clock /* in Hz */, + unsigned *r2_out, unsigned *n2_out, unsigned *p_out) +{ + uint64_t freq2k; + unsigned p, n2, r2; + struct wrpll_rnp best = { 0, 0, 0 }; + unsigned budget; - if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) - i--; + freq2k = clock / 100; - *p = wrpll_tmds_clock_table[i].p; - *n2 = wrpll_tmds_clock_table[i].n2; - *r2 = wrpll_tmds_clock_table[i].r2; + budget = wrpll_get_budget_for_freq(clock); + + /* Special case handling for 540 pixel clock: bypass WR PLL entirely + * and directly pass the LC PLL to it. */ + if (freq2k == 5400000) { + *n2_out = 2; + *p_out = 1; + *r2_out = 2; + return; + } + + /* + * Ref = LC_FREQ / R, where Ref is the actual reference input seen by + * the WR PLL. + * + * We want R so that REF_MIN <= Ref <= REF_MAX. + * Injecting R2 = 2 * R gives: + * REF_MAX * r2 > LC_FREQ * 2 and + * REF_MIN * r2 < LC_FREQ * 2 + * + * Which means the desired boundaries for r2 are: + * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN + * + */ + for (r2 = LC_FREQ * 2 / REF_MAX + 1; + r2 <= LC_FREQ * 2 / REF_MIN; + r2++) { + + /* + * VCO = N * Ref, that is: VCO = N * LC_FREQ / R + * + * Once again we want VCO_MIN <= VCO <= VCO_MAX. + * Injecting R2 = 2 * R and N2 = 2 * N, we get: + * VCO_MAX * r2 > n2 * LC_FREQ and + * VCO_MIN * r2 < n2 * LC_FREQ) + * + * Which means the desired boundaries for n2 are: + * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ + */ + for (n2 = VCO_MIN * r2 / LC_FREQ + 1; + n2 <= VCO_MAX * r2 / LC_FREQ; + n2++) { + + for (p = P_MIN; p <= P_MAX; p += P_INC) + wrpll_update_rnp(freq2k, budget, + r2, n2, p, &best); + } + } - if (wrpll_tmds_clock_table[i].clock != clock) - DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n", - wrpll_tmds_clock_table[i].clock, clock); + *n2_out = best.n2; + *p_out = best.p; + *r2_out = best.r2; - DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", - clock, *p, *n2, *r2); + DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, *p_out, *n2_out, *r2_out); } bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) @@ -851,7 +662,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) return true; } else if (type == INTEL_OUTPUT_HDMI) { - int p, n2, r2; + unsigned p, n2, r2; if (plls->wrpll1_refcount == 0) { DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n", @@ -873,7 +684,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) WARN(I915_READ(reg) & WRPLL_PLL_ENABLE, "WRPLL already enabled\n"); - intel_ddi_calculate_wrpll(clock, &p, &n2, &r2); + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) | -- cgit v1.2.3 From 7881d4f11c00f506907b1bccb73df81509dc9c15 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 30 Apr 2013 14:01:46 +0200 Subject: drm/i915: rip out an unused lvds_reg variable Somehow this has been forgotten in commit 1974cad0ee4ce84e5cb792e49c4f0d9421e0312c Author: Daniel Vetter Date: Mon Nov 26 17:22:09 2012 +0100 drm/i915: move is_dual_link_lvds to intel_lvds.c Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 50814ce84a9f..e9d01e5d6ccb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -651,12 +651,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, found = false; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - int lvds_reg; - - if (HAS_PCH_SPLIT(dev)) - lvds_reg = PCH_LVDS; - else - lvds_reg = LVDS; if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else -- cgit v1.2.3 From 7dd23ba0899bd1a203cc1d6e7878d7dfc910a511 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 10 May 2013 14:33:17 +0100 Subject: drm/i915: Add missing platform tags to FBC workaround comments There was a race between Rodrigo writing those patches and me formalizing the addition of platform tags. This patches fixes it. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d806448f84fa..28cec57e3f8c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -243,13 +243,13 @@ static void ironlake_disable_fbc(struct drm_device *dev) I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); if (IS_IVYBRIDGE(dev)) - /* WaFbcDisableDpfcClockGating */ + /* WaFbcDisableDpfcClockGating:ivb */ I915_WRITE(ILK_DSPCLK_GATE_D, I915_READ(ILK_DSPCLK_GATE_D) & ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE); if (IS_HASWELL(dev)) - /* WaFbcDisableDpfcClockGating */ + /* WaFbcDisableDpfcClockGating:hsw */ I915_WRITE(HSW_CLKGATE_DISABLE_PART_1, I915_READ(HSW_CLKGATE_DISABLE_PART_1) & ~HSW_DPFC_GATING_DISABLE); @@ -281,17 +281,17 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT); if (IS_IVYBRIDGE(dev)) { - /* WaFbcAsynchFlipDisableFbcQueue */ + /* WaFbcAsynchFlipDisableFbcQueue:ivb */ I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS); - /* WaFbcDisableDpfcClockGating */ + /* WaFbcDisableDpfcClockGating:ivb */ I915_WRITE(ILK_DSPCLK_GATE_D, I915_READ(ILK_DSPCLK_GATE_D) | ILK_DPFCUNIT_CLOCK_GATE_DISABLE); } else { - /* WaFbcAsynchFlipDisableFbcQueue */ + /* WaFbcAsynchFlipDisableFbcQueue:hsw */ I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe), HSW_BYPASS_FBC_QUEUE); - /* WaFbcDisableDpfcClockGating */ + /* WaFbcDisableDpfcClockGating:hsw */ I915_WRITE(HSW_CLKGATE_DISABLE_PART_1, I915_READ(HSW_CLKGATE_DISABLE_PART_1) | HSW_DPFC_GATING_DISABLE); -- cgit v1.2.3 From 0a790cdbfc526890af7dc41515a563f09e427129 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 17 Apr 2013 18:15:49 -0300 Subject: drm/i915: implement WADPOClockGatingDisable for LPT This should prevent mode set failures on LPT. Signed-off-by: Paulo Zanoni Reviewed-by: Damien Lespiau [danvet: Pimp the w/a tag to fit into Damien's new scheme.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 28cec57e3f8c..1a765723d37e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4093,6 +4093,11 @@ static void lpt_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, I915_READ(SOUTH_DSPCLK_GATE_D) | PCH_LP_PARTITION_LEVEL_DISABLE); + + /* WADPOClockGatingDisable:hsw */ + I915_WRITE(_TRANSA_CHICKEN1, + I915_READ(_TRANSA_CHICKEN1) | + TRANS_CHICKEN1_DP0UNIT_GC_DISABLE); } static void lpt_suspend_hw(struct drm_device *dev) -- cgit v1.2.3 From 2fa2fe9a142cf8c8a30916ccf7ca6a27019fd6d2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 May 2013 23:34:16 +0200 Subject: drm/i915: panel fitter hw state readout&check support Pfit state readout is a bit ugly on gen2/3 due to the intermingling with the lvds state, but alas. Also note that since state is always cleared to zero we can unconditonally compare all the state and completely neglect the actual platform we're running on. v2: Properly check for the pfit power domain on haswell. v3: Don't check pgm_ratios on gen4+, they're auto-computed by the hw. v4: Properly clear the lvds border bits, upset the state checker a bit. v5: Unconditionally read out panel dither settings on gen2/3. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 67 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_lvds.c | 1 + 2 files changed, 66 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9d01e5d6ccb..12a92edbdd1a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4976,6 +4976,36 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, return ret; } +static void i9xx_get_pfit_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PFIT_CONTROL); + + if (INTEL_INFO(dev)->gen < 4) { + if (crtc->pipe != PIPE_B) + return; + + /* gen2/3 store dither state in pfit control, needs to match */ + pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE; + } else { + if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT)) + return; + } + + if (!(tmp & PFIT_ENABLE)) + return; + + pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL); + pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS); + if (INTEL_INFO(dev)->gen < 5) + pipe_config->gmch_pfit.lvds_border_bits = + I915_READ(LVDS) & LVDS_BORDER_ENABLE; +} + static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -4989,6 +5019,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + i9xx_get_pfit_config(crtc, pipe_config); + return true; } @@ -5820,6 +5852,21 @@ static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc, & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1; } +static void ironlake_get_pfit_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(PF_CTL(crtc->pipe)); + + if (tmp & PF_ENABLE) { + pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe)); + pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe)); + } +} + static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { @@ -5843,6 +5890,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + ironlake_get_pfit_config(crtc, pipe_config); + return true; } @@ -5962,6 +6011,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; + enum intel_display_power_domain pfit_domain; uint32_t tmp; if (!intel_display_power_enabled(dev, @@ -5991,6 +6041,10 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, intel_get_pipe_timings(crtc, pipe_config); + pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe); + if (intel_display_power_enabled(dev, pfit_domain)) + ironlake_get_pfit_config(crtc, pipe_config); + return true; } @@ -7956,7 +8010,8 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) if (mask & (1 <<(intel_crtc)->pipe)) static bool -intel_pipe_config_compare(struct intel_crtc_config *current_config, +intel_pipe_config_compare(struct drm_device *dev, + struct intel_crtc_config *current_config, struct intel_crtc_config *pipe_config) { #define PIPE_CONF_CHECK_I(name) \ @@ -8005,6 +8060,14 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config, PIPE_CONF_CHECK_I(requested_mode.hdisplay); PIPE_CONF_CHECK_I(requested_mode.vdisplay); + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); + PIPE_CONF_CHECK_I(pch_pfit.pos); + PIPE_CONF_CHECK_I(pch_pfit.size); + #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS @@ -8116,7 +8179,7 @@ intel_modeset_check_state(struct drm_device *dev) "(expected %i, found %i)\n", crtc->active, active); WARN(active && - !intel_pipe_config_compare(&crtc->config, &pipe_config), + !intel_pipe_config_compare(dev, &crtc->config, &pipe_config), "pipe state doesn't match!\n"); } } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e34e290c29eb..36fe291172ee 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -116,6 +116,7 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) } /* set the corresponsding LVDS_BORDER bit */ + temp &= ~LVDS_BORDER_ENABLE; temp |= intel_crtc->config.gmch_pfit.lvds_border_bits; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. -- cgit v1.2.3 From 3f8dce3ade6ae025a8a77e7b74ec58a5c26b17e2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 May 2013 10:36:30 +0200 Subject: drm/i915: Use pipe_config state to disable ilk+ pfit No more need to guard the write with a power well check on Haswell now that we have proper pfit state readout: We can simply only clear the pfit if it's actually on. This removes some duplication of knowledge between the haswell pfit disable and pfit state readout code about. While at it extract a little helper for this. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12a92edbdd1a..33544a256f15 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3410,6 +3410,21 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_wait_for_vblank(dev, intel_crtc->pipe); } +static void ironlake_pfit_disable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe = crtc->pipe; + + /* To avoid upsetting the power well on haswell only disable the pfit if + * it's in use. The hw state code will make sure we get this right. */ + if (crtc->config.pch_pfit.size) { + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_POS(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); + } +} + static void ironlake_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3439,9 +3454,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_set_pch_fifo_underrun_reporting(dev, pipe, false); intel_disable_pipe(dev_priv, pipe); - /* Disable PF */ - I915_WRITE(PF_CTL(pipe), 0); - I915_WRITE(PF_WIN_SZ(pipe), 0); + ironlake_pfit_disable(intel_crtc); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) @@ -3524,14 +3537,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); - /* XXX: Once we have proper panel fitter state tracking implemented with - * hardware state read/check support we should switch to only disable - * the panel fitter when we know it's used. */ - if (intel_display_power_enabled(dev, - POWER_DOMAIN_PIPE_PANEL_FITTER(pipe))) { - I915_WRITE(PF_CTL(pipe), 0); - I915_WRITE(PF_WIN_SZ(pipe), 0); - } + ironlake_pfit_disable(intel_crtc); intel_ddi_disable_pipe_clock(intel_crtc); -- cgit v1.2.3 From 328d8e829b9a05814af4722c1091d62c5533c4f8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 May 2013 10:36:31 +0200 Subject: drm/i915: Use pipe config state to control gmch pfit enable/disable Allows us to rip out a few fragile checks (which are duplicated in the hw state readout now, too). Also prepares us a bit for more than one panel/pfit. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 33544a256f15..7358e4e9761e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3624,8 +3624,7 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc_config *pipe_config = &crtc->config; - if (!(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || - intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS))) + if (!crtc->config.gmch_pfit.control) return; WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); @@ -3744,20 +3743,15 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - uint32_t pctl = I915_READ(PFIT_CONTROL); - assert_pipe_disabled(dev_priv, crtc->pipe); + if (!crtc->config.gmch_pfit.control) + return; - if (INTEL_INFO(dev)->gen >= 4) - pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; - else - pipe = PIPE_B; + assert_pipe_disabled(dev_priv, crtc->pipe); - if (pipe == crtc->pipe) { - DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl); - I915_WRITE(PFIT_CONTROL, 0); - } + DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", + I915_READ(PFIT_CONTROL)); + I915_WRITE(PFIT_CONTROL, 0); } static void i9xx_crtc_disable(struct drm_crtc *crtc) -- cgit v1.2.3 From 98304ad186296dc1e655399e28d5973c21db6a73 Mon Sep 17 00:00:00 2001 From: "braggle@free.fr" Date: Thu, 16 May 2013 12:57:38 +0200 Subject: drm/i915: add support for dvo Chrontel 7010B This patch add dvo detection for the Chrontel 7010B on some old hardware. References: https://bugzilla.kernel.org/show_bug.cgi?id=55101 Signed-off-by: Braggle [danvet: Fix up whitespace mangling.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ch7xxx.c | 28 ++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dvo.c | 7 +++++++ 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index 3edd981e0770..757e0fa11043 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -32,12 +32,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define CH7xxx_REG_DID 0x4b #define CH7011_VID 0x83 /* 7010 as well */ +#define CH7010B_VID 0x05 #define CH7009A_VID 0x84 #define CH7009B_VID 0x85 #define CH7301_VID 0x95 #define CH7xxx_VID 0x84 #define CH7xxx_DID 0x17 +#define CH7010_DID 0x16 #define CH7xxx_NUM_REGS 0x4c @@ -87,11 +89,20 @@ static struct ch7xxx_id_struct { char *name; } ch7xxx_ids[] = { { CH7011_VID, "CH7011" }, + { CH7010B_VID, "CH7010B" }, { CH7009A_VID, "CH7009A" }, { CH7009B_VID, "CH7009B" }, { CH7301_VID, "CH7301" }, }; +static struct ch7xxx_did_struct { + uint8_t did; + char *name; +} ch7xxx_dids[] = { + { CH7xxx_DID, "CH7XXX" }, + { CH7010_DID, "CH7010B" }, +}; + struct ch7xxx_priv { bool quiet; }; @@ -108,6 +119,18 @@ static char *ch7xxx_get_id(uint8_t vid) return NULL; } +static char *ch7xxx_get_did(uint8_t did) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) { + if (ch7xxx_dids[i].did == did) + return ch7xxx_dids[i].name; + } + + return NULL; +} + /** Reads an 8 bit register */ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) { @@ -179,7 +202,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, /* this will detect the CH7xxx chip on the specified i2c bus */ struct ch7xxx_priv *ch7xxx; uint8_t vendor, device; - char *name; + char *name, *devid; ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL); if (ch7xxx == NULL) @@ -204,7 +227,8 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device)) goto out; - if (device != CH7xxx_DID) { + devid = ch7xxx_get_did(device); + if (!devid) { DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s " "slave %d.\n", vendor, adapter->name, dvo->slave_addr); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 00e70dbe82da..ee328ce8e9fe 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -53,6 +53,13 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .slave_addr = CH7xxx_ADDR, .dev_ops = &ch7xxx_ops, }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ch7xxx", + .dvo_reg = DVOC, + .slave_addr = 0x75, /* For some ch7010 */ + .dev_ops = &ch7xxx_ops, + }, { .type = INTEL_DVO_CHIP_LVDS, .name = "ivch", -- cgit v1.2.3 From 045ac3b5629d9711531a408e92f9074db6afe7ce Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 14 May 2013 17:08:26 -0700 Subject: drm/i915: add encoder get_config function v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use this for fetching encoder specific pipe_config state, like mode flags, adjusted clock, etc. Just used for mode flags atm, so we can check the pipe config state at mode set time. v2: get_config when checking hw state too v3: fix DVO and LVDS mode flags (Ville) get SDVO DTD for flag fetch (Ville) v4: use input timings (Ville) correct command used (Ville) remove gen4 check (Ville) v5: get DDI flag config too Signed-off-by: Jesse Barnes Reviewed-by: Ville Syrjälä (v4) Tested-by: Paulo Zanoni (the new hsw ddi stuff) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 23 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_ddi.c | 23 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++++++--- drivers/gpu/drm/i915/intel_dp.c | 23 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_dvo.c | 21 ++++++++++++++++++ drivers/gpu/drm/i915/intel_hdmi.c | 23 ++++++++++++++++++++ drivers/gpu/drm/i915/intel_lvds.c | 26 ++++++++++++++++++++++ drivers/gpu/drm/i915/intel_sdvo.c | 42 ++++++++++++++++++++++++++++++++++++ 9 files changed, 202 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 66a0c6f0bb81..5e9f93e53255 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -84,6 +84,28 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_crt_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crt *crt = intel_encoder_to_crt(encoder); + u32 tmp, flags = 0; + + tmp = I915_READ(crt->adpa_reg); + + if (tmp & ADPA_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (tmp & ADPA_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + /* Note: The caller is required to filter out dpms modes not supported by the * platform. */ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) @@ -778,6 +800,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.compute_config = intel_crt_compute_config; crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; + crt->base.get_config = intel_crt_get_config; if (I915_HAS_HOTPLUG(dev)) crt->base.hpd_pin = HPD_CRT; if (HAS_DDI(dev)) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 062de679f38f..e66852186751 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1259,6 +1259,28 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) intel_dp_check_link_status(intel_dp); } +static void intel_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + u32 temp, flags = 0; + + temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + if (temp & TRANS_DDI_PHSYNC) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + if (temp & TRANS_DDI_PVSYNC) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; + pipe_config->pixel_multiplier = 1; +} + static void intel_ddi_destroy(struct drm_encoder *encoder) { /* HDMI has nothing special to destroy, so we can go with this. */ @@ -1318,6 +1340,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->disable = intel_disable_ddi; intel_encoder->post_disable = intel_ddi_post_disable; intel_encoder->get_hw_state = intel_ddi_get_hw_state; + intel_encoder->get_config = intel_ddi_get_config; intel_dig_port->port = port; intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) & diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2d90594016d9..4196155cf964 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8067,6 +8067,15 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, DRM_MODE_FLAG_INTERLACE); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PVSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NVSYNC); + PIPE_CONF_CHECK_I(requested_mode.hdisplay); PIPE_CONF_CHECK_I(requested_mode.vdisplay); @@ -8159,6 +8168,8 @@ intel_modeset_check_state(struct drm_device *dev) bool enabled = false; bool active = false; + memset(&pipe_config, 0, sizeof(pipe_config)); + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.base.id); @@ -8172,6 +8183,8 @@ intel_modeset_check_state(struct drm_device *dev) enabled = true; if (encoder->connectors_active) active = true; + if (encoder->get_config) + encoder->get_config(encoder, &pipe_config); } WARN(active != crtc->active, "crtc's computed active state doesn't match tracked active state " @@ -8180,7 +8193,6 @@ intel_modeset_check_state(struct drm_device *dev) "crtc's computed enabled state doesn't match tracked enabled state " "(expected %i, found %i)\n", enabled, crtc->base.enabled); - memset(&pipe_config, 0, sizeof(pipe_config)); pipe_config.cpu_transcoder = crtc->config.cpu_transcoder; active = dev_priv->display.get_pipe_config(crtc, &pipe_config); @@ -9589,8 +9601,10 @@ setup_pipes: pipe = 0; if (encoder->get_hw_state(encoder, &pipe)) { - encoder->base.crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + encoder->base.crtc = &crtc->base; + if (encoder->get_config) + encoder->get_config(encoder, &crtc->config); } else { encoder->base.crtc = NULL; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6ba9f09fe21a..7c5eb2f6208f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1346,6 +1346,28 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_dp_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + u32 tmp, flags = 0; + + tmp = I915_READ(intel_dp->output_reg); + + if (tmp & DP_SYNC_HS_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (tmp & DP_SYNC_VS_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + static void intel_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); @@ -3184,6 +3206,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->disable = intel_disable_dp; intel_encoder->post_disable = intel_post_disable_dp; intel_encoder->get_hw_state = intel_dp_get_hw_state; + intel_encoder->get_config = intel_dp_get_config; if (IS_VALLEYVIEW(dev)) intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9b0af7e27c82..a435ce1d075e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -139,6 +139,10 @@ struct intel_encoder { * the encoder is active. If the encoder is enabled it also set the pipe * it is connected to in the pipe parameter. */ bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); + /* Reconstructs the equivalent mode flags for the current hardware + * state. */ + void (*get_config)(struct intel_encoder *, + struct intel_crtc_config *pipe_config); int crtc_mask; enum hpd_pin hpd_pin; }; diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 2c0be924e9a9..9e80d487b5cb 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -136,6 +136,26 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_dvo_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base); + u32 tmp, flags = 0; + + tmp = I915_READ(intel_dvo->dev.dvo_reg); + if (tmp & DVO_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + if (tmp & DVO_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + static void intel_disable_dvo(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -447,6 +467,7 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder->disable = intel_disable_dvo; intel_encoder->enable = intel_enable_dvo; intel_encoder->get_hw_state = intel_dvo_get_hw_state; + intel_encoder->get_config = intel_dvo_get_config; intel_connector->get_hw_state = intel_dvo_connector_get_hw_state; /* Now, try to find a controller */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2b727f0d201f..18f8ce0404c6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -658,6 +658,28 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_hdmi_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + u32 tmp, flags = 0; + + tmp = I915_READ(intel_hdmi->hdmi_reg); + + if (tmp & SDVO_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (tmp & SDVO_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + static void intel_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -1216,6 +1238,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->enable = intel_enable_hdmi; intel_encoder->disable = intel_disable_hdmi; intel_encoder->get_hw_state = intel_hdmi_get_hw_state; + intel_encoder->get_config = intel_hdmi_get_config; if (IS_VALLEYVIEW(dev)) { intel_encoder->pre_enable = intel_hdmi_pre_enable; intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 36fe291172ee..655486099b76 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -86,6 +86,31 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_lvds_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 lvds_reg, tmp, flags = 0; + + if (HAS_PCH_SPLIT(dev)) + lvds_reg = PCH_LVDS; + else + lvds_reg = LVDS; + + tmp = I915_READ(lvds_reg); + if (tmp & LVDS_HSYNC_POLARITY) + flags |= DRM_MODE_FLAG_NHSYNC; + else + flags |= DRM_MODE_FLAG_PHSYNC; + if (tmp & LVDS_VSYNC_POLARITY) + flags |= DRM_MODE_FLAG_NVSYNC; + else + flags |= DRM_MODE_FLAG_PVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. @@ -921,6 +946,7 @@ bool intel_lvds_init(struct drm_device *dev) intel_encoder->compute_config = intel_lvds_compute_config; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; + intel_encoder->get_config = intel_lvds_get_config; intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector_attach_encoder(intel_connector, intel_encoder); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 78f0631b1c43..4d4a3f0cadfb 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -712,6 +712,13 @@ static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); } +static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); +} + static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { @@ -726,6 +733,13 @@ static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); } +static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_timing(intel_sdvo, + SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + static bool intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, uint16_t clock, @@ -1295,6 +1309,33 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, return true; } +static void intel_sdvo_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); + struct intel_sdvo_dtd dtd; + u32 flags = 0; + bool ret; + + ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd); + if (!ret) { + DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n"); + return; + } + + if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + pipe_config->adjusted_mode.flags |= flags; +} + static void intel_disable_sdvo(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -2827,6 +2868,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) intel_encoder->mode_set = intel_sdvo_mode_set; intel_encoder->enable = intel_enable_sdvo; intel_encoder->get_hw_state = intel_sdvo_get_hw_state; + intel_encoder->get_config = intel_sdvo_get_config; /* In default case sdvo lvds is false */ if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) -- cgit v1.2.3 From 5a41254eac1137d0335c0aed7b00f1f3138ee9ca Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:37 -0300 Subject: drm/i915: ILK, SNB and IVB don't have linetime watermarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So don't call intel_update_linetime_watermarks from ironlake_crtc_mode_set. Only Haswell has these watermarks. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4196155cf964..c7bdbcb6a675 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5841,8 +5841,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_update_watermarks(dev); - intel_update_linetime_watermarks(dev, pipe, adjusted_mode); - return ret; } -- cgit v1.2.3 From 1011d8c4373b229012208b5aedad4f46396bdd94 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 9 May 2013 16:55:50 -0300 Subject: drm/i915: remove intel_update_linetime_watermarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec says the linetime watermarks must be programmed before enabling any display low power watermarks, but we're currently updating the linetime watermarks after we call intel_update_watermarks (and only at crtc_mode_set, not at crtc_{enable,disable}). So IMHO the best way guarantee the linetime watermarks will be updated before the low power watermarks is inside the update_wm function, because it's the function that enables low power watermarks. And since Haswell is the only platform that has linetime watermarks, let's completely kill the "intel_update_linetime_watermarks" abstraction and just use the intel_update_watermarks abstraction by creating haswell_update_wm. For now haswell_update_wm is still calling sandybridge_update_wm, but in the future I plan to implement a function specific to Haswell. v2: - Rename patch - Disable LP watermarks before changing linetime WMs (Chris) - Add a comment explaining that this is just temporary code. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 2 -- drivers/gpu/drm/i915/intel_pm.c | 43 +++++++++++++++++++++++++----------- 4 files changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 14817de37405..639ec0b61450 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -316,8 +316,6 @@ struct drm_i915_display_funcs { void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); - void (*update_linetime_wm)(struct drm_device *dev, int pipe, - struct drm_display_mode *mode); void (*modeset_global_resources)(struct drm_device *dev); /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c7bdbcb6a675..684ab6417dd4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6008,8 +6008,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, intel_update_watermarks(dev); - intel_update_linetime_watermarks(dev, pipe, adjusted_mode); - return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a435ce1d075e..75a7f22262d4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -732,8 +732,6 @@ extern void intel_update_watermarks(struct drm_device *dev); extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); -extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe, - struct drm_display_mode *mode); extern unsigned long intel_gen4_compute_page_offset(int *x, int *y, unsigned int tiling_mode, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e2255ed97894..2ae4e459faa5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2073,12 +2073,19 @@ static void ivybridge_update_wm(struct drm_device *dev) } static void -haswell_update_linetime_wm(struct drm_device *dev, int pipe, - struct drm_display_mode *mode) +haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; u32 temp; + if (!intel_crtc_active(crtc)) { + I915_WRITE(PIPE_WM_LINETIME(pipe), 0); + return; + } + temp = I915_READ(PIPE_WM_LINETIME(pipe)); temp &= ~PIPE_WM_LINETIME_MASK; @@ -2099,6 +2106,26 @@ haswell_update_linetime_wm(struct drm_device *dev, int pipe, I915_WRITE(PIPE_WM_LINETIME(pipe), temp); } +static void haswell_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + enum pipe pipe; + + /* Disable the LP WMs before changine the linetime registers. This is + * just a temporary code that will be replaced soon. */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + for_each_pipe(pipe) { + crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + haswell_update_linetime_wm(dev, crtc); + } + + sandybridge_update_wm(dev); +} + static bool sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, uint32_t sprite_width, int pixel_size, @@ -2294,15 +2321,6 @@ void intel_update_watermarks(struct drm_device *dev) dev_priv->display.update_wm(dev); } -void intel_update_linetime_watermarks(struct drm_device *dev, - int pipe, struct drm_display_mode *mode) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.update_linetime_wm) - dev_priv->display.update_linetime_wm(dev, pipe, mode); -} - void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size) { @@ -4624,9 +4642,8 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; } else if (IS_HASWELL(dev)) { if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_wm = haswell_update_wm; dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - dev_priv->display.update_linetime_wm = haswell_update_linetime_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); -- cgit v1.2.3 From 7366937312d4e406539b1cf70e1562358bdd560e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:39 -0300 Subject: drm/i915: use the mode->htotal to calculate linetime watermarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... instead of mode->crtc_display. The spec says "pipe horizontal total number of pixels" and the "Haswell Watermark Calculator" tool uses the "Pipe H Total" instead of "Pipe H Src" as the value. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2ae4e459faa5..198d9c9ada68 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2093,7 +2093,7 @@ haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) * row at the given clock rate, multiplied by 8. * */ temp |= PIPE_WM_LINETIME_TIME( - ((mode->crtc_hdisplay * 1000) / mode->clock) * 8); + ((mode->htotal * 1000) / mode->clock) * 8); /* IPS watermarks are only used by pipe A, and are ignored by * pipes B and C. They are calculated similarly to the common -- cgit v1.2.3 From eaa591ec528ad75bb4c77606c5cb671f05e04db6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:40 -0300 Subject: drm/i915: fix haswell linetime watermarks calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the "*8" calculation to the left side so we don't propagate rounding errors. Also use DIV_ROUND_CLOSEST because that's what the spec says we need to do. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 198d9c9ada68..2c406ddc6354 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2093,7 +2093,7 @@ haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) * row at the given clock rate, multiplied by 8. * */ temp |= PIPE_WM_LINETIME_TIME( - ((mode->htotal * 1000) / mode->clock) * 8); + DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock)); /* IPS watermarks are only used by pipe A, and are ignored by * pipes B and C. They are calculated similarly to the common -- cgit v1.2.3 From b2b877ffe37d699f77f45e993590b66010491c52 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:42 -0300 Subject: drm/i915: make intel_ddi_get_cdclk_freq return values in KHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this, that 338 can finally become the correct 337500. Due to the change we need to adjust the intel_dp_aux_ch function to set the correct value, so adjust the division and also use DIV_ROUND_CLOSEST instead of the old "round down" behavior because the spec says the value "should be programmed to get as close as possible to the ideal rate of 2MHz". Quoting Paulo's follow-up to a question from Chris Wilson to explain what exactly will change: I use the 337500 value on the next patch, when setting the ips_linetime value. The correct frequency is 337500, not 338000. ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, intel_ddi_get_cdclk_freq); For a mode with htotal of 2640 [0] we'll have: (i) (2640 * 1000 * 8) / 338000 = 62.48, resulting in 62 and (ii) (2640 * 1000 * 8) / 337500 = 62.57 resulting in 63. For the case inside intel_dp.c: Previously we were using 338. So with the old formula we were writing 338/2 = 169 to the register. And 337500 / 169 = 1997.04 (we use 337500 here because it's the real clock value). With the new value of 337500/2000 we'll have 168.75, which is 168 on the round-down case and 169 on the round-closest case. If we write 168 to the register, 337500 / 168 = 2008.92, and 2008.92 is more distant from 2000 than 1997.04. So with this patch we're changing the formula but still writing the same correct value to the DP AUX register. [0]: That's 1920x1080@50Hz on my DP monitor. Signed-off-by: Paulo Zanoni [danvet: Pimp the commit message with Paulo's follow-up.] Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 10 +++++----- drivers/gpu/drm/i915/intel_dp.c | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e66852186751..1fdd3b0b7040 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1153,14 +1153,14 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder) int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) { if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) - return 450; + return 450000; else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) == LCPLL_CLK_FREQ_450) - return 450; + return 450000; else if (IS_ULT(dev_priv->dev)) - return 338; + return 337500; else - return 540; + return 540000; } void intel_ddi_pll_init(struct drm_device *dev) @@ -1173,7 +1173,7 @@ void intel_ddi_pll_init(struct drm_device *dev) * Don't even try to turn it on. */ - DRM_DEBUG_KMS("CDCLK running at %dMHz\n", + DRM_DEBUG_KMS("CDCLK running at %dKHz\n", intel_ddi_get_cdclk_freq(dev_priv)); if (val & LCPLL_CD_SOURCE_FCLK) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7c5eb2f6208f..3426a6183188 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -319,7 +319,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ if (is_cpu_edp(intel_dp)) { if (HAS_DDI(dev)) - aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1; + aux_clock_divider = DIV_ROUND_CLOSEST( + intel_ddi_get_cdclk_freq(dev_priv), 2000); else if (IS_VALLEYVIEW(dev)) aux_clock_divider = 100; else if (IS_GEN6(dev) || IS_GEN7(dev)) -- cgit v1.2.3 From 85a02deb4ca5a7e1e39e8538b6eb3c7066469720 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:43 -0300 Subject: drm/i915: set the IPS linetime watermark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the "placeholder" comment and set the actual value described by the specification. We still don't enable IPS, but it won't hurt to already have the value set here. While at it, fully set the register value instead of just masking the values we're changing. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä [danvet: Resolve conflict due to reordered patches.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2c406ddc6354..ad1d35526a8f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2079,31 +2079,23 @@ haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; - u32 temp; + u32 linetime, ips_linetime; if (!intel_crtc_active(crtc)) { I915_WRITE(PIPE_WM_LINETIME(pipe), 0); return; } - temp = I915_READ(PIPE_WM_LINETIME(pipe)); - temp &= ~PIPE_WM_LINETIME_MASK; - /* The WM are computed with base on how long it takes to fill a single * row at the given clock rate, multiplied by 8. * */ - temp |= PIPE_WM_LINETIME_TIME( - DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock)); - - /* IPS watermarks are only used by pipe A, and are ignored by - * pipes B and C. They are calculated similarly to the common - * linetime values, except that we are using CD clock frequency - * in MHz instead of pixel rate for the division. - * - * This is a placeholder for the IPS watermark calculation code. - */ + linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock); + ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, + intel_ddi_get_cdclk_freq(dev_priv)); - I915_WRITE(PIPE_WM_LINETIME(pipe), temp); + I915_WRITE(PIPE_WM_LINETIME(pipe), + PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | + PIPE_WM_LINETIME_TIME(linetime)); } static void haswell_update_wm(struct drm_device *dev) -- cgit v1.2.3 From 3e1f72664e0a8a31e9b90c48459deb6642fd52f3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:44 -0300 Subject: drm/i915: MCH_SSKPD is a 64 bit register on Haswell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And the SNB_READ_WM0_LATENCY macro is not valid anymore because we have the "New WM0" at 63:56, so the "Old WM0" could maybe be zero if the new one is not zero. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ad1d35526a8f..912ab4d8d722 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4633,7 +4633,7 @@ void intel_init_pm(struct drm_device *dev) } dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; } else if (IS_HASWELL(dev)) { - if (SNB_READ_WM0_LATENCY()) { + if (I915_READ64(MCH_SSKPD)) { dev_priv->display.update_wm = haswell_update_wm; dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; } else { -- cgit v1.2.3 From 90a8864320b2a9f91e5b5d561924a4bb70b90dcc Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 May 2013 17:23:45 -0300 Subject: drm/i915: set FORCE_ARB_IDLE_PLANES workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1544d9d57396d5c0c6b7644ed5ae1f4d6caad07a added a workaround inside haswell_init_clock_gating and mentioned it is "a workaround for early silicon revisions and should be removed later". This workaround is documented in bit 31 of PRI_CTL. I asked Arthur and he mentioned that setting FORCE_ARB_IDLE_PLANES replaces that workaround for the newer machines. So use the new one. Also notice that there's still another workaround for PRI_CTL that involves WM_DBG, but it's not the one we're reverting. And notice that we were previously setting WM_DBG_DISALLOW_MULTIPIPE_LP which disables the LP watermarks when more than one pipe is used, and we really don't want this because we need the LP watermarks if we want to reach deeper PC states. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä [danvet: Add a comment for the w/a name Ville dug out of Bspec.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 11 +++-------- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e4cf382f0b75..55caedba53d1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3711,6 +3711,9 @@ # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5) # define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) +#define CHICKEN_PAR1_1 0x42080 +#define FORCE_ARB_IDLE_PLANES (1 << 14) + #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 912ab4d8d722..e198f3881f9a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4172,14 +4172,9 @@ static void haswell_init_clock_gating(struct drm_device *dev) /* WaSwitchSolVfFArbitrationPriority:hsw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); - /* XXX: This is a workaround for early silicon revisions and should be - * removed later. - */ - I915_WRITE(WM_DBG, - I915_READ(WM_DBG) | - WM_DBG_DISALLOW_MULTIPLE_LP | - WM_DBG_DISALLOW_SPRITE | - WM_DBG_DISALLOW_MAXFIFO); + /* WaRsPkgCStateDisplayPMReq:hsw */ + I915_WRITE(CHICKEN_PAR1_1, + I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES); lpt_init_clock_gating(dev); } -- cgit v1.2.3 From a36689cb771f06819c3fa8139c3d3716dfdf6d53 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 21 May 2013 16:58:49 +0100 Subject: drm/i915: Be more informative when reporting "too large for aperture" error This should help debugging the truly unexpected cases where it occurs - in particular to see which value is garbage. References: https://bugzilla.kernel.org/show_bug.cgi?id=58511 Signed-off-by: Chris Wilson [danvet: s/%ld/%zd/ as spotted by Wu Fengguang's autobuilder.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a1a282ce2466..39a9828cdff9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2975,7 +2975,10 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, */ if (obj->base.size > (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { - DRM_ERROR("Attempting to bind an object larger than the aperture\n"); + DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n", + obj->base.size, + map_and_fenceable ? "mappable" : "total", + map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total); return -E2BIG; } -- cgit v1.2.3 From df0a67979543e716d411eb11406848dcb50abd0a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 22 May 2013 11:36:40 +0300 Subject: drm/i915: Fix WARN_ON() on UP machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WARN_ON(!spin_is_locked()) is not a good idea on a UP system w/o spinlock debugging. Use WARN_ON_SMP() instead. This check has been added in commit 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0 Author: Jani Nikula Date: Fri Apr 12 15:18:37 2013 +0300 drm/i915: protect backlight registers and data with a spinlock Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 56f17b2382fc..80bea1d3209f 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -332,7 +332,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 val; - WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); + WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); /* Restore the CTL value if it lost, e.g. GPU reset */ -- cgit v1.2.3 From 2dc8aae06d53458dd3624dc0accd4f81100ee631 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 May 2013 17:08:06 +0100 Subject: drm/i915: Workaround incoherence with fence updates on Valleyview In commit 25ff1195f8a0b3724541ae7bbe331b4296de9c06 Author: Chris Wilson Date: Thu Apr 4 21:31:03 2013 +0100 drm/i915: Workaround incoherence between fences and LLC across multiple CPUs we introduced an empirical workaround for memory corruption when using fences from multiple CPUs. At the time, we did not have any results for Valleyview, so the presumption was that it was limited to recent generations using LLC. Now we have evidence that Valleyview also suffers incoherence and requires a similar but different workaround. For Valleyview, the wbinvd instruction is insufficient and we require the serialising register write per-CPU. Conversely, that serialising register write is not enough for SNB/IVB/HSW. To compromise and keep the code relatively clean, employ both serialisation techniques in the same workaround. Reported-by: Jon Bloomfield Tested-by: Jon Bloomfield Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=62191 Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 39a9828cdff9..1b735a4a2873 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2693,18 +2693,33 @@ static inline int fence_number(struct drm_i915_private *dev_priv, return fence - dev_priv->fence_regs; } +struct write_fence { + struct drm_device *dev; + struct drm_i915_gem_object *obj; + int fence; +}; + static void i915_gem_write_fence__ipi(void *data) { + struct write_fence *args = data; + + /* Required for SNB+ with LLC */ wbinvd(); + + /* Required for VLV */ + i915_gem_write_fence(args->dev, args->fence, args->obj); } static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable) { - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int fence_reg = fence_number(dev_priv, fence); + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct write_fence args = { + .dev = obj->base.dev, + .fence = fence_number(dev_priv, fence), + .obj = enable ? obj : NULL, + }; /* In order to fully serialize access to the fenced region and * the update to the fence register we need to take extreme @@ -2715,13 +2730,19 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, * SNB+ we need to take a step further and emit an explicit wbinvd() * on each processor in order to manually flush all memory * transactions before updating the fence register. + * + * However, Valleyview complicates matter. There the wbinvd is + * insufficient and unlike SNB/IVB requires the serialising + * register write. (Note that that register write by itself is + * conversely not sufficient for SNB+.) To compromise, we do both. */ - if (HAS_LLC(obj->base.dev)) - on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); - i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); + if (INTEL_INFO(args.dev)->gen >= 6) + on_each_cpu(i915_gem_write_fence__ipi, &args, 1); + else + i915_gem_write_fence(args.dev, args.fence, args.obj); if (enable) { - obj->fence_reg = fence_reg; + obj->fence_reg = args.fence; fence->obj = obj; list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); } else { -- cgit v1.2.3 From edbe1581c5f94f7fba39cd9a5b2facd624aab661 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Wed, 22 May 2013 23:07:09 +0200 Subject: drm/i915: Cocci spatch "memdup.spatch" Signed-off-by: Thomas Meyer Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3426a6183188..9332558fc3dc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2511,11 +2511,10 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) return NULL; size = (intel_connector->edid->extensions + 1) * EDID_LENGTH; - edid = kmalloc(size, GFP_KERNEL); + edid = kmemdup(intel_connector->edid, size, GFP_KERNEL); if (!edid) return NULL; - memcpy(edid, intel_connector->edid, size); return edid; } -- cgit v1.2.3 From edc3d8848dc9fe2a470316363dab8ef211d77e01 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 23 May 2013 13:55:35 +0300 Subject: drm/i915: avoid big kmallocs on reading error state Sometimes when user is trying to get error state out from debugfs after gpu hang, the memory is low and/or fragmented enough that kmalloc in seq_file will fail. Prevent big kmalloc by avoiding seq_file and instead convert error state to string in smaller chunks. v2: better alloc flags, better truncate, correct locking, and error handling improvements (Chris Wilson) v3: printf annotations (Daniel Vetter) Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 242 ++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 16 ++- drivers/gpu/drm/i915/intel_display.c | 54 ++++---- drivers/gpu/drm/i915/intel_overlay.c | 13 +- 4 files changed, 232 insertions(+), 93 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a55630a80f83..3a8409a31266 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -604,15 +604,80 @@ static const char *purgeable_flag(int purgeable) return purgeable ? " purgeable" : ""; } -static void print_error_buffers(struct seq_file *m, +static void i915_error_vprintf(struct drm_i915_error_state_buf *e, + const char *f, va_list args) +{ + unsigned len; + + if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { + e->err = -ENOSPC; + return; + } + + if (e->bytes == e->size - 1 || e->err) + return; + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + len = vsnprintf(NULL, 0, f, args); + if (e->pos + len <= e->start) { + e->pos += len; + return; + } + + /* First vsnprintf needs to fit in full for memmove*/ + if (len >= e->size) { + e->err = -EIO; + return; + } + } + + len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + + /* If this is first printf in this window, adjust it so that + * start position matches start of the buffer + */ + if (e->pos < e->start) { + const size_t off = e->start - e->pos; + + /* Should not happen but be paranoid */ + if (off > len || e->bytes) { + e->err = -EIO; + return; + } + + memmove(e->buf, e->buf + off, len - off); + e->bytes = len - off; + e->pos = e->start; + return; + } + + e->bytes += len; + e->pos += len; +} + +void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) +{ + va_list args; + + va_start(args, f); + i915_error_vprintf(e, f, args); + va_end(args); +} + +#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) + +static void print_error_buffers(struct drm_i915_error_state_buf *m, const char *name, struct drm_i915_error_buffer *err, int count) { - seq_printf(m, "%s [%d]:\n", name, count); + err_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", + err_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, @@ -627,50 +692,50 @@ static void print_error_buffers(struct seq_file *m, cache_level_str(err->cache_level)); if (err->name) - seq_printf(m, " (name: %d)", err->name); + err_printf(m, " (name: %d)", err->name); if (err->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d)", err->fence_reg); + err_printf(m, " (fence: %d)", err->fence_reg); - seq_printf(m, "\n"); + err_printf(m, "\n"); err++; } } -static void i915_ring_error_state(struct seq_file *m, +static void i915_ring_error_state(struct drm_i915_error_state_buf *m, struct drm_device *dev, struct drm_i915_error_state *error, unsigned ring) { BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */ - seq_printf(m, "%s command stream:\n", ring_str(ring)); - seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]); - seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); - seq_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); - seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); - seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); - seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); - seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); + err_printf(m, "%s command stream:\n", ring_str(ring)); + err_printf(m, " HEAD: 0x%08x\n", error->head[ring]); + err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]); + err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]); + err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]); + err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); + err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); + err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); if (ring == RCS && INTEL_INFO(dev)->gen >= 4) - seq_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); + err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); if (INTEL_INFO(dev)->gen >= 4) - seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); - seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); - seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); + err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); + err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); if (INTEL_INFO(dev)->gen >= 6) { - seq_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); - seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); - seq_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", + err_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]); + err_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]); + err_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n", error->semaphore_mboxes[ring][0], error->semaphore_seqno[ring][0]); - seq_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", + err_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n", error->semaphore_mboxes[ring][1], error->semaphore_seqno[ring][1]); } - seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); - seq_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); - seq_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); - seq_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); + err_printf(m, " seqno: 0x%08x\n", error->seqno[ring]); + err_printf(m, " waiting: %s\n", yesno(error->waiting[ring])); + err_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]); + err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); } struct i915_error_state_file_priv { @@ -678,9 +743,11 @@ struct i915_error_state_file_priv { struct drm_i915_error_state *error; }; -static int i915_error_state(struct seq_file *m, void *unused) + +static int i915_error_state(struct i915_error_state_file_priv *error_priv, + struct drm_i915_error_state_buf *m) + { - struct i915_error_state_file_priv *error_priv = m->private; struct drm_device *dev = error_priv->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_state *error = error_priv->error; @@ -688,34 +755,35 @@ static int i915_error_state(struct seq_file *m, void *unused) int i, j, page, offset, elt; if (!error) { - seq_printf(m, "no error state collected\n"); + err_printf(m, "no error state collected\n"); return 0; } - seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, + err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); - seq_printf(m, "Kernel: " UTS_RELEASE "\n"); - seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); - seq_printf(m, "EIR: 0x%08x\n", error->eir); - seq_printf(m, "IER: 0x%08x\n", error->ier); - seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); - seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); - seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr); - seq_printf(m, "CCID: 0x%08x\n", error->ccid); + err_printf(m, "Kernel: " UTS_RELEASE "\n"); + err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); + err_printf(m, "EIR: 0x%08x\n", error->eir); + err_printf(m, "IER: 0x%08x\n", error->ier); + err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); + err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); + err_printf(m, "DERRMR: 0x%08x\n", error->derrmr); + err_printf(m, "CCID: 0x%08x\n", error->ccid); for (i = 0; i < dev_priv->num_fence_regs; i++) - seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); + err_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++) - seq_printf(m, " INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]); + err_printf(m, " INSTDONE_%d: 0x%08x\n", i, + error->extra_instdone[i]); if (INTEL_INFO(dev)->gen >= 6) { - seq_printf(m, "ERROR: 0x%08x\n", error->error); - seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); + err_printf(m, "ERROR: 0x%08x\n", error->error); + err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); } if (INTEL_INFO(dev)->gen == 7) - seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int); + err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); for_each_ring(ring, dev_priv, i) i915_ring_error_state(m, dev, error, i); @@ -734,24 +802,25 @@ static int i915_error_state(struct seq_file *m, void *unused) struct drm_i915_error_object *obj; if ((obj = error->ring[i].batchbuffer)) { - seq_printf(m, "%s --- gtt_offset = 0x%08x\n", + err_printf(m, "%s --- gtt_offset = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); offset = 0; for (page = 0; page < obj->page_count; page++) { for (elt = 0; elt < PAGE_SIZE/4; elt++) { - seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); + err_printf(m, "%08x : %08x\n", offset, + obj->pages[page][elt]); offset += 4; } } } if (error->ring[i].num_requests) { - seq_printf(m, "%s --- %d requests\n", + err_printf(m, "%s --- %d requests\n", dev_priv->ring[i].name, error->ring[i].num_requests); for (j = 0; j < error->ring[i].num_requests; j++) { - seq_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n", + err_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n", error->ring[i].requests[j].seqno, error->ring[i].requests[j].jiffies, error->ring[i].requests[j].tail); @@ -759,13 +828,13 @@ static int i915_error_state(struct seq_file *m, void *unused) } if ((obj = error->ring[i].ringbuffer)) { - seq_printf(m, "%s --- ringbuffer = 0x%08x\n", + err_printf(m, "%s --- ringbuffer = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); offset = 0; for (page = 0; page < obj->page_count; page++) { for (elt = 0; elt < PAGE_SIZE/4; elt++) { - seq_printf(m, "%08x : %08x\n", + err_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); offset += 4; @@ -775,12 +844,12 @@ static int i915_error_state(struct seq_file *m, void *unused) obj = error->ring[i].ctx; if (obj) { - seq_printf(m, "%s --- HW Context = 0x%08x\n", + err_printf(m, "%s --- HW Context = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); offset = 0; for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { - seq_printf(m, "[%04x] %08x %08x %08x %08x\n", + err_printf(m, "[%04x] %08x %08x %08x %08x\n", offset, obj->pages[0][elt], obj->pages[0][elt+1], @@ -806,8 +875,7 @@ i915_error_state_write(struct file *filp, size_t cnt, loff_t *ppos) { - struct seq_file *m = filp->private_data; - struct i915_error_state_file_priv *error_priv = m->private; + struct i915_error_state_file_priv *error_priv = filp->private_data; struct drm_device *dev = error_priv->dev; int ret; @@ -842,25 +910,81 @@ static int i915_error_state_open(struct inode *inode, struct file *file) kref_get(&error_priv->error->ref); spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); - return single_open(file, i915_error_state, error_priv); + file->private_data = error_priv; + + return 0; } static int i915_error_state_release(struct inode *inode, struct file *file) { - struct seq_file *m = file->private_data; - struct i915_error_state_file_priv *error_priv = m->private; + struct i915_error_state_file_priv *error_priv = file->private_data; if (error_priv->error) kref_put(&error_priv->error->ref, i915_error_state_free); kfree(error_priv); - return single_release(inode, file); + return 0; +} + +static ssize_t i915_error_state_read(struct file *file, char __user *userbuf, + size_t count, loff_t *pos) +{ + struct i915_error_state_file_priv *error_priv = file->private_data; + struct drm_i915_error_state_buf error_str; + loff_t tmp_pos = 0; + ssize_t ret_count = 0; + int ret = 0; + + memset(&error_str, 0, sizeof(error_str)); + + /* We need to have enough room to store any i915_error_state printf + * so that we can move it to start position. + */ + error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE; + error_str.buf = kmalloc(error_str.size, + GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN); + + if (error_str.buf == NULL) { + error_str.size = PAGE_SIZE; + error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY); + } + + if (error_str.buf == NULL) { + error_str.size = 128; + error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY); + } + + if (error_str.buf == NULL) + return -ENOMEM; + + error_str.start = *pos; + + ret = i915_error_state(error_priv, &error_str); + if (ret) + goto out; + + if (error_str.bytes == 0 && error_str.err) { + ret = error_str.err; + goto out; + } + + ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos, + error_str.buf, + error_str.bytes); + + if (ret_count < 0) + ret = ret_count; + else + *pos = error_str.start + ret_count; +out: + kfree(error_str.buf); + return ret ?: ret_count; } static const struct file_operations i915_error_state_fops = { .owner = THIS_MODULE, .open = i915_error_state_open, - .read = seq_read, + .read = i915_error_state_read, .write = i915_error_state_write, .llseek = default_llseek, .release = i915_error_state_release, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 639ec0b61450..7772bb6f73ba 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -826,6 +826,15 @@ struct i915_gem_mm { u32 object_count; }; +struct drm_i915_error_state_buf { + unsigned bytes; + unsigned size; + int err; + u8 *buf; + loff_t start; + loff_t pos; +}; + struct i915_gpu_error { /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ @@ -1818,6 +1827,8 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, /* i915_debugfs.c */ int i915_debugfs_init(struct drm_minor *minor); void i915_debugfs_cleanup(struct drm_minor *minor); +__printf(2, 3) +void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); @@ -1899,10 +1910,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data, /* overlay */ #ifdef CONFIG_DEBUG_FS extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); -extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); +extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e, + struct intel_overlay_error_state *error); extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev); -extern void intel_display_print_error_state(struct seq_file *m, +extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, struct drm_device *dev, struct intel_display_error_state *error); #endif diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 684ab6417dd4..1c0d6d3bfe83 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9858,48 +9858,50 @@ intel_display_capture_error_state(struct drm_device *dev) return error; } +#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) + void -intel_display_print_error_state(struct seq_file *m, +intel_display_print_error_state(struct drm_i915_error_state_buf *m, struct drm_device *dev, struct intel_display_error_state *error) { int i; - seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); + err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); if (HAS_POWER_WELL(dev)) - seq_printf(m, "PWR_WELL_CTL2: %08x\n", + err_printf(m, "PWR_WELL_CTL2: %08x\n", error->power_well_driver); for_each_pipe(i) { - seq_printf(m, "Pipe [%d]:\n", i); - seq_printf(m, " CPU transcoder: %c\n", + err_printf(m, "Pipe [%d]:\n", i); + err_printf(m, " CPU transcoder: %c\n", transcoder_name(error->pipe[i].cpu_transcoder)); - seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); - seq_printf(m, " SRC: %08x\n", error->pipe[i].source); - seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); - seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); - seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); - seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); - seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); - seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); - - seq_printf(m, "Plane [%d]:\n", i); - seq_printf(m, " CNTR: %08x\n", error->plane[i].control); - seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); + err_printf(m, " CONF: %08x\n", error->pipe[i].conf); + err_printf(m, " SRC: %08x\n", error->pipe[i].source); + err_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); + err_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); + err_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); + err_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); + err_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); + err_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); + + err_printf(m, "Plane [%d]:\n", i); + err_printf(m, " CNTR: %08x\n", error->plane[i].control); + err_printf(m, " STRIDE: %08x\n", error->plane[i].stride); if (INTEL_INFO(dev)->gen <= 3) { - seq_printf(m, " SIZE: %08x\n", error->plane[i].size); - seq_printf(m, " POS: %08x\n", error->plane[i].pos); + err_printf(m, " SIZE: %08x\n", error->plane[i].size); + err_printf(m, " POS: %08x\n", error->plane[i].pos); } if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) - seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); + err_printf(m, " ADDR: %08x\n", error->plane[i].addr); if (INTEL_INFO(dev)->gen >= 4) { - seq_printf(m, " SURF: %08x\n", error->plane[i].surface); - seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); + err_printf(m, " SURF: %08x\n", error->plane[i].surface); + err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); } - seq_printf(m, "Cursor [%d]:\n", i); - seq_printf(m, " CNTR: %08x\n", error->cursor[i].control); - seq_printf(m, " POS: %08x\n", error->cursor[i].position); - seq_printf(m, " BASE: %08x\n", error->cursor[i].base); + err_printf(m, "Cursor [%d]:\n", i); + err_printf(m, " CNTR: %08x\n", error->cursor[i].control); + err_printf(m, " POS: %08x\n", error->cursor[i].position); + err_printf(m, " BASE: %08x\n", error->cursor[i].base); } } #endif diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 67a2501d519d..836794b68fc6 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1485,14 +1485,15 @@ err: } void -intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error) +intel_overlay_print_error_state(struct drm_i915_error_state_buf *m, + struct intel_overlay_error_state *error) { - seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", - error->dovsta, error->isr); - seq_printf(m, " Register file at 0x%08lx:\n", - error->base); + i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", + error->dovsta, error->isr); + i915_error_printf(m, " Register file at 0x%08lx:\n", + error->base); -#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x) +#define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x) P(OBUF_0Y); P(OBUF_1Y); P(OBUF_0U); -- cgit v1.2.3 From 59de08136f0c8d91bfd607d03cf722c5b6c60d1b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 May 2013 15:36:16 +0300 Subject: drm/i915: group sideband register accessors to a new file Group both the HSW/LPT SBI interface and VLV IOSF sideband register accessor functions into a new file. No functional changes. v2: also move intel_sbi_{read,write} (Daniel) Signed-off-by: Jani Nikula Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 8 ++ drivers/gpu/drm/i915/intel_display.c | 98 ------------------ drivers/gpu/drm/i915/intel_drv.h | 4 - drivers/gpu/drm/i915/intel_pm.c | 60 ----------- drivers/gpu/drm/i915/intel_sideband.c | 183 ++++++++++++++++++++++++++++++++++ 6 files changed, 192 insertions(+), 162 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_sideband.c (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 91f3ac6cef35..40034ecefd3b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -36,6 +36,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ intel_overlay.o \ intel_sprite.o \ intel_opregion.o \ + intel_sideband.o \ dvo_ch7xxx.o \ dvo_ch7017.o \ dvo_ivch.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7772bb6f73ba..5a0dfca88668 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1929,9 +1929,17 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); + +/* intel_sideband.c */ int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); +u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); +void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val); +u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, + enum intel_sbi_destination destination); +void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, + enum intel_sbi_destination destination); int vlv_gpu_freq(int ddr_freq, int val); int vlv_freq_opcode(int ddr_freq, int val); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1c0d6d3bfe83..e07ee4c73592 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -381,43 +381,6 @@ static const intel_limit_t intel_limits_vlv_dp = { .find_pll = intel_vlv_find_best_pll, }; -u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) -{ - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO idle wait timed out\n"); - return 0; - } - - I915_WRITE(DPIO_REG, reg); - I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID | - DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO read wait timed out\n"); - return 0; - } - - return I915_READ(DPIO_DATA); -} - -void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) -{ - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO idle wait timed out\n"); - return; - } - - I915_WRITE(DPIO_DATA, val); - I915_WRITE(DPIO_REG, reg); - I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | - DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) - DRM_ERROR("DPIO write wait timed out\n"); -} - static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { @@ -1404,67 +1367,6 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) POSTING_READ(reg); } -/* SBI access */ -static void -intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, - enum intel_sbi_destination destination) -{ - u32 tmp; - - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, - 100)) { - DRM_ERROR("timeout waiting for SBI to become ready\n"); - return; - } - - I915_WRITE(SBI_ADDR, (reg << 16)); - I915_WRITE(SBI_DATA, value); - - if (destination == SBI_ICLK) - tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR; - else - tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR; - I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp); - - if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, - 100)) { - DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); - return; - } -} - -static u32 -intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, - enum intel_sbi_destination destination) -{ - u32 value = 0; - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - - if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, - 100)) { - DRM_ERROR("timeout waiting for SBI to become ready\n"); - return 0; - } - - I915_WRITE(SBI_ADDR, (reg << 16)); - - if (destination == SBI_ICLK) - value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; - else - value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; - I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY); - - if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, - 100)) { - DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); - return 0; - } - - return I915_READ(SBI_DATA); -} - void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) { u32 port_mask; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 75a7f22262d4..83b4fe4b7be0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -743,10 +743,6 @@ extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data, extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); -extern void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, - u32 val); - /* Power-related functions, located in intel_pm.c */ extern void intel_init_pm(struct drm_device *dev); /* FBC */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e198f3881f9a..cd5bd88980bb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4956,66 +4956,6 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) return 0; } -static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode, - u8 addr, u32 *val) -{ - u32 cmd, devfn, be, bar; - - bar = 0; - be = 0xf; - devfn = PCI_DEVFN(2, 0); - - cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | - (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | - (bar << IOSF_BAR_SHIFT); - - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); - - if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) { - DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n", - opcode == PUNIT_OPCODE_REG_READ ? - "read" : "write"); - return -EAGAIN; - } - - I915_WRITE(VLV_IOSF_ADDR, addr); - if (opcode == PUNIT_OPCODE_REG_WRITE) - I915_WRITE(VLV_IOSF_DATA, *val); - I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); - - if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, - 5)) { - DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", - opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", - addr); - return -ETIMEDOUT; - } - - if (opcode == PUNIT_OPCODE_REG_READ) - *val = I915_READ(VLV_IOSF_DATA); - I915_WRITE(VLV_IOSF_DATA, 0); - - return 0; -} - -int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) -{ - return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ, - addr, val); -} - -int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) -{ - return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE, - addr, &val); -} - -int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) -{ - return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ, - addr, val); -} - int vlv_gpu_freq(int ddr_freq, int val) { int mult, base; diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c new file mode 100644 index 000000000000..81af8857857d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -0,0 +1,183 @@ +/* + * Copyright © 2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include "i915_drv.h" +#include "intel_drv.h" + +/* IOSF sideband */ +static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode, + u8 addr, u32 *val) +{ + u32 cmd, devfn, be, bar; + + bar = 0; + be = 0xf; + devfn = PCI_DEVFN(2, 0); + + cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | + (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | + (bar << IOSF_BAR_SHIFT); + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) { + DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n", + opcode == PUNIT_OPCODE_REG_READ ? + "read" : "write"); + return -EAGAIN; + } + + I915_WRITE(VLV_IOSF_ADDR, addr); + if (opcode == PUNIT_OPCODE_REG_WRITE) + I915_WRITE(VLV_IOSF_DATA, *val); + I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); + + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, + 5)) { + DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", + opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", + addr); + return -ETIMEDOUT; + } + + if (opcode == PUNIT_OPCODE_REG_READ) + *val = I915_READ(VLV_IOSF_DATA); + I915_WRITE(VLV_IOSF_DATA, 0); + + return 0; +} + +int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +{ + return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ, + addr, val); +} + +int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) +{ + return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE, + addr, &val); +} + +int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +{ + return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ, + addr, val); +} + +u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) +{ + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO idle wait timed out\n"); + return 0; + } + + I915_WRITE(DPIO_REG, reg); + I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID | + DPIO_BYTE); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO read wait timed out\n"); + return 0; + } + + return I915_READ(DPIO_DATA); +} + +void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) +{ + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + DRM_ERROR("DPIO idle wait timed out\n"); + return; + } + + I915_WRITE(DPIO_DATA, val); + I915_WRITE(DPIO_REG, reg); + I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | + DPIO_BYTE); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) + DRM_ERROR("DPIO write wait timed out\n"); +} + +/* SBI access */ +u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, + enum intel_sbi_destination destination) +{ + u32 value = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + return 0; + } + + I915_WRITE(SBI_ADDR, (reg << 16)); + + if (destination == SBI_ICLK) + value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD; + else + value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD; + I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); + return 0; + } + + return I915_READ(SBI_DATA); +} + +void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, + enum intel_sbi_destination destination) +{ + u32 tmp; + + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to become ready\n"); + return; + } + + I915_WRITE(SBI_ADDR, (reg << 16)); + I915_WRITE(SBI_DATA, value); + + if (destination == SBI_ICLK) + tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR; + else + tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR; + I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp); + + if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, + 100)) { + DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); + return; + } +} -- cgit v1.2.3 From 5a09ae9fd509d7dded34e0d599e1afa5142c6987 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 May 2013 15:36:17 +0300 Subject: drm/i915: refactor VLV IOSF sideband accessors to use one helper Both the intel_dpio_{read,write} and valleyview_{punit,nc}_{read,write} use the IOSF sideband interface. They access the same registers and do mostly the same stuff, but no shared code. There are even duplicate register defines for the same registers. Both have locking, but the former use dpio_lock and the latter rps.hw_lock. It's racy. This patch refactors the sideband access to a single function that expects dpio_lock to be held. The dpio_lock is only used for sideband stuff, so it's a better match than rps.hw_lock for the purpose. The rps stuff still needs rps.hw_lock, since it's used to protect more than just the register access, so rps code will need to hold both locks. Based on the work by Shobhit Kumar and Yogesh Mohan Marimuthu . Signed-off-by: Jani Nikula Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 93 ++++++++++++++----------------- drivers/gpu/drm/i915/intel_sideband.c | 102 +++++++++++++++++----------------- 2 files changed, 93 insertions(+), 102 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 55caedba53d1..dbd9de5abde0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -342,27 +342,54 @@ #define DEBUG_RESET_DISPLAY (1<<9) /* - * DPIO - a special bus for various display related registers to hide behind: - * 0x800c: m1, m2, n, p1, p2, k dividers - * 0x8014: REF and SFR select - * 0x8014: N divider, VCO select - * 0x801c/3c: core clock bits - * 0x8048/68: low pass filter coefficients - * 0x8100: fast clock controls + * IOSF sideband + */ +#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100) +#define IOSF_DEVFN_SHIFT 24 +#define IOSF_OPCODE_SHIFT 16 +#define IOSF_PORT_SHIFT 8 +#define IOSF_BYTE_ENABLES_SHIFT 4 +#define IOSF_BAR_SHIFT 1 +#define IOSF_SB_BUSY (1<<0) +#define IOSF_PORT_PUNIT 0x4 +#define IOSF_PORT_NC 0x11 +#define IOSF_PORT_DPIO 0x12 +#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) +#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) + +#define PUNIT_OPCODE_REG_READ 6 +#define PUNIT_OPCODE_REG_WRITE 7 + +#define PUNIT_REG_GPU_LFM 0xd3 +#define PUNIT_REG_GPU_FREQ_REQ 0xd4 +#define PUNIT_REG_GPU_FREQ_STS 0xd8 +#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc + +#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ +#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ + +#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c +#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 +#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 +#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 +#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 +#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 +#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 +#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 +#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 + +/* + * DPIO - a special bus for various display related registers to hide behind * * DPIO is VLV only. * * Note: digital port B is DDI0, digital pot C is DDI1 */ -#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100) -#define DPIO_RID (0<<24) -#define DPIO_OP_WRITE (1<<16) -#define DPIO_OP_READ (0<<16) -#define DPIO_PORTID (0x12<<8) -#define DPIO_BYTE (0xf<<4) -#define DPIO_BUSY (1<<0) /* status only */ -#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104) -#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108) +#define DPIO_DEVFN 0 +#define DPIO_OPCODE_REG_WRITE 1 +#define DPIO_OPCODE_REG_READ 0 + #define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) #define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ #define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ @@ -4541,40 +4568,6 @@ #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 -#define VLV_IOSF_DOORBELL_REQ 0x182100 -#define IOSF_DEVFN_SHIFT 24 -#define IOSF_OPCODE_SHIFT 16 -#define IOSF_PORT_SHIFT 8 -#define IOSF_BYTE_ENABLES_SHIFT 4 -#define IOSF_BAR_SHIFT 1 -#define IOSF_SB_BUSY (1<<0) -#define IOSF_PORT_PUNIT 0x4 -#define IOSF_PORT_NC 0x11 -#define VLV_IOSF_DATA 0x182104 -#define VLV_IOSF_ADDR 0x182108 - -#define PUNIT_OPCODE_REG_READ 6 -#define PUNIT_OPCODE_REG_WRITE 7 - -#define PUNIT_REG_GPU_LFM 0xd3 -#define PUNIT_REG_GPU_FREQ_REQ 0xd4 -#define PUNIT_REG_GPU_FREQ_STS 0xd8 -#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc - -#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */ -#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */ - -#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c -#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3 -#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8 -#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11 -#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800 -#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34 -#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007 -#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30 -#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 -#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 - #define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_RCn_MASK 7 diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index 81af8857857d..a7c4b61e9c30 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -26,42 +26,37 @@ #include "intel_drv.h" /* IOSF sideband */ -static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode, - u8 addr, u32 *val) +static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, + u32 port, u32 opcode, u32 addr, u32 *val) { - u32 cmd, devfn, be, bar; - - bar = 0; - be = 0xf; - devfn = PCI_DEVFN(2, 0); + u32 cmd, be = 0xf, bar = 0; + bool is_read = (opcode == PUNIT_OPCODE_REG_READ || + opcode == DPIO_OPCODE_REG_READ); cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) | (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) | (bar << IOSF_BAR_SHIFT); - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) { - DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n", - opcode == PUNIT_OPCODE_REG_READ ? - "read" : "write"); + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) { + DRM_DEBUG_DRIVER("IOSF sideband idle wait (%s) timed out\n", + is_read ? "read" : "write"); return -EAGAIN; } I915_WRITE(VLV_IOSF_ADDR, addr); - if (opcode == PUNIT_OPCODE_REG_WRITE) + if (!is_read) I915_WRITE(VLV_IOSF_DATA, *val); I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd); - if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, - 5)) { - DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n", - opcode == PUNIT_OPCODE_REG_READ ? "read" : "write", - addr); + if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) { + DRM_DEBUG_DRIVER("IOSF sideband finish wait (%s) timed out\n", + is_read ? "read" : "write"); return -ETIMEDOUT; } - if (opcode == PUNIT_OPCODE_REG_READ) + if (is_read) *val = I915_READ(VLV_IOSF_DATA); I915_WRITE(VLV_IOSF_DATA, 0); @@ -70,57 +65,60 @@ static int vlv_punit_rw(struct drm_i915_private *dev_priv, u32 port, u8 opcode, int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) { - return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_READ, - addr, val); + int ret; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_READ, addr, val); + mutex_unlock(&dev_priv->dpio_lock); + + return ret; } int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) { - return vlv_punit_rw(dev_priv, IOSF_PORT_PUNIT, PUNIT_OPCODE_REG_WRITE, - addr, &val); + int ret; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_WRITE, addr, &val); + mutex_unlock(&dev_priv->dpio_lock); + + return ret; } int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) { - return vlv_punit_rw(dev_priv, IOSF_PORT_NC, PUNIT_OPCODE_REG_READ, - addr, val); + int ret; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + mutex_lock(&dev_priv->dpio_lock); + ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC, + PUNIT_OPCODE_REG_READ, addr, val); + mutex_unlock(&dev_priv->dpio_lock); + + return ret; } u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) { - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + u32 val = 0; - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO idle wait timed out\n"); - return 0; - } + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO, + DPIO_OPCODE_REG_READ, reg, &val); - I915_WRITE(DPIO_REG, reg); - I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID | - DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO read wait timed out\n"); - return 0; - } - - return I915_READ(DPIO_DATA); + return val; } void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { - DRM_ERROR("DPIO idle wait timed out\n"); - return; - } - - I915_WRITE(DPIO_DATA, val); - I915_WRITE(DPIO_REG, reg); - I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | - DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) - DRM_ERROR("DPIO write wait timed out\n"); + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO, + DPIO_OPCODE_REG_WRITE, reg, &val); } /* SBI access */ -- cgit v1.2.3 From a1ca802d98acbc5fd87cc399b6aaf38f54be33e1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 May 2013 15:36:18 +0300 Subject: drm/i915: drop redundant warnings on not holding dpio_lock The lower level sideband read/write functions already do this. Signed-off-by: Jani Nikula Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 6 ------ drivers/gpu/drm/i915/intel_hdmi.c | 4 ---- 2 files changed, 10 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9332558fc3dc..098e7c25f4ef 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1442,8 +1442,6 @@ static void intel_pre_enable_dp(struct intel_encoder *encoder) int pipe = intel_crtc->pipe; u32 val; - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); val = 0; if (pipe) @@ -1470,8 +1468,6 @@ static void intel_dp_pre_pll_enable(struct intel_encoder *encoder) if (!IS_VALLEYVIEW(dev)) return; - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - /* Program Tx lane resets to default */ intel_dpio_write(dev_priv, DPIO_PCS_TX(port), DPIO_PCS_TX_LANE2_RESET | @@ -1622,8 +1618,6 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp) uint8_t train_set = intel_dp->train_set[0]; int port = vlv_dport_to_channel(dport); - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) { case DP_TRAIN_PRE_EMPHASIS_0: preemph_reg_value = 0x0004000; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 18f8ce0404c6..83b63d72af83 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1018,8 +1018,6 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder) if (!IS_VALLEYVIEW(dev)) return; - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - /* Enable clock channels for this port */ val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); val = 0; @@ -1063,8 +1061,6 @@ static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder) if (!IS_VALLEYVIEW(dev)) return; - WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - /* Program Tx lane resets to default */ intel_dpio_write(dev_priv, DPIO_PCS_TX(port), DPIO_PCS_TX_LANE2_RESET | -- cgit v1.2.3 From ae99258f02fe189c008af94f26140ed691258e9f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 May 2013 15:36:19 +0300 Subject: drm/i915: rename VLV IOSF sideband functions logically Rename all VLV IOSF sideband register accessor functions to vlv__{read,write}. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 24 +++++++++--------- drivers/gpu/drm/i915/i915_drv.h | 10 ++++---- drivers/gpu/drm/i915/i915_sysfs.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 46 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_dp.c | 32 ++++++++++++------------ drivers/gpu/drm/i915/intel_hdmi.c | 42 ++++++++++++++++---------------- drivers/gpu/drm/i915/intel_pm.c | 16 ++++++------ drivers/gpu/drm/i915/intel_sideband.c | 10 ++++---- 8 files changed, 91 insertions(+), 91 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3a8409a31266..bc0f6a55c74b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1137,16 +1137,16 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 freq_sts, val; mutex_lock(&dev_priv->rps.hw_lock); - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, + vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq_sts); seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); - valleyview_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val); + vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val); seq_printf(m, "max GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv->mem_freq, val)); - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); seq_printf(m, "min GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv->mem_freq, val)); @@ -1787,27 +1787,27 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); seq_printf(m, "DPIO_DIV_A: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_DIV_A)); + vlv_dpio_read(dev_priv, _DPIO_DIV_A)); seq_printf(m, "DPIO_DIV_B: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_DIV_B)); + vlv_dpio_read(dev_priv, _DPIO_DIV_B)); seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_REFSFR_A)); + vlv_dpio_read(dev_priv, _DPIO_REFSFR_A)); seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_REFSFR_B)); + vlv_dpio_read(dev_priv, _DPIO_REFSFR_B)); seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A)); + vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_A)); seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); + vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); + vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n", - intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); + vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", - intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); + vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); mutex_unlock(&dev_priv->dpio_lock); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5a0dfca88668..28d14d6cf4cc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1931,11 +1931,11 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); /* intel_sideband.c */ -int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); -int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); -int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); -u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); -void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val); +int vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); +int vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); +int vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); +u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg); +void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val); u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, enum intel_sbi_destination destination); void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index c0d7875b475c..588fa00e6938 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -214,7 +214,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq); ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff); } else { ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e07ee4c73592..2a9d0671f8c3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4245,24 +4245,24 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv) * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1)); reg_val &= 0xffffff00; reg_val |= 0x00000030; - intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val); - reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION); reg_val &= 0x8cffffff; reg_val = 0x8c000000; - intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); - reg_val = intel_dpio_read(dev_priv, DPIO_IREF(1)); + reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1)); reg_val &= 0xffffff00; - intel_dpio_write(dev_priv, DPIO_IREF(1), reg_val); + vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val); - reg_val = intel_dpio_read(dev_priv, DPIO_CALIBRATION); + reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION); reg_val &= 0x00ffffff; reg_val |= 0xb0000000; - intel_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); + vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val); } static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc, @@ -4337,15 +4337,15 @@ static void vlv_update_pll(struct intel_crtc *crtc) vlv_pllb_recal_opamp(dev_priv); /* Set up Tx target for periodic Rcomp update */ - intel_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f); + vlv_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - reg_val = intel_dpio_read(dev_priv, DPIO_IREF_CTL(pipe)); + reg_val = vlv_dpio_read(dev_priv, DPIO_IREF_CTL(pipe)); reg_val &= 0x00ffffff; - intel_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val); + vlv_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val); /* Disable fast lock */ - intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610); + vlv_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610); /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); @@ -4359,47 +4359,47 @@ static void vlv_update_pll(struct intel_crtc *crtc) * Note: don't use the DAC post divider as it seems unstable. */ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; - intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); + vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ if (adjusted_mode->clock == 162000 || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) - intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f0021); else - intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x00d0000f); if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) { /* Use SSC source */ if (!pipe) - intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe), 0x0df40000); else - intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (!pipe) - intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe), 0x0df70000); else - intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), + vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe), 0x0df40000); } - coreclk = intel_dpio_read(dev_priv, DPIO_CORE_CLK(pipe)); + coreclk = vlv_dpio_read(dev_priv, DPIO_CORE_CLK(pipe)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) coreclk |= 0x01000000; - intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk); + vlv_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk); - intel_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000); + vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000); for_each_encoder_on_crtc(dev, &crtc->base, encoder) if (encoder->pre_pll_enable) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 098e7c25f4ef..cdb1c2a6d2b2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1442,18 +1442,18 @@ static void intel_pre_enable_dp(struct intel_encoder *encoder) int pipe = intel_crtc->pipe; u32 val; - val = intel_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); + val = vlv_dpio_read(dev_priv, DPIO_DATA_LANE_A(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val); + vlv_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val); - intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port), + vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port), 0x00760018); - intel_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port), + vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port), 0x00400888); } } @@ -1469,19 +1469,19 @@ static void intel_dp_pre_pll_enable(struct intel_encoder *encoder) return; /* Program Tx lane resets to default */ - intel_dpio_write(dev_priv, DPIO_PCS_TX(port), + vlv_dpio_write(dev_priv, DPIO_PCS_TX(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), + vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<dpio_lock); - intel_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000); - intel_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060); + vlv_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000); + vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060); mutex_unlock(&dev_priv->dpio_lock); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cd5bd88980bb..52f1b39148c0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2566,10 +2566,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) if (val == dev_priv->rps.cur_delay) return; - valleyview_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); + vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); do { - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); if (time_after(jiffies, timeout)) { DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); break; @@ -2577,7 +2577,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) udelay(10); } while (pval & 1); - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); if ((pval >> 8) != val) DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n", val, pval >> 8); @@ -2882,7 +2882,7 @@ int valleyview_rps_max_freq(struct drm_i915_private *dev_priv) { u32 val, rp0; - valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val); + vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val); rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT; /* Clamp to max */ @@ -2895,9 +2895,9 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv) { u32 val, rpe; - valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val); + vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val); rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT; - valleyview_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val); + vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val); rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5; return rpe; @@ -2907,7 +2907,7 @@ int valleyview_rps_min_freq(struct drm_i915_private *dev_priv) { u32 val; - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); return val & 0xff; } @@ -3018,7 +3018,7 @@ static void valleyview_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, GEN7_RC_CTL_TO_MODE); - valleyview_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val); + vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val); switch ((val >> 6) & 3) { case 0: case 1: diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index a7c4b61e9c30..d150972da048 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -63,7 +63,7 @@ static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, return 0; } -int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +int vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) { int ret; @@ -77,7 +77,7 @@ int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) return ret; } -int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) +int vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) { int ret; @@ -91,7 +91,7 @@ int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) return ret; } -int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +int vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) { int ret; @@ -105,7 +105,7 @@ int valleyview_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) return ret; } -u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) +u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg) { u32 val = 0; @@ -115,7 +115,7 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) return val; } -void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) +void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO, DPIO_OPCODE_REG_WRITE, reg, &val); -- cgit v1.2.3 From 64936258d7e426bee5f2392269b1b20172db9ffb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 May 2013 15:36:20 +0300 Subject: drm/i915: change VLV IOSF sideband accessors to not return error code We never check the return values, and there's not much we could do on errors anyway. Just simplify the signatures. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 7 +++---- drivers/gpu/drm/i915/i915_drv.h | 6 +++--- drivers/gpu/drm/i915/i915_sysfs.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 18 +++++++----------- drivers/gpu/drm/i915/intel_sideband.c | 30 +++++++++++++----------------- 5 files changed, 27 insertions(+), 36 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc0f6a55c74b..2eb572afbcd3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1137,16 +1137,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 freq_sts, val; mutex_lock(&dev_priv->rps.hw_lock); - vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, - &freq_sts); + freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); - vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1, &val); + val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1); seq_printf(m, "max GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv->mem_freq, val)); - vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM); seq_printf(m, "min GPU freq: %d MHz\n", vlv_gpu_freq(dev_priv->mem_freq, val)); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 28d14d6cf4cc..f6419f40df38 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1931,9 +1931,9 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); /* intel_sideband.c */ -int vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); -int vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); -int vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val); +u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr); +void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val); +u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr); u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg); void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val); u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 588fa00e6938..6875b5654c63 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -214,7 +214,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); if (IS_VALLEYVIEW(dev_priv->dev)) { u32 freq; - vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &freq); + freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff); } else { ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 52f1b39148c0..fa4c818d4b00 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2569,7 +2569,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); do { - vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); if (time_after(jiffies, timeout)) { DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); break; @@ -2577,7 +2577,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) udelay(10); } while (pval & 1); - vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &pval); + pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); if ((pval >> 8) != val) DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n", val, pval >> 8); @@ -2882,7 +2882,7 @@ int valleyview_rps_max_freq(struct drm_i915_private *dev_priv) { u32 val, rp0; - vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE, &val); + val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE); rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT; /* Clamp to max */ @@ -2895,9 +2895,9 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv) { u32 val, rpe; - vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO, &val); + val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO); rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT; - vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI, &val); + val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI); rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5; return rpe; @@ -2905,11 +2905,7 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv) int valleyview_rps_min_freq(struct drm_i915_private *dev_priv) { - u32 val; - - vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM, &val); - - return val & 0xff; + return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff; } static void vlv_rps_timer_work(struct work_struct *work) @@ -3018,7 +3014,7 @@ static void valleyview_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, GEN7_RC_CTL_TO_MODE); - vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS, &val); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); switch ((val >> 6) & 3) { case 0: case 1: diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index d150972da048..9a0e6c5ea540 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -63,46 +63,42 @@ static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn, return 0; } -int vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr) { - int ret; + u32 val = 0; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); mutex_lock(&dev_priv->dpio_lock); - ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, - PUNIT_OPCODE_REG_READ, addr, val); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_READ, addr, &val); mutex_unlock(&dev_priv->dpio_lock); - return ret; + return val; } -int vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) +void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val) { - int ret; - WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); mutex_lock(&dev_priv->dpio_lock); - ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, - PUNIT_OPCODE_REG_WRITE, addr, &val); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT, + PUNIT_OPCODE_REG_WRITE, addr, &val); mutex_unlock(&dev_priv->dpio_lock); - - return ret; } -int vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val) +u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr) { - int ret; + u32 val = 0; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); mutex_lock(&dev_priv->dpio_lock); - ret = vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC, - PUNIT_OPCODE_REG_READ, addr, val); + vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC, + PUNIT_OPCODE_REG_READ, addr, &val); mutex_unlock(&dev_priv->dpio_lock); - return ret; + return val; } u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg) -- cgit v1.2.3 From 1c0f6749e86a990eca10499c8da2b04888ce4560 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 13 May 2013 23:58:44 +0000 Subject: i915: Use arch_phys_wc_{add,del} i915 open-coded logic that was essentially equivalent to the new API. Reviewed-by: Daniel Vetter Signed-off-by: Andy Lutomirski Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_dma.c | 42 ++++------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f5addac7c154..b76da1470e71 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,7 +42,6 @@ #include #include #include -#include #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) @@ -1397,29 +1396,6 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -static void -i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base, - unsigned long size) -{ - dev_priv->mm.gtt_mtrr = -1; - -#if defined(CONFIG_X86_PAT) - if (cpu_has_pat) - return; -#endif - - /* Set up a WC MTRR for non-PAT systems. This is more common than - * one would think, because the kernel disables PAT on first - * generation Core chips because WC PAT gets overridden by a UC - * MTRR if present. Even if a UC MTRR isn't present. - */ - dev_priv->mm.gtt_mtrr = mtrr_add(base, size, MTRR_TYPE_WRCOMB, 1); - if (dev_priv->mm.gtt_mtrr < 0) { - DRM_INFO("MTRR allocation failed. Graphics " - "performance may suffer.\n"); - } -} - static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) { struct apertures_struct *ap; @@ -1578,8 +1554,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_rmmap; } - i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base, - aperture_size); + dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, + aperture_size); /* The i915 workqueue is primarily used for batched retirement of * requests (and thus managing bo) once the task has been completed @@ -1684,12 +1660,7 @@ out_gem_unload: intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); out_mtrrfree: - if (dev_priv->mm.gtt_mtrr >= 0) { - mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->gtt.mappable_base, - aperture_size); - dev_priv->mm.gtt_mtrr = -1; - } + arch_phys_wc_del(dev_priv->mm.gtt_mtrr); io_mapping_free(dev_priv->gtt.mappable); dev_priv->gtt.gtt_remove(dev); out_rmmap: @@ -1724,12 +1695,7 @@ int i915_driver_unload(struct drm_device *dev) cancel_delayed_work_sync(&dev_priv->mm.retire_work); io_mapping_free(dev_priv->gtt.mappable); - if (dev_priv->mm.gtt_mtrr >= 0) { - mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->gtt.mappable_base, - dev_priv->gtt.mappable_end); - dev_priv->mm.gtt_mtrr = -1; - } + arch_phys_wc_del(dev_priv->mm.gtt_mtrr); acpi_video_unregister(); -- cgit v1.2.3 From 4c4ff43a692b44c6e326f9f28208f3d78ea51f7e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 24 May 2013 11:59:17 -0300 Subject: drm/i915: add "enable" argument to intel_update_sprite_watermarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because we want to call it from the "sprite disable" paths, since on Haswell we need to update the sprite watermarks when we disable sprites. For now, all this patch does is to add the "enable" argument and call intel_update_sprite_watermarks from inside ivb_disable_plane. This shouldn't change how the code behaves because on sandybridge_update_sprite_wm we just ignore the "!enable" case. The patches that implement Haswell watermarks will make use of the changes introduced by this patch. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 11 ++++++++--- drivers/gpu/drm/i915/intel_sprite.c | 8 +++++--- 4 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f6419f40df38..e09c54c73a22 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -315,7 +315,8 @@ struct drm_i915_display_funcs { int (*get_fifo_size)(struct drm_device *dev, int plane); void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size); + uint32_t sprite_width, int pixel_size, + bool enable); void (*modeset_global_resources)(struct drm_device *dev); /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 83b4fe4b7be0..3e6e5e7b089f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -731,7 +731,7 @@ extern void intel_ddi_init(struct drm_device *dev, enum port port); extern void intel_update_watermarks(struct drm_device *dev); extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, - int pixel_size); + int pixel_size, bool enable); extern unsigned long intel_gen4_compute_page_offset(int *x, int *y, unsigned int tiling_mode, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fa4c818d4b00..3515efd049dd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2195,7 +2195,8 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, } static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) + uint32_t sprite_width, int pixel_size, + bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ @@ -2203,6 +2204,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, int sprite_wm, reg; int ret; + if (!enable) + return; + switch (pipe) { case 0: reg = WM0_PIPEA_ILK; @@ -2314,13 +2318,14 @@ void intel_update_watermarks(struct drm_device *dev) } void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) + uint32_t sprite_width, int pixel_size, + bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->display.update_sprite_wm) dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, - pixel_size); + pixel_size, enable); } static struct drm_i915_gem_object * diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 19b9cb961b5a..04d38d4d811a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -114,7 +114,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb, crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true); I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); @@ -268,7 +268,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true); /* * IVB workaround: must disable low power watermarks for at least @@ -335,6 +335,8 @@ ivb_disable_plane(struct drm_plane *plane) dev_priv->sprite_scaling_enabled &= ~(1 << pipe); + intel_update_sprite_watermarks(dev, pipe, 0, 0, false); + /* potentially re-enable LP watermarks */ if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) intel_update_watermarks(dev); @@ -453,7 +455,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, crtc_w--; crtc_h--; - intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); + intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true); dvsscale = 0; if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) -- cgit v1.2.3 From 526682e9fabf22e82a02383e8f864a7330b73b25 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 24 May 2013 11:59:18 -0300 Subject: drm/i915: add haswell_update_sprite_wm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Haswell, whenever we change the sprites we need to completely recalculate all the watermarks, because the sprites are one of the parameters to the LP watermarks, so a change on the sprites may trigger a change on which LP levels are enabled. So on this commit we store all the parameters we need to store for proper recalculation of the Haswell WMs and then call haswell_update_wm. Notice that for now our haswell_update_wm function is not really using these parameters we're storing, but on the next commits we'll use these parameters. Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 12 ++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3e6e5e7b089f..bb4c50b57085 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -326,6 +326,18 @@ struct intel_plane { unsigned int crtc_w, crtc_h; uint32_t src_x, src_y; uint32_t src_w, src_h; + + /* Since we need to change the watermarks before/after + * enabling/disabling the planes, we need to store the parameters here + * as the other pieces of the struct may not reflect the values we want + * for the watermark calculations. Currently only Haswell uses this. + */ + struct { + bool enable; + uint8_t bytes_per_pixel; + uint32_t horiz_pixels; + } wm; + void (*update_plane)(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3515efd049dd..9328ed98ce2f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2118,6 +2118,26 @@ static void haswell_update_wm(struct drm_device *dev) sandybridge_update_wm(dev); } +static void haswell_update_sprite_wm(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size, + bool enable) +{ + struct drm_plane *plane; + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + + if (intel_plane->pipe == pipe) { + intel_plane->wm.enable = enable; + intel_plane->wm.horiz_pixels = sprite_width + 1; + intel_plane->wm.bytes_per_pixel = pixel_size; + break; + } + } + + haswell_update_wm(dev); +} + static bool sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, uint32_t sprite_width, int pixel_size, @@ -4631,7 +4651,8 @@ void intel_init_pm(struct drm_device *dev) } else if (IS_HASWELL(dev)) { if (I915_READ64(MCH_SSKPD)) { dev_priv->display.update_wm = haswell_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + dev_priv->display.update_sprite_wm = + haswell_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); -- cgit v1.2.3 From 79ee20dc85072b0edfb5e461799d192a9cc9d422 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 13 May 2013 16:32:09 +0300 Subject: drm/i915: pass seqno to i915_hangcheck_ring_idle In preparation for next commit, pass seqno as a parameter to i915_hangcheck_ring_idle as it will be used inside i915_hangcheck_elapsed. Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 879c4ccb00db..0e5c9b0cc5a6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2274,11 +2274,11 @@ ring_last_seqno(struct intel_ring_buffer *ring) struct drm_i915_gem_request, list)->seqno; } -static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err) +static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, + u32 ring_seqno, bool *err) { if (list_empty(&ring->request_list) || - i915_seqno_passed(ring->get_seqno(ring, false), - ring_last_seqno(ring))) { + i915_seqno_passed(ring_seqno, ring_last_seqno(ring))) { /* Issue a wake-up to catch stuck h/w. */ if (waitqueue_active(&ring->irq_queue)) { DRM_ERROR("Hangcheck timer elapsed... %s idle\n", @@ -2395,7 +2395,10 @@ void i915_hangcheck_elapsed(unsigned long data) memset(acthd, 0, sizeof(acthd)); idle = true; for_each_ring(ring, dev_priv, i) { - idle &= i915_hangcheck_ring_idle(ring, &err); + u32 seqno; + + seqno = ring->get_seqno(ring, false); + idle &= i915_hangcheck_ring_idle(ring, seqno, &err); acthd[i] = intel_ring_get_active_head(ring); } -- cgit v1.2.3 From 92cab7345131db7af18f630a799ce6b2e8e624c5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 24 May 2013 17:16:07 +0300 Subject: drm/i915: track ring progression using seqnos Instead of relying in acthd, track ring seqno progression to detect if ring has hung. v2: put hangcheck stuff inside struct (Chris Wilson) v3: initialize hangcheck.seqno (Ben Widawsky) Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++----------------- drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + drivers/gpu/drm/i915/intel_ringbuffer.h | 6 ++++++ 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e09c54c73a22..e417049ea581 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -842,8 +842,6 @@ struct i915_gpu_error { #define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; int hangcheck_count; - uint32_t last_acthd[I915_NUM_RINGS]; - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; /* For reset and error_state handling. */ spinlock_t lock; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0e5c9b0cc5a6..004ad3455992 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2384,22 +2384,19 @@ void i915_hangcheck_elapsed(unsigned long data) { struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG]; struct intel_ring_buffer *ring; bool err = false, idle; int i; + u32 seqno[I915_NUM_RINGS]; + bool work_done; if (!i915_enable_hangcheck) return; - memset(acthd, 0, sizeof(acthd)); idle = true; for_each_ring(ring, dev_priv, i) { - u32 seqno; - - seqno = ring->get_seqno(ring, false); - idle &= i915_hangcheck_ring_idle(ring, seqno, &err); - acthd[i] = intel_ring_get_active_head(ring); + seqno[i] = ring->get_seqno(ring, false); + idle &= i915_hangcheck_ring_idle(ring, seqno[i], &err); } /* If all work is done then ACTHD clearly hasn't advanced. */ @@ -2415,20 +2412,19 @@ void i915_hangcheck_elapsed(unsigned long data) return; } - i915_get_extra_instdone(dev, instdone); - if (memcmp(dev_priv->gpu_error.last_acthd, acthd, - sizeof(acthd)) == 0 && - memcmp(dev_priv->gpu_error.prev_instdone, instdone, - sizeof(instdone)) == 0) { + work_done = false; + for_each_ring(ring, dev_priv, i) { + if (ring->hangcheck.seqno != seqno[i]) { + work_done = true; + ring->hangcheck.seqno = seqno[i]; + } + } + + if (!work_done) { if (i915_hangcheck_hung(dev)) return; } else { dev_priv->gpu_error.hangcheck_count = 0; - - memcpy(dev_priv->gpu_error.last_acthd, acthd, - sizeof(acthd)); - memcpy(dev_priv->gpu_error.prev_instdone, instdone, - sizeof(instdone)); } repeat: diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3d2c236e15ab..5698faeee6f6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1502,6 +1502,7 @@ void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) } ring->set_seqno(ring, seqno); + ring->hangcheck.seqno = seqno; } void intel_ring_advance(struct intel_ring_buffer *ring) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index dac1614a1bca..ef374a892105 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -37,6 +37,10 @@ struct intel_hw_status_page { #define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base)) #define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base)) +struct intel_ring_hangcheck { + u32 seqno; +}; + struct intel_ring_buffer { const char *name; enum intel_ring_id { @@ -137,6 +141,8 @@ struct intel_ring_buffer { struct i915_hw_context *default_context; struct i915_hw_context *last_context; + struct intel_ring_hangcheck hangcheck; + void *private; }; -- cgit v1.2.3 From ed5cbb0355779dc5516b2f7b62cedce185b00439 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 13 May 2013 16:32:11 +0300 Subject: drm/i915: introduce i915_hangcheck_ring_hung In preparation to track per ring progress in hangcheck, add i915_hangcheck_ring_hung. v2: omit dev parameter (Ben Widawsky) Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 004ad3455992..6efe3b0d3e84 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2345,28 +2345,33 @@ static bool kick_ring(struct intel_ring_buffer *ring) return false; } +static bool i915_hangcheck_ring_hung(struct intel_ring_buffer *ring) +{ + if (IS_GEN2(ring->dev)) + return false; + + /* Is the chip hanging on a WAIT_FOR_EVENT? + * If so we can simply poke the RB_WAIT bit + * and break the hang. This should work on + * all but the second generation chipsets. + */ + return !kick_ring(ring); +} + static bool i915_hangcheck_hung(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; if (dev_priv->gpu_error.hangcheck_count++ > 1) { bool hung = true; + struct intel_ring_buffer *ring; + int i; DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); i915_handle_error(dev, true); - if (!IS_GEN2(dev)) { - struct intel_ring_buffer *ring; - int i; - - /* Is the chip hanging on a WAIT_FOR_EVENT? - * If so we can simply poke the RB_WAIT bit - * and break the hang. This should work on - * all but the second generation chipsets. - */ - for_each_ring(ring, dev_priv, i) - hung &= !kick_ring(ring); - } + for_each_ring(ring, dev_priv, i) + hung &= i915_hangcheck_ring_hung(ring); return hung; } -- cgit v1.2.3 From 7ed73da0eac4e2e06c06e8baf518e124fc1f6a17 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 14:42:54 -0700 Subject: drm/i915: Fix error state memory leaks Found with kmemleak. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6efe3b0d3e84..4df2b3fa4ebd 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1564,11 +1564,13 @@ i915_error_state_free(struct kref *error_ref) for (i = 0; i < ARRAY_SIZE(error->ring); i++) { i915_error_object_free(error->ring[i].batchbuffer); i915_error_object_free(error->ring[i].ringbuffer); + i915_error_object_free(error->ring[i].ctx); kfree(error->ring[i].requests); } kfree(error->active_bo); kfree(error->overlay); + kfree(error->display); kfree(error); } static void capture_bo(struct drm_i915_error_buffer *err, -- cgit v1.2.3 From 0a9ae0d7f8249da5906c8cac7d56768975c38de4 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 12:26:35 -0700 Subject: drm/i915: pre-fixes for checkpatch Since I'll need to modify i915_gem_object_bind_to_gtt(), fix the errors now to get checkpatch to not complain. Signed-off-by: Ben Widawsky [danvet: Resolve conflict with Chris' improved debug output, and bikeshed the new variable with s/max/gtt_max/ a bit while at it.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1b735a4a2873..9496fb5f2fe1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2968,6 +2968,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, struct drm_mm_node *node; u32 size, fence_size, fence_alignment, unfenced_alignment; bool mappable, fenceable; + size_t gtt_max = map_and_fenceable ? + dev_priv->gtt.mappable_end : dev_priv->gtt.total; int ret; fence_size = i915_gem_get_gtt_size(dev, @@ -2994,12 +2996,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ - if (obj->base.size > - (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { + if (obj->base.size > gtt_max) { DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n", obj->base.size, map_and_fenceable ? "mappable" : "total", - map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total); + gtt_max); return -E2BIG; } @@ -3015,14 +3016,10 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, return -ENOMEM; } - search_free: - if (map_and_fenceable) - ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, - size, alignment, obj->cache_level, - 0, dev_priv->gtt.mappable_end); - else - ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node, - size, alignment, obj->cache_level); +search_free: + ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node, + size, alignment, + obj->cache_level, 0, gtt_max); if (ret) { ret = i915_gem_evict_something(dev, size, alignment, obj->cache_level, -- cgit v1.2.3 From f64e29227d80cc15c37c7dbf7030ffc8c415cbd4 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 12:26:36 -0700 Subject: drm/i915: use mappable size for fb kickout The GTT start is either 0 in the KMS case, or some value which is set only after the init IOCTL in the UMS case. In both cases, we don't have this information until after we've tried to kick out the firmware fb. This patch should have no functional change since we kzalloc the GTT struct anyway. It only clarifies the situation for people who end up having to look at that code. This weirdness was introduced in: commit 93d187993b783c68383a884091a600d9ad499ea6 Author: Ben Widawsky Date: Thu Jan 17 12:45:17 2013 -0800 drm/i915: Remove use of gtt_mappable_entries Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f5addac7c154..3cda7521e8d7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1431,7 +1431,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) return; ap->ranges[0].base = dev_priv->gtt.mappable_base; - ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start; + ap->ranges[0].size = dev_priv->gtt.mappable_end; primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; -- cgit v1.2.3 From dd62eabd1d54336a2d5d3758ab4393cd13254102 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 12:26:37 -0700 Subject: drm/i915: use drm_mm_takedown I noticed this while doing the VMA abstraction. AFAICT, it won't actually fix anything, but it is the correct thing to do. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3cda7521e8d7..45283679ac87 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1361,6 +1361,7 @@ cleanup_gem: i915_gem_cleanup_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); + drm_mm_takedown(&dev_priv->mm.gtt_space); cleanup_irq: drm_irq_uninstall(dev); cleanup_gem_stolen: @@ -1778,6 +1779,7 @@ int i915_driver_unload(struct drm_device *dev) i915_free_hws(dev); } + drm_mm_takedown(&dev_priv->mm.gtt_space); if (dev_priv->regs != NULL) pci_iounmap(dev->pdev, dev_priv->regs); -- cgit v1.2.3 From bb0364130fb0d272c838149b2ffe698a6c7afbfc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 12:26:38 -0700 Subject: drm/i915: context debug messages Add some debug messages to help figure out what goes wrong on context initialization. Later in the PPGTT series, I ended up having a lot of failures after reset. In many cases it was extra difficult to debug because I hadn't even realized that contexts failed to reinitialize after reset (again an artifact of some later patches). This fairly benign patch does help debug some potential issues which arise later. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 64cb1909a0ce..39bcc087db96 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -156,7 +156,8 @@ create_hw_context(struct drm_device *dev, if (INTEL_INFO(dev)->gen >= 7) { ret = i915_gem_object_set_cache_level(ctx->obj, I915_CACHE_LLC_MLC); - if (ret) + /* Failure shouldn't ever happen this early */ + if (WARN_ON(ret)) goto err_out; } @@ -214,12 +215,16 @@ static int create_default_context(struct drm_i915_private *dev_priv) */ dev_priv->ring[RCS].default_context = ctx; ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false); - if (ret) + if (ret) { + DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret); goto err_destroy; + } ret = do_switch(ctx); - if (ret) + if (ret) { + DRM_DEBUG_DRIVER("Switch failed %d\n", ret); goto err_unpin; + } DRM_DEBUG_DRIVER("Default HW context loaded\n"); return 0; @@ -237,6 +242,7 @@ void i915_gem_context_init(struct drm_device *dev) if (!HAS_HW_CONTEXTS(dev)) { dev_priv->hw_contexts_disabled = true; + DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n"); return; } @@ -249,11 +255,13 @@ void i915_gem_context_init(struct drm_device *dev) if (dev_priv->hw_context_size > (1<<20)) { dev_priv->hw_contexts_disabled = true; + DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); return; } if (create_default_context(dev_priv)) { dev_priv->hw_contexts_disabled = true; + DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n"); return; } -- cgit v1.2.3 From 55d23285745b1be7bd25a2a4ba5ba79e05ab843a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 25 May 2013 12:26:39 -0700 Subject: drm/i915: Call context fini at cleanup If contexts were actually initialized, and we fail somewhere later during init this would possibly leak memory, and lead to some error messages about unclean takedown. As the odds of this occurring, and someone actually caring/noticing are pretty slim, the patch isn't terribly important. Found by code inspection while working on something else. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 45283679ac87..bd56c5560fa0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1359,6 +1359,7 @@ static int i915_load_modeset_init(struct drm_device *dev) cleanup_gem: mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); + i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); drm_mm_takedown(&dev_priv->mm.gtt_space); -- cgit v1.2.3 From 6640aab6f2aed89470bc44c7450b7573659e651e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 22 May 2013 17:47:13 +0300 Subject: drm/i915: release scratch page at module unload Signed-off-by: Imre Deak Acked-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index bd56c5560fa0..3cd2b606aaba 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1790,6 +1790,8 @@ int i915_driver_unload(struct drm_device *dev) destroy_workqueue(dev_priv->wq); pm_qos_remove_request(&dev_priv->pm_qos); + dev_priv->gtt.gtt_remove(dev); + if (dev_priv->slab) kmem_cache_destroy(dev_priv->slab); -- cgit v1.2.3 From 982a38667dd9f175f8dd8a78651426ae6baac463 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 23 May 2013 19:39:40 +0300 Subject: drm/i915: stop using is_cpu_edp() in intel_disable/post_disable_dp Based on 3739850b46f - "drm/i915: disable the cpu edp port after the cpu pipe" and the bspec disabling sequence for IVB and older it seems we have to distinguish only the CPU vs. PCH port case, whether it's a DP or eDP doesn't seem to matter. For IVB and older on the CPU side we can only have eDP on port A, DP ports can only be on the PCH side. On VLV we have only CPU side eDP/DP ports, no PCH. So the condition for the disabling sequence we need for CPU ports is port == A || IS_VLV. This allows us to remove is_cpu_edp() completely in a later patch. v2: - simplify (and fix) the condition for CPU side ports and adjust the commit message accordingly (Daniel) Signed-off-by: Imre Deak Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cdb1c2a6d2b2..ee157091f92e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1372,6 +1372,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder, static void intel_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + enum port port = dp_to_dig_port(intel_dp)->port; + struct drm_device *dev = encoder->base.dev; /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ @@ -1381,16 +1383,17 @@ static void intel_disable_dp(struct intel_encoder *encoder) ironlake_edp_panel_off(intel_dp); /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */ - if (!is_cpu_edp(intel_dp)) + if (!(port == PORT_A || IS_VALLEYVIEW(dev))) intel_dp_link_down(intel_dp); } static void intel_post_disable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + enum port port = dp_to_dig_port(intel_dp)->port; struct drm_device *dev = encoder->base.dev; - if (is_cpu_edp(intel_dp)) { + if (port == PORT_A || IS_VALLEYVIEW(dev)) { intel_dp_link_down(intel_dp); if (!IS_VALLEYVIEW(dev)) ironlake_edp_pll_off(intel_dp); -- cgit v1.2.3 From a62d0834dee83994e41fcd0e5b7f10aad3d80de0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 May 2013 14:40:35 +0300 Subject: drm/i915: merge VLV eDP and DP AUX clock divider calculation On ValleyView for both eDP and DP the AUX input clock is 200MHz, so we can calculate for both the clock divider for the 2MHz target rate at the same place. Afterwards we can also replace the is_cpu_edp() check with a check for port A. Signed-off-by: Imre Deak Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ee157091f92e..320bd61ea2f2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -317,12 +317,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * Note that PCH attached eDP panels should use a 125MHz input * clock divider. */ - if (is_cpu_edp(intel_dp)) { + if (IS_VALLEYVIEW(dev)) { + aux_clock_divider = 100; + } else if (intel_dig_port->port == PORT_A) { if (HAS_DDI(dev)) aux_clock_divider = DIV_ROUND_CLOSEST( intel_ddi_get_cdclk_freq(dev_priv), 2000); - else if (IS_VALLEYVIEW(dev)) - aux_clock_divider = 100; else if (IS_GEN6(dev) || IS_GEN7(dev)) aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ else -- cgit v1.2.3 From bc7d38a43ab1af4cad1c235c3aa30426b6c7d6c5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 May 2013 14:40:36 +0300 Subject: drm/i915: replace is_cpu_edp() with a check for port A The patch changes all remaining is_cpu_edp() check with a check for port A. We can do this, since in all these cases ValleyView is handled separately and port A is always a CPU side eDP port. Signed-off-by: Imre Deak Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 49 +++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 320bd61ea2f2..91918f99611e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -685,6 +685,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + enum port port = dp_to_dig_port(intel_dp)->port; struct intel_crtc *intel_crtc = encoder->new_crtc; struct intel_connector *intel_connector = intel_dp->attached_connector; int lane_count, clock; @@ -694,7 +695,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; int target_clock, link_avail, link_clock; - if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp)) + if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A) pipe_config->has_pch_encoder = true; pipe_config->has_dp_encoder = true; @@ -828,6 +829,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + enum port port = dp_to_dig_port(intel_dp)->port; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -868,7 +870,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* Split out the IBX/CPU vs CPT settings */ - if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { + if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -885,7 +887,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_PLL_FREQ_160MHZ; else intel_dp->DP |= DP_PLL_FREQ_270MHZ; - } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { + } else if (!HAS_PCH_CPT(dev) || port == PORT_A) { if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) intel_dp->DP |= intel_dp->color_range; @@ -901,7 +903,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_crtc->pipe == 1) intel_dp->DP |= DP_PIPEB_SELECT; - if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { + if (port == PORT_A && !IS_VALLEYVIEW(dev)) { /* don't miss out required setting for eDP */ if (adjusted_mode->clock < 200000) intel_dp->DP |= DP_PLL_FREQ_160MHZ; @@ -912,7 +914,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } - if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) + if (port == PORT_A && !IS_VALLEYVIEW(dev)) ironlake_set_pll_edp(crtc, adjusted_mode->clock); } @@ -1302,6 +1304,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + enum port port = dp_to_dig_port(intel_dp)->port; struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp = I915_READ(intel_dp->output_reg); @@ -1309,9 +1312,9 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, if (!(tmp & DP_PORT_EN)) return false; - if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { + if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) { *pipe = PORT_TO_PIPE_CPT(tmp); - } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { + } else if (!HAS_PCH_CPT(dev) || port == PORT_A) { *pipe = PORT_TO_PIPE(tmp); } else { u32 trans_sel; @@ -1431,14 +1434,14 @@ static void intel_enable_dp(struct intel_encoder *encoder) static void intel_pre_enable_dp(struct intel_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); + struct intel_digital_port *dport = dp_to_dig_port(intel_dp); struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) + if (dport->port == PORT_A && !IS_VALLEYVIEW(dev)) ironlake_edp_pll_on(intel_dp); if (IS_VALLEYVIEW(dev)) { - struct intel_digital_port *dport = enc_to_dig_port(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); int port = vlv_dport_to_channel(dport); @@ -1546,12 +1549,13 @@ static uint8_t intel_dp_voltage_max(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + enum port port = dp_to_dig_port(intel_dp)->port; if (IS_VALLEYVIEW(dev)) return DP_TRAIN_VOLTAGE_SWING_1200; - else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) + else if (IS_GEN7(dev) && port == PORT_A) return DP_TRAIN_VOLTAGE_SWING_800; - else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + else if (HAS_PCH_CPT(dev) && port != PORT_A) return DP_TRAIN_VOLTAGE_SWING_1200; else return DP_TRAIN_VOLTAGE_SWING_800; @@ -1561,6 +1565,7 @@ static uint8_t intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + enum port port = dp_to_dig_port(intel_dp)->port; if (HAS_DDI(dev)) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { @@ -1586,7 +1591,7 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) default: return DP_TRAIN_PRE_EMPHASIS_0; } - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + } else if (IS_GEN7(dev) && port == PORT_A) { switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { case DP_TRAIN_VOLTAGE_SWING_400: return DP_TRAIN_PRE_EMPHASIS_6; @@ -1873,6 +1878,7 @@ static void intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + enum port port = intel_dig_port->port; struct drm_device *dev = intel_dig_port->base.base.dev; uint32_t signal_levels, mask; uint8_t train_set = intel_dp->train_set[0]; @@ -1883,10 +1889,10 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) } else if (IS_VALLEYVIEW(dev)) { signal_levels = intel_vlv_signal_levels(intel_dp); mask = 0; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + } else if (IS_GEN7(dev) && port == PORT_A) { signal_levels = intel_gen7_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; - } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { + } else if (IS_GEN6(dev) && port == PORT_A) { signal_levels = intel_gen6_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; } else { @@ -1936,8 +1942,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, } I915_WRITE(DP_TP_CTL(port), temp); - } else if (HAS_PCH_CPT(dev) && - (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { + } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) { dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { @@ -2188,6 +2193,7 @@ static void intel_dp_link_down(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + enum port port = intel_dig_port->port; struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = @@ -2217,7 +2223,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) DRM_DEBUG_KMS("\n"); - if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); } else { @@ -2944,9 +2950,6 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, pp_div_reg = PIPEA_PP_DIVISOR; } - if (IS_VALLEYVIEW(dev)) - port_sel = I915_READ(pp_on_reg) & 0xc0000000; - /* And finally store the new values in the power sequencer. */ pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT); @@ -2960,8 +2963,10 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, /* Haswell doesn't have any port selection bits for the panel * power sequencer any more. */ - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - if (is_cpu_edp(intel_dp)) + if (IS_VALLEYVIEW(dev)) { + port_sel = I915_READ(pp_on_reg) & 0xc0000000; + } else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + if (dp_to_dig_port(intel_dp)->port == PORT_A) port_sel = PANEL_POWER_PORT_DP_A; else port_sel = PANEL_POWER_PORT_DP_D; -- cgit v1.2.3 From 55aab33e898eb61d6187b18c2446e2cb1b06b910 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 16 May 2013 14:40:37 +0300 Subject: drm/i915: remove unused is_cpu_edp() Signed-off-by: Imre Deak Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 91918f99611e..a899f93cb0ee 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -59,22 +59,6 @@ static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) return intel_dig_port->base.base.dev; } -/** - * is_cpu_edp - is the port on the CPU and attached to an eDP panel? - * @intel_dp: DP struct - * - * Returns true if the given DP struct corresponds to a CPU eDP port. - */ -static bool is_cpu_edp(struct intel_dp *intel_dp) -{ - struct drm_device *dev = intel_dp_to_dev(intel_dp); - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - enum port port = intel_dig_port->port; - - return is_edp(intel_dp) && - (port == PORT_A || (port == PORT_C && IS_VALLEYVIEW(dev))); -} - static struct intel_dp *intel_attached_dp(struct drm_connector *connector) { return enc_to_intel_dp(&intel_attached_encoder(connector)->base); -- cgit v1.2.3 From a01025afa89ccaf1b0521f5862cbfcc73f970481 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 May 2013 00:50:23 +0200 Subject: drm/i915: fixup i915_pipe_enabled check in i915_irq.c Well, as well as we can without completely revamping the drm vblank code. The issue are that - The vblank code needs to work on both ums and kms. - It deals always deals with pipes. - It doesn't take any of the kms locks. The last part is not really fixable without revamping the drm vblank code, since the drm core <-> driver interactions is a veritable pile of spaghettis. But the other pieces can be fixed by switching on the MODESET driver flag and either checking the hw state directly (ums case) or just querying our sw tracking (with broken locking, but that's not worse than what we've had). Note that this essentially reverts commit 702e7a56af3780d8b3a717f698209bef44187bb0 Author: Paulo Zanoni Date: Tue Oct 23 18:29:59 2012 -0200 drm/i915: convert PIPECONF to use transcoder instead of pipe for the ums case, which will fix a NULL deref (since we really don't have any crtcs set up). But the real reason to do this is to drop our reliance on the cpu_transcoder: By only checking intel_crtc->active we don't need to make sure that the pipe_config (or at least the cpu_transcoder) contain safe values even when the pipe is off. Cc: Paulo Zanoni Cc: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4df2b3fa4ebd..557acd37c788 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -381,14 +381,16 @@ static int i915_pipe_enabled(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, - pipe); - if (!intel_display_power_enabled(dev, - POWER_DOMAIN_TRANSCODER(cpu_transcoder))) - return false; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* Locking is horribly broken here, but whatever. */ + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE; + return intel_crtc->active; + } else { + return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE; + } } /* Called from drm generic code, passed a 'crtc', which -- cgit v1.2.3 From eccb140bca6727f2ef849e8811d5fe4c9fbfd5dd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 May 2013 00:50:22 +0200 Subject: drm/i915: hw state readout&check support for cpu_transcoder This allows us to drop a bunch of ugly hacks and finally implement what commit cc464b2a17c59adedbdc02cc54341d630354edc3 Author: Paulo Zanoni Date: Fri Jan 25 16:59:16 2013 -0200 drm/i915: set TRANSCODER_EDP even earlier tried to achieve, but that was reverted again in commit bba2181c49f1dddf8b592804a1b53cc1a3cf408a Author: Daniel Vetter Date: Fri Mar 22 10:53:40 2013 +0100 Revert "drm/i915: set TRANSCODER_EDP even earlier" Now we should always have a consistent cpu_transcoder in the pipe_config. v2: Fix up the code as spotted by Paulo: - read the register for real - assign the right pipes - break out if the hw state doesn't make sense v3: Shut up gcc. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 4 ++ drivers/gpu/drm/i915/intel_display.c | 90 +++++++++++++----------------------- 2 files changed, 37 insertions(+), 57 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1fdd3b0b7040..9649df806079 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1291,9 +1291,13 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { int type = encoder->type; + int port = intel_ddi_get_encoder_port(encoder); WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n"); + if (port == PORT_A) + pipe_config->cpu_transcoder = TRANSCODER_EDP; + if (type == INTEL_OUTPUT_HDMI) return intel_hdmi_compute_config(encoder, pipe_config); else diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a9d0671f8c3..cb2437d1e0ea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3469,12 +3469,6 @@ static void ironlake_crtc_off(struct drm_crtc *crtc) static void haswell_crtc_off(struct drm_crtc *crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* Stop saying we're using TRANSCODER_EDP because some other CRTC might - * start using it. */ - intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe; - intel_ddi_put_crtc_pll(crtc); } @@ -4925,6 +4919,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + pipe_config->cpu_transcoder = crtc->pipe; + tmp = I915_READ(PIPECONF(crtc->pipe)); if (!(tmp & PIPECONF_ENABLE)) return false; @@ -5647,8 +5643,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); - intel_crtc->config.cpu_transcoder = pipe; - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock); if (!ok) { @@ -5784,6 +5778,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; + pipe_config->cpu_transcoder = crtc->pipe; + tmp = I915_READ(PIPECONF(crtc->pipe)); if (!(tmp & PIPECONF_ENABLE)) return false; @@ -5860,11 +5856,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - if (is_cpu_edp) - intel_crtc->config.cpu_transcoder = TRANSCODER_EDP; - else - intel_crtc->config.cpu_transcoder = pipe; - /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); @@ -5918,15 +5909,37 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; enum intel_display_power_domain pfit_domain; uint32_t tmp; + pipe_config->cpu_transcoder = crtc->pipe; + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); + if (tmp & TRANS_DDI_FUNC_ENABLE) { + enum pipe trans_edp_pipe; + switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { + default: + WARN(1, "unknown pipe linked to edp transcoder\n"); + case TRANS_DDI_EDP_INPUT_A_ONOFF: + case TRANS_DDI_EDP_INPUT_A_ON: + trans_edp_pipe = PIPE_A; + break; + case TRANS_DDI_EDP_INPUT_B_ONOFF: + trans_edp_pipe = PIPE_B; + break; + case TRANS_DDI_EDP_INPUT_C_ONOFF: + trans_edp_pipe = PIPE_C; + break; + } + + if (trans_edp_pipe == crtc->pipe) + pipe_config->cpu_transcoder = TRANSCODER_EDP; + } + if (!intel_display_power_enabled(dev, - POWER_DOMAIN_TRANSCODER(cpu_transcoder))) + POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder))) return false; - tmp = I915_READ(PIPECONF(cpu_transcoder)); + tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder)); if (!(tmp & PIPECONF_ENABLE)) return false; @@ -5935,7 +5948,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, * DDI E. So just check whether this pipe is wired to DDI E and whether * the PCH transcoder is on. */ - tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); + tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder)); if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) && I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) { pipe_config->has_pch_encoder = true; @@ -7690,6 +7703,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, drm_mode_copy(&pipe_config->adjusted_mode, mode); drm_mode_copy(&pipe_config->requested_mode, mode); + pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe; plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config); if (plane_bpp < 0) @@ -7940,6 +7954,8 @@ intel_pipe_config_compare(struct drm_device *dev, return false; \ } + PIPE_CONF_CHECK_I(cpu_transcoder); + PIPE_CONF_CHECK_I(has_pch_encoder); PIPE_CONF_CHECK_I(fdi_lanes); PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); @@ -8091,7 +8107,6 @@ intel_modeset_check_state(struct drm_device *dev) "crtc's computed enabled state doesn't match tracked enabled state " "(expected %i, found %i)\n", enabled, crtc->base.enabled); - pipe_config.cpu_transcoder = crtc->config.cpu_transcoder; active = dev_priv->display.get_pipe_config(crtc, &pipe_config); WARN(crtc->active != active, @@ -8154,12 +8169,10 @@ static int __intel_set_mode(struct drm_crtc *crtc, * to set it here already despite that we pass it down the callchain. */ if (modeset_pipes) { - enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder; crtc->mode = *mode; /* mode_set/enable/disable functions rely on a correct pipe * config. */ to_intel_crtc(crtc)->config = *pipe_config; - to_intel_crtc(crtc)->config.cpu_transcoder = tmp; } /* Only after disabling all output pipelines that will be changed can we @@ -8570,7 +8583,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) /* Swap pipes & planes for FBC on pre-965 */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - intel_crtc->config.cpu_transcoder = pipe; if (IS_MOBILE(dev) && IS_GEN3(dev)) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; @@ -9436,50 +9448,14 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; - u32 tmp; struct drm_plane *plane; struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; - if (HAS_DDI(dev)) { - tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); - - if (tmp & TRANS_DDI_FUNC_ENABLE) { - switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { - case TRANS_DDI_EDP_INPUT_A_ON: - case TRANS_DDI_EDP_INPUT_A_ONOFF: - pipe = PIPE_A; - break; - case TRANS_DDI_EDP_INPUT_B_ONOFF: - pipe = PIPE_B; - break; - case TRANS_DDI_EDP_INPUT_C_ONOFF: - pipe = PIPE_C; - break; - default: - /* A bogus value has been programmed, disable - * the transcoder */ - WARN(1, "Bogus eDP source %08x\n", tmp); - intel_ddi_disable_transcoder_func(dev_priv, - TRANSCODER_EDP); - goto setup_pipes; - } - - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - crtc->config.cpu_transcoder = TRANSCODER_EDP; - - DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n", - pipe_name(pipe)); - } - } - -setup_pipes: list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - enum transcoder tmp = crtc->config.cpu_transcoder; memset(&crtc->config, 0, sizeof(crtc->config)); - crtc->config.cpu_transcoder = tmp; crtc->active = dev_priv->display.get_pipe_config(crtc, &crtc->config); -- cgit v1.2.3 From 6b1c087ba5789aceb25a2170b217055ce2476f67 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 28 May 2013 12:35:02 +0300 Subject: drm/i915: document why dvo/sdvo/crt need a special dpms function In the cloned case, changing just one output but keeping the other, the pipe state won't change and intel_crtc_update_dpms will be a nop, but we still need to update the dpms state of the output being changed. Only dvo, sdvo and crt are cloneable, so only those three have special dpms functions. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_crt.c | 4 +++- drivers/gpu/drm/i915/intel_dvo.c | 3 +++ drivers/gpu/drm/i915/intel_sdvo.c | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 5e9f93e53255..3acec8c48166 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -149,7 +149,7 @@ static void intel_enable_crt(struct intel_encoder *encoder) intel_crt_set_dpms(encoder, crt->connector->base.dpms); } - +/* Special dpms function to support cloning between dvo/sdvo/crt. */ static void intel_crt_dpms(struct drm_connector *connector, int mode) { struct drm_device *dev = connector->dev; @@ -180,6 +180,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) else encoder->connectors_active = true; + /* We call connector dpms manually below in case pipe dpms doesn't + * change due to cloning. */ if (mode < old_dpms) { /* From off to on, enable the pipe first. */ intel_crtc_update_dpms(crtc); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 9e80d487b5cb..eb2020eb2b7e 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -180,6 +180,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder) intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true); } +/* Special dpms function to support cloning between dvo/sdvo/crt. */ static void intel_dvo_dpms(struct drm_connector *connector, int mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); @@ -201,6 +202,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) return; } + /* We call connector dpms manually below in case pipe dpms doesn't + * change due to cloning. */ if (mode == DRM_MODE_DPMS_ON) { intel_dvo->base.connectors_active = true; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 4d4a3f0cadfb..7068195376ef 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1416,6 +1416,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } +/* Special dpms function to support cloning between dvo/sdvo/crt. */ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) { struct drm_crtc *crtc; @@ -1437,6 +1438,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) return; } + /* We set active outputs manually below in case pipe dpms doesn't change + * due to cloning. */ if (mode != DRM_MODE_DPMS_ON) { intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) -- cgit v1.2.3 From 56b085a01befc7907d270e9acb349580015e7bad Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 28 May 2013 17:51:44 +0800 Subject: drm/i915: fix error return code in init_pipe_control() Fix to return -ENOMEM in the kmap() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5698faeee6f6..9b97cf66a5ae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -464,9 +464,11 @@ init_pipe_control(struct intel_ring_buffer *ring) goto err_unref; pc->gtt_offset = obj->gtt_offset; - pc->cpu_page = kmap(sg_page(obj->pages->sgl)); - if (pc->cpu_page == NULL) + pc->cpu_page = kmap(sg_page(obj->pages->sgl)); + if (pc->cpu_page == NULL) { + ret = -ENOMEM; goto err_unpin; + } DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n", ring->name, pc->gtt_offset); -- cgit v1.2.3 From c0b0341121f2e2b329e60986aee766e4d1d80fde Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 May 2013 12:05:54 +0200 Subject: drm/i915: add basic pipe config dump support All this pipe config abstraction adds another layer of complexity, so it's good to have better visibility into what's going on exactly. Doesn't dump out everything yet, and some bits are a bit duplicated but this should be a good start. Note that at boot-up a lot of the fields are 0 even for enabled pipes, this is simply because our hw state readout code doesn't support everything. v2: Remove a few more now redudant debug output lines. v3: Review from Paulo - use transcoder_name - fix up format specifiers - add missing ':' in debug output Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 74 +++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cb2437d1e0ea..21cbb3d0e1d8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3523,18 +3523,12 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) if (!crtc->config.gmch_pfit.control) return; - WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); - assert_pipe_disabled(dev_priv, crtc->pipe); - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. + * The panel fitter should only be adjusted whilst the pipe is disabled, + * according to register description and PRM. */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - pipe_config->gmch_pfit.control, - pipe_config->gmch_pfit.pgm_ratios); + WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE); + assert_pipe_disabled(dev_priv, crtc->pipe); I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios); I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control); @@ -4857,9 +4851,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); - drm_mode_debug_printmodeline(mode); - intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); /* pipesrc and dspsize control the size that is scaled from, @@ -5661,9 +5652,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); - drm_mode_debug_printmodeline(mode); - /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ if (intel_crtc->config.has_pch_encoder) { struct intel_pch_pll *pll; @@ -5874,9 +5862,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); - DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe_name(pipe)); - drm_mode_debug_printmodeline(mode); - if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); @@ -7685,6 +7670,35 @@ pipe_config_set_bpp(struct drm_crtc *crtc, return bpp; } +static void intel_dump_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config, + const char *context) +{ + DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id, + context, pipe_name(crtc->pipe)); + + DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder)); + DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n", + pipe_config->pipe_bpp, pipe_config->dither); + DRM_DEBUG_KMS("fdi/pch: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n", + pipe_config->has_pch_encoder, + pipe_config->fdi_lanes, + pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n, + pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n, + pipe_config->fdi_m_n.tu); + DRM_DEBUG_KMS("requested mode:\n"); + drm_mode_debug_printmodeline(&pipe_config->requested_mode); + DRM_DEBUG_KMS("adjusted mode:\n"); + drm_mode_debug_printmodeline(&pipe_config->adjusted_mode); + DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n", + pipe_config->gmch_pfit.control, + pipe_config->gmch_pfit.pgm_ratios, + pipe_config->gmch_pfit.lvds_border_bits); + DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n", + pipe_config->pch_pfit.pos, + pipe_config->pch_pfit.size); +} + static struct intel_crtc_config * intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -7755,8 +7769,6 @@ encoder_retry: goto encoder_retry; } - DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - pipe_config->dither = pipe_config->pipe_bpp != plane_bpp; DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", plane_bpp, pipe_config->pipe_bpp, pipe_config->dither); @@ -8113,9 +8125,14 @@ intel_modeset_check_state(struct drm_device *dev) "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); - WARN(active && - !intel_pipe_config_compare(dev, &crtc->config, &pipe_config), - "pipe state doesn't match!\n"); + if (active && + !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) { + WARN(1, "pipe state doesn't match!\n"); + intel_dump_pipe_config(crtc, &pipe_config, + "[hw state]"); + intel_dump_pipe_config(crtc, &crtc->config, + "[sw state]"); + } } } @@ -8155,6 +8172,8 @@ static int __intel_set_mode(struct drm_crtc *crtc, goto out; } + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, + "[modeset]"); } for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) @@ -8491,12 +8510,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) goto fail; if (config->mode_changed) { - if (set->mode) { - DRM_DEBUG_KMS("attempting to set mode from" - " userspace\n"); - drm_mode_debug_printmodeline(set->mode); - } - ret = intel_set_mode(set->crtc, set->mode, set->x, set->y, set->fb); if (ret) { @@ -9516,6 +9529,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, for_each_pipe(pipe) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); intel_sanitize_crtc(crtc); + intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]"); } if (force_restore) { -- cgit v1.2.3 From 64eae94134d2fd0a0f1cf2162fb91e46da4ec75f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 May 2013 16:28:55 +0200 Subject: drm/i915: drop a few really redundant WARNs in hsw mode_set - Correct cpu->pch display matching is already check when we detect the PCH type at driver load. - Plane/pipe state is already checked both when a) enabling, b) disabling and in c) the modeset state checker. No need to go overboard and also check it in in between a) and b). Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 21cbb3d0e1d8..a45309130a34 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5844,18 +5844,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } - /* We are not sure yet this won't happen. */ - WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", - INTEL_PCH_TYPE(dev)); - WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); - WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) & - (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); - - WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); - if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) return -EINVAL; -- cgit v1.2.3 From 2e7c8ee7a6bf3440478120f14cbf597d416f88b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 May 2013 10:38:44 +0100 Subject: drm/i915: Avoid promoting a simulated hang to 'wedged' It appears that a beneficial side-effect of Mika's more accurate hangman work is to speed up hang detection and execution. This exposes a bug in the reset code that then treats repeated simulated hangs as an indication that the machine is wedged. Jiggle the code around so that we only do the simulation processing from the hangcheck and avoid confusing it with a real hang. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65060 Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 55 +++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a1a936fd34e0..af224501b4ec 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -839,37 +839,14 @@ static int gen6_do_reset(struct drm_device *dev) int intel_gpu_reset(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - int ret = -ENODEV; - switch (INTEL_INFO(dev)->gen) { case 7: - case 6: - ret = gen6_do_reset(dev); - break; - case 5: - ret = ironlake_do_reset(dev); - break; - case 4: - ret = i965_do_reset(dev); - break; - case 2: - ret = i8xx_do_reset(dev); - break; - } - - /* Also reset the gpu hangman. */ - if (dev_priv->gpu_error.stop_rings) { - DRM_INFO("Simulated gpu hang, resetting stop_rings\n"); - dev_priv->gpu_error.stop_rings = 0; - if (ret == -ENODEV) { - DRM_ERROR("Reset not implemented, but ignoring " - "error for simulated gpu hangs\n"); - ret = 0; - } + case 6: return gen6_do_reset(dev); + case 5: return ironlake_do_reset(dev); + case 4: return i965_do_reset(dev); + case 2: return i8xx_do_reset(dev); + default: return -ENODEV; } - - return ret; } /** @@ -890,6 +867,7 @@ int intel_gpu_reset(struct drm_device *dev) int i915_reset(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + bool simulated; int ret; if (!i915_try_reset) @@ -899,13 +877,26 @@ int i915_reset(struct drm_device *dev) i915_gem_reset(dev); - ret = -ENODEV; - if (get_seconds() - dev_priv->gpu_error.last_reset < 5) + simulated = dev_priv->gpu_error.stop_rings != 0; + + if (!simulated && get_seconds() - dev_priv->gpu_error.last_reset < 5) { DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); - else + ret = -ENODEV; + } else { ret = intel_gpu_reset(dev); - dev_priv->gpu_error.last_reset = get_seconds(); + /* Also reset the gpu hangman. */ + if (simulated) { + DRM_INFO("Simulated gpu hang, resetting stop_rings\n"); + dev_priv->gpu_error.stop_rings = 0; + if (ret == -ENODEV) { + DRM_ERROR("Reset not implemented, but ignoring " + "error for simulated gpu hangs\n"); + ret = 0; + } + } else + dev_priv->gpu_error.last_reset = get_seconds(); + } if (ret) { DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 40ccc72b84a848e6fcbdb38fe716f0ac6939609e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 23 Apr 2013 17:27:08 +0300 Subject: drm/i915: release cursor when crtc is destroyed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crtc is holding a reference to a cursor bo and it needs to be released when crtc is destroyed so that we don't leak the cursor bo. v2: Enhance set and move cursor so that disabled cursor is handled correctly (Ville Syrjälä) Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a45309130a34..161b064592af 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6509,7 +6509,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_width = width; intel_crtc->cursor_height = height; - intel_crtc_update_cursor(crtc, true); + intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); return 0; fail_unpin: @@ -6528,7 +6528,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) intel_crtc->cursor_x = x; intel_crtc->cursor_y = y; - intel_crtc_update_cursor(crtc, true); + intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); return 0; } @@ -7042,6 +7042,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) kfree(work); } + intel_crtc_cursor_set(crtc, NULL, 0, 0, 0); + drm_crtc_cleanup(crtc); kfree(intel_crtc); -- cgit v1.2.3 From 5586181fce2b2e89a0e281d78ffbdfa103bb0dde Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:17 -0700 Subject: drm/i915: Comments for semaphore clarification Semaphores are tied very closely to the rings in the GPU. Trivial patch adds comments to the existing code so that when we add new rings we can include comments there as well. It also helps distinguish the ring to semaphore mailbox interactions by using the ringname in the semaphore data structures. This patch should have no functional impact. v2: The English parts (as opposed to register names) of the comments were reversed. (Damien) Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 ++++++------ drivers/gpu/drm/i915/intel_ringbuffer.c | 18 +++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index dbd9de5abde0..6579d0c0d2f1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -265,12 +265,12 @@ #define MI_SEMAPHORE_UPDATE (1<<21) #define MI_SEMAPHORE_COMPARE (1<<20) #define MI_SEMAPHORE_REGISTER (1<<18) -#define MI_SEMAPHORE_SYNC_RV (2<<16) -#define MI_SEMAPHORE_SYNC_RB (0<<16) -#define MI_SEMAPHORE_SYNC_VR (0<<16) -#define MI_SEMAPHORE_SYNC_VB (2<<16) -#define MI_SEMAPHORE_SYNC_BR (2<<16) -#define MI_SEMAPHORE_SYNC_BV (0<<16) +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ #define MI_SEMAPHORE_SYNC_INVALID (1<<0) /* * 3D instructions used by the kernel diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9b97cf66a5ae..2d2a3622639c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1671,9 +1671,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; ring->sync_to = gen6_ring_sync; - ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; - ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; + ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV; + ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB; ring->signal_mbox[0] = GEN6_VRSYNC; ring->signal_mbox[1] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { @@ -1830,9 +1830,9 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; ring->sync_to = gen6_ring_sync; - ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR; - ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB; + ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; + ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB; ring->signal_mbox[0] = GEN6_RVSYNC; ring->signal_mbox[1] = GEN6_BVSYNC; } else { @@ -1876,9 +1876,9 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; ring->sync_to = gen6_ring_sync; - ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR; - ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV; - ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; + ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV; + ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID; ring->signal_mbox[0] = GEN6_RBSYNC; ring->signal_mbox[1] = GEN6_VBSYNC; ring->init = init_ring_common; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ef374a892105..24268fbe6855 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -105,8 +105,8 @@ struct intel_ring_buffer { int (*sync_to)(struct intel_ring_buffer *ring, struct intel_ring_buffer *to, u32 seqno); - - u32 semaphore_register[3]; /*our mbox written by others */ + /* our mbox written by others */ + u32 semaphore_register[I915_NUM_RINGS]; u32 signal_mbox[2]; /* mboxes this ring signals to */ /** * List of objects currently involved in rendering from the -- cgit v1.2.3 From ad776f8b09d66e0145479fdbde2a710e5892441f Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:18 -0700 Subject: drm/i915: Semaphore MBOX update generalization This replaces the existing MBOX update code with a more generalized calculation for emitting mbox updates. We also create a sentinel for doing the updates so we can more abstractly deal with the rings. When doing MBOX updates the code must be aware of the /other/ rings. Until now the platforms which supported semaphores had a fixed number of rings and so it made sense for the code to be very specialized (hardcoded). The patch does contain a functional change, but should have no behavioral changes. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 43 ++++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +++- 3 files changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6579d0c0d2f1..19f8e51d2bdc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -593,6 +593,7 @@ #define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE)) #define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE)) #define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE)) +#define GEN6_NOSYNC 0 #define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE)) #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2d2a3622639c..5df179127e8b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -582,9 +582,16 @@ static void update_mboxes(struct intel_ring_buffer *ring, u32 mmio_offset) { +/* NB: In order to be able to do semaphore MBOX updates for varying number + * of rings, it's easiest if we round up each individual update to a + * multiple of 2 (since ring updates must always be a multiple of 2) + * even though the actual update only requires 3 dwords. + */ +#define MBOX_UPDATE_DWORDS 4 intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, mmio_offset); intel_ring_emit(ring, ring->outstanding_lazy_request); + intel_ring_emit(ring, MI_NOOP); } /** @@ -599,19 +606,24 @@ update_mboxes(struct intel_ring_buffer *ring, static int gen6_add_request(struct intel_ring_buffer *ring) { - u32 mbox1_reg; - u32 mbox2_reg; - int ret; + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *useless; + int i, ret; - ret = intel_ring_begin(ring, 10); + ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) * + MBOX_UPDATE_DWORDS) + + 4); if (ret) return ret; +#undef MBOX_UPDATE_DWORDS - mbox1_reg = ring->signal_mbox[0]; - mbox2_reg = ring->signal_mbox[1]; + for_each_ring(useless, dev_priv, i) { + u32 mbox_reg = ring->signal_mbox[i]; + if (mbox_reg != GEN6_NOSYNC) + update_mboxes(ring, mbox_reg); + } - update_mboxes(ring, mbox1_reg); - update_mboxes(ring, mbox2_reg); intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); intel_ring_emit(ring, ring->outstanding_lazy_request); @@ -1674,8 +1686,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB; - ring->signal_mbox[0] = GEN6_VRSYNC; - ring->signal_mbox[1] = GEN6_BRSYNC; + ring->signal_mbox[RCS] = GEN6_NOSYNC; + ring->signal_mbox[VCS] = GEN6_VRSYNC; + ring->signal_mbox[BCS] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->flush = gen4_render_ring_flush; @@ -1833,8 +1846,9 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB; - ring->signal_mbox[0] = GEN6_RVSYNC; - ring->signal_mbox[1] = GEN6_BVSYNC; + ring->signal_mbox[RCS] = GEN6_RVSYNC; + ring->signal_mbox[VCS] = GEN6_NOSYNC; + ring->signal_mbox[BCS] = GEN6_BVSYNC; } else { ring->mmio_base = BSD_RING_BASE; ring->flush = bsd_ring_flush; @@ -1879,8 +1893,9 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID; - ring->signal_mbox[0] = GEN6_RBSYNC; - ring->signal_mbox[1] = GEN6_VBSYNC; + ring->signal_mbox[RCS] = GEN6_RBSYNC; + ring->signal_mbox[VCS] = GEN6_VBSYNC; + ring->signal_mbox[BCS] = GEN6_NOSYNC; ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 24268fbe6855..f55d92eb6c2a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -105,9 +105,12 @@ struct intel_ring_buffer { int (*sync_to)(struct intel_ring_buffer *ring, struct intel_ring_buffer *to, u32 seqno); + /* our mbox written by others */ u32 semaphore_register[I915_NUM_RINGS]; - u32 signal_mbox[2]; /* mboxes this ring signals to */ + /* mboxes this ring signals to */ + u32 signal_mbox[I915_NUM_RINGS]; + /** * List of objects currently involved in rendering from the * ringbuffer. -- cgit v1.2.3 From 4a3dd19d94c65323d71b2ffc7e63940f00acfb47 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:19 -0700 Subject: drm/i915: Introduce VECS: the 4th ring The video enhancement command streamer is a new ring on HSW which does what it sounds like it does. This patch provides the most minimal inception of the ring. In order to support a new ring, we need to bump the number. The patch may look trivial to the untrained eye, but bumping the number of rings is a bit scary. As such the patch is not terribly useful by itself, but a pretty nice place to find issues during a bisection. Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5df179127e8b..ead979a94105 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -915,6 +915,8 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) case VCS: mmio = BSD_HWS_PGA_GEN7; break; + case VECS: + BUG(); } } else if (IS_GEN6(ring->dev)) { mmio = RING_HWS_PGA_GEN6(ring->mmio_base); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index f55d92eb6c2a..73619cb34631 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -47,8 +47,9 @@ struct intel_ring_buffer { RCS = 0x0, VCS, BCS, + VECS, } id; -#define I915_NUM_RINGS 3 +#define I915_NUM_RINGS 4 u32 mmio_base; void __iomem *virtual_start; struct drm_device *dev; -- cgit v1.2.3 From 1950de14fd1b8ea27a411929156c7eccee2ad7c3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:20 -0700 Subject: drm/i915: Add VECS semaphore bits Like the other rings, the VECS supports semaphores. The semaphore stuff is a bit wonky so this patch on it's own should be nice for review. This patch should have no functional impact. v2: Fix the English parts of clarification (again, register names were right, text was reversed) (Damien) Restore the still valid invariant. (Damien) The bsd semaphore register should be MI_SEMAPHORE_SYNC_VVE (Damien) Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 40 ++++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++++ 2 files changed, 33 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 19f8e51d2bdc..41c5d45362b2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -265,13 +265,19 @@ #define MI_SEMAPHORE_UPDATE (1<<21) #define MI_SEMAPHORE_COMPARE (1<<20) #define MI_SEMAPHORE_REGISTER (1<<18) -#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ -#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ -#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ -#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ -#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ -#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ -#define MI_SEMAPHORE_SYNC_INVALID (1<<0) +#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */ +#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */ +#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */ +#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */ +#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */ +#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */ +#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */ +#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */ +#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */ +#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */ +#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */ +#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */ +#define MI_SEMAPHORE_SYNC_INVALID (3<<16) /* * 3D instructions used by the kernel */ @@ -581,6 +587,7 @@ #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 +#define VEBOX_RING_BASE 0x1a000 #define BLT_RING_BASE 0x22000 #define RING_TAIL(base) ((base)+0x30) #define RING_HEAD(base) ((base)+0x34) @@ -588,13 +595,20 @@ #define RING_CTL(base) ((base)+0x3c) #define RING_SYNC_0(base) ((base)+0x40) #define RING_SYNC_1(base) ((base)+0x44) -#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE)) -#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE)) -#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE)) -#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE)) -#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE)) +#define RING_SYNC_2(base) ((base)+0x48) +#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE)) +#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE)) +#define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE)) +#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE)) +#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE)) +#define GEN6_VVESYNC (RING_SYNC_2(GEN6_BSD_RING_BASE)) +#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE)) +#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE)) +#define GEN6_BVESYNC (RING_SYNC_2(BLT_RING_BASE)) +#define GEN6_VEBSYNC (RING_SYNC_0(VEBOX_RING_BASE)) +#define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) +#define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) #define GEN6_NOSYNC 0 -#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE)) #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ead979a94105..93ccd1e982e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1688,9 +1688,11 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB; + ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE; ring->signal_mbox[RCS] = GEN6_NOSYNC; ring->signal_mbox[VCS] = GEN6_VRSYNC; ring->signal_mbox[BCS] = GEN6_BRSYNC; + ring->signal_mbox[VECS] = GEN6_VERSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->flush = gen4_render_ring_flush; @@ -1848,9 +1850,11 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB; + ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE; ring->signal_mbox[RCS] = GEN6_RVSYNC; ring->signal_mbox[VCS] = GEN6_NOSYNC; ring->signal_mbox[BCS] = GEN6_BVSYNC; + ring->signal_mbox[VECS] = GEN6_VEVSYNC; } else { ring->mmio_base = BSD_RING_BASE; ring->flush = bsd_ring_flush; @@ -1895,9 +1899,11 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR; ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV; ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE; ring->signal_mbox[RCS] = GEN6_RBSYNC; ring->signal_mbox[VCS] = GEN6_VBSYNC; ring->signal_mbox[BCS] = GEN6_NOSYNC; + ring->signal_mbox[VECS] = GEN6_VEBSYNC; ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); -- cgit v1.2.3 From ea251324cac6c1e0402db073e5193f33aedd94f3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:21 -0700 Subject: drm/i915: Rename ring flush functions Historically we considered the render ring to have special flush semantics and everything else to fall under a more general umbrella. Probably by coincidence more than anything we decided to make the bsd ring have the default *other* flush. As the new vebox ring exposes, the bsd ring is actually the weird one. Doing this allows us to call gen6_ring_flush for the vebox because calling blt_ring_flush would be weird... This patch should have no functional change. Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 93ccd1e982e0..3022e1579e58 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1565,8 +1565,8 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE)); } -static int gen6_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate, u32 flush) +static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate, u32 flush) { uint32_t cmd; int ret; @@ -1637,8 +1637,8 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, /* Blitter support (SandyBridge+) */ -static int blt_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate, u32 flush) +static int gen6_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate, u32 flush) { uint32_t cmd; int ret; @@ -1838,7 +1838,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) /* gen6 bsd needs a special wa for tail updates */ if (IS_GEN6(dev)) ring->write_tail = gen6_bsd_ring_write_tail; - ring->flush = gen6_ring_flush; + ring->flush = gen6_bsd_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; @@ -1887,7 +1887,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->mmio_base = BLT_RING_BASE; ring->write_tail = ring_write_tail; - ring->flush = blt_ring_flush; + ring->flush = gen6_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; -- cgit v1.2.3 From f72a1183b31cd1bebf926f904c1f025a90d153a1 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Tue, 28 May 2013 19:22:22 -0700 Subject: drm/i915: add HAS_VEBOX The flag will be useful to help share code between IVB, and HSW as the programming is similar in many places with this as one of the major differences. Signed-off-by: Xiang, Haihao [Commit message + small fix by] Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index af224501b4ec..a4e8f16a38e8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -311,6 +311,7 @@ static const struct intel_device_info intel_haswell_d_info = { .is_haswell = 1, .has_ddi = 1, .has_fpga_dbg = 1, + .has_vebox_ring = 1, }; static const struct intel_device_info intel_haswell_m_info = { @@ -320,6 +321,7 @@ static const struct intel_device_info intel_haswell_m_info = { .has_ddi = 1, .has_fpga_dbg = 1, .has_fbc = 1, + .has_vebox_ring = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e417049ea581..a18da3c6c96e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -374,6 +374,7 @@ struct drm_i915_gt_funcs { func(supports_tv) sep \ func(has_bsd_ring) sep \ func(has_blt_ring) sep \ + func(has_vebox_ring) sep \ func(has_llc) sep \ func(has_ddi) sep \ func(has_fpga_dbg) @@ -1373,6 +1374,7 @@ struct drm_i915_file_private { #define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring) #define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring) +#define HAS_VEBOX(dev) (INTEL_INFO(dev)->has_vebox_ring) #define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -- cgit v1.2.3 From 9a8a2213a778509b724c8fda04be70528a1f7130 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:23 -0700 Subject: drm/i915: Vebox ringbuffer init v2: Add set_seqno which didn't exist before rebase (Haihao) Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Xiang, Haihao Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 11 ++++++++++- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 35 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 4 files changed, 46 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9496fb5f2fe1..84d2aa21435a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4013,12 +4013,21 @@ static int i915_gem_init_rings(struct drm_device *dev) goto cleanup_bsd_ring; } + if (HAS_VEBOX(dev)) { + ret = intel_init_vebox_ring_buffer(dev); + if (ret) + goto cleanup_blt_ring; + } + + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); if (ret) - goto cleanup_blt_ring; + goto cleanup_vebox_ring; return 0; +cleanup_vebox_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[VECS]); cleanup_blt_ring: intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); cleanup_bsd_ring: diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 41c5d45362b2..a5717f179332 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -620,6 +620,7 @@ #define DONE_REG 0x40b0 #define BSD_HWS_PGA_GEN7 (0x04180) #define BLT_HWS_PGA_GEN7 (0x04280) +#define VEBOX_HWS_PGA_GEN7 (0x04380) #define RING_ACTHD(base) ((base)+0x74) #define RING_NOPID(base) ((base)+0x94) #define RING_IMR(base) ((base)+0xa8) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3022e1579e58..89dfc63677ad 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -916,7 +916,8 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) mmio = BSD_HWS_PGA_GEN7; break; case VECS: - BUG(); + mmio = VEBOX_HWS_PGA_GEN7; + break; } } else if (IS_GEN6(ring->dev)) { mmio = RING_HWS_PGA_GEN6(ring->mmio_base); @@ -1909,6 +1910,38 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) return intel_init_ring_buffer(dev, ring); } +int intel_init_vebox_ring_buffer(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring = &dev_priv->ring[VECS]; + + ring->name = "video enhancement ring"; + ring->id = VECS; + + ring->mmio_base = VEBOX_RING_BASE; + ring->write_tail = ring_write_tail; + ring->flush = gen6_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; + ring->irq_enable_mask = 0; + ring->irq_get = NULL; + ring->irq_put = NULL; + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + ring->sync_to = gen6_ring_sync; + ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER; + ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV; + ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB; + ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID; + ring->signal_mbox[RCS] = GEN6_RVESYNC; + ring->signal_mbox[VCS] = GEN6_VVESYNC; + ring->signal_mbox[BCS] = GEN6_BVESYNC; + ring->signal_mbox[VECS] = GEN6_NOSYNC; + ring->init = init_ring_common; + + return intel_init_ring_buffer(dev, ring); +} + int intel_ring_flush_all_caches(struct intel_ring_buffer *ring) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 73619cb34631..1c79520c7e45 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -234,6 +234,7 @@ int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); int intel_init_render_ring_buffer(struct drm_device *dev); int intel_init_bsd_ring_buffer(struct drm_device *dev); int intel_init_blt_ring_buffer(struct drm_device *dev); +int intel_init_vebox_ring_buffer(struct drm_device *dev); u32 intel_ring_get_active_head(struct intel_ring_buffer *ring); void intel_ring_setup_status_page(struct intel_ring_buffer *ring); -- cgit v1.2.3 From 692a04cf77e6073a60a9eaa87b7c409b6cf0283b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 29 May 2013 21:43:05 +0200 Subject: drm/i915: fix pch_nop support This was accidentally broken in the south error interrupt handling work: commit 8664281b64c457705db72fc60143d03827e75ca9 Author: Paulo Zanoni Date: Fri Apr 12 17:57:57 2013 -0300 drm/i915: report Gen5+ CPU and PCH FIFO underruns Cc: Paulo Zanoni Cc: Ben Widawsky Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 557acd37c788..338e726f4ef5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2551,6 +2551,9 @@ static void ibx_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 mask; + if (HAS_PCH_NOP(dev)) + return; + if (HAS_PCH_IBX(dev)) { mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER | SDE_TRANSA_FIFO_UNDER | SDE_POISON; @@ -2560,9 +2563,6 @@ static void ibx_irq_postinstall(struct drm_device *dev) I915_WRITE(SERR_INT, I915_READ(SERR_INT)); } - if (HAS_PCH_NOP(dev)) - return; - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, ~mask); } -- cgit v1.2.3 From 801bcfffbb0721d7131e930f9a46103e539c43a4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 10:08:35 -0300 Subject: drm/i915: properly set HSW WM_PIPE registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were previously calling sandybridge_update_wm on HSW, but the SNB function didn't really match the HSW specification, so we were just writing the wrong values. With this patch, the haswell_update_wm function will set the correct values for the WM_PIPE registers, but it will still keep all the LP watermarks disabled. The patch may look a little bit over-complicated for now, but it's because much of the infrastructure for setting the LP watermarks is already in place, so we won't have too much code churn on the patch that sets the LP watermarks. v2: - Fix pixel_rate on panel fitter case (Ville) - Try to not overflow (Ville) - Remove useless variable (Ville) - Fix p->pri_horiz_pixels (Paulo) v3: - Fix rounding errors on hsw_wm_method2 (Ville) v4: - Fix memcmp bug (Paulo) Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_pm.c | 342 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 327 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a5717f179332..19021bd8b030 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4947,6 +4947,9 @@ #define SFUSE_STRAP_DDIC_DETECTED (1<<1) #define SFUSE_STRAP_DDID_DETECTED (1<<0) +#define WM_MISC 0x45260 +#define WM_MISC_DATA_PARTITION_5_6 (1 << 0) + #define WM_DBG 0x45280 #define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0) #define WM_DBG_DISALLOW_MAXFIFO (1<<1) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9328ed98ce2f..fda727921748 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2072,19 +2072,170 @@ static void ivybridge_update_wm(struct drm_device *dev) cursor_wm); } -static void -haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) +static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev, + struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + uint32_t pixel_rate, pfit_size; + + if (intel_crtc->config.pixel_target_clock) + pixel_rate = intel_crtc->config.pixel_target_clock; + else + pixel_rate = intel_crtc->config.adjusted_mode.clock; + + /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to + * adjust the pixel_rate here. */ + + pfit_size = intel_crtc->config.pch_pfit.size; + if (pfit_size) { + uint64_t pipe_w, pipe_h, pfit_w, pfit_h; + + pipe_w = intel_crtc->config.requested_mode.hdisplay; + pipe_h = intel_crtc->config.requested_mode.vdisplay; + pfit_w = (pfit_size >> 16) & 0xFFFF; + pfit_h = pfit_size & 0xFFFF; + if (pipe_w < pfit_w) + pipe_w = pfit_w; + if (pipe_h < pfit_h) + pipe_h = pfit_h; + + pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h, + pfit_w * pfit_h); + } + + return pixel_rate; +} + +static uint32_t hsw_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel, + uint32_t latency) +{ + uint64_t ret; + + ret = (uint64_t) pixel_rate * bytes_per_pixel * latency; + ret = DIV_ROUND_UP_ULL(ret, 64 * 10000) + 2; + + return ret; +} + +static uint32_t hsw_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, + uint32_t horiz_pixels, uint8_t bytes_per_pixel, + uint32_t latency) +{ + uint32_t ret; + + ret = (latency * pixel_rate) / (pipe_htotal * 10000); + ret = (ret + 1) * horiz_pixels * bytes_per_pixel; + ret = DIV_ROUND_UP(ret, 64) + 2; + return ret; +} + +struct hsw_pipe_wm_parameters { + bool active; + bool sprite_enabled; + uint8_t pri_bytes_per_pixel; + uint8_t spr_bytes_per_pixel; + uint8_t cur_bytes_per_pixel; + uint32_t pri_horiz_pixels; + uint32_t spr_horiz_pixels; + uint32_t cur_horiz_pixels; + uint32_t pipe_htotal; + uint32_t pixel_rate; +}; + +struct hsw_wm_values { + uint32_t wm_pipe[3]; + uint32_t wm_lp[3]; + uint32_t wm_lp_spr[3]; + uint32_t wm_linetime[3]; +}; + +enum hsw_data_buf_partitioning { + HSW_DATA_BUF_PART_1_2, + HSW_DATA_BUF_PART_5_6, +}; + +/* Only for WM_PIPE. */ +static uint32_t hsw_compute_pri_wm_pipe(struct hsw_pipe_wm_parameters *params, + uint32_t mem_value) +{ + /* TODO: for now, assume the primary plane is always enabled. */ + if (!params->active) + return 0; + + return hsw_wm_method1(params->pixel_rate, + params->pri_bytes_per_pixel, + mem_value); +} + +/* For both WM_PIPE and WM_LP. */ +static uint32_t hsw_compute_spr_wm(struct hsw_pipe_wm_parameters *params, + uint32_t mem_value) +{ + uint32_t method1, method2; + + if (!params->active || !params->sprite_enabled) + return 0; + + method1 = hsw_wm_method1(params->pixel_rate, + params->spr_bytes_per_pixel, + mem_value); + method2 = hsw_wm_method2(params->pixel_rate, + params->pipe_htotal, + params->spr_horiz_pixels, + params->spr_bytes_per_pixel, + mem_value); + return min(method1, method2); +} + +/* For both WM_PIPE and WM_LP. */ +static uint32_t hsw_compute_cur_wm(struct hsw_pipe_wm_parameters *params, + uint32_t mem_value) +{ + if (!params->active) + return 0; + + return hsw_wm_method2(params->pixel_rate, + params->pipe_htotal, + params->cur_horiz_pixels, + params->cur_bytes_per_pixel, + mem_value); +} + +static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv, + uint32_t mem_value, enum pipe pipe, + struct hsw_pipe_wm_parameters *params) +{ + uint32_t pri_val, cur_val, spr_val; + + pri_val = hsw_compute_pri_wm_pipe(params, mem_value); + spr_val = hsw_compute_spr_wm(params, mem_value); + cur_val = hsw_compute_cur_wm(params, mem_value); + + WARN(pri_val > 127, + "Primary WM error, mode not supported for pipe %c\n", + pipe_name(pipe)); + WARN(spr_val > 127, + "Sprite WM error, mode not supported for pipe %c\n", + pipe_name(pipe)); + WARN(cur_val > 63, + "Cursor WM error, mode not supported for pipe %c\n", + pipe_name(pipe)); + + return (pri_val << WM0_PIPE_PLANE_SHIFT) | + (spr_val << WM0_PIPE_SPRITE_SHIFT) | + cur_val; +} + +static uint32_t +hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode; u32 linetime, ips_linetime; - if (!intel_crtc_active(crtc)) { - I915_WRITE(PIPE_WM_LINETIME(pipe), 0); - return; - } + if (!intel_crtc_active(crtc)) + return 0; /* The WM are computed with base on how long it takes to fill a single * row at the given clock rate, multiplied by 8. @@ -2093,29 +2244,184 @@ haswell_update_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, intel_ddi_get_cdclk_freq(dev_priv)); - I915_WRITE(PIPE_WM_LINETIME(pipe), - PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | - PIPE_WM_LINETIME_TIME(linetime)); + return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | + PIPE_WM_LINETIME_TIME(linetime); } -static void haswell_update_wm(struct drm_device *dev) +static void hsw_compute_wm_parameters(struct drm_device *dev, + struct hsw_pipe_wm_parameters *params, + uint32_t *wm) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + struct drm_plane *plane; + uint64_t sskpd = I915_READ64(MCH_SSKPD); enum pipe pipe; - /* Disable the LP WMs before changine the linetime registers. This is - * just a temporary code that will be replaced soon. */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); + if ((sskpd >> 56) & 0xFF) + wm[0] = (sskpd >> 56) & 0xFF; + else + wm[0] = sskpd & 0xF; + wm[1] = ((sskpd >> 4) & 0xFF) * 5; + wm[2] = ((sskpd >> 12) & 0xFF) * 5; + wm[3] = ((sskpd >> 20) & 0x1FF) * 5; + wm[4] = ((sskpd >> 32) & 0x1FF) * 5; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct hsw_pipe_wm_parameters *p; + + pipe = intel_crtc->pipe; + p = ¶ms[pipe]; + + p->active = intel_crtc_active(crtc); + if (!p->active) + continue; + + p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal; + p->pixel_rate = hsw_wm_get_pixel_rate(dev, crtc); + p->pri_bytes_per_pixel = crtc->fb->bits_per_pixel / 8; + p->cur_bytes_per_pixel = 4; + p->pri_horiz_pixels = + intel_crtc->config.requested_mode.hdisplay; + p->cur_horiz_pixels = 64; + } + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + struct hsw_pipe_wm_parameters *p; + + pipe = intel_plane->pipe; + p = ¶ms[pipe]; + + p->sprite_enabled = intel_plane->wm.enable; + p->spr_bytes_per_pixel = intel_plane->wm.bytes_per_pixel; + p->spr_horiz_pixels = intel_plane->wm.horiz_pixels; + } +} + +static void hsw_compute_wm_results(struct drm_device *dev, + struct hsw_pipe_wm_parameters *params, + uint32_t *wm, + struct hsw_wm_values *results) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + enum pipe pipe; + + /* No support for LP WMs yet. */ + results->wm_lp[2] = 0; + results->wm_lp[1] = 0; + results->wm_lp[0] = 0; + results->wm_lp_spr[2] = 0; + results->wm_lp_spr[1] = 0; + results->wm_lp_spr[0] = 0; + + for_each_pipe(pipe) + results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, wm[0], + pipe, + ¶ms[pipe]); for_each_pipe(pipe) { crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - haswell_update_linetime_wm(dev, crtc); + results->wm_linetime[pipe] = hsw_compute_linetime_wm(dev, crtc); } +} + +/* + * The spec says we shouldn't write when we don't need, because every write + * causes WMs to be re-evaluated, expending some power. + */ +static void hsw_write_wm_values(struct drm_i915_private *dev_priv, + struct hsw_wm_values *results, + enum hsw_data_buf_partitioning partitioning) +{ + struct hsw_wm_values previous; + uint32_t val; + enum hsw_data_buf_partitioning prev_partitioning; + + previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); + previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK); + previous.wm_pipe[2] = I915_READ(WM0_PIPEC_IVB); + previous.wm_lp[0] = I915_READ(WM1_LP_ILK); + previous.wm_lp[1] = I915_READ(WM2_LP_ILK); + previous.wm_lp[2] = I915_READ(WM3_LP_ILK); + previous.wm_lp_spr[0] = I915_READ(WM1S_LP_ILK); + previous.wm_lp_spr[1] = I915_READ(WM2S_LP_IVB); + previous.wm_lp_spr[2] = I915_READ(WM3S_LP_IVB); + previous.wm_linetime[0] = I915_READ(PIPE_WM_LINETIME(PIPE_A)); + previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B)); + previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C)); + + prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? + HSW_DATA_BUF_PART_5_6 : HSW_DATA_BUF_PART_1_2; + + if (memcmp(results->wm_pipe, previous.wm_pipe, + sizeof(results->wm_pipe)) == 0 && + memcmp(results->wm_lp, previous.wm_lp, + sizeof(results->wm_lp)) == 0 && + memcmp(results->wm_lp_spr, previous.wm_lp_spr, + sizeof(results->wm_lp_spr)) == 0 && + memcmp(results->wm_linetime, previous.wm_linetime, + sizeof(results->wm_linetime)) == 0 && + partitioning == prev_partitioning) + return; + + if (previous.wm_lp[2] != 0) + I915_WRITE(WM3_LP_ILK, 0); + if (previous.wm_lp[1] != 0) + I915_WRITE(WM2_LP_ILK, 0); + if (previous.wm_lp[0] != 0) + I915_WRITE(WM1_LP_ILK, 0); + + if (previous.wm_pipe[0] != results->wm_pipe[0]) + I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]); + if (previous.wm_pipe[1] != results->wm_pipe[1]) + I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]); + if (previous.wm_pipe[2] != results->wm_pipe[2]) + I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]); + + if (previous.wm_linetime[0] != results->wm_linetime[0]) + I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]); + if (previous.wm_linetime[1] != results->wm_linetime[1]) + I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]); + if (previous.wm_linetime[2] != results->wm_linetime[2]) + I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]); + + if (prev_partitioning != partitioning) { + val = I915_READ(WM_MISC); + if (partitioning == HSW_DATA_BUF_PART_1_2) + val &= ~WM_MISC_DATA_PARTITION_5_6; + else + val |= WM_MISC_DATA_PARTITION_5_6; + I915_WRITE(WM_MISC, val); + } + + if (previous.wm_lp_spr[0] != results->wm_lp_spr[0]) + I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); + if (previous.wm_lp_spr[1] != results->wm_lp_spr[1]) + I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]); + if (previous.wm_lp_spr[2] != results->wm_lp_spr[2]) + I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]); + + if (results->wm_lp[0] != 0) + I915_WRITE(WM1_LP_ILK, results->wm_lp[0]); + if (results->wm_lp[1] != 0) + I915_WRITE(WM2_LP_ILK, results->wm_lp[1]); + if (results->wm_lp[2] != 0) + I915_WRITE(WM3_LP_ILK, results->wm_lp[2]); +} + +static void haswell_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct hsw_pipe_wm_parameters params[3]; + struct hsw_wm_values results; + uint32_t wm[5]; - sandybridge_update_wm(dev); + hsw_compute_wm_parameters(dev, params, wm); + hsw_compute_wm_results(dev, params, wm, &results); + hsw_write_wm_values(dev_priv, &results, HSW_DATA_BUF_PART_1_2); } static void haswell_update_sprite_wm(struct drm_device *dev, int pipe, -- cgit v1.2.3 From cca32e9ad372172c808b93eebff536459ce37d85 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 11:45:06 -0300 Subject: drm/i915: properly set HSW WM_LP watermarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were previously only setting the WM_PIPE registers, now we are setting the LP watermark registers. This should allow deeper PC states, resulting in power savings. We're only using 1/2 data buffer partitioning for now. v2: Merge both hsw_compute_pri_wm_* functions (Ville) v3: - Simplify hsw_compute_wm_results (Ville) - Rebase due to changes on the previous patch v4: Unconfuse wm_lp/level (Ville) Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 + drivers/gpu/drm/i915/intel_pm.c | 179 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 165 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 19021bd8b030..e00422128a0a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3100,6 +3100,10 @@ #define WM3S_LP_IVB 0x45128 #define WM1S_LP_EN (1<<31) +#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \ + (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \ + ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur)) + /* Memory latency timer register */ #define MLTR_ILK 0x11222 #define MLTR_WM1_SHIFT 0 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fda727921748..1373552732e6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2129,6 +2129,12 @@ static uint32_t hsw_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal, return ret; } +static uint32_t hsw_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, + uint8_t bytes_per_pixel) +{ + return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; +} + struct hsw_pipe_wm_parameters { bool active; bool sprite_enabled; @@ -2142,11 +2148,28 @@ struct hsw_pipe_wm_parameters { uint32_t pixel_rate; }; +struct hsw_wm_maximums { + uint16_t pri; + uint16_t spr; + uint16_t cur; + uint16_t fbc; +}; + +struct hsw_lp_wm_result { + bool enable; + bool fbc_enable; + uint32_t pri_val; + uint32_t spr_val; + uint32_t cur_val; + uint32_t fbc_val; +}; + struct hsw_wm_values { uint32_t wm_pipe[3]; uint32_t wm_lp[3]; uint32_t wm_lp_spr[3]; uint32_t wm_linetime[3]; + bool enable_fbc_wm; }; enum hsw_data_buf_partitioning { @@ -2154,17 +2177,31 @@ enum hsw_data_buf_partitioning { HSW_DATA_BUF_PART_5_6, }; -/* Only for WM_PIPE. */ -static uint32_t hsw_compute_pri_wm_pipe(struct hsw_pipe_wm_parameters *params, - uint32_t mem_value) +/* For both WM_PIPE and WM_LP. */ +static uint32_t hsw_compute_pri_wm(struct hsw_pipe_wm_parameters *params, + uint32_t mem_value, + bool is_lp) { + uint32_t method1, method2; + /* TODO: for now, assume the primary plane is always enabled. */ if (!params->active) return 0; - return hsw_wm_method1(params->pixel_rate, - params->pri_bytes_per_pixel, - mem_value); + method1 = hsw_wm_method1(params->pixel_rate, + params->pri_bytes_per_pixel, + mem_value); + + if (!is_lp) + return method1; + + method2 = hsw_wm_method2(params->pixel_rate, + params->pipe_htotal, + params->pri_horiz_pixels, + params->pri_bytes_per_pixel, + mem_value); + + return min(method1, method2); } /* For both WM_PIPE and WM_LP. */ @@ -2201,13 +2238,60 @@ static uint32_t hsw_compute_cur_wm(struct hsw_pipe_wm_parameters *params, mem_value); } +/* Only for WM_LP. */ +static uint32_t hsw_compute_fbc_wm(struct hsw_pipe_wm_parameters *params, + uint32_t pri_val, + uint32_t mem_value) +{ + if (!params->active) + return 0; + + return hsw_wm_fbc(pri_val, + params->pri_horiz_pixels, + params->pri_bytes_per_pixel); +} + +static bool hsw_compute_lp_wm(uint32_t mem_value, struct hsw_wm_maximums *max, + struct hsw_pipe_wm_parameters *params, + struct hsw_lp_wm_result *result) +{ + enum pipe pipe; + uint32_t pri_val[3], spr_val[3], cur_val[3], fbc_val[3]; + + for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) { + struct hsw_pipe_wm_parameters *p = ¶ms[pipe]; + + pri_val[pipe] = hsw_compute_pri_wm(p, mem_value, true); + spr_val[pipe] = hsw_compute_spr_wm(p, mem_value); + cur_val[pipe] = hsw_compute_cur_wm(p, mem_value); + fbc_val[pipe] = hsw_compute_fbc_wm(p, pri_val[pipe], mem_value); + } + + result->pri_val = max3(pri_val[0], pri_val[1], pri_val[2]); + result->spr_val = max3(spr_val[0], spr_val[1], spr_val[2]); + result->cur_val = max3(cur_val[0], cur_val[1], cur_val[2]); + result->fbc_val = max3(fbc_val[0], fbc_val[1], fbc_val[2]); + + if (result->fbc_val > max->fbc) { + result->fbc_enable = false; + result->fbc_val = 0; + } else { + result->fbc_enable = true; + } + + result->enable = result->pri_val <= max->pri && + result->spr_val <= max->spr && + result->cur_val <= max->cur; + return result->enable; +} + static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv, uint32_t mem_value, enum pipe pipe, struct hsw_pipe_wm_parameters *params) { uint32_t pri_val, cur_val, spr_val; - pri_val = hsw_compute_pri_wm_pipe(params, mem_value); + pri_val = hsw_compute_pri_wm(params, mem_value, false); spr_val = hsw_compute_spr_wm(params, mem_value); cur_val = hsw_compute_cur_wm(params, mem_value); @@ -2250,13 +2334,15 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) static void hsw_compute_wm_parameters(struct drm_device *dev, struct hsw_pipe_wm_parameters *params, - uint32_t *wm) + uint32_t *wm, + struct hsw_wm_maximums *lp_max_1_2) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; struct drm_plane *plane; uint64_t sskpd = I915_READ64(MCH_SSKPD); enum pipe pipe; + int pipes_active = 0, sprites_enabled = 0; if ((sskpd >> 56) & 0xFF) wm[0] = (sskpd >> 56) & 0xFF; @@ -2278,6 +2364,8 @@ static void hsw_compute_wm_parameters(struct drm_device *dev, if (!p->active) continue; + pipes_active++; + p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal; p->pixel_rate = hsw_wm_get_pixel_rate(dev, crtc); p->pri_bytes_per_pixel = crtc->fb->bits_per_pixel / 8; @@ -2297,25 +2385,66 @@ static void hsw_compute_wm_parameters(struct drm_device *dev, p->sprite_enabled = intel_plane->wm.enable; p->spr_bytes_per_pixel = intel_plane->wm.bytes_per_pixel; p->spr_horiz_pixels = intel_plane->wm.horiz_pixels; + + if (p->sprite_enabled) + sprites_enabled++; + } + + if (pipes_active > 1) { + lp_max_1_2->pri = sprites_enabled ? 128 : 256; + lp_max_1_2->spr = 128; + lp_max_1_2->cur = 64; + } else { + lp_max_1_2->pri = sprites_enabled ? 384 : 768; + lp_max_1_2->spr = 384; + lp_max_1_2->cur = 255; } + lp_max_1_2->fbc = 15; } static void hsw_compute_wm_results(struct drm_device *dev, struct hsw_pipe_wm_parameters *params, uint32_t *wm, + struct hsw_wm_maximums *lp_maximums, struct hsw_wm_values *results) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + struct hsw_lp_wm_result lp_results[4] = {}; enum pipe pipe; + int level, max_level, wm_lp; + + for (level = 1; level <= 4; level++) + if (!hsw_compute_lp_wm(wm[level], lp_maximums, params, + &lp_results[level - 1])) + break; + max_level = level - 1; + + /* The spec says it is preferred to disable FBC WMs instead of disabling + * a WM level. */ + results->enable_fbc_wm = true; + for (level = 1; level <= max_level; level++) { + if (!lp_results[level - 1].fbc_enable) { + results->enable_fbc_wm = false; + break; + } + } + + memset(results, 0, sizeof(*results)); + for (wm_lp = 1; wm_lp <= 3; wm_lp++) { + const struct hsw_lp_wm_result *r; - /* No support for LP WMs yet. */ - results->wm_lp[2] = 0; - results->wm_lp[1] = 0; - results->wm_lp[0] = 0; - results->wm_lp_spr[2] = 0; - results->wm_lp_spr[1] = 0; - results->wm_lp_spr[0] = 0; + level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp; + if (level > max_level) + break; + + r = &lp_results[level - 1]; + results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2, + r->fbc_val, + r->pri_val, + r->cur_val); + results->wm_lp_spr[wm_lp - 1] = r->spr_val; + } for_each_pipe(pipe) results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, wm[0], @@ -2339,6 +2468,7 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, struct hsw_wm_values previous; uint32_t val; enum hsw_data_buf_partitioning prev_partitioning; + bool prev_enable_fbc_wm; previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK); previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK); @@ -2356,6 +2486,8 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ? HSW_DATA_BUF_PART_5_6 : HSW_DATA_BUF_PART_1_2; + prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS); + if (memcmp(results->wm_pipe, previous.wm_pipe, sizeof(results->wm_pipe)) == 0 && memcmp(results->wm_lp, previous.wm_lp, @@ -2364,7 +2496,8 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, sizeof(results->wm_lp_spr)) == 0 && memcmp(results->wm_linetime, previous.wm_linetime, sizeof(results->wm_linetime)) == 0 && - partitioning == prev_partitioning) + partitioning == prev_partitioning && + results->enable_fbc_wm == prev_enable_fbc_wm) return; if (previous.wm_lp[2] != 0) @@ -2397,6 +2530,15 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, I915_WRITE(WM_MISC, val); } + if (prev_enable_fbc_wm != results->enable_fbc_wm) { + val = I915_READ(DISP_ARB_CTL); + if (results->enable_fbc_wm) + val &= ~DISP_FBC_WM_DIS; + else + val |= DISP_FBC_WM_DIS; + I915_WRITE(DISP_ARB_CTL, val); + } + if (previous.wm_lp_spr[0] != results->wm_lp_spr[0]) I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]); if (previous.wm_lp_spr[1] != results->wm_lp_spr[1]) @@ -2415,12 +2557,13 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, static void haswell_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct hsw_wm_maximums lp_max_1_2; struct hsw_pipe_wm_parameters params[3]; struct hsw_wm_values results; uint32_t wm[5]; - hsw_compute_wm_parameters(dev, params, wm); - hsw_compute_wm_results(dev, params, wm, &results); + hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2); + hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results); hsw_write_wm_values(dev_priv, &results, HSW_DATA_BUF_PART_1_2); } -- cgit v1.2.3 From 861f3389c6627460bcd19d1442eb650001f15c9b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 10:19:21 -0300 Subject: drm/i915: add support for 5/6 data buffer partitioning on Haswell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now we compute the results for both 1/2 and 5/6 partitioning and then use hsw_find_best_result to choose which one to use. With this patch, Haswell watermarks support should be in good shape. The only improvement we're missing is the case where the primary plane is disabled: we always assume it's enabled, so we take it into consideration when calculating the watermarks. v2: - Check the latency when finding the best result Signed-off-by: Paulo Zanoni Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 64 ++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1373552732e6..b676b578f70f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2335,7 +2335,8 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) static void hsw_compute_wm_parameters(struct drm_device *dev, struct hsw_pipe_wm_parameters *params, uint32_t *wm, - struct hsw_wm_maximums *lp_max_1_2) + struct hsw_wm_maximums *lp_max_1_2, + struct hsw_wm_maximums *lp_max_5_6) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -2391,15 +2392,17 @@ static void hsw_compute_wm_parameters(struct drm_device *dev, } if (pipes_active > 1) { - lp_max_1_2->pri = sprites_enabled ? 128 : 256; - lp_max_1_2->spr = 128; - lp_max_1_2->cur = 64; + lp_max_1_2->pri = lp_max_5_6->pri = sprites_enabled ? 128 : 256; + lp_max_1_2->spr = lp_max_5_6->spr = 128; + lp_max_1_2->cur = lp_max_5_6->cur = 64; } else { lp_max_1_2->pri = sprites_enabled ? 384 : 768; + lp_max_5_6->pri = sprites_enabled ? 128 : 768; lp_max_1_2->spr = 384; - lp_max_1_2->cur = 255; + lp_max_5_6->spr = 640; + lp_max_1_2->cur = lp_max_5_6->cur = 255; } - lp_max_1_2->fbc = 15; + lp_max_1_2->fbc = lp_max_5_6->fbc = 15; } static void hsw_compute_wm_results(struct drm_device *dev, @@ -2457,6 +2460,32 @@ static void hsw_compute_wm_results(struct drm_device *dev, } } +/* Find the result with the highest level enabled. Check for enable_fbc_wm in + * case both are at the same level. Prefer r1 in case they're the same. */ +struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1, + struct hsw_wm_values *r2) +{ + int i, val_r1 = 0, val_r2 = 0; + + for (i = 0; i < 3; i++) { + if (r1->wm_lp[i] & WM3_LP_EN) + val_r1 = r1->wm_lp[i] & WM1_LP_LATENCY_MASK; + if (r2->wm_lp[i] & WM3_LP_EN) + val_r2 = r2->wm_lp[i] & WM1_LP_LATENCY_MASK; + } + + if (val_r1 == val_r2) { + if (r2->enable_fbc_wm && !r1->enable_fbc_wm) + return r2; + else + return r1; + } else if (val_r1 > val_r2) { + return r1; + } else { + return r2; + } +} + /* * The spec says we shouldn't write when we don't need, because every write * causes WMs to be re-evaluated, expending some power. @@ -2557,14 +2586,27 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv, static void haswell_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct hsw_wm_maximums lp_max_1_2; + struct hsw_wm_maximums lp_max_1_2, lp_max_5_6; struct hsw_pipe_wm_parameters params[3]; - struct hsw_wm_values results; + struct hsw_wm_values results_1_2, results_5_6, *best_results; uint32_t wm[5]; + enum hsw_data_buf_partitioning partitioning; + + hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2, &lp_max_5_6); + + hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results_1_2); + if (lp_max_1_2.pri != lp_max_5_6.pri) { + hsw_compute_wm_results(dev, params, wm, &lp_max_5_6, + &results_5_6); + best_results = hsw_find_best_result(&results_1_2, &results_5_6); + } else { + best_results = &results_1_2; + } + + partitioning = (best_results == &results_1_2) ? + HSW_DATA_BUF_PART_1_2 : HSW_DATA_BUF_PART_5_6; - hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2); - hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results); - hsw_write_wm_values(dev_priv, &results, HSW_DATA_BUF_PART_1_2); + hsw_write_wm_values(dev_priv, best_results, partitioning); } static void haswell_update_sprite_wm(struct drm_device *dev, int pipe, -- cgit v1.2.3 From baf02a1fb0485b0cca8666241577b4ef87914d87 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:24 -0700 Subject: drm/i915: Create a more generic pm handler for hsw+ HSW has some special requirements for the VEBOX. Splitting out the interrupt handler will make the code a bit nicer and less error prone when we begin to handle those. The slight functional change in this patch (queueing work while holding the spinlock) is intentional as it makes a subsequent patch a bit nicer. The change should also only effect HSW platforms. Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 338e726f4ef5..0f052f90f39a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -842,6 +842,7 @@ static void snb_gt_irq_handler(struct drm_device *dev, ivybridge_handle_parity_error(dev); } +/* Legacy way of handling PM interrupts */ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, u32 pm_iir) { @@ -921,6 +922,31 @@ static void dp_aux_irq_handler(struct drm_device *dev) wake_up_all(&dev_priv->gmbus_wait_queue); } +/* Unlike gen6_queue_rps_work() from which this function is originally derived, + * we must be able to deal with other PM interrupts. This is complicated because + * of the way in which we use the masks to defer the RPS work (which for + * posterity is necessary because of forcewake). + */ +static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, + u32 pm_iir) +{ + unsigned long flags; + + spin_lock_irqsave(&dev_priv->rps.lock, flags); + dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_DEFERRED_EVENTS; + if (dev_priv->rps.pm_iir) { + I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); + /* never want to mask useful interrupts. (also posting read) */ + WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_DEFERRED_EVENTS); + /* TODO: if queue_work is slow, move it out of the spinlock */ + queue_work(dev_priv->wq, &dev_priv->rps.work); + } + spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + + if (pm_iir & ~GEN6_PM_DEFERRED_EVENTS) + DRM_ERROR("Unexpected PM interrupted\n"); +} + static irqreturn_t valleyview_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -1231,7 +1257,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) pm_iir = I915_READ(GEN6_PMIIR); if (pm_iir) { - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + if (IS_HASWELL(dev)) + hsw_pm_irq_handler(dev_priv, pm_iir); + else if (pm_iir & GEN6_PM_DEFERRED_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GEN6_PMIIR, pm_iir); ret = IRQ_HANDLED; -- cgit v1.2.3 From 7d99163da69e04ccae0b52093f716167ed71d66d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:25 -0700 Subject: drm/i915: Create an ivybridge_irq_preinstall Just duplicates ironlake_irq_preinstall for now. v2: Add new PCH_NOP check (Damien) Add SDEIMR comment (Damien) Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau [danvet: Update now outdated comment.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0f052f90f39a..5d5bb8ce0fb4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2491,6 +2491,37 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); POSTING_READ(GTIER); + /* south display irq */ + I915_WRITE(SDEIMR, 0xffffffff); + /* + * SDEIER is also touched by the interrupt handler to work around missed + * PCH interrupts. Hence we can't update it after the interrupt handler + * is enabled - instead we unconditionally enable all PCH interrupt + * sources here, but then only unmask them as needed with SDEIMR. + */ + I915_WRITE(SDEIER, 0xffffffff); + POSTING_READ(SDEIER); +} + +static void ivybridge_irq_preinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + atomic_set(&dev_priv->irq_received, 0); + + I915_WRITE(HWSTAM, 0xeffe); + + /* XXX hotplug from PCH */ + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + POSTING_READ(DEIER); + + /* and GT */ + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + POSTING_READ(GTIER); + if (HAS_PCH_NOP(dev)) return; @@ -3494,9 +3525,9 @@ void intel_irq_init(struct drm_device *dev) dev->driver->disable_vblank = valleyview_disable_vblank; dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { - /* Share pre & uninstall handlers with ILK/SNB */ + /* Share uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; - dev->driver->irq_preinstall = ironlake_irq_preinstall; + dev->driver->irq_preinstall = ivybridge_irq_preinstall; dev->driver->irq_postinstall = ivybridge_irq_postinstall; dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; -- cgit v1.2.3 From eda63ffb906c2fb3b609a0e87aeb63c0f25b9e6b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:26 -0700 Subject: drm/i915: Add PM regs to pre/post install At the moment, these values are wiped out anyway by the rps enable/disable. That will be changed in the next patch though. v2: Add post install setup to address issue found by Damien in the next patch. replaced WARN_ON(dev_priv->rps.pm_iir != 0); with rps.pm_iir = 0; With the v2 of this patch and the deferred pm enabling (which changed since the original patches) we're now able to get PM interrupts before we've brought up enabled rps. At this point in boot, we don't want to do anything about it, so we simply ignore it. Since writing the original assertion, the code has changed quite a bit, and I believe removing this assertion is perfectly safe. Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau [danvet: I don't agree with the justification to drop the WARN and added a FIXME to that effect.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_pm.c | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5d5bb8ce0fb4..b7e096008a9f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2522,6 +2522,11 @@ static void ivybridge_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); POSTING_READ(GTIER); + /* Power management */ + I915_WRITE(GEN6_PMIMR, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0x0); + POSTING_READ(GEN6_PMIER); + if (HAS_PCH_NOP(dev)) return; @@ -2710,6 +2715,11 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); + /* Power management */ + I915_WRITE(GEN6_PMIMR, ~GEN6_PM_DEFERRED_EVENTS); + I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); + POSTING_READ(GEN6_PMIMR); + ibx_irq_postinstall(dev); return 0; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b676b578f70f..b1d0d0366fdf 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3309,7 +3309,9 @@ static void gen6_enable_rps(struct drm_device *dev) /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); spin_lock_irq(&dev_priv->rps.lock); - WARN_ON(dev_priv->rps.pm_iir != 0); + /* FIXME: Our interrupt enabling sequence is bonghits. + * dev_priv->rps.pm_iir really should be 0 here. */ + dev_priv->rps.pm_iir = 0; I915_WRITE(GEN6_PMIMR, 0); spin_unlock_irq(&dev_priv->rps.lock); /* enable all PM interrupts */ -- cgit v1.2.3 From 4848405cced3b46f4ec7d404b8ed5873171ae10a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:27 -0700 Subject: drm/i915: make PM interrupt writes non-destructive PM interrupts have an expanded role on HSW. It helps route the EBOX interrupts. This patch is necessary to make the existing code which touches the mask, and enable registers more friendly to other code paths that also will need these registers. To be more explicit: At preinstall all interrupts are masked and disabled. This implies that preinstall should always happen before any enabling/disabling of RPS or other interrupts. The PMIMR is touched by the workqueue, so enable/disable touch IER and IIR. Similarly, the code currently expects IMR has no use outside of the RPS related interrupts so they unconditionally set 0, or ~0. We could use IER in the workqueue, and IMR elsewhere, but since the workqueue use-case is more transient the existing usage makes sense. Disable RPS events: IER := IER & ~GEN6_PM_RPS_EVENTS // Disable RPS related interrupts IIR := GEN6_PM_RPS_EVENTS // Disable any outstanding interrupts Enable RPS events: IER := IER | GEN6_PM_RPS_EVENTS // Enable the RPS related interrupts IIR := GEN6_PM_RPS_EVENTS // Make sure there were no leftover events (really shouldn't happen) v2: Shouldn't destroy PMIIR or PMIMR VEBOX interrupt state in enable/disable rps functions (Haihao) v3: Bug found by Chris where we were clearing the wrong bits at rps disable. expanded commit message v4: v3 was based off the wrong branch v5: Added the setting of PMIMR because of previous patch update CC: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 21 +++++++++++---------- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 13 +++++++------ 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b7e096008a9f..953060dc9ff0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -700,10 +700,11 @@ static void gen6_pm_rps_work(struct work_struct *work) pm_iir = dev_priv->rps.pm_iir; dev_priv->rps.pm_iir = 0; pm_imr = I915_READ(GEN6_PMIMR); - I915_WRITE(GEN6_PMIMR, 0); + /* Make sure not to corrupt PMIMR state used by ringbuffer code */ + I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS); spin_unlock_irq(&dev_priv->rps.lock); - if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) + if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0) return; mutex_lock(&dev_priv->rps.hw_lock); @@ -933,17 +934,17 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, unsigned long flags; spin_lock_irqsave(&dev_priv->rps.lock, flags); - dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_DEFERRED_EVENTS; + dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS; if (dev_priv->rps.pm_iir) { I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir); /* never want to mask useful interrupts. (also posting read) */ - WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_DEFERRED_EVENTS); + WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); /* TODO: if queue_work is slow, move it out of the spinlock */ queue_work(dev_priv->wq, &dev_priv->rps.work); } spin_unlock_irqrestore(&dev_priv->rps.lock, flags); - if (pm_iir & ~GEN6_PM_DEFERRED_EVENTS) + if (pm_iir & ~GEN6_PM_RPS_EVENTS) DRM_ERROR("Unexpected PM interrupted\n"); } @@ -1018,7 +1019,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) gmbus_irq_handler(dev); - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + if (pm_iir & GEN6_PM_RPS_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); @@ -1259,7 +1260,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) if (pm_iir) { if (IS_HASWELL(dev)) hsw_pm_irq_handler(dev_priv, pm_iir); - else if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + else if (pm_iir & GEN6_PM_RPS_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GEN6_PMIIR, pm_iir); ret = IRQ_HANDLED; @@ -1374,7 +1375,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT) ironlake_handle_rps_change(dev); - if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) + if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); @@ -2716,8 +2717,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) POSTING_READ(GTIER); /* Power management */ - I915_WRITE(GEN6_PMIMR, ~GEN6_PM_DEFERRED_EVENTS); - I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); + I915_WRITE(GEN6_PMIMR, ~GEN6_PM_RPS_EVENTS); + I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); POSTING_READ(GEN6_PMIMR); ibx_irq_postinstall(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e00422128a0a..8fced1914178 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4566,7 +4566,7 @@ #define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) #define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) #define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) -#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ +#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b1d0d0366fdf..49a188718f9d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3116,7 +3116,7 @@ static void gen6_disable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, 0); I915_WRITE(GEN6_RPNSWREQ, 1 << 31); I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0); + I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS); /* Complete PM interrupt masking here doesn't race with the rps work * item again unmasking PM interrupts because that is using a different * register (PMIMR) to mask PM interrupts. The only risk is in leaving @@ -3126,7 +3126,7 @@ static void gen6_disable_rps(struct drm_device *dev) dev_priv->rps.pm_iir = 0; spin_unlock_irq(&dev_priv->rps.lock); - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); + I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); } static void valleyview_disable_rps(struct drm_device *dev) @@ -3307,14 +3307,15 @@ static void gen6_enable_rps(struct drm_device *dev) gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8); /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); + I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS); spin_lock_irq(&dev_priv->rps.lock); /* FIXME: Our interrupt enabling sequence is bonghits. * dev_priv->rps.pm_iir really should be 0 here. */ dev_priv->rps.pm_iir = 0; - I915_WRITE(GEN6_PMIMR, 0); + I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS); + I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS); spin_unlock_irq(&dev_priv->rps.lock); - /* enable all PM interrupts */ + /* unmask all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); rc6vids = 0; @@ -3577,7 +3578,7 @@ static void valleyview_enable_rps(struct drm_device *dev) valleyview_set_rps(dev_priv->dev, rpe); /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS); + I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); spin_lock_irq(&dev_priv->rps.lock); WARN_ON(dev_priv->rps.pm_iir != 0); I915_WRITE(GEN6_PMIMR, 0); -- cgit v1.2.3 From aeb0659338793746b8a4e482fa588ba1dd9ee559 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:28 -0700 Subject: drm/i915: Convert irq_refounct to struct It's overkill on older gens, but it's useful for newer gens. Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +++- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 89dfc63677ad..c7a89bb051a0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -795,7 +795,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount++ == 0) { + if (ring->irq_refcount.gt++ == 0) { dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); @@ -813,7 +813,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount == 0) { + if (--ring->irq_refcount.gt == 0) { dev_priv->gt_irq_mask |= ring->irq_enable_mask; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); POSTING_READ(GTIMR); @@ -832,7 +832,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount++ == 0) { + if (ring->irq_refcount.gt++ == 0) { dev_priv->irq_mask &= ~ring->irq_enable_mask; I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); @@ -850,7 +850,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount == 0) { + if (--ring->irq_refcount.gt == 0) { dev_priv->irq_mask |= ring->irq_enable_mask; I915_WRITE(IMR, dev_priv->irq_mask); POSTING_READ(IMR); @@ -869,7 +869,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount++ == 0) { + if (ring->irq_refcount.gt++ == 0) { dev_priv->irq_mask &= ~ring->irq_enable_mask; I915_WRITE16(IMR, dev_priv->irq_mask); POSTING_READ16(IMR); @@ -887,7 +887,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount == 0) { + if (--ring->irq_refcount.gt == 0) { dev_priv->irq_mask |= ring->irq_enable_mask; I915_WRITE16(IMR, dev_priv->irq_mask); POSTING_READ16(IMR); @@ -980,7 +980,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) gen6_gt_force_wake_get(dev_priv); spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (ring->irq_refcount++ == 0) { + if (ring->irq_refcount.gt++ == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | GEN6_RENDER_L3_PARITY_ERROR)); @@ -1003,7 +1003,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) unsigned long flags; spin_lock_irqsave(&dev_priv->irq_lock, flags); - if (--ring->irq_refcount == 0) { + if (--ring->irq_refcount.gt == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); else diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1c79520c7e45..153b87f67aae 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -72,7 +72,9 @@ struct intel_ring_buffer { */ u32 last_retired_head; - u32 irq_refcount; /* protected by dev_priv->irq_lock */ + struct { + u32 gt; + } irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 trace_irq_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; -- cgit v1.2.3 From cc609d5da5c78c92a2e2565604b2603a0965b494 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:29 -0700 Subject: drm/i915: consolidate interrupt naming scheme The motivation here is we're going to add some new interrupt definitions and handling outside of the GT interrupts which is all we've managed so far (with some RPS exceptions). By consolidating the names in the future we can make thing a bit cleaner as we don't need to define register names twice, and we can leverage pretty decent overlap in HW registers since ILK. To explain briefly what is in the comments: there are two sets of interrupt masking/enabling registers. At least so far, the definitions of the two sets overlap. The old code setup distinct names for interrupts in each set, ie. one for global, and one for ring. This made things confusing when using the wrong defines in the wrong places. rebase: Modified VLV bits v2: Renamed GT_RENDER_MASTER to GT_RENDER_CS_MASTER (Damien) Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 61 ++++++++++--------- drivers/gpu/drm/i915/i915_reg.h | 101 ++++++++++++++------------------ drivers/gpu/drm/i915/intel_ringbuffer.c | 21 ++++--- 3 files changed, 85 insertions(+), 98 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 953060dc9ff0..90ed599611cb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -780,7 +780,7 @@ static void ivybridge_parity_work(struct work_struct *work) I915_WRITE(GEN7_MISCCPCTL, misccpctl); spin_lock_irqsave(&dev_priv->irq_lock, flags); - dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT; + dev_priv->gt_irq_mask &= ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, flags); @@ -812,7 +812,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev) return; spin_lock_irqsave(&dev_priv->irq_lock, flags); - dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT; + dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; I915_WRITE(GTIMR, dev_priv->gt_irq_mask); spin_unlock_irqrestore(&dev_priv->irq_lock, flags); @@ -824,22 +824,22 @@ static void snb_gt_irq_handler(struct drm_device *dev, u32 gt_iir) { - if (gt_iir & (GEN6_RENDER_USER_INTERRUPT | - GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT)) + if (gt_iir & + (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)) notify_ring(dev, &dev_priv->ring[RCS]); - if (gt_iir & GEN6_BSD_USER_INTERRUPT) + if (gt_iir & GT_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); - if (gt_iir & GEN6_BLITTER_USER_INTERRUPT) + if (gt_iir & GT_BLT_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[BCS]); - if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT | - GT_GEN6_BSD_CS_ERROR_INTERRUPT | - GT_RENDER_CS_ERROR_INTERRUPT)) { + if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT | + GT_BSD_CS_ERROR_INTERRUPT | + GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) { DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir); i915_handle_error(dev, false); } - if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT) + if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT) ivybridge_handle_parity_error(dev); } @@ -1283,9 +1283,10 @@ static void ilk_gt_irq_handler(struct drm_device *dev, struct drm_i915_private *dev_priv, u32 gt_iir) { - if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) + if (gt_iir & + (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT)) notify_ring(dev, &dev_priv->ring[RCS]); - if (gt_iir & GT_BSD_USER_INTERRUPT) + if (gt_iir & ILK_BSD_USER_INTERRUPT) notify_ring(dev, &dev_priv->ring[VCS]); } @@ -2640,7 +2641,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN | DE_POISON; - u32 render_irqs; + u32 gt_irqs; dev_priv->irq_mask = ~display_mask; @@ -2655,17 +2656,15 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + gt_irqs = GT_RENDER_USER_INTERRUPT; + if (IS_GEN6(dev)) - render_irqs = - GT_USER_INTERRUPT | - GEN6_BSD_USER_INTERRUPT | - GEN6_BLITTER_USER_INTERRUPT; + gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT; else - render_irqs = - GT_USER_INTERRUPT | - GT_PIPE_NOTIFY | - GT_BSD_USER_INTERRUPT; - I915_WRITE(GTIER, render_irqs); + gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT | + ILK_BSD_USER_INTERRUPT; + + I915_WRITE(GTIER, gt_irqs); POSTING_READ(GTIER); ibx_irq_postinstall(dev); @@ -2691,7 +2690,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB | DE_ERR_INT_IVB; - u32 render_irqs; + u32 gt_irqs; dev_priv->irq_mask = ~display_mask; @@ -2706,14 +2705,14 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PIPEA_VBLANK_IVB); POSTING_READ(DEIER); - dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT; + dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | - GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT; - I915_WRITE(GTIER, render_irqs); + gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT | + GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT; + I915_WRITE(GTIER, gt_irqs); POSTING_READ(GTIER); /* Power management */ @@ -2729,9 +2728,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) static int valleyview_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 gt_irqs; u32 enable_mask; u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; - u32 render_irqs; enable_mask = I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | @@ -2767,9 +2766,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT | - GEN6_BLITTER_USER_INTERRUPT; - I915_WRITE(GTIER, render_irqs); + gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT | + GT_BLT_USER_INTERRUPT; + I915_WRITE(GTIER, gt_irqs); POSTING_READ(GTIER); /* ack & enable invalid PTE error interrupts */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8fced1914178..bdb2c1734da8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -742,24 +742,6 @@ #define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) #define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) #define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120) -#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) -#define I915_DISPLAY_PORT_INTERRUPT (1<<17) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) -#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */ -#define I915_HWB_OOM_INTERRUPT (1<<13) -#define I915_SYNC_STATUS_INTERRUPT (1<<12) -#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) -#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) -#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) -#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) -#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) -#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) -#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) -#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) -#define I915_DEBUG_INTERRUPT (1<<2) -#define I915_USER_INTERRUPT (1<<1) -#define I915_ASLE_INTERRUPT (1<<0) -#define I915_BSD_USER_INTERRUPT (1<<25) #define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ #define EIR 0x020b0 #define EMR 0x020b4 @@ -871,28 +853,6 @@ #define CACHE_MODE_1 0x7004 /* IVB+ */ #define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) -/* GEN6 interrupt control - * Note that the per-ring interrupt bits do alias with the global interrupt bits - * in GTIMR. */ -#define GEN6_RENDER_HWSTAM 0x2098 -#define GEN6_RENDER_IMR 0x20a8 -#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) -#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7) -#define GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED (1 << 6) -#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5) -#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4) -#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3) -#define GEN6_RENDER_SYNC_STATUS (1 << 2) -#define GEN6_RENDER_DEBUG_INTERRUPT (1 << 1) -#define GEN6_RENDER_USER_INTERRUPT (1 << 0) - -#define GEN6_BLITTER_HWSTAM 0x22098 -#define GEN6_BLITTER_IMR 0x220a8 -#define GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT (1 << 26) -#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25) -#define GEN6_BLITTER_SYNC_STATUS (1 << 24) -#define GEN6_BLITTER_USER_INTERRUPT (1 << 22) - #define GEN6_BLITTER_ECOSKPD 0x221d0 #define GEN6_BLITTER_LOCK_SHIFT 16 #define GEN6_BLITTER_FBC_NOTIFY (1<<3) @@ -903,9 +863,49 @@ #define GEN6_BSD_SLEEP_INDICATOR (1 << 3) #define GEN6_BSD_GO_INDICATOR (1 << 4) -#define GEN6_BSD_HWSTAM 0x12098 -#define GEN6_BSD_IMR 0x120a8 -#define GEN6_BSD_USER_INTERRUPT (1 << 12) +/* On modern GEN architectures interrupt control consists of two sets + * of registers. The first set pertains to the ring generating the + * interrupt. The second control is for the functional block generating the + * interrupt. These are PM, GT, DE, etc. + * + * Luckily *knocks on wood* all the ring interrupt bits match up with the + * GT interrupt bits, so we don't need to duplicate the defines. + * + * These defines should cover us well from SNB->HSW with minor exceptions + * it can also work on ILK. + */ +#define GT_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26) +#define GT_BLT_CS_ERROR_INTERRUPT (1 << 25) +#define GT_BLT_USER_INTERRUPT (1 << 22) +#define GT_BSD_CS_ERROR_INTERRUPT (1 << 15) +#define GT_BSD_USER_INTERRUPT (1 << 12) +#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */ +#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4) +#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3) +#define GT_RENDER_SYNC_STATUS_INTERRUPT (1 << 2) +#define GT_RENDER_DEBUG_INTERRUPT (1 << 1) +#define GT_RENDER_USER_INTERRUPT (1 << 0) + +/* These are all the "old" interrupts */ +#define ILK_BSD_USER_INTERRUPT (1<<5) +#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) +#define I915_DISPLAY_PORT_INTERRUPT (1<<17) +#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) +#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */ +#define I915_HWB_OOM_INTERRUPT (1<<13) +#define I915_SYNC_STATUS_INTERRUPT (1<<12) +#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) +#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) +#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) +#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) +#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) +#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) +#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) +#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) +#define I915_DEBUG_INTERRUPT (1<<2) +#define I915_USER_INTERRUPT (1<<1) +#define I915_ASLE_INTERRUPT (1<<0) +#define I915_BSD_USER_INTERRUPT (1 << 25) #define GEN6_BSD_RNCID 0x12198 @@ -3714,21 +3714,6 @@ #define DEIIR 0x44008 #define DEIER 0x4400c -/* GT interrupt. - * Note that for gen6+ the ring-specific interrupt bits do alias with the - * corresponding bits in the per-ring interrupt control registers. */ -#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26) -#define GT_GEN6_BLT_CS_ERROR_INTERRUPT (1 << 25) -#define GT_GEN6_BLT_USER_INTERRUPT (1 << 22) -#define GT_GEN6_BSD_CS_ERROR_INTERRUPT (1 << 15) -#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12) -#define GT_BSD_USER_INTERRUPT (1 << 5) /* ilk only */ -#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT (1 << 5) -#define GT_PIPE_NOTIFY (1 << 4) -#define GT_RENDER_CS_ERROR_INTERRUPT (1 << 3) -#define GT_SYNC_STATUS (1 << 2) -#define GT_USER_INTERRUPT (1 << 0) - #define GTISR 0x44010 #define GTIMR 0x44014 #define GTIIR 0x44018 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c7a89bb051a0..5ab8cc2cafe2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -560,7 +560,7 @@ static int init_render_ring(struct intel_ring_buffer *ring) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); if (HAS_L3_GPU_CACHE(dev)) - I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); + I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); return ret; } @@ -982,8 +982,9 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, flags); if (ring->irq_refcount.gt++ == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) - I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | - GEN6_RENDER_L3_PARITY_ERROR)); + I915_WRITE_IMR(ring, + ~(ring->irq_enable_mask | + GT_RENDER_L3_PARITY_ERROR_INTERRUPT)); else I915_WRITE_IMR(ring, ~ring->irq_enable_mask); dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; @@ -1005,7 +1006,8 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) spin_lock_irqsave(&dev_priv->irq_lock, flags); if (--ring->irq_refcount.gt == 0) { if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS) - I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR); + I915_WRITE_IMR(ring, + ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT); else I915_WRITE_IMR(ring, ~0); dev_priv->gt_irq_mask |= ring->irq_enable_mask; @@ -1682,7 +1684,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->flush = gen6_render_ring_flush; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; - ring->irq_enable_mask = GT_USER_INTERRUPT; + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; ring->sync_to = gen6_ring_sync; @@ -1701,7 +1703,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->set_seqno = pc_render_set_seqno; ring->irq_get = gen5_ring_get_irq; ring->irq_put = gen5_ring_put_irq; - ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; + ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT | + GT_RENDER_PIPECTL_NOTIFY_INTERRUPT; } else { ring->add_request = i9xx_add_request; if (INTEL_INFO(dev)->gen < 4) @@ -1843,7 +1846,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT; + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; @@ -1863,7 +1866,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->get_seqno = ring_get_seqno; ring->set_seqno = ring_set_seqno; if (IS_GEN5(dev)) { - ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; + ring->irq_enable_mask = ILK_BSD_USER_INTERRUPT; ring->irq_get = gen5_ring_get_irq; ring->irq_put = gen5_ring_put_irq; } else { @@ -1892,7 +1895,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT; + ring->irq_enable_mask = GT_BLT_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; -- cgit v1.2.3 From a19d2933cbc4c7b8e3d72e9fd2d48847c25bb41d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:30 -0700 Subject: drm/i915: vebox interrupt get/put v2: Use the correct lock to protect PM interrupt regs, this was accidentally lost from earlier (Haihao) Fix return types (Ben) Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 46 +++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++-- 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5ab8cc2cafe2..8a6a0ee6d350 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1019,6 +1019,48 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) gen6_gt_force_wake_put(dev_priv); } +static bool +hsw_vebox_get_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + if (!dev->irq_enabled) + return false; + + spin_lock_irqsave(&dev_priv->rps.lock, flags); + if (ring->irq_refcount.pm++ == 0) { + u32 pm_imr = I915_READ(GEN6_PMIMR); + I915_WRITE_IMR(ring, ~ring->irq_enable_mask); + I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask); + POSTING_READ(GEN6_PMIMR); + } + spin_unlock_irqrestore(&dev_priv->rps.lock, flags); + + return true; +} + +static void +hsw_vebox_put_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long flags; + + if (!dev->irq_enabled) + return; + + spin_lock_irqsave(&dev_priv->rps.lock, flags); + if (--ring->irq_refcount.pm == 0) { + u32 pm_imr = I915_READ(GEN6_PMIMR); + I915_WRITE_IMR(ring, ~0); + I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask); + POSTING_READ(GEN6_PMIMR); + } + spin_unlock_irqrestore(&dev_priv->rps.lock, flags); +} + static int i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length, @@ -1928,8 +1970,8 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; ring->irq_enable_mask = 0; - ring->irq_get = NULL; - ring->irq_put = NULL; + ring->irq_get = hsw_vebox_get_irq; + ring->irq_put = hsw_vebox_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; ring->sync_to = gen6_ring_sync; ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 153b87f67aae..022d07e43d12 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -73,8 +73,9 @@ struct intel_ring_buffer { u32 last_retired_head; struct { - u32 gt; - } irq_refcount; /* protected by dev_priv->irq_lock */ + u32 gt; /* protected by dev_priv->irq_lock */ + u32 pm; /* protected by dev_priv->rps.lock (sucks) */ + } irq_refcount; u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 trace_irq_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; -- cgit v1.2.3 From 12638c57f31952127c734c26315e1348fa1334c2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 28 May 2013 19:22:31 -0700 Subject: drm/i915: Enable vebox interrupts Similar to a patch originally written by: v2: Reversed the meanings of masked and enabled (Haihao) Made non-destructive writes in case enable/disabler rps runs first (Haihao) v3: Reword error message (Damien) Modify postinstall to do the right thing based on previous fixup. (Ben) CC: Xiang, Haihao Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 31 +++++++++++++++++++++++++------ drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- 3 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 90ed599611cb..e17bbe201195 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -944,8 +944,15 @@ static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv, } spin_unlock_irqrestore(&dev_priv->rps.lock, flags); - if (pm_iir & ~GEN6_PM_RPS_EVENTS) - DRM_ERROR("Unexpected PM interrupted\n"); + if (pm_iir & ~GEN6_PM_RPS_EVENTS) { + if (pm_iir & PM_VEBOX_USER_INTERRUPT) + notify_ring(dev_priv->dev, &dev_priv->ring[VECS]); + + if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) { + DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir); + i915_handle_error(dev_priv->dev, false); + } + } } static irqreturn_t valleyview_irq_handler(int irq, void *arg) @@ -2690,6 +2697,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB | DE_ERR_INT_IVB; + u32 pm_irqs = GEN6_PM_RPS_EVENTS; u32 gt_irqs; dev_priv->irq_mask = ~display_mask; @@ -2715,10 +2723,21 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, gt_irqs); POSTING_READ(GTIER); - /* Power management */ - I915_WRITE(GEN6_PMIMR, ~GEN6_PM_RPS_EVENTS); - I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); - POSTING_READ(GEN6_PMIMR); + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); + if (HAS_VEBOX(dev)) + pm_irqs |= PM_VEBOX_USER_INTERRUPT | + PM_VEBOX_CS_ERROR_INTERRUPT; + + /* Our enable/disable rps functions may touch these registers so + * make sure to set a known state for only the non-RPS bits. + * The RMW is extra paranoia since this should be called after being set + * to a known state in preinstall. + * */ + I915_WRITE(GEN6_PMIMR, + (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs); + I915_WRITE(GEN6_PMIER, + (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs); + POSTING_READ(GEN6_PMIER); ibx_irq_postinstall(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bdb2c1734da8..89fac19d3249 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -886,6 +886,9 @@ #define GT_RENDER_DEBUG_INTERRUPT (1 << 1) #define GT_RENDER_USER_INTERRUPT (1 << 0) +#define PM_VEBOX_CS_ERROR_INTERRUPT (1 << 12) /* hsw+ */ +#define PM_VEBOX_USER_INTERRUPT (1 << 10) /* hsw+ */ + /* These are all the "old" interrupts */ #define ILK_BSD_USER_INTERRUPT (1<<5) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8a6a0ee6d350..0e72da6ad0fa 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1969,7 +1969,8 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; ring->set_seqno = ring_set_seqno; - ring->irq_enable_mask = 0; + ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT | + PM_VEBOX_CS_ERROR_INTERRUPT; ring->irq_get = hsw_vebox_get_irq; ring->irq_put = hsw_vebox_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; -- cgit v1.2.3 From 9010ebfd2b803ebab6c2fc70b9004b2a59e7937a Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Wed, 29 May 2013 09:22:36 -0700 Subject: drm/i915: add VEBOX into debugfs v2: Removed rebase relic VECS ring from i915_gem_request_info (Damien) v3: s/hsw/hws in debugfs which I introduced in v2 (Jon) Signed-off-by: Xiang, Haihao [Order changed, and modified by] CC: "Bloomfield, Jon" Signed-off-by: Ben Widawsky Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2eb572afbcd3..2b4a6fa6350e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -570,6 +570,7 @@ static const char *ring_str(int ring) case RCS: return "render"; case VCS: return "bsd"; case BCS: return "blt"; + case VECS: return "vebox"; default: return ""; } } @@ -2222,6 +2223,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_hws", i915_hws_info, 0, (void *)RCS}, {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS}, {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, + {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS}, {"i915_rstdby_delays", i915_rstdby_delays, 0}, {"i915_cur_delayinfo", i915_cur_delayinfo, 0}, {"i915_delayfreq_table", i915_delayfreq_table, 0}, -- cgit v1.2.3 From 82f91b6e93e2138c7e02b5a866f63d04cf040c86 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Tue, 28 May 2013 19:22:33 -0700 Subject: drm/i915: add I915_EXEC_VEBOX to i915_gem_do_execbuffer() A user can run batchbuffer via VEBOX ring. Signed-off-by: Xiang, Haihao Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 9 +++++++++ include/uapi/drm/i915_drm.h | 1 + 2 files changed, 10 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 117ce3813681..a8bb62ca8756 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -885,6 +885,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EPERM; } break; + case I915_EXEC_VEBOX: + ring = &dev_priv->ring[VECS]; + if (ctx_id != 0) { + DRM_DEBUG("Ring %s doesn't support contexts\n", + ring->name); + return -EPERM; + } + break; + default: DRM_DEBUG("execbuf with unknown ring: %d\n", (int)(args->flags & I915_EXEC_RING_MASK)); diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 07d59419fe6b..81b99817198e 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -660,6 +660,7 @@ struct drm_i915_gem_execbuffer2 { #define I915_EXEC_RENDER (1<<0) #define I915_EXEC_BSD (2<<0) #define I915_EXEC_BLT (3<<0) +#define I915_EXEC_VEBOX (4<<0) /* Used for switching the constants addressing mode on gen4+ RENDER ring. * Gen6+ only supports relative addressing to dynamic state (default) and -- cgit v1.2.3 From a1f2cc73c762868435ae6ec9126bb2240337c61c Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Tue, 28 May 2013 19:22:34 -0700 Subject: drm/i915: add I915_PARAM_HAS_VEBOX to i915_getparam This will let userland only try to use the new ring when the appropriate kernel is present Signed-off-by: Xiang, Haihao Reviewed-by: Damien Lespiau Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ include/uapi/drm/i915_drm.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 3cd2b606aaba..03ee1936e737 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -956,6 +956,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_BLT: value = intel_ring_initialized(&dev_priv->ring[BCS]); break; + case I915_PARAM_HAS_VEBOX: + value = intel_ring_initialized(&dev_priv->ring[VECS]); + break; case I915_PARAM_HAS_RELAXED_FENCING: value = 1; break; diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 81b99817198e..923ed7fe5775 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -305,7 +305,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_WAIT_TIMEOUT 19 #define I915_PARAM_HAS_SEMAPHORES 20 #define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21 -#define I915_PARAM_RSVD_FOR_FUTURE_USE 22 +#define I915_PARAM_HAS_VEBOX 22 #define I915_PARAM_HAS_SECURE_BATCHES 23 #define I915_PARAM_HAS_PINNED_BATCHES 24 #define I915_PARAM_HAS_EXEC_NO_RELOC 25 -- cgit v1.2.3 From e7a639c445e1f7c44adc1665539fa8e3af0b8e30 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 31 May 2013 17:49:17 +0200 Subject: drm/i915: fix up the edp power well check Now that we track the cpu transcoder we need accurately in the pipe config we can finally fix up the transcoder check. With the current code eDP on port D will be broken since we'd errornously cut the power. For reference see commit 2124b72e6283c4e84a55e71077fee91793f4c801 Author: Paulo Zanoni Date: Fri Mar 22 14:07:23 2013 -0300 drm/i915: don't disable the power well yet v2: - Kill the now outdated comment (Paulo) - Add the missing crtc->base.enabled check and consolidate it (Paulo) - Smash all checks together, looks neater that way. v3: Kill the unused encoder variable. Cc: Takashi Iwai Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 161b064592af..2e2c6a370f52 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5793,23 +5793,13 @@ static void haswell_modeset_global_resources(struct drm_device *dev) { bool enable = false; struct intel_crtc *crtc; - struct intel_encoder *encoder; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - if (crtc->pipe != PIPE_A && crtc->base.enabled) - enable = true; - /* XXX: Should check for edp transcoder here, but thanks to init - * sequence that's not yet available. Just in case desktop eDP - * on PORT D is possible on haswell, too. */ - /* Even the eDP panel fitter is outside the always-on well. */ - if (crtc->config.pch_pfit.size && crtc->base.enabled) - enable = true; - } + if (!crtc->base.enabled) + continue; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - base.head) { - if (encoder->type != INTEL_OUTPUT_EDP && - encoder->connectors_active) + if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size || + crtc->config.cpu_transcoder != TRANSCODER_EDP) enable = true; } -- cgit v1.2.3 From 42db64efcd95014570835c7b0a08277c60486f07 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 16:33:22 -0300 Subject: drm/i915: implement IPS feature Intermediate Pixel Storage is a feature that should reduce the number of times the display engine wakes up memory to read pixels, so it should allow deeper PC states. IPS can only be enabled on ULT pipe A with 8:8:8 pipe pixel formats. With eDP 1920x1080 and correct watermarks but without FBC this moves my PC7 residency from 2.5% to around 38%. v2: - It's tied to pipe A, not port A - Add pipe_config support (Chris) - Add some assertions (Chris) - Rebase against latest dinq v3: - Don't ever set ips_enabled to false (Daniel) - Only check for ips_enabled at hsw_disable_ips (Daniel) v4: - Add hsw_compute_ips_config (Daniel) - Use the new dump_pipe_config (Daniel) Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 +++++ drivers/gpu/drm/i915/intel_display.c | 78 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 2 + 3 files changed, 88 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 89fac19d3249..5a593d20036c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1023,6 +1023,8 @@ /* Framebuffer compression for Ivybridge */ #define IVB_FBC_RT_BASE 0x7020 +#define IPS_CTL 0x43408 +#define IPS_ENABLE (1 << 31) #define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 #define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 @@ -3666,6 +3668,15 @@ #define _LGC_PALETTE_B 0x4a800 #define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) +#define _GAMMA_MODE_A 0x4a480 +#define _GAMMA_MODE_B 0x4ac80 +#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define GAMMA_MODE_MODE_MASK (3 << 0) +#define GAMMA_MODE_MODE_8bit (0 << 0) +#define GAMMA_MODE_MODE_10bit (1 << 0) +#define GAMMA_MODE_MODE_12bit (2 << 0) +#define GAMMA_MODE_MODE_SPLIT (3 << 0) + /* interrupts */ #define DE_MASTER_IRQ_CONTROL (1 << 31) #define DE_SPRITEB_FLIP_DONE (1 << 29) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2e2c6a370f52..acfc6a164a59 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3242,6 +3242,42 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_wait_for_vblank(dev, intel_crtc->pipe); } +/* IPS only exists on ULT machines and is tied to pipe A. */ +static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) +{ + return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A; +} + +static void hsw_enable_ips(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + /* We can only enable IPS after we enable a plane and wait for a vblank. + * We guarantee that the plane is enabled by calling intel_enable_ips + * only after intel_enable_plane. And intel_enable_plane already waits + * for a vblank, so all we need to do here is to enable the IPS bit. */ + assert_plane_enabled(dev_priv, crtc->plane); + I915_WRITE(IPS_CTL, IPS_ENABLE); +} + +static void hsw_disable_ips(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!crtc->config.ips_enabled) + return; + + assert_plane_enabled(dev_priv, crtc->plane); + I915_WRITE(IPS_CTL, 0); + + /* We need to wait for a vblank before we can disable the plane. */ + intel_wait_for_vblank(dev, crtc->pipe); +} + static void haswell_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3289,6 +3325,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + hsw_enable_ips(intel_crtc); + if (intel_crtc->config.has_pch_encoder) lpt_pch_enable(crtc); @@ -3431,6 +3469,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + hsw_disable_ips(intel_crtc); + intel_disable_plane(dev_priv, plane, pipe); if (intel_crtc->config.has_pch_encoder) @@ -3991,11 +4031,19 @@ retry: return setup_ok ? 0 : -EINVAL; } +static void hsw_compute_ips_config(struct intel_crtc *crtc, + struct intel_crtc_config *pipe_config) +{ + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + pipe_config->pipe_bpp == 24; +} + static int intel_crtc_compute_config(struct drm_crtc *crtc, struct intel_crtc_config *pipe_config) { struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ @@ -4025,8 +4073,11 @@ static int intel_crtc_compute_config(struct drm_crtc *crtc, pipe_config->pipe_bpp = 8*3; } + if (IS_HASWELL(dev)) + hsw_compute_ips_config(intel_crtc, pipe_config); + if (pipe_config->has_pch_encoder) - return ironlake_fdi_compute_config(to_intel_crtc(crtc), pipe_config); + return ironlake_fdi_compute_config(intel_crtc, pipe_config); return 0; } @@ -5932,6 +5983,9 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, if (intel_display_power_enabled(dev, pfit_domain)) ironlake_get_pfit_config(crtc, pipe_config); + pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + (I915_READ(IPS_CTL) & IPS_ENABLE); + return true; } @@ -6236,8 +6290,10 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int palreg = PALETTE(intel_crtc->pipe); + enum pipe pipe = intel_crtc->pipe; + int palreg = PALETTE(pipe); int i; + bool reenable_ips = false; /* The clocks have to be on to load the palette. */ if (!crtc->enabled || !intel_crtc->active) @@ -6245,7 +6301,17 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) /* use legacy palette for Ironlake */ if (HAS_PCH_SPLIT(dev)) - palreg = LGC_PALETTE(intel_crtc->pipe); + palreg = LGC_PALETTE(pipe); + + /* Workaround : Do not read or write the pipe palette/gamma data while + * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled. + */ + if (intel_crtc->config.ips_enabled && + ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) == + GAMMA_MODE_MODE_SPLIT)) { + hsw_disable_ips(intel_crtc); + reenable_ips = true; + } for (i = 0; i < 256; i++) { I915_WRITE(palreg + 4 * i, @@ -6253,6 +6319,9 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) (intel_crtc->lut_g[i] << 8) | intel_crtc->lut_b[i]); } + + if (reenable_ips) + hsw_enable_ips(intel_crtc); } static void i845_update_cursor(struct drm_crtc *crtc, u32 base) @@ -7680,6 +7749,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n", pipe_config->pch_pfit.pos, pipe_config->pch_pfit.size); + DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled); } static struct intel_crtc_config * @@ -7996,6 +8066,8 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pch_pfit.pos); PIPE_CONF_CHECK_I(pch_pfit.size); + PIPE_CONF_CHECK_I(ips_enabled); + #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb4c50b57085..fdf6303be0a9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -268,6 +268,8 @@ struct intel_crtc_config { /* FDI configuration, only valid if has_pch_encoder is set. */ int fdi_lanes; struct intel_link_m_n fdi_m_n; + + bool ips_enabled; }; struct intel_crtc { -- cgit v1.2.3 From 3c4ca58c12a3bf71433425df534dfbb85d8a5dc5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 16:33:23 -0300 Subject: drm/i915: add enable_ips module option IPS is still enabled by default. Feature requested by the power management team. This should also help testing the feature on some early pre-production hardware where there were relationship problems between IPS and PSR. v2: Rebase on top of the newest IPS implementation. v3: Check i915_enable_ips at compute_config, not supports_ips, so the kernel parameter will be ignored at haswell_get_pipe_config. Requested-by: Kristen Accardi Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a4e8f16a38e8..b23cd63b9fda 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -128,6 +128,10 @@ module_param_named(disable_power_well, i915_disable_power_well, int, 0600); MODULE_PARM_DESC(disable_power_well, "Disable the power well when possible (default: false)"); +int i915_enable_ips __read_mostly = 1; +module_param_named(enable_ips, i915_enable_ips, int, 0600); +MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a18da3c6c96e..be869f261993 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1470,6 +1470,7 @@ extern bool i915_enable_hangcheck __read_mostly; extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; extern int i915_disable_power_well __read_mostly; +extern int i915_enable_ips __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index acfc6a164a59..c112466bb769 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4034,7 +4034,8 @@ retry: static void hsw_compute_ips_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { - pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && + pipe_config->ips_enabled = i915_enable_ips && + hsw_crtc_supports_ips(crtc) && pipe_config->pipe_bpp == 24; } -- cgit v1.2.3 From 92d44621ad2d083bc03920c904ca0a5eb10d9ded Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 31 May 2013 16:33:24 -0300 Subject: drm/i915: add i915_ips_status debugfs entry It just prints whether it's supported/enabled/disabled. Feature requested by the power management team. v2: Checkpatch started complaining about seq_printf with 1 argument. Requested-by: Kristen Accardi Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2b4a6fa6350e..76255a69752a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1435,6 +1435,25 @@ static int i915_fbc_status(struct seq_file *m, void *unused) return 0; } +static int i915_ips_status(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_ULT(dev)) { + seq_puts(m, "not supported\n"); + return 0; + } + + if (I915_READ(IPS_CTL) & IPS_ENABLE) + seq_puts(m, "enabled\n"); + else + seq_puts(m, "disabled\n"); + + return 0; +} + static int i915_sr_status(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -2233,6 +2252,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_ring_freq_table", i915_ring_freq_table, 0}, {"i915_gfxec", i915_gfxec, 0}, {"i915_fbc_status", i915_fbc_status, 0}, + {"i915_ips_status", i915_ips_status, 0}, {"i915_sr_status", i915_sr_status, 0}, {"i915_opregion", i915_opregion, 0}, {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, -- cgit v1.2.3 From e29c32da531dfd94cffb150fd69760605739fb3a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 31 May 2013 11:28:45 -0700 Subject: drm/i915: Demote unknown param to DRM_DEBUG It's not terribly interesting to know that a parameter doesn't exist, and it can get in the way of interesting messages, especially with the staggered VECS merging as we've done. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 03ee1936e737..22534c3b4fe5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1002,8 +1002,7 @@ static int i915_getparam(struct drm_device *dev, void *data, value = 1; break; default: - DRM_DEBUG_DRIVER("Unknown parameter %d\n", - param->param); + DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; } -- cgit v1.2.3 From dd53e1b0ed82ba72b2e9f11ae9c3d38bb82113cc Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 31 May 2013 14:46:19 -0700 Subject: drm/i915: Make stolen use pin pages This makes it easier to catch leaks. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 89cbfab9570e..bc593e353576 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -279,7 +279,7 @@ _i915_gem_object_create_stolen(struct drm_device *dev, goto cleanup; obj->has_dma_mapping = true; - obj->pages_pin_count = 1; + i915_gem_object_pin_pages(obj); obj->stolen = stolen; obj->base.write_domain = I915_GEM_DOMAIN_GTT; -- cgit v1.2.3 From 1d64ae719b436f2a5f8f5da801b4c560bf24aaa9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 31 May 2013 14:46:20 -0700 Subject: drm/i915: Unpin stolen pages The way the stolen handling works is we take a pin on the backing pages, but we never actually get a reference to the bo. On freeing objects allocated with stolen memory, the final unref will end up freeing the object with pinned pages count left. To enable an assertion to catch bugs in this code path, this patch cleans up that remaining pin. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 84d2aa21435a..28642a9d77cd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3860,6 +3860,11 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) dev_priv->mm.interruptible = was_interruptible; } + /* Stolen objects don't hold a ref, but do hold pin count. Fix that up + * before progressing. */ + if (obj->stolen) + i915_gem_object_unpin_pages(obj); + obj->pages_pin_count = 0; i915_gem_object_put_pages(obj); i915_gem_object_free_mmap_offset(obj); -- cgit v1.2.3 From 401c29f607702864fd00b6154325f7570ebaba4f Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 31 May 2013 11:28:47 -0700 Subject: drm/i915: unpin pages at unbind If we properly keep track of the pages_pin_count, then when we later add multiple address spaces, the put_pages doesn't need any special checks to be able to perform it's job. CC: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson [danvet: Rebased on top of the fix for stolen memory pinning.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 28642a9d77cd..977a0aa5ecd0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2511,6 +2511,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) obj->has_aliasing_ppgtt_mapping = 0; } i915_gem_gtt_finish_object(obj); + i915_gem_object_unpin_pages(obj); list_del(&obj->mm_list); list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); @@ -3060,7 +3061,6 @@ search_free: obj->map_and_fenceable = mappable && fenceable; - i915_gem_object_unpin_pages(obj); trace_i915_gem_object_bind(obj, map_and_fenceable); i915_gem_verify_gtt(dev); return 0; @@ -3865,7 +3865,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->stolen) i915_gem_object_unpin_pages(obj); - obj->pages_pin_count = 0; + if (WARN_ON(obj->pages_pin_count)) + obj->pages_pin_count = 0; i915_gem_object_put_pages(obj); i915_gem_object_free_mmap_offset(obj); i915_gem_object_release_stolen(obj); -- cgit v1.2.3 From 35c20a60c7549b11fd1d8c5d5d7ab5b6b54d6ff9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 31 May 2013 11:28:48 -0700 Subject: drm/i915: Rename the gtt_list to global_list Since it will be used for the global bound/unbound list with full PPGTT, this helps clarify things for upcoming code rework. Recommended-by: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 11 ++++++----- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 23 ++++++++++++----------- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 6 +++--- 6 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 76255a69752a..0e7e3c04d939 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -215,7 +215,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) dev_priv->mm.object_memory); size = count = mappable_size = mappable_count = 0; - count_objects(&dev_priv->mm.bound_list, gtt_list); + count_objects(&dev_priv->mm.bound_list, global_list); seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n", count, mappable_count, size, mappable_size); @@ -230,7 +230,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) count, mappable_count, size, mappable_size); size = count = purgeable_size = purgeable_count = 0; - list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) { size += obj->base.size, ++count; if (obj->madv == I915_MADV_DONTNEED) purgeable_size += obj->base.size, ++purgeable_count; @@ -238,7 +238,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_printf(m, "%u unbound objects, %zu bytes\n", count, size); size = count = mappable_size = mappable_count = 0; - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if (obj->fault_mappable) { size += obj->gtt_space->size; ++count; @@ -283,7 +283,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data) return ret; total_obj_size = total_gtt_size = count = 0; - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if (list == PINNED_LIST && obj->pin_count == 0) continue; @@ -1944,7 +1944,8 @@ i915_drop_caches_set(void *data, u64 val) } if (val & DROP_UNBOUND) { - list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list) + list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, + global_list) if (obj->pages_pin_count == 0) { ret = i915_gem_object_put_pages(obj); if (ret) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index be869f261993..3acf3f50d08a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1154,7 +1154,7 @@ struct drm_i915_gem_object { struct drm_mm_node *gtt_space; /** Stolen memory for this object, instead of being backed by shmem. */ struct drm_mm_node *stolen; - struct list_head gtt_list; + struct list_head global_list; /** This object's place on the active/inactive lists */ struct list_head ring_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 977a0aa5ecd0..58048d49256c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -179,7 +179,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, pinned = 0; mutex_lock(&dev->struct_mutex); - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) if (obj->pin_count) pinned += obj->gtt_space->size; mutex_unlock(&dev->struct_mutex); @@ -1679,7 +1679,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj) /* ->put_pages might need to allocate memory for the bit17 swizzle * array, hence protect them from being reaped by removing them from gtt * lists early. */ - list_del(&obj->gtt_list); + list_del(&obj->global_list); ops->put_pages(obj); obj->pages = NULL; @@ -1699,7 +1699,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target, list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, - gtt_list) { + global_list) { if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && i915_gem_object_put_pages(obj) == 0) { count += obj->base.size >> PAGE_SHIFT; @@ -1736,7 +1736,8 @@ i915_gem_shrink_all(struct drm_i915_private *dev_priv) i915_gem_evict_everything(dev_priv->dev); - list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list) + list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, + global_list) i915_gem_object_put_pages(obj); } @@ -1861,7 +1862,7 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) if (ret) return ret; - list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); + list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list); return 0; } @@ -2514,7 +2515,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) i915_gem_object_unpin_pages(obj); list_del(&obj->mm_list); - list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); + list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); /* Avoid an unnecessary call to unbind on rebind. */ obj->map_and_fenceable = true; @@ -2922,7 +2923,7 @@ static void i915_gem_verify_gtt(struct drm_device *dev) struct drm_i915_gem_object *obj; int err = 0; - list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.gtt_list, global_list) { if (obj->gtt_space == NULL) { printk(KERN_ERR "object found on GTT list with no space reserved\n"); err++; @@ -3046,7 +3047,7 @@ search_free: return ret; } - list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list); + list_move_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); obj->gtt_space = node; @@ -3760,7 +3761,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops) { INIT_LIST_HEAD(&obj->mm_list); - INIT_LIST_HEAD(&obj->gtt_list); + INIT_LIST_HEAD(&obj->global_list); INIT_LIST_HEAD(&obj->ring_list); INIT_LIST_HEAD(&obj->exec_list); @@ -4507,10 +4508,10 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc) } cnt = 0; - list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) + list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) if (obj->pages_pin_count == 0) cnt += obj->base.size >> PAGE_SHIFT; - list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list) + list_for_each_entry(obj, &dev_priv->mm.inactive_list, global_list) if (obj->pin_count == 0 && obj->pages_pin_count == 0) cnt += obj->base.size >> PAGE_SHIFT; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ddad13fa3156..5101ab6869b4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -439,7 +439,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, dev_priv->gtt.total / PAGE_SIZE); - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { i915_gem_clflush_object(obj); i915_gem_gtt_bind_object(obj, obj->cache_level); } @@ -631,7 +631,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust; /* Mark any preallocated objects as occupied */ - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n", obj->gtt_offset, obj->base.size); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index bc593e353576..f713294618fe 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -383,7 +383,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, obj->gtt_offset = gtt_offset; obj->has_global_gtt_mapping = 1; - list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list); + list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list); return obj; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e17bbe201195..5ae5ca8854d4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1656,7 +1656,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err, struct drm_i915_gem_object *obj; int i = 0; - list_for_each_entry(obj, head, gtt_list) { + list_for_each_entry(obj, head, global_list) { if (obj->pin_count == 0) continue; @@ -1798,7 +1798,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring, if (ring->id != RCS || !error->ccid) return; - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { if ((error->ccid & PAGE_MASK) == obj->gtt_offset) { ering->ctx = i915_error_object_create_sized(dev_priv, obj, 1); @@ -1935,7 +1935,7 @@ static void i915_capture_error_state(struct drm_device *dev) list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) i++; error->active_bo_count = i; - list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) + list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) if (obj->pin_count) i++; error->pinned_bo_count = i - error->active_bo_count; -- cgit v1.2.3 From 05407ff889ceebe383aa5907219f86582ef96b72 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 May 2013 09:04:29 +0300 Subject: drm/i915: detect hang using per ring hangcheck_score Keep track of ring seqno progress and if there are no progress detected, declare hang. Use actual head (acthd) to distinguish between ring stuck and batchbuffer looping situation. Stuck ring will be kicked to trigger progress. This commit adds a hard limit for batchbuffer completion time. If batchbuffer completion time is more than 4.5 seconds, the gpu will be declared hung. Review comment from Ben which nicely clarifies the semantic change: "Maybe I'm just stating the functional changes of the patch, but in case they were unintended here is what I see as potential issues: 1. "If ring B is waiting on ring A via semaphore, and ring A is making progress, albeit slowly - the hangcheck will fire. The check will determine that A is moving, however ring B will appear hung because the ACTHD doesn't move. I honestly can't say if that's actually a realistic problem to hit it probably implies the timeout value is too low. 2. "There's also another corner case on the kick. If the seqno = 2 (though not stuck), and on the 3rd hangcheck, the ring is stuck, and we try to kick it... we don't actually try to find out if the kick helped" v2: use atchd to detect stuck ring from loop (Ben Widawsky) v3: Use acthd to check when ring needs kicking. Declare hang on third time in order to give time for kick_ring to take effect. v4: Update commit msg Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky [danvet: Paste in Ben's review comment.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 80 +++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 + 2 files changed, 49 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5ae5ca8854d4..e88f173d6b33 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -683,7 +683,6 @@ static void notify_ring(struct drm_device *dev, wake_up_all(&ring->irq_queue); if (i915_enable_hangcheck) { - dev_priv->gpu_error.hangcheck_count = 0; mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } @@ -2422,61 +2421,76 @@ static bool i915_hangcheck_hung(struct drm_device *dev) /** * This is called when the chip hasn't reported back with completed - * batchbuffers in a long time. The first time this is called we simply record - * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses - * again, we assume the chip is wedged and try to fix it. + * batchbuffers in a long time. We keep track per ring seqno progress and + * if there are no progress, hangcheck score for that ring is increased. + * Further, acthd is inspected to see if the ring is stuck. On stuck case + * we kick the ring. If we see no progress on three subsequent calls + * we assume chip is wedged and try to fix it by resetting the chip. */ void i915_hangcheck_elapsed(unsigned long data) { struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - bool err = false, idle; int i; - u32 seqno[I915_NUM_RINGS]; - bool work_done; + int busy_count = 0, rings_hung = 0; + bool stuck[I915_NUM_RINGS]; if (!i915_enable_hangcheck) return; - idle = true; for_each_ring(ring, dev_priv, i) { - seqno[i] = ring->get_seqno(ring, false); - idle &= i915_hangcheck_ring_idle(ring, seqno[i], &err); - } + u32 seqno, acthd; + bool idle, err = false; + + seqno = ring->get_seqno(ring, false); + acthd = intel_ring_get_active_head(ring); + idle = i915_hangcheck_ring_idle(ring, seqno, &err); + stuck[i] = ring->hangcheck.acthd == acthd; + + if (idle) { + if (err) + ring->hangcheck.score += 2; + else + ring->hangcheck.score = 0; + } else { + busy_count++; - /* If all work is done then ACTHD clearly hasn't advanced. */ - if (idle) { - if (err) { - if (i915_hangcheck_hung(dev)) - return; + if (ring->hangcheck.seqno == seqno) { + ring->hangcheck.score++; - goto repeat; + /* Kick ring if stuck*/ + if (stuck[i]) + i915_hangcheck_ring_hung(ring); + } else { + ring->hangcheck.score = 0; + } } - dev_priv->gpu_error.hangcheck_count = 0; - return; + ring->hangcheck.seqno = seqno; + ring->hangcheck.acthd = acthd; } - work_done = false; for_each_ring(ring, dev_priv, i) { - if (ring->hangcheck.seqno != seqno[i]) { - work_done = true; - ring->hangcheck.seqno = seqno[i]; + if (ring->hangcheck.score > 2) { + rings_hung++; + DRM_ERROR("%s: %s on %s 0x%x\n", ring->name, + stuck[i] ? "stuck" : "no progress", + stuck[i] ? "addr" : "seqno", + stuck[i] ? ring->hangcheck.acthd & HEAD_ADDR : + ring->hangcheck.seqno); } } - if (!work_done) { - if (i915_hangcheck_hung(dev)) - return; - } else { - dev_priv->gpu_error.hangcheck_count = 0; - } + if (rings_hung) + return i915_handle_error(dev, true); -repeat: - /* Reset timer case chip hangs without another request being added */ - mod_timer(&dev_priv->gpu_error.hangcheck_timer, - round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); + if (busy_count) + /* Reset timer case chip hangs without another request + * being added */ + mod_timer(&dev_priv->gpu_error.hangcheck_timer, + round_jiffies_up(jiffies + + DRM_I915_HANGCHECK_JIFFIES)); } /* drm_dma.h hooks diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 022d07e43d12..4c7e103e6fa4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -39,6 +39,8 @@ struct intel_hw_status_page { struct intel_ring_hangcheck { u32 seqno; + u32 acthd; + int score; }; struct intel_ring_buffer { -- cgit v1.2.3 From 96a764d983647636b39c462ea14cd1f588f6c0bd Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 13 May 2013 16:32:13 +0300 Subject: drm/i915: remove i915_hangcheck_hung Rework of per ring hangcheck made this obsolete. Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_irq.c | 21 --------------------- 2 files changed, 22 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3acf3f50d08a..9d86ce578384 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -842,7 +842,6 @@ struct i915_gpu_error { #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ #define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; - int hangcheck_count; /* For reset and error_state handling. */ spinlock_t lock; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e88f173d6b33..63996aa3fb17 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2398,27 +2398,6 @@ static bool i915_hangcheck_ring_hung(struct intel_ring_buffer *ring) return !kick_ring(ring); } -static bool i915_hangcheck_hung(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (dev_priv->gpu_error.hangcheck_count++ > 1) { - bool hung = true; - struct intel_ring_buffer *ring; - int i; - - DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); - i915_handle_error(dev, true); - - for_each_ring(ring, dev_priv, i) - hung &= i915_hangcheck_ring_hung(ring); - - return hung; - } - - return false; -} - /** * This is called when the chip hasn't reported back with completed * batchbuffers in a long time. We keep track per ring seqno progress and -- cgit v1.2.3 From 3430824b4ba9f8b658d5503d390ce9a7286b0b4a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 31 May 2013 20:07:05 +0300 Subject: drm/i915: Use container_of() in the fbdev code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use container_of() instead of a cast to get struct intel_fbdev from struct drm_fb_helper. Also populate the fb_info->par correctly with the drm_fb_helper pointer instead of the intel_fbdev pointer. There's no actual functional change since the drm_fb_helper happens to be the first member inside intel_fbdev. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 6b7c3ca2c035..3f03e88d5fc5 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -60,8 +60,9 @@ static struct fb_ops intelfb_ops = { static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; - struct drm_device *dev = ifbdev->helper.dev; + struct intel_fbdev *ifbdev = + container_of(helper, struct intel_fbdev, helper); + struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; @@ -108,7 +109,7 @@ static int intelfb_create(struct drm_fb_helper *helper, goto out_unpin; } - info->par = ifbdev; + info->par = helper; ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); if (ret) -- cgit v1.2.3 From b51b32cde1757cd0f3f75bc15d5e0e98c3007dff Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 31 May 2013 20:07:06 +0300 Subject: drm/i915: s/drm_i915_private_t/struct drm_i915_private/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit People don't like typedefs these days. Eliminate their use from intel_fb.c. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 3f03e88d5fc5..7a77d4cf96c2 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -218,7 +218,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, int intel_fbdev_init(struct drm_device *dev) { struct intel_fbdev *ifbdev; - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); @@ -243,7 +243,7 @@ int intel_fbdev_init(struct drm_device *dev) void intel_fbdev_initial_config(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; /* Due to peculiar init order wrt to hpd handling this is separate. */ drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); @@ -251,7 +251,7 @@ void intel_fbdev_initial_config(struct drm_device *dev) void intel_fbdev_fini(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; if (!dev_priv->fbdev) return; @@ -262,7 +262,7 @@ void intel_fbdev_fini(struct drm_device *dev) void intel_fbdev_set_suspend(struct drm_device *dev, int state) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_fbdev *ifbdev = dev_priv->fbdev; struct fb_info *info; @@ -285,14 +285,14 @@ MODULE_LICENSE("GPL and additional rights"); void intel_fb_output_poll_changed(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } void intel_fb_restore_mode(struct drm_device *dev) { int ret; - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; -- cgit v1.2.3 From d7697eea3eec74c561d12887d892c53ac4380c00 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 2 Jun 2013 17:23:01 +0200 Subject: drm/i915: optimize vblank waits in set_base_atomic We only need to do them if the pipe is actually running and if the framebuffers have changed. Removes two "wait for vblank timed out" messages when doing a suspend/resume cycle on my i855gm. v2: s/to_intel_ctrc(crtc)/intel_crtc/ spotted by Chris. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c112466bb769..988e3dee5ece 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2212,7 +2212,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, crtc->y = y; if (old_fb) { - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (intel_crtc->active && old_fb != fb) + intel_wait_for_vblank(dev, intel_crtc->pipe); intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); } -- cgit v1.2.3 From 050f7aeb129c1b9fb63dd523ca9bc1101bbae6cc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 2 Jun 2013 13:26:23 +0200 Subject: drm/i915: refactor sink bpp clamping As a prep work to fix it up: - Use intel_connector instead of drm_connector to avoid too much upcasting in the bugfix patch. - Extract the connector bpp clamping from the loop-over-connectors logic. - Bikeshed function names (to make it clearer that acompute_baseline_pipe_bpp runs in the compute stage of the modeset sequence) and add a comment to make it clearer what it does. No functional change in this patch. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 63 +++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 988e3dee5ece..faeacf43904c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7652,13 +7652,39 @@ static void intel_modeset_commit_output_state(struct drm_device *dev) } } +static void +connected_sink_compute_bpp(struct intel_connector * connector, + struct intel_crtc_config *pipe_config) +{ + int bpp = pipe_config->pipe_bpp; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n", + connector->base.base.id, + drm_get_connector_name(&connector->base)); + + /* Don't use an invalid EDID bpc value */ + if (connector->base.display_info.bpc && + connector->base.display_info.bpc * 3 < bpp) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", + bpp, connector->base.display_info.bpc*3); + pipe_config->pipe_bpp = connector->base.display_info.bpc*3; + } + + /* Clamp bpp to 8 on screens without EDID 1.4 */ + if (connector->base.display_info.bpc == 0 && bpp > 24) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", + bpp); + pipe_config->pipe_bpp = 24; + } +} + static int -pipe_config_set_bpp(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct intel_crtc_config *pipe_config) +compute_baseline_pipe_bpp(struct intel_crtc *crtc, + struct drm_framebuffer *fb, + struct intel_crtc_config *pipe_config) { - struct drm_device *dev = crtc->dev; - struct drm_connector *connector; + struct drm_device *dev = crtc->base.dev; + struct intel_connector *connector; int bpp; switch (fb->pixel_format) { @@ -7701,24 +7727,12 @@ pipe_config_set_bpp(struct drm_crtc *crtc, /* Clamp display bpp to EDID value */ list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - if (connector->encoder && connector->encoder->crtc != crtc) + base.head) { + if (connector->base.encoder && + connector->base.encoder->crtc != crtc) continue; - /* Don't use an invalid EDID bpc value */ - if (connector->display_info.bpc && - connector->display_info.bpc * 3 < bpp) { - DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n", - bpp, connector->display_info.bpc*3); - pipe_config->pipe_bpp = connector->display_info.bpc*3; - } - - /* Clamp bpp to 8 on screens without EDID 1.4 */ - if (connector->display_info.bpc == 0 && bpp > 24) { - DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", - bpp); - pipe_config->pipe_bpp = 24; - } + connected_sink_compute_bpp(connector, pipe_config); } return bpp; @@ -7774,7 +7788,12 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, drm_mode_copy(&pipe_config->requested_mode, mode); pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe; - plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config); + /* Compute a starting value for pipe_config->pipe_bpp taking the source + * plane pixel format and any sink constraints into account. Returns the + * source plane bpp so that dithering can be selected on mismatches + * after encoders and crtc also have had their say. */ + plane_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc), + fb, pipe_config); if (plane_bpp < 0) goto fail; -- cgit v1.2.3 From 1b829e05469963301736df69f0a2a2c3d3fb2225 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 2 Jun 2013 13:26:24 +0200 Subject: drm/i915: fix EDID/sink-based bpp clamping Since this is run in the compute config stage we need to check the new_ pointers, i.e the stage output routing, not the current modeset layout. Also there was a little logic bug in properly skipping connectors: The old code did not skip any unused connectors and so clamped to whatever was left in there (usually 0 if that connector hasn't seen a EDID 1.4 screen ever since boot-up). This has been broken when moving the pipe bpp selection in commit 4e53c2e010e531b4a014692199e978482d471c7e Author: Daniel Vetter Date: Wed Mar 27 00:44:58 2013 +0100 drm/i915: precompute pipe bpp before touching the hw To avoid too much casting switch from drm_ to intel_ types. Also add a bit of debug output to help reconstructing what's going on. v2: Try to clarify this a bit: - s/pipe_config_set_bpp/compute_baseline_pipe_bpp/ to make it clearer at which stage this function is run. Also add a comment about what it does. - Extract the sink clamping into it's own function. v3: Actually make it compile. v4: Split out all the prep refactoring to make the bugfix stick out really badly. Also elaborate a bit in the commit message about the nature of the bugfix. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index faeacf43904c..cd22680e595c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7728,8 +7728,8 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc, /* Clamp display bpp to EDID value */ list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { - if (connector->base.encoder && - connector->base.encoder->crtc != crtc) + if (!connector->new_encoder || + connector->new_encoder->new_crtc != crtc) continue; connected_sink_compute_bpp(connector, pipe_config); -- cgit v1.2.3 From ac58c3f046dde3c29b0e3fc7ea71a82b5f80c470 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:17 +0200 Subject: drm/i915: split out intel_pnv_find_best_PLL Pineview is just different. Also split out i9xx_clock from intel_clock and drop the now redundant struct device * parameter. Note that in this patch I kill an XXX comment about 100MHz clocks. I couldn't figure out what this is about, and we don't seem to have any bug reports about this either. I suspect that it's a remnant from when the i9xx and ilk+ modeset code was all in the same file since ilk+ does indeed have a 100MHz clock. So I've just killed it to stop the cargo-culting. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 92 ++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cd22680e595c..5d22abe19b1f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -97,10 +97,13 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock); static bool +intel_pnv_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock); +static bool intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock); - static bool intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, @@ -246,7 +249,7 @@ static const intel_limit_t intel_limits_pineview_sdvo = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, .p2_slow = 10, .p2_fast = 5 }, - .find_pll = intel_find_best_PLL, + .find_pll = intel_pnv_find_best_PLL, }; static const intel_limit_t intel_limits_pineview_lvds = { @@ -260,7 +263,7 @@ static const intel_limit_t intel_limits_pineview_lvds = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, .p2_slow = 14, .p2_fast = 14 }, - .find_pll = intel_find_best_PLL, + .find_pll = intel_pnv_find_best_PLL, }; /* Ironlake / Sandybridge @@ -475,12 +478,8 @@ static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); } -static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock) +static void i9xx_clock(int refclk, intel_clock_t *clock) { - if (IS_PINEVIEW(dev)) { - pineview_clock(refclk, clock); - return; - } clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; clock->vco = refclk * clock->m / (clock->n + 2); @@ -541,7 +540,68 @@ static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + intel_clock_t clock; + int err = target; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + /* + * For LVDS just rely on its current settings for dual-channel. + * We haven't figured out how to reliably set up different + * single/dual channel state, if we even can. + */ + if (intel_is_dual_link_lvds(dev)) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; + clock.m1++) { + for (clock.m2 = limit->m2.min; + clock.m2 <= limit->m2.max; clock.m2++) { + /* m1 is always 0 in Pineview */ + if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev)) + break; + for (clock.n = limit->n.min; + clock.n <= limit->n.max; clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; clock.p1++) { + int this_err; + i9xx_clock(refclk, &clock); + if (!intel_PLL_is_valid(dev, limit, + &clock)) + continue; + if (match_clock && + clock.p != match_clock->p) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + } + + return (err != target); +} + +static bool +intel_pnv_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) { struct drm_device *dev = crtc->dev; intel_clock_t clock; @@ -579,7 +639,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - intel_clock(dev, refclk, &clock); + pineview_clock(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -638,7 +698,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, clock.p1 >= limit->p1.min; clock.p1--) { int this_err; - intel_clock(dev, refclk, &clock); + i9xx_clock(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -6910,8 +6970,10 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) return 0; } - /* XXX: Handle the 100Mhz refclk */ - intel_clock(dev, 96000, &clock); + if (IS_PINEVIEW(dev)) + pineview_clock(96000, &clock); + else + i9xx_clock(96000, &clock); } else { bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); @@ -6923,9 +6985,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) { /* XXX: might not be 66MHz */ - intel_clock(dev, 66000, &clock); + i9xx_clock(66000, &clock); } else - intel_clock(dev, 48000, &clock); + i9xx_clock(48000, &clock); } else { if (dpll & PLL_P1_DIVIDE_BY_TWO) clock.p1 = 2; @@ -6938,7 +7000,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) else clock.p2 = 2; - intel_clock(dev, 48000, &clock); + i9xx_clock(48000, &clock); } } -- cgit v1.2.3 From ee9300bb5fa423117585a57c6a158522d2298b4e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Jun 2013 22:40:22 +0200 Subject: drm/i915: move find_pll callback to dev_priv->display Now that the DP madness is cleared out, this is all only per-platform. So move it out from the intel clock limits structure. While at it drop the intel prefix on the static functions, call the vtable entry find_dpll (since it's for the display pll) and rip out the now unnecessary forward declarations. Note that the parameters of ->find_dpll are still unchanged, but they eventually need to be moved over to just take in a pipe configuration. But currently a lot of things are still missing from the pipe configuration (reflock, output-specific dpll limits and preferences, downclocked dotclock). So this will happen in a later step. Note that intel_g4x_limit has a peculiar case where it selects intel_limits_i9xx_sdvo as the limit. This is pretty bogus and also not used since the only output types left are DP and native TV-out which both use special pre-tuned dpll values. v2: Re-add comment for the find_pll callback (requested by Paulo) and elaborate on why the transformation is correct for g4x platforms (to clarify a review question from Paulo). Double up on that by adding a WARN as suggested by Paulo Zanoni on irc. v3: Initialize limits to NULL since gcc is now unhappy. v4: v2/3 will blow up with a NULL dereference in ->find_dpll for dp and TV-out ports, spotted by Paulo on irc. So just give up on this madness for now, and leave this to be fixed in a later patch. v5: Since the ever-so-slight change for g4x might result in some dpll parameter computation failing spuriously where before it didn't for ports with preset dpll settings (DP & TV-out) override this. For paranoia also do it in the ilk+ code. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 20 +++++++ drivers/gpu/drm/i915/intel_display.c | 110 +++++++++++------------------------ 2 files changed, 53 insertions(+), 77 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9d86ce578384..215aa63e3f47 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -306,6 +306,8 @@ struct drm_i915_error_state { struct intel_crtc_config; struct intel_crtc; +struct intel_limit; +struct dpll; struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); @@ -313,6 +315,24 @@ struct drm_i915_display_funcs { void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); + /** + * find_dpll() - Find the best values for the PLL + * @limit: limits for the PLL + * @crtc: current CRTC + * @target: target frequency in kHz + * @refclk: reference clock frequency in kHz + * @match_clock: if provided, @best_clock P divider must + * match the P divider from @match_clock + * used for LVDS downclocking + * @best_clock: best PLL values found + * + * Returns true on success, false on failure. + */ + bool (*find_dpll)(const struct intel_limit *limit, + struct drm_crtc *crtc, + int target, int refclk, + struct dpll *match_clock, + struct dpll *best_clock); void (*update_wm)(struct drm_device *dev); void (*update_sprite_wm)(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5d22abe19b1f..537b8a44107d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -59,24 +59,6 @@ typedef struct intel_limit intel_limit_t; struct intel_limit { intel_range_t dot, vco, n, m, m1, m2, p, p1; intel_p2_t p2; - /** - * find_pll() - Find the best values for the PLL - * @limit: limits for the PLL - * @crtc: current CRTC - * @target: target frequency in kHz - * @refclk: reference clock frequency in kHz - * @match_clock: if provided, @best_clock P divider must - * match the P divider from @match_clock - * used for LVDS downclocking - * @best_clock: best PLL values found - * - * Returns true on success, false on failure. - */ - bool (*find_pll)(const intel_limit_t *limit, - struct drm_crtc *crtc, - int target, int refclk, - intel_clock_t *match_clock, - intel_clock_t *best_clock); }; /* FDI */ @@ -92,23 +74,6 @@ intel_pch_rawclk(struct drm_device *dev) return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK; } -static bool -intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); -static bool -intel_pnv_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); -static bool -intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); -static bool -intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock); - static inline u32 /* units of 100MHz */ intel_fdi_link_freq(struct drm_device *dev) { @@ -130,7 +95,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = { .p1 = { .min = 2, .max = 33 }, .p2 = { .dot_limit = 165000, .p2_slow = 4, .p2_fast = 2 }, - .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_i8xx_lvds = { @@ -144,7 +108,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = { .p1 = { .min = 1, .max = 6 }, .p2 = { .dot_limit = 165000, .p2_slow = 14, .p2_fast = 7 }, - .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_i9xx_sdvo = { @@ -158,7 +121,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, .p2_slow = 10, .p2_fast = 5 }, - .find_pll = intel_find_best_PLL, }; static const intel_limit_t intel_limits_i9xx_lvds = { @@ -172,7 +134,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, .p2_slow = 14, .p2_fast = 7 }, - .find_pll = intel_find_best_PLL, }; @@ -189,7 +150,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = { .p2_slow = 10, .p2_fast = 10 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_hdmi = { @@ -203,7 +163,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = { .p1 = { .min = 1, .max = 8}, .p2 = { .dot_limit = 165000, .p2_slow = 10, .p2_fast = 5 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_single_channel_lvds = { @@ -218,7 +177,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = { .p2 = { .dot_limit = 0, .p2_slow = 14, .p2_fast = 14 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { @@ -233,7 +191,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = { .p2 = { .dot_limit = 0, .p2_slow = 7, .p2_fast = 7 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_pineview_sdvo = { @@ -249,7 +206,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 200000, .p2_slow = 10, .p2_fast = 5 }, - .find_pll = intel_pnv_find_best_PLL, }; static const intel_limit_t intel_limits_pineview_lvds = { @@ -263,7 +219,6 @@ static const intel_limit_t intel_limits_pineview_lvds = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, .p2_slow = 14, .p2_fast = 14 }, - .find_pll = intel_pnv_find_best_PLL, }; /* Ironlake / Sandybridge @@ -282,7 +237,6 @@ static const intel_limit_t intel_limits_ironlake_dac = { .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 225000, .p2_slow = 10, .p2_fast = 5 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_single_lvds = { @@ -296,7 +250,6 @@ static const intel_limit_t intel_limits_ironlake_single_lvds = { .p1 = { .min = 2, .max = 8 }, .p2 = { .dot_limit = 225000, .p2_slow = 14, .p2_fast = 14 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_dual_lvds = { @@ -310,7 +263,6 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds = { .p1 = { .min = 2, .max = 8 }, .p2 = { .dot_limit = 225000, .p2_slow = 7, .p2_fast = 7 }, - .find_pll = intel_g4x_find_best_PLL, }; /* LVDS 100mhz refclk limits. */ @@ -325,7 +277,6 @@ static const intel_limit_t intel_limits_ironlake_single_lvds_100m = { .p1 = { .min = 2, .max = 8 }, .p2 = { .dot_limit = 225000, .p2_slow = 14, .p2_fast = 14 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { @@ -339,7 +290,6 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = { .p1 = { .min = 2, .max = 6 }, .p2 = { .dot_limit = 225000, .p2_slow = 7, .p2_fast = 7 }, - .find_pll = intel_g4x_find_best_PLL, }; static const intel_limit_t intel_limits_vlv_dac = { @@ -353,7 +303,6 @@ static const intel_limit_t intel_limits_vlv_dac = { .p1 = { .min = 1, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, - .find_pll = intel_vlv_find_best_pll, }; static const intel_limit_t intel_limits_vlv_hdmi = { @@ -367,7 +316,6 @@ static const intel_limit_t intel_limits_vlv_hdmi = { .p1 = { .min = 2, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, - .find_pll = intel_vlv_find_best_pll, }; static const intel_limit_t intel_limits_vlv_dp = { @@ -381,7 +329,6 @@ static const intel_limit_t intel_limits_vlv_dp = { .p1 = { .min = 1, .max = 3 }, .p2 = { .dot_limit = 270000, .p2_slow = 2, .p2_fast = 20 }, - .find_pll = intel_vlv_find_best_pll, }; static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, @@ -537,7 +484,7 @@ static bool intel_PLL_is_valid(struct drm_device *dev, } static bool -intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, +i9xx_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { @@ -599,9 +546,9 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } static bool -intel_pnv_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) +pnv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) { struct drm_device *dev = crtc->dev; intel_clock_t clock; @@ -661,9 +608,9 @@ intel_pnv_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } static bool -intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) +g4x_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) { struct drm_device *dev = crtc->dev; intel_clock_t clock; @@ -718,9 +665,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } static bool -intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) +vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) { u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2; u32 m, n, fastclk; @@ -4911,9 +4858,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ limit = intel_limit(crtc, refclk); - ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, - &clock); - if (!ok) { + ok = dev_priv->display.find_dpll(limit, crtc, adjusted_mode->clock, + refclk, NULL, &clock); + if (!ok && !intel_crtc->config.clock_set) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; } @@ -4928,10 +4875,10 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, * by using the FP0/FP1. In such case we will disable the LVDS * downclock feature. */ - has_reduced_clock = limit->find_pll(limit, crtc, + has_reduced_clock = + dev_priv->display.find_dpll(limit, crtc, dev_priv->lvds_downclock, - refclk, - &clock, + refclk, &clock, &reduced_clock); } /* Compat-code for transition, will disappear. */ @@ -5547,8 +5494,8 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ limit = intel_limit(crtc, refclk); - ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL, - clock); + ret = dev_priv->display.find_dpll(limit, crtc, adjusted_mode->clock, + refclk, NULL, clock); if (!ret) return false; @@ -5559,11 +5506,11 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, * by using the FP0/FP1. In such case we will disable the LVDS * downclock feature. */ - *has_reduced_clock = limit->find_pll(limit, crtc, - dev_priv->lvds_downclock, - refclk, - clock, - reduced_clock); + *has_reduced_clock = + dev_priv->display.find_dpll(limit, crtc, + dev_priv->lvds_downclock, + refclk, clock, + reduced_clock); } return true; @@ -5749,7 +5696,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock); - if (!ok) { + if (!ok && !intel_crtc->config.clock_set) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); return -EINVAL; } @@ -9073,6 +9020,15 @@ static void intel_init_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (HAS_PCH_SPLIT(dev) || IS_G4X(dev)) + dev_priv->display.find_dpll = g4x_find_best_dpll; + else if (IS_VALLEYVIEW(dev)) + dev_priv->display.find_dpll = vlv_find_best_dpll; + else if (IS_PINEVIEW(dev)) + dev_priv->display.find_dpll = pnv_find_best_dpll; + else + dev_priv->display.find_dpll = i9xx_find_best_dpll; + if (HAS_DDI(dev)) { dev_priv->display.get_pipe_config = haswell_get_pipe_config; dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; -- cgit v1.2.3 From c0efc387a8893470c1744e775e214c069bd2465e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 3 Jun 2013 20:56:24 +0200 Subject: drm/i915: fold in IS_PNV checks from the split up find_dpll functions Since I stand by my rule that splitting functions should only do an exact copy, this is a follow-up patch. Suggested-by: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 537b8a44107d..ed6addf74275 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -515,8 +515,7 @@ i9xx_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, clock.m1++) { for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) { - /* m1 is always 0 in Pineview */ - if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev)) + if (clock.m2 >= clock.m1) break; for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { @@ -577,9 +576,6 @@ pnv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc, clock.m1++) { for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) { - /* m1 is always 0 in Pineview */ - if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev)) - break; for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) { for (clock.p1 = limit->p1.min; -- cgit v1.2.3 From 2bd89a07db684573d2fce0d5148103c3dcfb0873 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:19 +0200 Subject: drm/i915: clear up the fdi dotclock semantics for M/N computation We currently mutliply the link_bw of the fdi link with the pixel multiplier, which is wrong: The FDI link doesn't suddenly grow more bandwidth. In reality the pixel mutliplication only happens in the PCH, before the pixels are fed into the port. But since we our code treats the uses the target clock after pixels are doubled (tripled, ...) already, we need to correct this. Semantically it's clearer to divide the target clock to get the fdi dotclock instead of multiplying the bw, so do that instead. Note that the target clock is already multiplied by the same factor, so the division will never loose accuracy for the M/N computation. The lane computation otoh used the wrong value, we also need to feed the fdi dotclock to that. Split out on a request from Paulo Zanoni. v2: Also fix the lane computation, it used the target clock to compute the bw requirements, not the fdi dotclock (i.e. adjusted with the pixel multiplier). Since sdvo only uses the pixel multiplier for low-res modes (with a dotclock below 100MHz) we wouldn't ever have rejected a bogus mode, but just used an inefficient fdi config. v3: Amend the commit message to explain better what the change for the fdi lane config computation is all about. Requested by Paulo. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ed6addf74275..711ec3314893 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3989,7 +3989,7 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, { struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - int target_clock, lane, link_bw; + int target_clock, lane, link_bw, fdi_dotclock; bool setup_ok, needs_recompute = false; retry: @@ -4007,14 +4007,16 @@ retry: else target_clock = adjusted_mode->clock; - lane = ironlake_get_lanes_required(target_clock, link_bw, + fdi_dotclock = target_clock; + if (pipe_config->pixel_multiplier > 1) + fdi_dotclock /= pipe_config->pixel_multiplier; + + lane = ironlake_get_lanes_required(fdi_dotclock, link_bw, pipe_config->pipe_bpp); pipe_config->fdi_lanes = lane; - if (pipe_config->pixel_multiplier > 1) - link_bw *= pipe_config->pixel_multiplier; - intel_link_compute_m_n(pipe_config->pipe_bpp, lane, target_clock, + intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, link_bw, &pipe_config->fdi_m_n); setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev, -- cgit v1.2.3 From 7c62a164faea430c6e4c411eb0870640cf51a6e5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:20 +0200 Subject: drm/i915: refactor cpu eDP PLL handling a bit This prepares a bit for the next big patch, where we switch the semantics of the different clocks in the pipe config around. Since I've broken cpu eDP PLL handling in the first version I've figured some refactoring is in order. Split out on request from Paulo Zanoni. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a899f93cb0ee..3b490c097400 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -780,24 +780,29 @@ void intel_dp_init_link_config(struct intel_dp *intel_dp) } } -static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) +static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp) { - struct drm_device *dev = crtc->dev; + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); + struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 dpa_ctl; - DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock); + DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", + crtc->config.adjusted_mode.clock); dpa_ctl = I915_READ(DP_A); dpa_ctl &= ~DP_PLL_FREQ_MASK; - if (clock < 200000) { + if (crtc->config.adjusted_mode.clock == 162000) { /* For a long time we've carried around a ILK-DevA w/a for the * 160MHz clock. If we're really unlucky, it's still required. */ DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n"); dpa_ctl |= DP_PLL_FREQ_160MHZ; + intel_dp->DP |= DP_PLL_FREQ_160MHZ; } else { dpa_ctl |= DP_PLL_FREQ_270MHZ; + intel_dp->DP |= DP_PLL_FREQ_270MHZ; } I915_WRITE(DP_A, dpa_ctl); @@ -814,8 +819,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); enum port port = dp_to_dig_port(intel_dp)->port; - struct drm_crtc *crtc = encoder->crtc; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); /* * There are four kinds of DP registers: @@ -845,7 +849,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_dp->has_audio) { DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", - pipe_name(intel_crtc->pipe)); + pipe_name(crtc->pipe)); intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_write_eld(encoder, adjusted_mode); } @@ -864,13 +868,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) intel_dp->DP |= DP_ENHANCED_FRAMING; - intel_dp->DP |= intel_crtc->pipe << 29; - - /* don't miss out required setting for eDP */ - if (adjusted_mode->clock < 200000) - intel_dp->DP |= DP_PLL_FREQ_160MHZ; - else - intel_dp->DP |= DP_PLL_FREQ_270MHZ; + intel_dp->DP |= crtc->pipe << 29; } else if (!HAS_PCH_CPT(dev) || port == PORT_A) { if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) intel_dp->DP |= intel_dp->color_range; @@ -884,22 +882,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) intel_dp->DP |= DP_ENHANCED_FRAMING; - if (intel_crtc->pipe == 1) + if (crtc->pipe == 1) intel_dp->DP |= DP_PIPEB_SELECT; - - if (port == PORT_A && !IS_VALLEYVIEW(dev)) { - /* don't miss out required setting for eDP */ - if (adjusted_mode->clock < 200000) - intel_dp->DP |= DP_PLL_FREQ_160MHZ; - else - intel_dp->DP |= DP_PLL_FREQ_270MHZ; - } } else { intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } if (port == PORT_A && !IS_VALLEYVIEW(dev)) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); + ironlake_set_pll_cpu_edp(intel_dp); } #define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) -- cgit v1.2.3 From ff9a6750aca3553c78385a9aa89b678b2b9be7df Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:21 +0200 Subject: drm/i915: store adjusted dotclock in adjusted_mode->clock ... not the port clock. This allows us to kill the funny semantics around pixel_target_clock. Since the dpll code still needs the real port clock, add a new port_clock field to the pipe configuration. Handling the default case for that one is a bit tricky, since encoders might not consistently overwrite it when retrying the crtc/encoder bw arbitrage step in the compute config stage. Hence we need to always clear port_clock and update it again if the encoder hasn't put in something more specific. This can't be done in one step since the encoder might want to adjust the mode first. I was a bit on the fence whether I should subsume the pixel multiplier handling into the port_clock, too. But then I decided against this since it's on an abstract level still the dotclock of the adjusted mode, and only our hw makes it a bit special due to the separate pixel mulitplier setting (which requires that the dpll runs at the non-multiplied dotclock). So after this patch the adjusted_mode accurately describes the mode we feed into the port, after the panel fitter and pixel multiplier (or line doubling, if we ever bother with that) have done their job. Since the fdi link is between the pfit and the pixel multiplier steps we need to be careful with calculating the fdi link config. v2: Fix up ilk cpu pll handling. v3: Introduce an fdi_dotclock variable in ironlake_fdi_compute_config to make it clearer that we transmit the adjusted_mode without the pixel multiplier taken into account. The old code multiplied the the available link bw with the pixel multiplier, which results in the same fdi configuration, but is much more confusing. v4: Rebase on top of Imre's is_cpu_edp removal. v5: Rebase on top of Paulo's haswell watermark fixes, which introduce a new place which looked at the pixel_clock and so needed conversion. v6: Split out prep patches as requested by Paulo Zanoni. Also rebase on top of the fdi dotclock handling fix in the fdi lanes/bw computation code. Reviewed-by: Jesse Barnes (v3) Reviewed-by: Paulo Zanoni (v6) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 ++- drivers/gpu/drm/i915/intel_display.c | 32 +++++++++++++++++--------------- drivers/gpu/drm/i915/intel_dp.c | 18 +++++++----------- drivers/gpu/drm/i915/intel_drv.h | 13 +++++++------ drivers/gpu/drm/i915/intel_hdmi.c | 4 +--- drivers/gpu/drm/i915/intel_pm.c | 5 +---- 6 files changed, 35 insertions(+), 40 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9649df806079..486c46bf5ccf 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -624,7 +624,7 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, clock, *p_out, *n2_out, *r2_out); } -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) +bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); @@ -634,6 +634,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock) int type = intel_encoder->type; enum pipe pipe = intel_crtc->pipe; uint32_t reg, val; + int clock = intel_crtc->config.port_clock; /* TODO: reuse PLLs when possible (compare values) */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 711ec3314893..60d4bfd40107 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3989,7 +3989,7 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc, { struct drm_device *dev = intel_crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - int target_clock, lane, link_bw, fdi_dotclock; + int lane, link_bw, fdi_dotclock; bool setup_ok, needs_recompute = false; retry: @@ -4002,12 +4002,7 @@ retry: */ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; - if (pipe_config->pixel_target_clock) - target_clock = pipe_config->pixel_target_clock; - else - target_clock = adjusted_mode->clock; - - fdi_dotclock = target_clock; + fdi_dotclock = adjusted_mode->clock; if (pipe_config->pixel_multiplier > 1) fdi_dotclock /= pipe_config->pixel_multiplier; @@ -4357,8 +4352,6 @@ static void vlv_update_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode = - &crtc->config.adjusted_mode; struct intel_encoder *encoder; int pipe = crtc->pipe; u32 dpll, mdiv; @@ -4411,7 +4404,7 @@ static void vlv_update_pll(struct intel_crtc *crtc) vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ - if (adjusted_mode->clock == 162000 || + if (crtc->config.port_clock == 162000 || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f0021); @@ -4856,7 +4849,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ limit = intel_limit(crtc, refclk); - ok = dev_priv->display.find_dpll(limit, crtc, adjusted_mode->clock, + ok = dev_priv->display.find_dpll(limit, crtc, + intel_crtc->config.port_clock, refclk, NULL, &clock); if (!ok && !intel_crtc->config.clock_set) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); @@ -5464,7 +5458,6 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc) } static bool ironlake_compute_clocks(struct drm_crtc *crtc, - struct drm_display_mode *adjusted_mode, intel_clock_t *clock, bool *has_reduced_clock, intel_clock_t *reduced_clock) @@ -5492,7 +5485,8 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. */ limit = intel_limit(crtc, refclk); - ret = dev_priv->display.find_dpll(limit, crtc, adjusted_mode->clock, + ret = dev_priv->display.find_dpll(limit, crtc, + to_intel_crtc(crtc)->config.port_clock, refclk, NULL, clock); if (!ret) return false; @@ -5692,7 +5686,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, + ok = ironlake_compute_clocks(crtc, &clock, &has_reduced_clock, &reduced_clock); if (!ok && !intel_crtc->config.clock_set) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); @@ -5895,7 +5889,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); - if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) + if (!intel_ddi_pll_mode_set(crtc)) return -EINVAL; /* Ensure that the cursor is valid for the new mode before changing... */ @@ -7805,6 +7799,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, goto fail; encoder_retry: + /* Ensure the port clock default is reset when retrying. */ + pipe_config->port_clock = 0; + /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. @@ -7833,6 +7830,11 @@ encoder_retry: } } + /* Set default port clock if not overwritten by the encoder. Needs to be + * done afterwards in case the encoder adjusts the mode. */ + if (!pipe_config->port_clock) + pipe_config->port_clock = pipe_config->adjusted_mode.clock; + ret = intel_crtc_compute_config(crtc, pipe_config); if (ret < 0) { DRM_DEBUG_KMS("CRTC fixup failed\n"); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3b490c097400..759a1c5d170d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -677,7 +677,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; int bpp, mode_rate; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; - int target_clock, link_avail, link_clock; + int link_avail, link_clock; if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A) pipe_config->has_pch_encoder = true; @@ -694,8 +694,6 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_pch_panel_fitting(intel_crtc, pipe_config, intel_connector->panel.fitting_mode); } - /* We need to take the panel's fixed mode into account. */ - target_clock = adjusted_mode->clock; if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) return false; @@ -711,7 +709,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, bpp = min_t(int, bpp, dev_priv->vbt.edp_bpp); for (; bpp >= 6*3; bpp -= 2*3) { - mode_rate = intel_dp_link_required(target_clock, bpp); + mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); for (clock = 0; clock <= max_clock; clock++) { for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { @@ -746,18 +744,17 @@ found: intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; - adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); pipe_config->pipe_bpp = bpp; - pipe_config->pixel_target_clock = target_clock; + pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", intel_dp->link_bw, intel_dp->lane_count, - adjusted_mode->clock, bpp); + pipe_config->port_clock, bpp); DRM_DEBUG_KMS("DP link bw required %i available %i\n", mode_rate, link_avail); intel_link_compute_m_n(bpp, lane_count, - target_clock, adjusted_mode->clock, + adjusted_mode->clock, pipe_config->port_clock, &pipe_config->dp_m_n); intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); @@ -788,12 +785,11 @@ static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; u32 dpa_ctl; - DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", - crtc->config.adjusted_mode.clock); + DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", crtc->config.port_clock); dpa_ctl = I915_READ(DP_A); dpa_ctl &= ~DP_PLL_FREQ_MASK; - if (crtc->config.adjusted_mode.clock == 162000) { + if (crtc->config.port_clock == 162000) { /* For a long time we've carried around a ILK-DevA w/a for the * 160MHz clock. If we're really unlucky, it's still required. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fdf6303be0a9..afda71fdb4a6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -243,12 +243,13 @@ struct intel_crtc_config { int pipe_bpp; struct intel_link_m_n dp_m_n; - /** - * This is currently used by DP and HDMI encoders since those can have a - * target pixel clock != the port link clock (which is currently stored - * in adjusted_mode->clock). + + /* + * Frequence the dpll for the port should run at. Differs from the + * adjusted dotclock e.g. for DP or 12bpc hdmi mode. */ - int pixel_target_clock; + int port_clock; + /* Used by SDVO (and if we ever fix it, HDMI). */ unsigned pixel_multiplier; @@ -786,7 +787,7 @@ extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); extern void intel_ddi_setup_hw_pll_state(struct drm_device *dev); -extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock); +extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8062a92e6e80..bc12518a21b4 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -835,9 +835,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, desired_bpp = 12*3; /* Need to adjust the port link by 1.5x for 12bpc. */ - adjusted_mode->clock = clock_12bpc; - pipe_config->pixel_target_clock = - pipe_config->requested_mode.clock; + pipe_config->port_clock = clock_12bpc; } else { DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); desired_bpp = 8*3; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 49a188718f9d..4126fb1b3dd4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2078,10 +2078,7 @@ static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pixel_rate, pfit_size; - if (intel_crtc->config.pixel_target_clock) - pixel_rate = intel_crtc->config.pixel_target_clock; - else - pixel_rate = intel_crtc->config.adjusted_mode.clock; + pixel_rate = intel_crtc->config.adjusted_mode.clock; /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to * adjust the pixel_rate here. */ -- cgit v1.2.3 From 8a654f3b743d0f645848f5fde5059f31a78260bf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:22 +0200 Subject: drm/i915: Drop some no longer required mode/adjusted_mode parameters We can get at this easily through intel_crtc->config now. v2: Drop more stuff gcc spotted. v3: Drop even more stuff gcc spotted. v4: Yet more ... Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60d4bfd40107..8ddd9a4ecbbc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4577,7 +4577,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc, } static void i8xx_update_pll(struct intel_crtc *crtc, - struct drm_display_mode *adjusted_mode, intel_clock_t *reduced_clock, int num_connectors) { @@ -4632,14 +4631,15 @@ static void i8xx_update_pll(struct intel_crtc *crtc, I915_WRITE(DPLL(pipe), dpll); } -static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void intel_set_pipe_timings(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; + struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + struct drm_display_mode *mode = &intel_crtc->config.requested_mode; uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end; /* We need to be careful not to changed the adjusted mode, for otherwise @@ -4817,8 +4817,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config.adjusted_mode; struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; @@ -4883,7 +4881,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } if (IS_GEN2(dev)) - i8xx_update_pll(intel_crtc, adjusted_mode, + i8xx_update_pll(intel_crtc, has_reduced_clock ? &reduced_clock : NULL, num_connectors); else if (IS_VALLEYVIEW(dev)) @@ -4903,7 +4901,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; } - intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); + intel_set_pipe_timings(intel_crtc); /* pipesrc and dspsize control the size that is scaled from, * which should always be the user's requested size. @@ -5660,9 +5658,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config.adjusted_mode; - struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; @@ -5757,7 +5752,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } } - intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); + intel_set_pipe_timings(intel_crtc); if (intel_crtc->config.has_pch_encoder) { intel_cpu_transcoder_set_m_n(intel_crtc, @@ -5865,9 +5860,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_display_mode *adjusted_mode = - &intel_crtc->config.adjusted_mode; - struct drm_display_mode *mode = &intel_crtc->config.requested_mode; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; @@ -5900,7 +5892,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, intel_crtc->lowfreq_avail = false; - intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); + intel_set_pipe_timings(intel_crtc); if (intel_crtc->config.has_pch_encoder) { intel_cpu_transcoder_set_m_n(intel_crtc, -- cgit v1.2.3 From cb8b2a30b32cde5ac9053d399d084c487598976a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:16:23 +0200 Subject: drm/i915: check for strange pfit pipe assignemnt on ivb/hsw Panel fitters on ivb/hsw are not created equal since not all of them support the new high-quality upscaling mode. To offset this the hw allows us to freely assign the pfits to pipes. Since our code currently doesn't support this we might fall over when taking over firmware state. So check for this case and WARN about it. We can then improve the code once we've hit this in the wild. Or once we decide to support the improved upscale modes, though that requires global arbitrage of modeset resources across crtcs. v2: Check for IS_GEN7 instead of IS_IVB || IS_HSW as suggested by Paulo in his review comment. Suggested-by: Mika Kuoppala Cc: Mika Kuoppala Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ddd9a4ecbbc..a4b97caf85b0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5803,6 +5803,14 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc, if (tmp & PF_ENABLE) { pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe)); pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe)); + + /* We currently do not free assignements of panel fitters on + * ivb/hsw (since we don't use the higher upscaling modes which + * differentiates them) so just WARN about this case for now. */ + if (IS_GEN7(dev)) { + WARN_ON((tmp & PF_PIPE_SEL_MASK_IVB) != + PF_PIPE_SEL_IVB(crtc->pipe)); + } } } -- cgit v1.2.3 From 4548feb1fe1f17c0d7ad7acdd267a875b22e6910 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 21 May 2013 18:01:49 +0300 Subject: drm/i915: VLV doesn't have the ILK+ style LP watermark registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LP watermark registers don't exist on VLV, so don't touch them. Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4126fb1b3dd4..b970267bb5d4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4797,10 +4797,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); /* WaDisableEarlyCull:vlv */ -- cgit v1.2.3 From d7fe0cc0f2e0b302b247caa4306915a06218e0be Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 21 May 2013 18:01:50 +0300 Subject: drm/i915: Fix DSPCLK_GATE_D for VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the DSPCLK_GATE_D access for VLV. The code incorrectly tried to poke at the ILK+ version of the register which is at the wrong offset. Signed-off-by: Ville Syrjälä Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a593d20036c..47a9de0d51cc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1256,7 +1256,7 @@ #define DSTATE_PLL_D3_OFF (1<<3) #define DSTATE_GFX_CLOCK_GATING (1<<1) #define DSTATE_DOT_CLOCK_GATING (1<<0) -#define DSPCLK_GATE_D 0x6200 +#define DSPCLK_GATE_D (dev_priv->info->display_mmio_offset + 0x6200) # define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ # define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ # define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b970267bb5d4..50fe3d7303cb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4797,7 +4797,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); /* WaDisableEarlyCull:vlv */ I915_WRITE(_3D_CHICKEN3, -- cgit v1.2.3 From accfc0c50659c330cfde684017e5c1b58eee2857 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 May 2013 15:04:25 +0200 Subject: drm/i915: consolidate and tighten encoder cloning checks Only lvds/tv did actually check for cloning or not, but many more places should. Notices because my ivb tried to enable both cpu edp and vga on the first crtc - the resulting confusion between has_pch_encoder, has_dp_encoder but not actually being a pch dp encoder resulting in hilarity (hitting a BUG). We _really_ need an igt to random-walk our modeset space more exhaustively. The bug seems to have been exposed due to a race in the hw load detection support for VGA: Right after a hotplug VGA was still detected as connected, but obviously reading the EDID wasn't possible any more. Hence why restarting X a bit later fixed things. Due to the 1024x756 fallback resolution suddenly more outputs had the same resolution. On top of that SNA was confused with the possible_clones mask, trying to clone outputs which cannot be cloned. That bug is now fixed with commit fc1e0702b25e647cb423851fb7228989fec28bd6 Author: Daniel Vetter Date: Wed May 29 11:25:28 2013 +0100 sna: fixup up possible_clones kms->X impedance mismatch v2: Kill intel_encoder_check_is_cloned, spotted by Paulo. v3: Drop the now unused pipe param. v4: Kill the stray printk Chris spotted. v5: Elaborate on how the bug in userspace happened and why it was racy to reproduce. Cc: Chris Wilson Cc: stable@vger.kernel.org Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 64 ++++++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_lvds.c | 3 -- drivers/gpu/drm/i915/intel_tv.c | 3 -- 4 files changed, 24 insertions(+), 47 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a4b97caf85b0..827d7ca2d9d9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5868,27 +5868,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - int num_connectors = 0; - bool is_cpu_edp = false; - struct intel_encoder *encoder; int ret; - for_each_encoder_on_crtc(dev, crtc, encoder) { - switch (encoder->type) { - case INTEL_OUTPUT_EDP: - if (enc_to_dig_port(&encoder->base)->port == PORT_A) - is_cpu_edp = true; - break; - } - - num_connectors++; - } - - WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", - num_connectors, pipe_name(pipe)); - if (!intel_ddi_pll_mode_set(crtc)) return -EINVAL; @@ -7564,28 +7546,6 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = { .load_lut = intel_crtc_load_lut, }; -bool intel_encoder_check_is_cloned(struct intel_encoder *encoder) -{ - struct intel_encoder *other_encoder; - struct drm_crtc *crtc = &encoder->new_crtc->base; - - if (WARN_ON(!crtc)) - return false; - - list_for_each_entry(other_encoder, - &crtc->dev->mode_config.encoder_list, - base.head) { - - if (&other_encoder->new_crtc->base != crtc || - encoder == other_encoder) - continue; - else - return true; - } - - return false; -} - static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc) { @@ -7769,6 +7729,25 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled); } +static bool check_encoder_cloning(struct drm_crtc *crtc) +{ + int num_encoders = 0; + bool uncloneable_encoders = false; + struct intel_encoder *encoder; + + list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, + base.head) { + if (&encoder->new_crtc->base != crtc) + continue; + + num_encoders++; + if (!encoder->cloneable) + uncloneable_encoders = true; + } + + return !(num_encoders > 1 && uncloneable_encoders); +} + static struct intel_crtc_config * intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -7781,6 +7760,11 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, int plane_bpp, ret = -EINVAL; bool retry = true; + if (!check_encoder_cloning(crtc)) { + DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); + return ERR_PTR(-EINVAL); + } + pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL); if (!pipe_config) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index afda71fdb4a6..eae3dbc4e3ee 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -629,7 +629,6 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_destroy(struct drm_encoder *encoder); extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode); -extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder); extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_modeset_check_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 655486099b76..10c3d56332f5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -264,9 +264,6 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder, return false; } - if (intel_encoder_check_is_cloned(&lvds_encoder->base)) - return false; - if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP) lvds_bpp = 8*3; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 7d11a5adc985..39debd80d190 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -914,9 +914,6 @@ intel_tv_compute_config(struct intel_encoder *encoder, if (!tv_mode) return false; - if (intel_encoder_check_is_cloned(&intel_tv->base)) - return false; - pipe_config->adjusted_mode.clock = tv_mode->clock; DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); pipe_config->pipe_bpp = 8*3; -- cgit v1.2.3 From c2a2a1a722b7e4edce7dad285b461e0b2592eecc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 5 Jun 2013 21:55:29 +0300 Subject: drm/i915: distinguish between error messages in DIDL initialization Two exactly same error messages on different error paths makes debugging difficult. Clarify the messages and distinguish them from each other. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 5c2d6939600e..79be7cfd3152 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -312,7 +312,7 @@ static void intel_didl_outputs(struct drm_device *dev) list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { if (i >= 8) { dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected\n"); + "More than 8 outputs detected via ACPI\n"); return; } status = @@ -339,7 +339,7 @@ blind_set: int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected\n"); + "More than 8 outputs in connector list\n"); return; } switch (connector->connector_type) { -- cgit v1.2.3 From ef1b460d1bab7e5b04c34f88c3dfa042528e7c27 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 17:17:04 +0200 Subject: drm/i915: set default value for config->pixel_multiplier This way we can simplify the code quite a bit. Also add a WARN in the sdvo code to complain about a bogus value and kill the readout code in intel_ddi.c that Jesse sneaked in. HW state readout for the pixel multiplier will work a bit differently in the end. v2: Rebase on top of the fdi pixel mutliplier handling fix. Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 1 - drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++------------------- drivers/gpu/drm/i915/intel_sdvo.c | 1 + 3 files changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 486c46bf5ccf..224ce25129ce 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1279,7 +1279,6 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; - pipe_config->pixel_multiplier = 1; } static void intel_ddi_destroy(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 827d7ca2d9d9..ca90d36fd650 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4003,8 +4003,7 @@ retry: link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10; fdi_dotclock = adjusted_mode->clock; - if (pipe_config->pixel_multiplier > 1) - fdi_dotclock /= pipe_config->pixel_multiplier; + fdi_dotclock /= pipe_config->pixel_multiplier; lane = ironlake_get_lanes_required(fdi_dotclock, link_bw, pipe_config->pipe_bpp); @@ -4458,11 +4457,8 @@ static void vlv_update_pll(struct intel_crtc *crtc) if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1)) DRM_ERROR("DPLL %d failed to lock\n", pipe); - dpll_md = 0; - if (crtc->config.pixel_multiplier > 1) { - dpll_md = (crtc->config.pixel_multiplier - 1) - << DPLL_MD_UDI_MULTIPLIER_SHIFT; - } + dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; I915_WRITE(DPLL_MD(pipe), dpll_md); POSTING_READ(DPLL_MD(pipe)); @@ -4496,8 +4492,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; - if ((crtc->config.pixel_multiplier > 1) && - (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) { + if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { dpll |= (crtc->config.pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; } @@ -4560,11 +4555,8 @@ static void i9xx_update_pll(struct intel_crtc *crtc, udelay(150); if (INTEL_INFO(dev)->gen >= 4) { - u32 dpll_md = 0; - if (crtc->config.pixel_multiplier > 1) { - dpll_md = (crtc->config.pixel_multiplier - 1) - << DPLL_MD_UDI_MULTIPLIER_SHIFT; - } + u32 dpll_md = (crtc->config.pixel_multiplier - 1) + << DPLL_MD_UDI_MULTIPLIER_SHIFT; I915_WRITE(DPLL_MD(pipe), dpll_md); } else { /* The pixel multiplier can only be updated once the @@ -5613,10 +5605,8 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, else dpll |= DPLLB_MODE_DAC_SERIAL; - if (intel_crtc->config.pixel_multiplier > 1) { - dpll |= (intel_crtc->config.pixel_multiplier - 1) - << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; - } + dpll |= (intel_crtc->config.pixel_multiplier - 1) + << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; if (is_sdvo) dpll |= DPLL_DVO_HIGH_SPEED; @@ -7783,8 +7773,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, goto fail; encoder_retry: - /* Ensure the port clock default is reset when retrying. */ + /* Ensure the port clock defaults are reset when retrying. */ pipe_config->port_clock = 0; + pipe_config->pixel_multiplier = 1; /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 7068195376ef..f4588a2c65ac 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1219,6 +1219,7 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder) switch (intel_crtc->config.pixel_multiplier) { default: + WARN(1, "unknown pixel mutlipler specified\n"); case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; -- cgit v1.2.3 From 2db8e9d6b255a4fd070df70fa58306bf64b41984 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 4 Jun 2013 23:49:08 +0100 Subject: drm/i915: Track clients and print their object usage in debugfs By stashing a pointer of who opened the device and keeping a list of open fd, we can then walk each client and inspect how many objects they have open. For example, i915_gem_objects: 1102 objects, 613646336 bytes 663 [662] objects, 468783104 [468750336] bytes in gtt 37 [37] active objects, 46874624 [46874624] bytes 626 [625] inactive objects, 421908480 [421875712] bytes 282 unbound objects, 6512640 bytes 85 purgeable objects, 6787072 bytes 28 pinned mappable objects, 3686400 bytes 40 fault mappable objects, 27783168 bytes 2145386496 [536870912] gtt total Xorg: 43 objects, 32243712 bytes (10223616 active, 16683008 inactive, 4096 unbound) gnome-shell: 30 objects, 28381184 bytes (0 active, 28336128 inactive, 0 unbound) xonotic-linux64: 1032 objects, 569933824 bytes (46874624 active, 383545344 inactive, 6508544 unbound) v2: Use existing drm->filelist as pointed out by Ben. v3: Not even stashing the task_struct is required as Ben pointed out drm_file->pid. Signed-off-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0e7e3c04d939..d4e78b64ca87 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -196,6 +196,32 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) } \ } while (0) +struct file_stats { + int count; + size_t total, active, inactive, unbound; +}; + +static int per_file_stats(int id, void *ptr, void *data) +{ + struct drm_i915_gem_object *obj = ptr; + struct file_stats *stats = data; + + stats->count++; + stats->total += obj->base.size; + + if (obj->gtt_space) { + if (!list_empty(&obj->ring_list)) + stats->active += obj->base.size; + else + stats->inactive += obj->base.size; + } else { + if (!list_empty(&obj->global_list)) + stats->unbound += obj->base.size; + } + + return 0; +} + static int i915_gem_object_info(struct seq_file *m, void* data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -204,6 +230,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) u32 count, mappable_count, purgeable_count; size_t size, mappable_size, purgeable_size; struct drm_i915_gem_object *obj; + struct drm_file *file; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -263,6 +290,21 @@ static int i915_gem_object_info(struct seq_file *m, void* data) dev_priv->gtt.total, dev_priv->gtt.mappable_end - dev_priv->gtt.start); + seq_printf(m, "\n"); + list_for_each_entry_reverse(file, &dev->filelist, lhead) { + struct file_stats stats; + + memset(&stats, 0, sizeof(stats)); + idr_for_each(&file->object_idr, per_file_stats, &stats); + seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n", + get_pid_task(file->pid, PIDTYPE_PID)->comm, + stats.count, + stats.total, + stats.active, + stats.inactive, + stats.unbound); + } + mutex_unlock(&dev->struct_mutex); return 0; -- cgit v1.2.3 From 91738a95bf40a3405bb7b8a3e76d30e060a80705 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 5 Jun 2013 14:21:51 -0300 Subject: drm/i915: add ibx_irq_preinstall So we can remove some duplicate code. All the PCHs are very similar and right now the code is the same. I plan to add more code, so we would have more duplicated code. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 63996aa3fb17..c482e8ae58dc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2472,6 +2472,25 @@ void i915_hangcheck_elapsed(unsigned long data) DRM_I915_HANGCHECK_JIFFIES)); } +static void ibx_irq_preinstall(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_NOP(dev)) + return; + + /* south display irq */ + I915_WRITE(SDEIMR, 0xffffffff); + /* + * SDEIER is also touched by the interrupt handler to work around missed + * PCH interrupts. Hence we can't update it after the interrupt handler + * is enabled - instead we unconditionally enable all PCH interrupt + * sources here, but then only unmask them as needed with SDEIMR. + */ + I915_WRITE(SDEIER, 0xffffffff); + POSTING_READ(SDEIER); +} + /* drm_dma.h hooks */ static void ironlake_irq_preinstall(struct drm_device *dev) @@ -2493,16 +2512,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); POSTING_READ(GTIER); - /* south display irq */ - I915_WRITE(SDEIMR, 0xffffffff); - /* - * SDEIER is also touched by the interrupt handler to work around missed - * PCH interrupts. Hence we can't update it after the interrupt handler - * is enabled - instead we unconditionally enable all PCH interrupt - * sources here, but then only unmask them as needed with SDEIMR. - */ - I915_WRITE(SDEIER, 0xffffffff); - POSTING_READ(SDEIER); + ibx_irq_preinstall(dev); } static void ivybridge_irq_preinstall(struct drm_device *dev) @@ -2529,19 +2539,7 @@ static void ivybridge_irq_preinstall(struct drm_device *dev) I915_WRITE(GEN6_PMIER, 0x0); POSTING_READ(GEN6_PMIER); - if (HAS_PCH_NOP(dev)) - return; - - /* south display irq */ - I915_WRITE(SDEIMR, 0xffffffff); - /* - * SDEIER is also touched by the interrupt handler to work around missed - * PCH interrupts. Hence we can't update it after the interrupt handler - * is enabled - instead we unconditionally enable all PCH interrupt - * sources here, but then only unmask them as needed with SDEIMR. - */ - I915_WRITE(SDEIER, 0xffffffff); - POSTING_READ(SDEIER); + ibx_irq_preinstall(dev); } static void valleyview_irq_preinstall(struct drm_device *dev) -- cgit v1.2.3 From 5434fd926d1e4de5d82fcbd4e7e4698cc6575bdb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 6 Jun 2013 13:09:32 +0300 Subject: Revert "drm/i915: Include display_mmio_offset in sequencer index/data registers" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use port I/O for VGA register access, so adding display_mmio_offset is just wrong. This reverts commit 56a12a509296c87d6f149be86c6694d312b21d35. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 47a9de0d51cc..ff9f71af9347 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -147,15 +147,9 @@ #define VGA_MSR_MEM_EN (1<<1) #define VGA_MSR_CGA_MODE (1<<0) -/* - * SR01 is the only VGA register touched on non-UMS setups. - * VLV doesn't do UMS, so the sequencer index/data registers - * are the only VGA registers which need to include - * display_mmio_offset. - */ -#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4) +#define VGA_SR_INDEX 0x3c4 #define SR01 1 -#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5) +#define VGA_SR_DATA 0x3c5 #define VGA_AR_INDEX 0x3c0 #define VGA_AR_VID_EN (1<<5) -- cgit v1.2.3 From 63cbb0747622d923665294519e9a24bc9c654c19 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:48:59 +0300 Subject: drm/i915: Always load the display palette before enabling the pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loading the palette after the planes are enabled can risk showing incorrect colors. ILK+ already load the palette before even the pipe is enabled. Just follow the same order for gen2-4 and VLV. According to BSpec the requirements for palette access are display core clock and display PLL running. In certain platforms just the core clock may be enough. But we definitely should have both running when this gets called during the modeset. v2: Amend the commit message with some display PLL/core clock info Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca90d36fd650..240dfc7af8b6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3618,10 +3618,11 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) /* Enable panel fitting for eDP */ i9xx_pfit_enable(intel_crtc); + intel_crtc_load_lut(crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); - intel_crtc_load_lut(crtc); intel_update_fbc(dev); /* Give the overlay scaler a chance to enable if it's on this pipe */ @@ -3657,12 +3658,13 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) /* Enable panel fitting for LVDS */ i9xx_pfit_enable(intel_crtc); + intel_crtc_load_lut(crtc); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); - intel_crtc_load_lut(crtc); intel_update_fbc(dev); /* Give the overlay scaler a chance to enable if it's on this pipe */ -- cgit v1.2.3 From 5c38d48cd8dfb3332c072a257bc2a6dab1e5dc3b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:00 +0300 Subject: drm/i915: Always enable the cursor right after the primary plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the same sequence when enabling the cursor plane during modeset. No point in doing this stuff in different order on different generations. This should also avoid a needless wait for vblank for the g4x cursor workaround when the cursor gets enabled anyway. Acked-by: Egbert Eich Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 240dfc7af8b6..532a4fa67bb2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3219,6 +3219,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + intel_crtc_update_cursor(crtc, true); if (intel_crtc->config.has_pch_encoder) ironlake_pch_enable(crtc); @@ -3227,8 +3228,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); - intel_crtc_update_cursor(crtc, true); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); @@ -3328,6 +3327,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + intel_crtc_update_cursor(crtc, true); hsw_enable_ips(intel_crtc); @@ -3338,8 +3338,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); - intel_crtc_update_cursor(crtc, true); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); @@ -3622,12 +3620,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + intel_crtc_update_cursor(crtc, true); intel_update_fbc(dev); /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); - intel_crtc_update_cursor(crtc, true); mutex_unlock(&dev_priv->dpio_lock); } @@ -3662,6 +3660,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + intel_crtc_update_cursor(crtc, true); if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); @@ -3669,7 +3668,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); - intel_crtc_update_cursor(crtc, true); for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); -- cgit v1.2.3 From f440eb1354bc92855bbbff08d3ac4a93029c3097 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:01 +0300 Subject: drm/i915: Enable the overlay right after primary and cursor planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again follow the same sequence for all generations, because doing otherwise just doesn't make sense. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 532a4fa67bb2..bf8fe819cfbd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3622,11 +3622,11 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_enable_plane(dev_priv, plane, pipe); intel_crtc_update_cursor(crtc, true); - intel_update_fbc(dev); - /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); + intel_update_fbc(dev); + mutex_unlock(&dev_priv->dpio_lock); } @@ -3664,11 +3664,11 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); - intel_update_fbc(dev); - /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); + intel_update_fbc(dev); + for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); } -- cgit v1.2.3 From 0d5b8c61d877072431d29f3338ec081a3f5d7981 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:02 +0300 Subject: drm/i915: Follow the same sequence when disabling planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First disable FBC, then IPS, then disable all planes, and finally disable the pipe. v2: Mention IPS in the commit message Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bf8fe819cfbd..1e3f31721615 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3386,13 +3386,13 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); - intel_crtc_update_cursor(crtc, false); - - intel_disable_plane(dev_priv, plane, pipe); if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + intel_crtc_update_cursor(crtc, false); + intel_disable_plane(dev_priv, plane, pipe); + intel_set_pch_fifo_underrun_reporting(dev, pipe, false); intel_disable_pipe(dev_priv, pipe); @@ -3465,7 +3465,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); - intel_crtc_update_cursor(crtc, false); /* FBC must be disabled before disabling the plane on HSW. */ if (dev_priv->cfb_plane == plane) @@ -3473,6 +3472,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); + intel_crtc_update_cursor(crtc, false); intel_disable_plane(dev_priv, plane, pipe); if (intel_crtc->config.has_pch_encoder) @@ -3706,13 +3706,14 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_wait_for_pending_flips(crtc); drm_vblank_off(dev, pipe); - intel_crtc_dpms_overlay(intel_crtc, false); - intel_crtc_update_cursor(crtc, false); if (dev_priv->cfb_plane == plane) intel_disable_fbc(dev); + intel_crtc_dpms_overlay(intel_crtc, false); + intel_crtc_update_cursor(crtc, false); intel_disable_plane(dev_priv, plane, pipe); + intel_disable_pipe(dev_priv, pipe); i9xx_pfit_disable(intel_crtc); -- cgit v1.2.3 From b85dfcf9240043e81ba13b1bc99afc8645bf4c6a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:03 +0300 Subject: drm/i915: Drop overlay DPMS call from valleyview_crtc_enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV doesn't have the old video overlay. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e3f31721615..62557ecc0eff 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3622,9 +3622,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_enable_plane(dev_priv, plane, pipe); intel_crtc_update_cursor(crtc, true); - /* Give the overlay scaler a chance to enable if it's on this pipe */ - intel_crtc_dpms_overlay(intel_crtc, true); - intel_update_fbc(dev); mutex_unlock(&dev_priv->dpio_lock); -- cgit v1.2.3 From bb53d4aeac59079240605ef9269166f204612b78 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:04 +0300 Subject: drm/i915: Disable/restore all sprite planes around modeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable/restore sprite planes around mode-set just like we do for the primary and cursor planes. Now that we have working sprite clipping, this actually works quite decently. Previosuly we didn't even bother to disable sprites when changing mode, which could lead to a corrupted sprite appearing on the screen after a modeset (at least on my IVB). Not sure if all hardware generations would be so forgiving when enabled sprites end up outside the pipe dimensons. v2: Disable rather than enable sprites in ironlake_crtc_disable() Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 8 ++++++++ 3 files changed, 38 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62557ecc0eff..f084a1dd8f4d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3164,6 +3164,28 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc) } } +static void intel_enable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_plane *intel_plane; + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + if (intel_plane->pipe == pipe) + intel_plane_restore(&intel_plane->base); +} + +static void intel_disable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct intel_plane *intel_plane; + + list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + if (intel_plane->pipe == pipe) + intel_plane_disable(&intel_plane->base); +} + static void ironlake_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3219,6 +3241,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); if (intel_crtc->config.has_pch_encoder) @@ -3327,6 +3350,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, intel_crtc->config.has_pch_encoder); intel_enable_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); hsw_enable_ips(intel_crtc); @@ -3391,6 +3415,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_disable_fbc(dev); intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); intel_disable_plane(dev_priv, plane, pipe); intel_set_pch_fifo_underrun_reporting(dev, pipe, false); @@ -3473,6 +3498,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); intel_disable_plane(dev_priv, plane, pipe); if (intel_crtc->config.has_pch_encoder) @@ -3620,6 +3646,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); intel_update_fbc(dev); @@ -3657,6 +3684,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + intel_enable_planes(crtc); intel_crtc_update_cursor(crtc, true); if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); @@ -3709,6 +3737,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_update_cursor(crtc, false); + intel_disable_planes(crtc); intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eae3dbc4e3ee..6bbebf824078 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -633,6 +633,7 @@ extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_modeset_check_state(struct drm_device *dev); extern void intel_plane_restore(struct drm_plane *plane); +extern void intel_plane_disable(struct drm_plane *plane); static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 04d38d4d811a..1fa5612a4572 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -957,6 +957,14 @@ void intel_plane_restore(struct drm_plane *plane) intel_plane->src_w, intel_plane->src_h); } +void intel_plane_disable(struct drm_plane *plane) +{ + if (!plane->crtc || !plane->fb) + return; + + intel_disable_plane(plane); +} + static const struct drm_plane_funcs intel_plane_funcs = { .update_plane = intel_update_plane, .disable_plane = intel_disable_plane, -- cgit v1.2.3 From 653e10266df8319d6003fbf46ec34865a5a363f6 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:05 +0300 Subject: drm/i915: Improve assert_planes_disabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since gen4 primary planes were fixed to pipes. And for gen2-3, don't check plane B if it doesn't exist. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f084a1dd8f4d..0f0ac933bd6c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1105,12 +1105,13 @@ static void assert_plane(struct drm_i915_private *dev_priv, static void assert_planes_disabled(struct drm_i915_private *dev_priv, enum pipe pipe) { + struct drm_device *dev = dev_priv->dev; int reg, i; u32 val; int cur_pipe; - /* Planes are fixed to pipes on ILK+ */ - if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) { + /* Primary planes are fixed to pipes on gen4+ */ + if (INTEL_INFO(dev)->gen >= 4) { reg = DSPCNTR(pipe); val = I915_READ(reg); WARN((val & DISPLAY_PLANE_ENABLE), @@ -1120,7 +1121,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, } /* Need to check both planes against the pipe */ - for (i = 0; i < 2; i++) { + for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) { reg = DSPCNTR(i); val = I915_READ(reg); cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> -- cgit v1.2.3 From 20674eef808dada6c30988a8cfcb908406cdea02 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:06 +0300 Subject: drm/i915: Spruce up assert_sprites_disabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make assert_sprites_disabled() operational on all platforms where we currently have sprite support enabled. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f0ac933bd6c..c593ed0ca1b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1135,19 +1135,30 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv, static void assert_sprites_disabled(struct drm_i915_private *dev_priv, enum pipe pipe) { + struct drm_device *dev = dev_priv->dev; int reg, i; u32 val; - if (!IS_VALLEYVIEW(dev_priv->dev)) - return; - - /* Need to check both planes against the pipe */ - for (i = 0; i < dev_priv->num_plane; i++) { - reg = SPCNTR(pipe, i); + if (IS_VALLEYVIEW(dev)) { + for (i = 0; i < dev_priv->num_plane; i++) { + reg = SPCNTR(pipe, i); + val = I915_READ(reg); + WARN((val & SP_ENABLE), + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + sprite_name(pipe, i), pipe_name(pipe)); + } + } else if (INTEL_INFO(dev)->gen >= 7) { + reg = SPRCTL(pipe); + val = I915_READ(reg); + WARN((val & SPRITE_ENABLE), + "sprite %c assertion failure, should be off on pipe %c but is still active\n", + plane_name(pipe), pipe_name(pipe)); + } else if (INTEL_INFO(dev)->gen >= 5) { + reg = DVSCNTR(pipe); val = I915_READ(reg); - WARN((val & SP_ENABLE), + WARN((val & DVS_ENABLE), "sprite %c assertion failure, should be off on pipe %c but is still active\n", - sprite_name(pipe, i), pipe_name(pipe)); + plane_name(pipe), pipe_name(pipe)); } } -- cgit v1.2.3 From 14420bd0065c1757a353e36ebc9cc4bdc6932dcd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 4 Jun 2013 13:49:07 +0300 Subject: drm/i915: Assert dpll running in intel_crtc_load_lut() on pre-PCH platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding more context from Ville's reply to Rodrigo's question why we need this: "The spec says that on some hardware you need to PLL running before you can poke at the palette registers. I didn't actually try to anger the hardware so I'm not really sure what would happen otherwise, but IIRC Jesse said something about a hard system hang..." And generally documenting such ordering constraints with asserts is Just Good. Signed-off-by: Ville Syrjälä Reviewed-by: Rodrigo Vivi [danvet: Spruce up the commit message a lot.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c593ed0ca1b9..0e1f82810f58 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6311,6 +6311,9 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) if (!crtc->enabled || !intel_crtc->active) return; + if (!HAS_PCH_SPLIT(dev_priv->dev)) + assert_pll_enabled(dev_priv, pipe); + /* use legacy palette for Ironlake */ if (HAS_PCH_SPLIT(dev)) palreg = LGC_PALETTE(pipe); -- cgit v1.2.3 From 6c49f24180c308a07be3f1d59ee7af33184ba17e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Jun 2013 12:45:25 +0200 Subject: drm/i915: hw state readout support for pixel_multiplier Incomplete since ilk+ support needs proper pch dpll tracking first. SDVO get_config parts based on a patch from Jesse Barnes, but fixed up to actually work. v2: Make sure that we call encoder->get_config _after_ we get_pipe_config to be consistent in both setup_hw_state and the modeset state checker. Otherwise the clever trick with handling the pixel mutliplier on i915G/GM where the encoder overrides the default value of 1 from the crtc get_pipe_config function doesn't work. Spotted by Imre Deak. v3: Actually cross-check the pixel mutliplier (but not on pch split platforms for now). Now actually also tested on a i915G with a sdvo encoder plugged in. Cc: Imre Deak Cc: Jesse Barnes Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 39 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_sdvo.c | 30 ++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0e1f82810f58..421b7e2ece3b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5001,6 +5001,23 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, i9xx_get_pfit_config(crtc, pipe_config); + if (INTEL_INFO(dev)->gen >= 4) { + tmp = I915_READ(DPLL_MD(crtc->pipe)); + pipe_config->pixel_multiplier = + ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK) + >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1; + } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { + tmp = I915_READ(DPLL(crtc->pipe)); + pipe_config->pixel_multiplier = + ((tmp & SDVO_MULTIPLIER_MASK) + >> SDVO_MULTIPLIER_SHIFT_HIRES) + 1; + } else { + /* Note that on i915G/GM the pixel multiplier is in the sdvo + * port and will be fixed up in the encoder->get_config + * function. */ + pipe_config->pixel_multiplier = 1; + } + return true; } @@ -5864,6 +5881,12 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, FDI_DP_PORT_WIDTH_SHIFT) + 1; ironlake_get_fdi_m_n_config(crtc, pipe_config); + + /* XXX: Can't properly read out the pch dpll pixel multiplier + * since we don't have state tracking for pch clocks yet. */ + pipe_config->pixel_multiplier = 1; + } else { + pipe_config->pixel_multiplier = 1; } intel_get_pipe_timings(crtc, pipe_config); @@ -5998,6 +6021,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) && (I915_READ(IPS_CTL) & IPS_ENABLE); + pipe_config->pixel_multiplier = 1; + return true; } @@ -8090,6 +8115,9 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start); PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end); + if (!HAS_PCH_SPLIT(dev)) + PIPE_CONF_CHECK_I(pixel_multiplier); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, DRM_MODE_FLAG_INTERLACE); @@ -8211,9 +8239,8 @@ intel_modeset_check_state(struct drm_device *dev) enabled = true; if (encoder->connectors_active) active = true; - if (encoder->get_config) - encoder->get_config(encoder, &pipe_config); } + WARN(active != crtc->active, "crtc's computed active state doesn't match tracked active state " "(expected %i, found %i)\n", active, crtc->active); @@ -8223,6 +8250,14 @@ intel_modeset_check_state(struct drm_device *dev) active = dev_priv->display.get_pipe_config(crtc, &pipe_config); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->base.crtc != &crtc->base) + continue; + if (encoder->get_config) + encoder->get_config(encoder, &pipe_config); + } + WARN(crtc->active != active, "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f4588a2c65ac..5c816dd75bec 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1313,9 +1313,13 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, static void intel_sdvo_get_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); struct intel_sdvo_dtd dtd; - u32 flags = 0; + int encoder_pixel_multiplier = 0; + u32 flags = 0, sdvox; + u8 val; bool ret; ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd); @@ -1335,6 +1339,30 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; + + if (IS_I915G(dev) || IS_I915GM(dev)) { + sdvox = I915_READ(intel_sdvo->sdvo_reg); + pipe_config->pixel_multiplier = + ((sdvox & SDVO_PORT_MULTIPLY_MASK) + >> SDVO_PORT_MULTIPLY_SHIFT) + 1; + } + + /* Cross check the port pixel multiplier with the sdvo encoder state. */ + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1); + switch (val) { + case SDVO_CLOCK_RATE_MULT_1X: + encoder_pixel_multiplier = 1; + break; + case SDVO_CLOCK_RATE_MULT_2X: + encoder_pixel_multiplier = 2; + break; + case SDVO_CLOCK_RATE_MULT_4X: + encoder_pixel_multiplier = 4; + break; + } + WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier, + "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n", + pipe_config->pixel_multiplier, encoder_pixel_multiplier); } static void intel_disable_sdvo(struct intel_encoder *encoder) -- cgit v1.2.3 From f85da868e3b998394634209cc1e48e0f4126901b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 4 Jun 2013 16:53:39 -0300 Subject: drm/i915: update FBC maximum fb sizes CTG/ILK/SNB/IVB support 4kx2k surfaces. HSW supports 4kx4k, but without proper front buffer invalidation on the last 2k lines, so don't enable FBC on these cases for now. v2: Use gen >= 5, not gen > 4 (Daniel). Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 50fe3d7303cb..1e1b48ec6c46 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -431,7 +431,7 @@ void intel_disable_fbc(struct drm_device *dev) * - no pixel mulitply/line duplication * - no alpha buffer discard * - no dual wide - * - framebuffer <= 2048 in width, 1536 in height + * - framebuffer <= max_hdisplay in width, max_vdisplay in height * * We can't assume that any compression will take place (worst case), * so the compressed buffer has to be the same size as the uncompressed @@ -449,6 +449,7 @@ void intel_update_fbc(struct drm_device *dev) struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj; int enable_fbc; + unsigned int max_hdisplay, max_vdisplay; if (!i915_powersave) return; @@ -507,8 +508,16 @@ void intel_update_fbc(struct drm_device *dev) dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; goto out_disable; } - if ((crtc->mode.hdisplay > 2048) || - (crtc->mode.vdisplay > 1536)) { + + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + max_hdisplay = 4096; + max_vdisplay = 2048; + } else { + max_hdisplay = 2048; + max_vdisplay = 1536; + } + if ((crtc->mode.hdisplay > max_hdisplay) || + (crtc->mode.vdisplay > max_vdisplay)) { DRM_DEBUG_KMS("mode too large for compression, disabling\n"); dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; goto out_disable; -- cgit v1.2.3 From a38911a3fede294e2adfd2deea8104dfbbd760c5 Mon Sep 17 00:00:00 2001 From: Wang Xingchao Date: Thu, 30 May 2013 22:07:11 +0800 Subject: i915/drm: Add private api for power well usage Haswell Display audio depends on power well in graphic side, it should request power well before use it and release power well after use. I915 will not shutdown power well if it detects audio is using. This patch protects display audio crash for Intel Haswell C3 stepping board. Signed-off-by: Wang Xingchao Reviewed-by: Takashi Iwai Reviewed-by: Damien Lespiau Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 6 +++ drivers/gpu/drm/i915/i915_drv.h | 12 ++++++ drivers/gpu/drm/i915/intel_drv.h | 4 ++ drivers/gpu/drm/i915/intel_pm.c | 81 ++++++++++++++++++++++++++++++++++++---- include/drm/i915_powerwell.h | 36 ++++++++++++++++++ 5 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 include/drm/i915_powerwell.h (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 22534c3b4fe5..fd8898c8f8e3 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1656,6 +1656,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Start out suspended */ dev_priv->mm.suspended = 1; + if (HAS_POWER_WELL(dev)) + i915_init_power_well(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_load_modeset_init(dev); if (ret < 0) { @@ -1712,6 +1715,9 @@ int i915_driver_unload(struct drm_device *dev) intel_gpu_ips_teardown(); + if (HAS_POWER_WELL(dev)) + i915_remove_power_well(dev); + i915_teardown_sysfs(dev); if (dev_priv->mm.inactive_shrinker.shrink) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 215aa63e3f47..87f7f88b1030 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -740,6 +740,15 @@ struct intel_ilk_power_mgmt { struct drm_i915_gem_object *renderctx; }; +/* Power well structure for haswell */ +struct i915_power_well { + struct drm_device *device; + spinlock_t lock; + /* power well enable/disable usage count */ + int count; + int i915_request; +}; + struct i915_dri1_state { unsigned allow_batchbuffer : 1; u32 __iomem *gfx_hws_cpu_addr; @@ -1099,6 +1108,9 @@ typedef struct drm_i915_private { * mchdev_lock in intel_pm.c */ struct intel_ilk_power_mgmt ips; + /* Haswell power well */ + struct i915_power_well power_well; + enum no_fbc_reason no_fbc_reason; struct drm_mm_node *compressed_fb; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6bbebf824078..1735cdc86770 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -768,6 +768,10 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); +/* Power well */ +extern int i915_init_power_well(struct drm_device *dev); +extern void i915_remove_power_well(struct drm_device *dev); + extern bool intel_display_power_enabled(struct drm_device *dev, enum intel_display_power_domain domain); extern void intel_init_power_well(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1e1b48ec6c46..a417d7b196c2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5024,18 +5024,12 @@ bool intel_display_power_enabled(struct drm_device *dev, } } -void intel_set_power_well(struct drm_device *dev, bool enable) +static void __intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; uint32_t tmp; - if (!HAS_POWER_WELL(dev)) - return; - - if (!i915_disable_power_well && !enable) - return; - tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE; enable_requested = tmp & HSW_PWR_WELL_ENABLE; @@ -5058,6 +5052,79 @@ void intel_set_power_well(struct drm_device *dev, bool enable) } } +static struct i915_power_well *hsw_pwr; + +/* Display audio driver power well request */ +void i915_request_power_well(void) +{ + if (WARN_ON(!hsw_pwr)) + return; + + spin_lock_irq(&hsw_pwr->lock); + if (!hsw_pwr->count++ && + !hsw_pwr->i915_request) + __intel_set_power_well(hsw_pwr->device, true); + spin_unlock_irq(&hsw_pwr->lock); +} +EXPORT_SYMBOL_GPL(i915_request_power_well); + +/* Display audio driver power well release */ +void i915_release_power_well(void) +{ + if (WARN_ON(!hsw_pwr)) + return; + + spin_lock_irq(&hsw_pwr->lock); + WARN_ON(!hsw_pwr->count); + if (!--hsw_pwr->count && + !hsw_pwr->i915_request) + __intel_set_power_well(hsw_pwr->device, false); + spin_unlock_irq(&hsw_pwr->lock); +} +EXPORT_SYMBOL_GPL(i915_release_power_well); + +int i915_init_power_well(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + hsw_pwr = &dev_priv->power_well; + + hsw_pwr->device = dev; + spin_lock_init(&hsw_pwr->lock); + hsw_pwr->count = 0; + + return 0; +} + +void i915_remove_power_well(struct drm_device *dev) +{ + hsw_pwr = NULL; +} + +void intel_set_power_well(struct drm_device *dev, bool enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_power_well *power_well = &dev_priv->power_well; + + if (!HAS_POWER_WELL(dev)) + return; + + if (!i915_disable_power_well && !enable) + return; + + spin_lock_irq(&power_well->lock); + power_well->i915_request = enable; + + /* only reject "disable" power well request */ + if (power_well->count && !enable) { + spin_unlock_irq(&power_well->lock); + return; + } + + __intel_set_power_well(dev, enable); + spin_unlock_irq(&power_well->lock); +} + /* * Starting with Haswell, we have a "Power Down Well" that can be turned off * when not needed anymore. We have 4 registers that can request the power well diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h new file mode 100644 index 000000000000..cfdc884405b7 --- /dev/null +++ b/include/drm/i915_powerwell.h @@ -0,0 +1,36 @@ +/************************************************************************** + * + * Copyright 2013 Intel Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + **************************************************************************/ + +#ifndef _I915_POWERWELL_H_ +#define _I915_POWERWELL_H_ + +/* For use by hda_i915 driver */ +extern void i915_request_power_well(void); +extern void i915_release_power_well(void); + +#endif /* _I915_POWERWELL_H_ */ -- cgit v1.2.3 From bb760063790fbbc3c956f23aff4dbdfdd3c03818 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Jun 2013 14:55:52 +0200 Subject: drm/i915: pipe config quirk infrastructure plus sdvo mode.flags fix For various reasons the hw state readout might not be able to faithfully match the hw state: - broken hw (like the case which motivated this patch here where the sdvo encoder does not implemented mandatory functionality correctly). - platforms which are not supported fully with the pipe config infrastructure - if our code doesn't support a given hw configuration natively, e.g. special restrictions on the per-pipe panel fitters when they're used in high-quality scaling modes. In all these cases both fastboot and the hw state cross checker need to be aware of these cases and act accordingly. To be able to do this add a new quirk flag to the pipe config structure. The specific case at hand is an sdvo encoder which doesn't implement the get_timings function, so adjusted_mode flags will be wrong. The strange thing though is that the encoder _does_ work, even though it doesn't implement any of the timings functions (so neither get nor set, neither for input nor output timings). Not that non-compliant sdvo encoder are any surprise at all ... v2: - Don't read random garbage from the dtd if the get_timings call failed (suggested by Chris). - Still check the interlaced flag, that's read out from someplace else. We want maximal paranoia, after all. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 22 ++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 11 +++++++++++ drivers/gpu/drm/i915/intel_sdvo.c | 24 +++++++++++++----------- 3 files changed, 38 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 421b7e2ece3b..8d9e7c0e9e4b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8091,6 +8091,9 @@ intel_pipe_config_compare(struct drm_device *dev, return false; \ } +#define PIPE_CONF_QUIRK(quirk) \ + ((current_config->quirks | pipe_config->quirks) & (quirk)) + PIPE_CONF_CHECK_I(cpu_transcoder); PIPE_CONF_CHECK_I(has_pch_encoder); @@ -8121,14 +8124,16 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, DRM_MODE_FLAG_INTERLACE); - PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, - DRM_MODE_FLAG_PHSYNC); - PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, - DRM_MODE_FLAG_NHSYNC); - PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, - DRM_MODE_FLAG_PVSYNC); - PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, - DRM_MODE_FLAG_NVSYNC); + if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) { + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NHSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_PVSYNC); + PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags, + DRM_MODE_FLAG_NVSYNC); + } PIPE_CONF_CHECK_I(requested_mode.hdisplay); PIPE_CONF_CHECK_I(requested_mode.vdisplay); @@ -8145,6 +8150,7 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS +#undef PIPE_CONF_QUIRK return true; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1735cdc86770..b76a956cfb9a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -193,6 +193,17 @@ typedef struct dpll { } intel_clock_t; struct intel_crtc_config { + /** + * quirks - bitfield with hw state readout quirks + * + * For various reasons the hw state readout code might not be able to + * completely faithfully read out the current state. These cases are + * tracked with quirk flags so that fastboot and state checker can act + * accordingly. + */ +#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ + unsigned long quirks; + struct drm_display_mode requested_mode; struct drm_display_mode adjusted_mode; /* This flag must be set by the encoder's compute_config callback if it diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 5c816dd75bec..960358d8e336 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1324,19 +1324,21 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd); if (!ret) { + /* Some sdvo encoders are not spec compliant and don't + * implement the mandatory get_timings function. */ DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n"); - return; - } - - if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) - flags |= DRM_MODE_FLAG_PHSYNC; - else - flags |= DRM_MODE_FLAG_NHSYNC; + pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS; + } else { + if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; - if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) - flags |= DRM_MODE_FLAG_PVSYNC; - else - flags |= DRM_MODE_FLAG_NVSYNC; + if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } pipe_config->adjusted_mode.flags |= flags; -- cgit v1.2.3 From 3e7ca9858d51a8df2bb18b82a529df5e5f9abc51 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 1 Jun 2013 19:45:56 +0200 Subject: drm/i915: enable 30bpp for DP outputs We always limited the link bw calculations to 24bpp. Tested with my shiny new high-bpc screen, seems to work as advertised. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65280 Tested-by: shui yangwei Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 759a1c5d170d..6d560755cf53 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -704,7 +704,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, /* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ - bpp = min_t(int, 8*3, pipe_config->pipe_bpp); + bpp = pipe_config->pipe_bpp; if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp) bpp = min_t(int, bpp, dev_priv->vbt.edp_bpp); -- cgit v1.2.3 From de1aa629aac8377bdfc55674bb8e30b5f15f418d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 10:47:01 +0300 Subject: drm/i915: Disable primary plane trickle feed for g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs say that the trickle feed disable bit is present (for primary planes only, not video sprites) on CTG, and that it must be set for ELK. Just set it for all g4x chipsets. v2: Do it in init_clock_gating too Reviewed-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8d9e7c0e9e4b..3f025ee299dd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1958,6 +1958,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, dspcntr &= ~DISPPLANE_TILED; } + if (IS_G4X(dev)) + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + I915_WRITE(reg, dspcntr); linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a417d7b196c2..47f3c48cd3c2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4908,6 +4908,7 @@ static void g4x_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate; + int pipe; I915_WRITE(RENCLK_GATE_D1, 0); I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | @@ -4924,6 +4925,14 @@ static void g4x_init_clock_gating(struct drm_device *dev) /* WaDisableRenderCachePipelinedFlush */ I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + } static void crestline_init_clock_gating(struct drm_device *dev) -- cgit v1.2.3 From 20f949670f51341f255b17ec4650fa69ba22cb87 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 10:47:02 +0300 Subject: drm/i915: Disable trickle feed via MI_ARB_STATE for the gen4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to BSpec, trickle feed should be disabled for BW and mobile CL. Those constraints seem to match all of our gen4 chipsets. Trickle feed is disabled via the MI_ARB_STATE register instead of per plane controls on gen4. Reviewed-by: Chris Wilson Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 47f3c48cd3c2..2948764d7e38 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4944,6 +4944,8 @@ static void crestline_init_clock_gating(struct drm_device *dev) I915_WRITE(DSPCLK_GATE_D, 0); I915_WRITE(RAMCLK_GATE_D, 0); I915_WRITE16(DEUC, 0); + I915_WRITE(MI_ARB_STATE, + _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE)); } static void broadwater_init_clock_gating(struct drm_device *dev) @@ -4956,6 +4958,8 @@ static void broadwater_init_clock_gating(struct drm_device *dev) I965_ISC_CLOCK_GATE_DISABLE | I965_FBC_CLOCK_GATE_DISABLE); I915_WRITE(RENCLK_GATE_D2, 0); + I915_WRITE(MI_ARB_STATE, + _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE)); } static void gen3_init_clock_gating(struct drm_device *dev) -- cgit v1.2.3 From bdad2b2f31852af4eb450d6a96e38940a0a1fdef Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 10:47:03 +0300 Subject: drm/i915: Disable trickle feed in ironlake_init_clock_gating() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We disable trickle feed in all the (relevant) clock gating functions, except ironlake_init_clock_gating(). Copy paste the same code there as well. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2948764d7e38..78addac68521 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4391,6 +4391,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; + int pipe; /* Required for FBC */ dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE | @@ -4450,6 +4451,13 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + ibx_init_clock_gating(dev); } -- cgit v1.2.3 From 0e088b8f33dab39bd8beb0c7a030d44beb936dd0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 10:47:04 +0300 Subject: drm/i915: Refactor ctg+ trickle feed disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the code to disable trickle feed for all primary planes into a separate function. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 62 +++++++++++++---------------------------- 1 file changed, 19 insertions(+), 43 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 78addac68521..8faa43fc9bc9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4387,11 +4387,23 @@ static void ibx_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); } +static void g4x_disable_trickle_feed(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } +} + static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; - int pipe; /* Required for FBC */ dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE | @@ -4451,12 +4463,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } + g4x_disable_trickle_feed(dev); ibx_init_clock_gating(dev); } @@ -4512,7 +4519,6 @@ static void gen6_check_mch_setup(struct drm_device *dev) static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE; I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate); @@ -4588,12 +4594,7 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | GEN6_MBCTL_ENABLE_BOOT_FETCH); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } + g4x_disable_trickle_feed(dev); /* The default value should be 0x200 according to docs, but the two * platforms I checked have a 0 for this. (Maybe BIOS overrides?) */ @@ -4654,7 +4655,6 @@ static void lpt_suspend_hw(struct drm_device *dev) static void haswell_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; I915_WRITE(WM3_LP_ILK, 0); I915_WRITE(WM2_LP_ILK, 0); @@ -4680,12 +4680,7 @@ static void haswell_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } + g4x_disable_trickle_feed(dev); /* WaVSRefCountFullforceMissDisable:hsw */ gen7_setup_fixed_func_scheduler(dev_priv); @@ -4711,7 +4706,6 @@ static void haswell_init_clock_gating(struct drm_device *dev) static void ivybridge_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; uint32_t snpcr; I915_WRITE(WM3_LP_ILK, 0); @@ -4780,12 +4774,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } + g4x_disable_trickle_feed(dev); /* WaMbcDriverBootEnable:ivb */ I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) | @@ -4812,7 +4801,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) static void valleyview_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); @@ -4885,12 +4873,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } + g4x_disable_trickle_feed(dev); I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); @@ -4916,7 +4899,6 @@ static void g4x_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate; - int pipe; I915_WRITE(RENCLK_GATE_D1, 0); I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | @@ -4934,13 +4916,7 @@ static void g4x_init_clock_gating(struct drm_device *dev) I915_WRITE(CACHE_MODE_0, _MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE)); - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } - + g4x_disable_trickle_feed(dev); } static void crestline_init_clock_gating(struct drm_device *dev) -- cgit v1.2.3 From c65355bbefaf02d8819a810aacfd566634e3b146 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 6 Jun 2013 16:53:41 -0300 Subject: drm/i915: Track when we dirty the scanout with render commands This is required for tracking render damage for use with FBC and will be used in subsequent patches. Signed-off-by: Chris Wilson Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++---- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a8bb62ca8756..c98333d74111 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -786,7 +786,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, obj->dirty = 1; obj->last_write_seqno = intel_ring_get_seqno(ring); if (obj->pin_count) /* check for potential scanout */ - intel_mark_fb_busy(obj); + intel_mark_fb_busy(obj, ring); } trace_i915_gem_object_change_domain(obj, old_read, old_write); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3f025ee299dd..7b9eb7ccc09a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7112,7 +7112,8 @@ void intel_mark_idle(struct drm_device *dev) } } -void intel_mark_fb_busy(struct drm_i915_gem_object *obj) +void intel_mark_fb_busy(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) { struct drm_device *dev = obj->base.dev; struct drm_crtc *crtc; @@ -7124,8 +7125,12 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj) if (!crtc->fb) continue; - if (to_intel_framebuffer(crtc->fb)->obj == obj) - intel_increase_pllclock(crtc); + if (to_intel_framebuffer(crtc->fb)->obj != obj) + continue; + + intel_increase_pllclock(crtc); + if (ring && intel_fbc_enabled(dev)) + ring->fbc_dirty = true; } } @@ -7575,7 +7580,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_pending; intel_disable_fbc(dev); - intel_mark_fb_busy(obj); + intel_mark_fb_busy(obj, NULL); mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b76a956cfb9a..bb4822a6c41e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -574,7 +574,8 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_mark_busy(struct drm_device *dev); -extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); +extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring); extern void intel_mark_idle(struct drm_device *dev); extern bool intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 4c7e103e6fa4..efc403d1e3e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -140,6 +140,7 @@ struct intel_ring_buffer { */ u32 outstanding_lazy_request; bool gpu_caches_dirty; + bool fbc_dirty; wait_queue_head_t irq_queue; -- cgit v1.2.3 From fd3da6c95b6d865446fa9b29df6edff4343e385a Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 6 Jun 2013 16:58:16 -0300 Subject: drm/i915: WA: FBC Render Nuke. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WaFbcNukeOn3DBlt for IVB, HSW. According BSPec: "Workaround: Do not enable Render Command Streamer tracking for FBC. Instead insert a LRI to address 0x50380 with data 0x00000004 after the PIPE_CONTROL that follows each render submission." v2: Chris noticed that flush_domains check was missing here and also suggested to do LRI only when fbc is enabled. To avoid do a I915_READ on every flush lets use the module parameter check. v3: Adding Wa name as Damien suggested. v4: Ville noticed VLV doesn't support fbc at all and comment came wrong from spec. v5: Ville noticed than on blt a Cache Clean LRI should be used instead the Nuke one. v6: Check for flush domain on blt (by Ville). Check for scanout dirty (by Chris). v7: Apply proper fbc_dirty implemented by Chris. v8: remove unused variables. Cc: Ville Syrjälä Cc: Chris Wilson Signed-off-by: Rodrigo Vivi Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ff9f71af9347..b1fdca9e96bb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1020,6 +1020,10 @@ #define IPS_CTL 0x43408 #define IPS_ENABLE (1 << 31) +#define MSG_FBC_REND_STATE 0x50380 +#define FBC_REND_NUKE (1<<2) +#define FBC_REND_CACHE_CLEAN (1<<1) + #define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0 #define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4 #define HSW_BYPASS_FBC_QUEUE (1<<22) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8faa43fc9bc9..adc44e42b23c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -274,7 +274,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); + I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset); I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X | IVB_DPFC_CTL_FENCE_EN | diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0e72da6ad0fa..1ef081cd1706 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -280,6 +280,27 @@ gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring) return 0; } +static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value) +{ + int ret; + + if (!ring->fbc_dirty) + return 0; + + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; + intel_ring_emit(ring, MI_NOOP); + /* WaFbcNukeOn3DBlt:ivb/hsw */ + intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); + intel_ring_emit(ring, MSG_FBC_REND_STATE); + intel_ring_emit(ring, value); + intel_ring_advance(ring); + + ring->fbc_dirty = false; + return 0; +} + static int gen7_render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) @@ -336,6 +357,9 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_advance(ring); + if (flush_domains) + return gen7_ring_fbc_flush(ring, FBC_REND_NUKE); + return 0; } @@ -1685,6 +1709,7 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, static int gen6_ring_flush(struct intel_ring_buffer *ring, u32 invalidate, u32 flush) { + struct drm_device *dev = ring->dev; uint32_t cmd; int ret; @@ -1707,6 +1732,10 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, 0); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); + + if (IS_GEN7(dev) && flush) + return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN); + return 0; } -- cgit v1.2.3 From 22e407d749a418b4bb4cc93ef76e0429a9f83c82 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 18:52:24 +0300 Subject: drm/i915: Make g4x_fixup_plane() operational again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't enable the cursor until g4x_fixup_plane() had a chance to do cast its magic spell. Egbert writes: "Today I had the chance to test this. First I tried if I can still reproduce the blank with this patch added when I disable my voodoo g4x_fixup_plane(): It turned out it still happens however very rarely (like 1 out of 20 tries). When I reenabled my voodoo the issue still occurred. I had to switch two lines around, ie: intel_enable_plane(dev_priv, plane, pipe); if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); + intel_crtc_update_cursor(crtc, true); to avoid the blank screen issue - which is it didn't happen in ~75 tries." v2: Add a comment to remind people of the ordering constraints Acked-by: Egbert Eich Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7b9eb7ccc09a..6b37b7555f24 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3700,9 +3700,10 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); intel_enable_planes(crtc); - intel_crtc_update_cursor(crtc, true); + /* The fixup needs to happen before cursor is enabled */ if (IS_G4X(dev)) g4x_fixup_plane(dev_priv, pipe); + intel_crtc_update_cursor(crtc, true); /* Give the overlay scaler a chance to enable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, true); -- cgit v1.2.3 From e596a02ccfc6503ae5c37b14c74b6b743eefe102 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 9 Jun 2013 16:02:05 +0100 Subject: drm/i915: Remove dead code from SDVO initialisation The hotplug_mask is no longer used as the hpd interrupt setup is now handled in the core. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 960358d8e336..ac923b74924a 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2850,7 +2850,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_sdvo *intel_sdvo; - u32 hotplug_mask; int i; intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); if (!intel_sdvo) @@ -2879,18 +2878,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) } } - hotplug_mask = 0; - if (IS_G4X(dev)) { - hotplug_mask = intel_sdvo->is_sdvob ? - SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X; - } else if (IS_GEN4(dev)) { - hotplug_mask = intel_sdvo->is_sdvob ? - SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965; - } else { - hotplug_mask = intel_sdvo->is_sdvob ? - SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915; - } - /* Only enable the hotplug irq if we need it, to work around noisy * hotplug lines. */ -- cgit v1.2.3 From b6f3eff7130bbdb3d3ca5b7bbff2384b362606b4 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 10 Jun 2013 15:48:09 +0100 Subject: drm/i915: Use FBINFO_STATE defines instead of 0 and 1 This makes, arguably, the condition on state easier to read. Suggested-by: Chris Wilson Signed-off-by: Damien Lespiau Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 6 +++--- drivers/gpu/drm/i915/intel_fb.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b23cd63b9fda..381c9dd4ab60 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -546,7 +546,7 @@ static int i915_drm_freeze(struct drm_device *dev) intel_opregion_fini(dev); console_lock(); - intel_fbdev_set_suspend(dev, 1); + intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED); console_unlock(); return 0; @@ -590,7 +590,7 @@ void intel_console_resume(struct work_struct *work) struct drm_device *dev = dev_priv->dev; console_lock(); - intel_fbdev_set_suspend(dev, 0); + intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING); console_unlock(); } @@ -659,7 +659,7 @@ static int __i915_drm_thaw(struct drm_device *dev) * path of resume if possible. */ if (console_trylock()) { - intel_fbdev_set_suspend(dev, 0); + intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING); console_unlock(); } else { schedule_work(&dev_priv->console_resume_work); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 7a77d4cf96c2..244060ad354b 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -275,7 +275,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) * been restored from swap. If the object is stolen however, it will be * full of whatever garbage was left in there. */ - if (!state && ifbdev->ifb.obj->stolen) + if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) memset_io(info->screen_base, 0, info->screen_size); fb_set_suspend(info, state); -- cgit v1.2.3 From cdbd2316a03f68b25a135a34d1d24f01ddef0c53 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:03 +0200 Subject: drm/i915: fix up pch pll handling in ->mode_set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We ->mode_set is called we can't just blindly reuse an existing pll since that might be shared with a different, still active pch output. v2: Only update the pll settings when the pch pll is know to be unused, otherwise we can wreak havoc with a running pipe. Which in the case of DP will likely result in a black screen due to loss of link lock. v3: Tighten up the asserts a bit more, especially make sure that the pch pll is still enabled when we try to disable it. This would have caught the bug fixed in this patch. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b37b7555f24..1d0aa24bb899 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1427,7 +1427,8 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) /* PCH refclock must be enabled first */ assert_pch_refclk_enabled(dev_priv); - if (pll->active++ && pll->on) { + if (pll->active++) { + WARN_ON(!pll->on); assert_pch_pll_enabled(dev_priv, pll, NULL); return; } @@ -1468,10 +1469,9 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) return; } - if (--pll->active) { - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_pch_pll_enabled(dev_priv, pll, NULL); + if (--pll->active) return; - } DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); @@ -3081,9 +3081,9 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 pll = intel_crtc->pch_pll; if (pll) { - DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n", + DRM_DEBUG_KMS("CRTC:%d dropping existing PCH PLL %x\n", intel_crtc->base.base.id, pll->pll_reg); - goto prepare; + intel_put_pch_pll(intel_crtc); } if (HAS_PCH_IBX(dev_priv->dev)) { @@ -3128,19 +3128,22 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 found: intel_crtc->pch_pll = pll; - pll->refcount++; DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe)); -prepare: /* separate function? */ - DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg); + if (pll->active == 0) { + DRM_DEBUG_DRIVER("setting up pll %d\n", i); + WARN_ON(pll->on); + assert_pch_pll_disabled(dev_priv, pll, NULL); - /* Wait for the clocks to stabilize before rewriting the regs */ - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(pll->pll_reg); - udelay(150); + /* Wait for the clocks to stabilize before rewriting the regs */ + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(pll->pll_reg); + udelay(150); + + I915_WRITE(pll->fp0_reg, fp); + I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + } + pll->refcount++; - I915_WRITE(pll->fp0_reg, fp); - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); - pll->on = false; return pll; } -- cgit v1.2.3 From d925c59a8174c8c150da7e0a38e35d89a8e7149c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:04 +0200 Subject: drm/i915: conditionally disable pch resources in ilk_crtc_disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simlar to how disable already works on haswell. This is possible since we now carefully track the pch state in the pipe config. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 69 +++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d0aa24bb899..39984fb07fa9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3436,7 +3436,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_disable_planes(crtc); intel_disable_plane(dev_priv, plane, pipe); - intel_set_pch_fifo_underrun_reporting(dev, pipe, false); + if (intel_crtc->config.has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev, pipe, false); + intel_disable_pipe(dev_priv, pipe); ironlake_pfit_disable(intel_crtc); @@ -3445,42 +3447,45 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) if (encoder->post_disable) encoder->post_disable(encoder); - ironlake_fdi_disable(crtc); + if (intel_crtc->config.has_pch_encoder) { + ironlake_fdi_disable(crtc); - ironlake_disable_pch_transcoder(dev_priv, pipe); - intel_set_pch_fifo_underrun_reporting(dev, pipe, true); + ironlake_disable_pch_transcoder(dev_priv, pipe); + intel_set_pch_fifo_underrun_reporting(dev, pipe, true); - if (HAS_PCH_CPT(dev)) { - /* disable TRANS_DP_CTL */ - reg = TRANS_DP_CTL(pipe); - temp = I915_READ(reg); - temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); - temp |= TRANS_DP_PORT_SEL_NONE; - I915_WRITE(reg, temp); - - /* disable DPLL_SEL */ - temp = I915_READ(PCH_DPLL_SEL); - switch (pipe) { - case 0: - temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); - break; - case 1: - temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - break; - case 2: - /* C shares PLL A or B */ - temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); - break; - default: - BUG(); /* wtf */ + if (HAS_PCH_CPT(dev)) { + /* disable TRANS_DP_CTL */ + reg = TRANS_DP_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_PORT_SEL_MASK); + temp |= TRANS_DP_PORT_SEL_NONE; + I915_WRITE(reg, temp); + + /* disable DPLL_SEL */ + temp = I915_READ(PCH_DPLL_SEL); + switch (pipe) { + case 0: + temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); + break; + case 1: + temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + break; + case 2: + /* C shares PLL A or B */ + temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); + break; + default: + BUG(); /* wtf */ + } + I915_WRITE(PCH_DPLL_SEL, temp); } - I915_WRITE(PCH_DPLL_SEL, temp); - } - /* disable PCH DPLL */ - intel_disable_pch_pll(intel_crtc); + /* disable PCH DPLL */ + intel_disable_pch_pll(intel_crtc); - ironlake_fdi_pll_disable(intel_crtc); + ironlake_fdi_pll_disable(intel_crtc); + } intel_crtc->active = false; intel_update_watermarks(dev); -- cgit v1.2.3 From f4a091c71baa55dc8822614ab716525779623c1c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Jun 2013 17:28:22 +0200 Subject: drm/i915: lock down pch pll accouting some more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before I start to make a complete mess out of this, crank up the paranoia level a bit. v2: Kill the has_pch_encoder check in put_shared_dpll - it's invalid as spotted by Ville since we currently only put the dpll when we already have the new pipe config. So a direct pch port -> cpu edp transition will hit this. v3: Now that I've lifted my blinders add the WARN_ON Ville requested. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 39984fb07fa9..34e6bf3b1142 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1432,6 +1432,7 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) assert_pch_pll_enabled(dev_priv, pll, NULL); return; } + WARN_ON(pll->on); DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg); @@ -1470,6 +1471,7 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) } assert_pch_pll_enabled(dev_priv, pll, NULL); + WARN_ON(!pll->on); if (--pll->active) return; @@ -3069,7 +3071,11 @@ static void intel_put_pch_pll(struct intel_crtc *intel_crtc) return; } - --pll->refcount; + if (--pll->refcount == 0) { + WARN_ON(pll->on); + WARN_ON(pll->active); + } + intel_crtc->pch_pll = NULL; } -- cgit v1.2.3 From e72f9fbf99c4277b2ccfd4d55d66aa6caf922f42 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:06 +0200 Subject: drm/i915: s/pch_pll/shared_dpll/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For fastboot we need some support to read out the sharing state of plls, at least for platforms where they can be shared (or freely assigned at least). Now for ivb we already have pretty extensive infrastructure for tracking pch plls, and it took us an aweful lot of tries to get that remotely right. Note that hsw could also share plls, but even now they're already freely assignable. So we need this on more than just ivb. So on top of the usual fastboot fun pll sharing seems to be an additional step up in fragility. Hence a common infrastructure for all shared/freely assignable display plls seems to be in order. The plan is to have a bit of dpll hw state readout code, which can be used individually, but also to fill in the pipe config. The hw state cross check code will then use that information to make sure that after every modeset every pipe still is connected to a pll which still has the correct configuration - a lot of the pch pll sharing bugs where due to incorrect sharing. We start this endeavour with a simple s/pch_pll/shared_dpll/ rename job. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 14 ++--- drivers/gpu/drm/i915/i915_drv.h | 6 +- drivers/gpu/drm/i915/intel_display.c | 112 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 2 +- 4 files changed, 67 insertions(+), 67 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 381c9dd4ab60..b0a4e6834c1d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -433,7 +433,7 @@ void intel_detect_pch(struct drm_device *dev) */ if (INTEL_INFO(dev)->num_pipes == 0) { dev_priv->pch_type = PCH_NOP; - dev_priv->num_pch_pll = 0; + dev_priv->num_shared_dpll = 0; return; } @@ -452,34 +452,34 @@ void intel_detect_pch(struct drm_device *dev) if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_IBX; - dev_priv->num_pch_pll = 2; + dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); WARN_ON(!IS_GEN5(dev)); } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_CPT; - dev_priv->num_pch_pll = 2; + dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found CougarPoint PCH\n"); WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { /* PantherPoint is CPT compatible */ dev_priv->pch_type = PCH_CPT; - dev_priv->num_pch_pll = 2; + dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found PatherPoint PCH\n"); WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; - dev_priv->num_pch_pll = 0; + dev_priv->num_shared_dpll = 0; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(IS_ULT(dev)); } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; - dev_priv->num_pch_pll = 0; + dev_priv->num_shared_dpll = 0; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_ULT(dev)); } - BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); + BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } pci_dev_put(pch); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 87f7f88b1030..f69ba390a649 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -132,7 +132,7 @@ enum hpd_pin { list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ if ((intel_encoder)->base.crtc == (__crtc)) -struct intel_pch_pll { +struct intel_shared_dpll { int refcount; /* count of number of CRTCs sharing this PLL */ int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ @@ -1026,7 +1026,6 @@ typedef struct drm_i915_private { u32 hpd_event_bits; struct timer_list hotplug_reenable_timer; - int num_pch_pll; int num_plane; unsigned long cfb_size; @@ -1087,7 +1086,8 @@ typedef struct drm_i915_private { struct drm_crtc *pipe_to_crtc_mapping[3]; wait_queue_head_t pending_flip_queue; - struct intel_pch_pll pch_plls[I915_NUM_PLLS]; + int num_shared_dpll; + struct intel_shared_dpll shared_dplls[I915_NUM_PLLS]; struct intel_ddi_plls ddi_plls; /* Reclocking support */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 34e6bf3b1142..d138b302f275 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -910,10 +910,10 @@ static void assert_pll(struct drm_i915_private *dev_priv, #define assert_pll_disabled(d, p) assert_pll(d, p, false) /* For ILK+ */ -static void assert_pch_pll(struct drm_i915_private *dev_priv, - struct intel_pch_pll *pll, - struct intel_crtc *crtc, - bool state) +static void assert_shared_dpll(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_crtc *crtc, + bool state) { u32 val; bool cur_state; @@ -952,8 +952,8 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv, } } } -#define assert_pch_pll_enabled(d, p, c) assert_pch_pll(d, p, c, true) -#define assert_pch_pll_disabled(d, p, c) assert_pch_pll(d, p, c, false) +#define assert_shared_dpll_enabled(d, p, c) assert_shared_dpll(d, p, c, true) +#define assert_shared_dpll_disabled(d, p, c) assert_shared_dpll(d, p, c, false) static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum pipe pipe, bool state) @@ -1397,23 +1397,23 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) } /** - * ironlake_enable_pch_pll - enable PCH PLL + * ironlake_enable_shared_dpll - enable PCH PLL * @dev_priv: i915 private structure * @pipe: pipe PLL to enable * * The PCH PLL needs to be enabled before the PCH transcoder, since it * drives the transcoder clock. */ -static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) +static void ironlake_enable_shared_dpll(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_pch_pll *pll; + struct intel_shared_dpll *pll; int reg; u32 val; /* PCH PLLs only available on ILK, SNB and IVB */ BUG_ON(dev_priv->info->gen < 5); - pll = intel_crtc->pch_pll; + pll = intel_crtc->shared_dpll; if (pll == NULL) return; @@ -1429,7 +1429,7 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) if (pll->active++) { WARN_ON(!pll->on); - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_shared_dpll_enabled(dev_priv, pll, NULL); return; } WARN_ON(pll->on); @@ -1446,10 +1446,10 @@ static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc) pll->on = true; } -static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) +static void intel_disable_shared_dpll(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_pch_pll *pll = intel_crtc->pch_pll; + struct intel_shared_dpll *pll = intel_crtc->shared_dpll; int reg; u32 val; @@ -1466,11 +1466,11 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) intel_crtc->base.base.id); if (WARN_ON(pll->active == 0)) { - assert_pch_pll_disabled(dev_priv, pll, NULL); + assert_shared_dpll_disabled(dev_priv, pll, NULL); return; } - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_shared_dpll_enabled(dev_priv, pll, NULL); WARN_ON(!pll->on); if (--pll->active) return; @@ -1501,9 +1501,9 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, BUG_ON(dev_priv->info->gen < 5); /* Make sure PCH DPLL is enabled */ - assert_pch_pll_enabled(dev_priv, - to_intel_crtc(crtc)->pch_pll, - to_intel_crtc(crtc)); + assert_shared_dpll_enabled(dev_priv, + to_intel_crtc(crtc)->shared_dpll, + to_intel_crtc(crtc)); /* FDI must be feeding us bits for PCH ports */ assert_fdi_tx_enabled(dev_priv, pipe); @@ -2966,10 +2966,10 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) * transcoder, and we actually should do this to not upset any PCH * transcoder that already use the clock when we share it. * - * Note that enable_pch_pll tries to do the right thing, but get_pch_pll - * unconditionally resets the pll - we need that to have the right LVDS - * enable sequence. */ - ironlake_enable_pch_pll(intel_crtc); + * Note that enable_shared_dpll tries to do the right thing, but + * get_shared_dpll unconditionally resets the pll - we need that to have + * the right LVDS enable sequence. */ + ironlake_enable_shared_dpll(intel_crtc); if (HAS_PCH_CPT(dev)) { u32 sel; @@ -2990,7 +2990,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) sel = TRANSC_DPLLB_SEL; break; } - if (intel_crtc->pch_pll->pll_reg == _PCH_DPLL_B) + if (intel_crtc->shared_dpll->pll_reg == _PCH_DPLL_B) temp |= sel; else temp &= ~sel; @@ -3059,9 +3059,9 @@ static void lpt_pch_enable(struct drm_crtc *crtc) lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } -static void intel_put_pch_pll(struct intel_crtc *intel_crtc) +static void intel_put_shared_dpll(struct intel_crtc *intel_crtc) { - struct intel_pch_pll *pll = intel_crtc->pch_pll; + struct intel_shared_dpll *pll = intel_crtc->shared_dpll; if (pll == NULL) return; @@ -3076,26 +3076,26 @@ static void intel_put_pch_pll(struct intel_crtc *intel_crtc) WARN_ON(pll->active); } - intel_crtc->pch_pll = NULL; + intel_crtc->shared_dpll = NULL; } -static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp) +static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_pch_pll *pll; + struct intel_shared_dpll *pll; int i; - pll = intel_crtc->pch_pll; + pll = intel_crtc->shared_dpll; if (pll) { DRM_DEBUG_KMS("CRTC:%d dropping existing PCH PLL %x\n", intel_crtc->base.base.id, pll->pll_reg); - intel_put_pch_pll(intel_crtc); + intel_put_shared_dpll(intel_crtc); } if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ i = intel_crtc->pipe; - pll = &dev_priv->pch_plls[i]; + pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n", intel_crtc->base.base.id, pll->pll_reg); @@ -3103,8 +3103,8 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 goto found; } - for (i = 0; i < dev_priv->num_pch_pll; i++) { - pll = &dev_priv->pch_plls[i]; + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ if (pll->refcount == 0) @@ -3121,8 +3121,8 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 } /* Ok no matching timings, maybe there's a free one? */ - for (i = 0; i < dev_priv->num_pch_pll; i++) { - pll = &dev_priv->pch_plls[i]; + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + pll = &dev_priv->shared_dplls[i]; if (pll->refcount == 0) { DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n", intel_crtc->base.base.id, pll->pll_reg); @@ -3133,12 +3133,12 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3 return NULL; found: - intel_crtc->pch_pll = pll; + intel_crtc->shared_dpll = pll; DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe)); if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up pll %d\n", i); WARN_ON(pll->on); - assert_pch_pll_disabled(dev_priv, pll, NULL); + assert_shared_dpll_disabled(dev_priv, pll, NULL); /* Wait for the clocks to stabilize before rewriting the regs */ I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); @@ -3488,7 +3488,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) } /* disable PCH DPLL */ - intel_disable_pch_pll(intel_crtc); + intel_disable_shared_dpll(intel_crtc); ironlake_fdi_pll_disable(intel_crtc); } @@ -3561,7 +3561,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) static void ironlake_crtc_off(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_put_pch_pll(intel_crtc); + intel_put_shared_dpll(intel_crtc); } static void haswell_crtc_off(struct drm_crtc *crtc) @@ -5765,7 +5765,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ if (intel_crtc->config.has_pch_encoder) { - struct intel_pch_pll *pll; + struct intel_shared_dpll *pll; fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll); if (has_reduced_clock) @@ -5775,14 +5775,14 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); - pll = intel_get_pch_pll(intel_crtc, dpll, fp); + pll = intel_get_shared_dpll(intel_crtc, dpll, fp); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", pipe_name(pipe)); return -EINVAL; } } else - intel_put_pch_pll(intel_crtc); + intel_put_shared_dpll(intel_crtc); if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); @@ -5791,11 +5791,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - if (intel_crtc->pch_pll) { - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + if (intel_crtc->shared_dpll) { + I915_WRITE(intel_crtc->shared_dpll->pll_reg, dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(intel_crtc->pch_pll->pll_reg); + POSTING_READ(intel_crtc->shared_dpll->pll_reg); udelay(150); /* The pixel multiplier can only be updated once the @@ -5803,16 +5803,16 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * * So write it again. */ - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); + I915_WRITE(intel_crtc->shared_dpll->pll_reg, dpll); } intel_crtc->lowfreq_avail = false; - if (intel_crtc->pch_pll) { + if (intel_crtc->shared_dpll) { if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); + I915_WRITE(intel_crtc->shared_dpll->fp1_reg, fp2); intel_crtc->lowfreq_avail = true; } else { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); + I915_WRITE(intel_crtc->shared_dpll->fp1_reg, fp); } } @@ -8723,20 +8723,20 @@ static void intel_cpu_pll_init(struct drm_device *dev) intel_ddi_pll_init(dev); } -static void intel_pch_pll_init(struct drm_device *dev) +static void intel_shared_dpll_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int i; - if (dev_priv->num_pch_pll == 0) { + if (dev_priv->num_shared_dpll == 0) { DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n"); return; } - for (i = 0; i < dev_priv->num_pch_pll; i++) { - dev_priv->pch_plls[i].pll_reg = _PCH_DPLL(i); - dev_priv->pch_plls[i].fp0_reg = _PCH_FP0(i); - dev_priv->pch_plls[i].fp1_reg = _PCH_FP1(i); + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + dev_priv->shared_dplls[i].pll_reg = _PCH_DPLL(i); + dev_priv->shared_dplls[i].fp0_reg = _PCH_FP0(i); + dev_priv->shared_dplls[i].fp1_reg = _PCH_FP1(i); } } @@ -9428,7 +9428,7 @@ void intel_modeset_init(struct drm_device *dev) } intel_cpu_pll_init(dev); - intel_pch_pll_init(dev); + intel_shared_dpll_init(dev); /* Just disable it once at startup */ i915_disable_vga(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb4822a6c41e..b094260f1e2b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -317,7 +317,7 @@ struct intel_crtc { struct intel_crtc_config config; /* We can share PLLs across outputs if the timings match */ - struct intel_pch_pll *pch_pll; + struct intel_shared_dpll *shared_dpll; uint32_t ddi_pll_sel; /* reset counter value when the last flip was submitted */ -- cgit v1.2.3 From e2b78267421c2b407409772119a4aa500da56cc8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Jun 2013 23:10:03 +0200 Subject: drm/i915: switch crtc->shared_dpll from a pointer to an enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dealing with discrete enum values is simpler for hw state readout and pipe config computations than pointers - having neat names instead of chasing pointers should look better in the code. This isn't a that good reason for pch plls, but on haswell we actually have 3 different types of plls: WRPLL, SPLL and the DP clocks. Having explicit names should help there. Since this also adds the intel_crtc_to_shared_dpll helper to further abstract away the crtc -> dpll relationship this will also help to make the next patch simpler, which moves the shared dpll into the pipe configuration. Also note that for uniformity we have two special dpll ids: NONE for pipes which need a shared pll but don't have one (yet) and private for when there's a non-shared pll (e.g. per-pipe or per-port pll). I've thought whether we should also add a 2nd enum for the type of the pll we want (for really generic pll selection code) but thrown that idea out again - likely there's too much platform craziness going on to be able to share the pll selection logic much. Since this touched all the shared_pll functions a bit I've also done an s/intel_crtc/crtc/ replacement on a few of them. v2: Kill DPLL_ID_NONE. It's probably better to call it DPLL_ID_INVALID and use it to check that the compute config stage assigns a dpll to every pipe. But since that code isn't ready yet until we move the dpll selection out of the ->mode_set callback, there's no use for it. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++ drivers/gpu/drm/i915/intel_display.c | 90 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 58 insertions(+), 41 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f69ba390a649..d83c80a9c0b9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -140,6 +140,13 @@ struct intel_shared_dpll { int fp0_reg; int fp1_reg; }; + +enum intel_dpll_id { + DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ + /* real shared dpll ids must be >= 0 */ + DPLL_ID_PCH_PLL_A, + DPLL_ID_PCH_PLL_B, +}; #define I915_NUM_PLLS 2 /* Used by dp and fdi links */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d138b302f275..60df867f6fc6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -909,6 +909,17 @@ static void assert_pll(struct drm_i915_private *dev_priv, #define assert_pll_enabled(d, p) assert_pll(d, p, true) #define assert_pll_disabled(d, p) assert_pll(d, p, false) +static struct intel_shared_dpll * +intel_crtc_to_shared_dpll(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (crtc->shared_dpll < 0) + return NULL; + + return &dev_priv->shared_dplls[crtc->shared_dpll]; +} + /* For ILK+ */ static void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, @@ -1404,16 +1415,15 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port) * The PCH PLL needs to be enabled before the PCH transcoder, since it * drives the transcoder clock. */ -static void ironlake_enable_shared_dpll(struct intel_crtc *intel_crtc) +static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_shared_dpll *pll; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); int reg; u32 val; /* PCH PLLs only available on ILK, SNB and IVB */ BUG_ON(dev_priv->info->gen < 5); - pll = intel_crtc->shared_dpll; if (pll == NULL) return; @@ -1422,7 +1432,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *intel_crtc) DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n", pll->pll_reg, pll->active, pll->on, - intel_crtc->base.base.id); + crtc->base.base.id); /* PCH refclock must be enabled first */ assert_pch_refclk_enabled(dev_priv); @@ -1446,10 +1456,10 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *intel_crtc) pll->on = true; } -static void intel_disable_shared_dpll(struct intel_crtc *intel_crtc) +static void intel_disable_shared_dpll(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_shared_dpll *pll = intel_crtc->shared_dpll; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); int reg; u32 val; @@ -1463,7 +1473,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *intel_crtc) DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n", pll->pll_reg, pll->active, pll->on, - intel_crtc->base.base.id); + crtc->base.base.id); if (WARN_ON(pll->active == 0)) { assert_shared_dpll_disabled(dev_priv, pll, NULL); @@ -1478,7 +1488,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *intel_crtc) DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); /* Make sure transcoder isn't still depending on us */ - assert_pch_transcoder_disabled(dev_priv, intel_crtc->pipe); + assert_pch_transcoder_disabled(dev_priv, crtc->pipe); reg = pll->pll_reg; val = I915_READ(reg); @@ -1495,6 +1505,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t reg, val, pipeconf_val; /* PCH only available on ILK+ */ @@ -1502,8 +1513,8 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, /* Make sure PCH DPLL is enabled */ assert_shared_dpll_enabled(dev_priv, - to_intel_crtc(crtc)->shared_dpll, - to_intel_crtc(crtc)); + intel_crtc_to_shared_dpll(intel_crtc), + intel_crtc); /* FDI must be feeding us bits for PCH ports */ assert_fdi_tx_enabled(dev_priv, pipe); @@ -2990,7 +3001,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) sel = TRANSC_DPLLB_SEL; break; } - if (intel_crtc->shared_dpll->pll_reg == _PCH_DPLL_B) + if (intel_crtc->shared_dpll == DPLL_ID_PCH_PLL_B) temp |= sel; else temp &= ~sel; @@ -3059,9 +3070,9 @@ static void lpt_pch_enable(struct drm_crtc *crtc) lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } -static void intel_put_shared_dpll(struct intel_crtc *intel_crtc) +static void intel_put_shared_dpll(struct intel_crtc *crtc) { - struct intel_shared_dpll *pll = intel_crtc->shared_dpll; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); if (pll == NULL) return; @@ -3076,29 +3087,28 @@ static void intel_put_shared_dpll(struct intel_crtc *intel_crtc) WARN_ON(pll->active); } - intel_crtc->shared_dpll = NULL; + crtc->shared_dpll = DPLL_ID_PRIVATE; } -static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp) +static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp) { - struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - struct intel_shared_dpll *pll; - int i; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); + enum intel_dpll_id i; - pll = intel_crtc->shared_dpll; if (pll) { DRM_DEBUG_KMS("CRTC:%d dropping existing PCH PLL %x\n", - intel_crtc->base.base.id, pll->pll_reg); - intel_put_shared_dpll(intel_crtc); + crtc->base.base.id, pll->pll_reg); + intel_put_shared_dpll(crtc); } if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ - i = intel_crtc->pipe; + i = crtc->pipe; pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n", - intel_crtc->base.base.id, pll->pll_reg); + crtc->base.base.id, pll->pll_reg); goto found; } @@ -3113,7 +3123,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *intel_ if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) && fp == I915_READ(pll->fp0_reg)) { DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n", - intel_crtc->base.base.id, + crtc->base.base.id, pll->pll_reg, pll->refcount, pll->active); goto found; @@ -3125,7 +3135,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *intel_ pll = &dev_priv->shared_dplls[i]; if (pll->refcount == 0) { DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n", - intel_crtc->base.base.id, pll->pll_reg); + crtc->base.base.id, pll->pll_reg); goto found; } } @@ -3133,8 +3143,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *intel_ return NULL; found: - intel_crtc->shared_dpll = pll; - DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(intel_crtc->pipe)); + crtc->shared_dpll = i; + DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(crtc->pipe)); if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up pll %d\n", i); WARN_ON(pll->on); @@ -5730,6 +5740,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool ok, has_reduced_clock = false; bool is_lvds = false; struct intel_encoder *encoder; + struct intel_shared_dpll *pll; int ret; for_each_encoder_on_crtc(dev, crtc, encoder) { @@ -5765,8 +5776,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */ if (intel_crtc->config.has_pch_encoder) { - struct intel_shared_dpll *pll; - fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll); if (has_reduced_clock) fp2 = i9xx_dpll_compute_fp(&reduced_clock); @@ -5791,11 +5800,15 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - if (intel_crtc->shared_dpll) { - I915_WRITE(intel_crtc->shared_dpll->pll_reg, dpll); + intel_crtc->lowfreq_avail = false; + + if (intel_crtc->config.has_pch_encoder) { + pll = intel_crtc_to_shared_dpll(intel_crtc); + + I915_WRITE(pll->pll_reg, dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(intel_crtc->shared_dpll->pll_reg); + POSTING_READ(pll->pll_reg); udelay(150); /* The pixel multiplier can only be updated once the @@ -5803,16 +5816,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * * So write it again. */ - I915_WRITE(intel_crtc->shared_dpll->pll_reg, dpll); - } + I915_WRITE(pll->pll_reg, dpll); - intel_crtc->lowfreq_avail = false; - if (intel_crtc->shared_dpll) { if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(intel_crtc->shared_dpll->fp1_reg, fp2); + I915_WRITE(pll->fp1_reg, fp2); intel_crtc->lowfreq_avail = true; } else { - I915_WRITE(intel_crtc->shared_dpll->fp1_reg, fp); + I915_WRITE(pll->fp1_reg, fp); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b094260f1e2b..1d4ec204b712 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -317,7 +317,7 @@ struct intel_crtc { struct intel_crtc_config config; /* We can share PLLs across outputs if the timings match */ - struct intel_shared_dpll *shared_dpll; + enum intel_dpll_id shared_dpll; uint32_t ddi_pll_sel; /* reset counter value when the last flip was submitted */ -- cgit v1.2.3 From a43f6e0fd6219e806268d5fef67db722875393a0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Jun 2013 23:10:32 +0200 Subject: drm/i915: move shared_dpll into the pipe config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the big sed-job prep work done this is now really simple. With the exception that we only assign the right shared dpll id in the ->mode_set callback but also depend upon the old one still being around. Until that mess is fixed up we need to jump through a few hoops to keep the old value save. v2: Kill the funny whitespace spotted by Chris. v3: Move the shared_dpll pipe config fixup into this patch as noticed by Ville. Also unconditionally set the shared_dpll with the current one, since otherwise we won't handle direct pch port -> cpu edp transitions correctly. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 26 +++++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 5 +++-- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 60df867f6fc6..a5ccce07386b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -914,10 +914,10 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (crtc->shared_dpll < 0) + if (crtc->config.shared_dpll < 0) return NULL; - return &dev_priv->shared_dplls[crtc->shared_dpll]; + return &dev_priv->shared_dplls[crtc->config.shared_dpll]; } /* For ILK+ */ @@ -3001,7 +3001,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) sel = TRANSC_DPLLB_SEL; break; } - if (intel_crtc->shared_dpll == DPLL_ID_PCH_PLL_B) + if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B) temp |= sel; else temp &= ~sel; @@ -3087,7 +3087,7 @@ static void intel_put_shared_dpll(struct intel_crtc *crtc) WARN_ON(pll->active); } - crtc->shared_dpll = DPLL_ID_PRIVATE; + crtc->config.shared_dpll = DPLL_ID_PRIVATE; } static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp) @@ -3143,7 +3143,7 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, return NULL; found: - crtc->shared_dpll = i; + crtc->config.shared_dpll = i; DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(crtc->pipe)); if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up pll %d\n", i); @@ -4106,12 +4106,11 @@ static void hsw_compute_ips_config(struct intel_crtc *crtc, pipe_config->pipe_bpp == 24; } -static int intel_crtc_compute_config(struct drm_crtc *crtc, +static int intel_crtc_compute_config(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = crtc->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ @@ -4142,10 +4141,15 @@ static int intel_crtc_compute_config(struct drm_crtc *crtc, } if (IS_HASWELL(dev)) - hsw_compute_ips_config(intel_crtc, pipe_config); + hsw_compute_ips_config(crtc, pipe_config); + + /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old + * clock survives for now. */ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + pipe_config->shared_dpll = crtc->config.shared_dpll; if (pipe_config->has_pch_encoder) - return ironlake_fdi_compute_config(intel_crtc, pipe_config); + return ironlake_fdi_compute_config(crtc, pipe_config); return 0; } @@ -7910,7 +7914,7 @@ encoder_retry: if (!pipe_config->port_clock) pipe_config->port_clock = pipe_config->adjusted_mode.clock; - ret = intel_crtc_compute_config(crtc, pipe_config); + ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config); if (ret < 0) { DRM_DEBUG_KMS("CRTC fixup failed\n"); goto fail; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1d4ec204b712..b77df049b773 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -252,6 +252,9 @@ struct intel_crtc_config { * haswell. */ struct dpll dpll; + /* Selected dpll when shared or DPLL_ID_PRIVATE. */ + enum intel_dpll_id shared_dpll; + int pipe_bpp; struct intel_link_m_n dp_m_n; @@ -316,8 +319,6 @@ struct intel_crtc { struct intel_crtc_config config; - /* We can share PLLs across outputs if the timings match */ - enum intel_dpll_id shared_dpll; uint32_t ddi_pll_sel; /* reset counter value when the last flip was submitted */ -- cgit v1.2.3 From 1188739757d0e78810de5fe83dbe0128f624b9e8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:09 +0200 Subject: drm/i915: refactor PCH_DPLL_SEL #defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bits are evenly space, so we can cut down on two big switch blocks. This also greatly simplifies the hw state readout which follows in the next patch. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 +++--------- drivers/gpu/drm/i915/intel_display.c | 32 +++----------------------------- 2 files changed, 6 insertions(+), 38 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b1fdca9e96bb..99638fc6285b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3978,15 +3978,9 @@ #define PCH_SSC4_AUX_PARMS 0xc6214 #define PCH_DPLL_SEL 0xc7000 -#define TRANSA_DPLL_ENABLE (1<<3) -#define TRANSA_DPLLB_SEL (1<<0) -#define TRANSA_DPLLA_SEL 0 -#define TRANSB_DPLL_ENABLE (1<<7) -#define TRANSB_DPLLB_SEL (1<<4) -#define TRANSB_DPLLA_SEL (0) -#define TRANSC_DPLL_ENABLE (1<<11) -#define TRANSC_DPLLB_SEL (1<<8) -#define TRANSC_DPLLA_SEL (0) +#define TRANS_DPLLB_SEL(pipe) (1 << (pipe * 4)) +#define TRANS_DPLLA_SEL(pipe) 0 +#define TRANS_DPLL_ENABLE(pipe) (1 << (pipe * 4 + 3)) /* transcoder */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a5ccce07386b..d5932ef76cde 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2986,21 +2986,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) u32 sel; temp = I915_READ(PCH_DPLL_SEL); - switch (pipe) { - default: - case 0: - temp |= TRANSA_DPLL_ENABLE; - sel = TRANSA_DPLLB_SEL; - break; - case 1: - temp |= TRANSB_DPLL_ENABLE; - sel = TRANSB_DPLLB_SEL; - break; - case 2: - temp |= TRANSC_DPLL_ENABLE; - sel = TRANSC_DPLLB_SEL; - break; - } + temp |= TRANS_DPLL_ENABLE(pipe); + sel = TRANS_DPLLB_SEL(pipe); if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B) temp |= sel; else @@ -3480,20 +3467,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) /* disable DPLL_SEL */ temp = I915_READ(PCH_DPLL_SEL); - switch (pipe) { - case 0: - temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); - break; - case 1: - temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); - break; - case 2: - /* C shares PLL A or B */ - temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); - break; - default: - BUG(); /* wtf */ - } + temp &= ~(TRANS_DPLL_ENABLE(pipe) | TRANS_DPLLB_SEL(pipe)); I915_WRITE(PCH_DPLL_SEL, temp); } -- cgit v1.2.3 From c0d43d62233b3d4523a62fe88896bfc7a609e572 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Jun 2013 23:11:08 +0200 Subject: drm/i915: hw state readout for shared pch plls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Well, the first step of a long road at least, it only reads out the pipe -> shared dpll association thus far. Other state which needs to follow: - hw state of the dpll (on/off + dpll registers). Currently we just read that out from the hw state, but that doesn't work too well when the dpll is in use, but not yet fully enabled. We get away since most likely it already has been enabled and so the correct state is left behind in the registers. But that doesn't hold for atomic modesets when we want to enable all pipes at once. - Refcount reconstruction for each dpll. - Cross-checking of all the above. For that we need to keep the dpll register state both in the pipe and in the shared_dpll struct, so that we can check that every pipe is still connected to a correctly configured dpll. Note that since the refcount resconstruction isn't done yet this will spill a few WARNs at boot-up while trying to disable pch plls which have bogus refcounts. But since there's still a pile of refactoring to do I'd like to lock down the state handling as soon as possible hence decided against reordering the patches to quiet these WARNs - after all the issues they're complaining about have existed since forever, as Jesse can testify by having pch pll states blow up consistently in his fastboot patches ... v2: We need to preserve the old shared_dpll since currently the shared dpll refcount dropping/getting is done in ->mode_set. With the usual pipe_config infrastructure the old dpll id is already lost at that point, hence preserve it in the new config. v3: Rebase on top of the ips patch from Paulo. v4: We need to unconditionally take over the shared_dpll id from the old pipe config when e.g. doing a direct pch port -> cpu edp transition. v5: Move the saving of the old shared_dpll id to an ealier patch. Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d5932ef76cde..51670ba56611 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4998,6 +4998,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, uint32_t tmp; pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; tmp = I915_READ(PIPECONF(crtc->pipe)); if (!(tmp & PIPECONF_ENABLE)) @@ -5874,6 +5875,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, uint32_t tmp; pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; tmp = I915_READ(PIPECONF(crtc->pipe)); if (!(tmp & PIPECONF_ENABLE)) @@ -5891,6 +5893,16 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, /* XXX: Can't properly read out the pch dpll pixel multiplier * since we don't have state tracking for pch clocks yet. */ pipe_config->pixel_multiplier = 1; + + if (HAS_PCH_IBX(dev_priv->dev)) { + pipe_config->shared_dpll = crtc->pipe; + } else { + tmp = I915_READ(PCH_DPLL_SEL); + if (tmp & TRANS_DPLLB_SEL(crtc->pipe)) + pipe_config->shared_dpll = DPLL_ID_PCH_PLL_B; + else + pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A; + } } else { pipe_config->pixel_multiplier = 1; } @@ -5971,6 +5983,8 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, uint32_t tmp; pipe_config->cpu_transcoder = crtc->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; + tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); if (tmp & TRANS_DDI_FUNC_ENABLE) { enum pipe trans_edp_pipe; @@ -7840,6 +7854,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, drm_mode_copy(&pipe_config->adjusted_mode, mode); drm_mode_copy(&pipe_config->requested_mode, mode); pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe; + pipe_config->shared_dpll = DPLL_ID_PRIVATE; /* Compute a starting value for pipe_config->pipe_bpp taking the source * plane pixel format and any sink constraints into account. Returns the @@ -8159,6 +8174,8 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(ips_enabled); + PIPE_CONF_CHECK_I(shared_dpll); + #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_QUIRK -- cgit v1.2.3 From 7c74ade1de5b5311e7c886de27aa54e3285bd220 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:11 +0200 Subject: drm/i915: consolidate ->num_shared_dplls assignement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the future this won't be just for pch plls, so move it into the shared dpll init code. v2: Bikeshed the uncessary {} away while applying to appease checkpatch. Reviewed-by: Ville Syrjälä (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 7 ------- drivers/gpu/drm/i915/intel_display.c | 21 ++++++++++++++++----- 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b0a4e6834c1d..c3e4f2915e5b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -433,7 +433,6 @@ void intel_detect_pch(struct drm_device *dev) */ if (INTEL_INFO(dev)->num_pipes == 0) { dev_priv->pch_type = PCH_NOP; - dev_priv->num_shared_dpll = 0; return; } @@ -452,34 +451,28 @@ void intel_detect_pch(struct drm_device *dev) if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_IBX; - dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); WARN_ON(!IS_GEN5(dev)); } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_CPT; - dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found CougarPoint PCH\n"); WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { /* PantherPoint is CPT compatible */ dev_priv->pch_type = PCH_CPT; - dev_priv->num_shared_dpll = 2; DRM_DEBUG_KMS("Found PatherPoint PCH\n"); WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev))); } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; - dev_priv->num_shared_dpll = 0; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(IS_ULT(dev)); } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; - dev_priv->num_shared_dpll = 0; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_ULT(dev)); } - BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } pci_dev_put(pch); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 51670ba56611..665602a13ea4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8728,15 +8728,12 @@ static void intel_cpu_pll_init(struct drm_device *dev) intel_ddi_pll_init(dev); } -static void intel_shared_dpll_init(struct drm_device *dev) +static void ibx_pch_dpll_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int i; - if (dev_priv->num_shared_dpll == 0) { - DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n"); - return; - } + dev_priv->num_shared_dpll = 2; for (i = 0; i < dev_priv->num_shared_dpll; i++) { dev_priv->shared_dplls[i].pll_reg = _PCH_DPLL(i); @@ -8745,6 +8742,20 @@ static void intel_shared_dpll_init(struct drm_device *dev) } } +static void intel_shared_dpll_init(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) + ibx_pch_dpll_init(dev); + else + dev_priv->num_shared_dpll = 0; + + BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); + DRM_DEBUG_KMS("%i shared PLLs initialized\n", + dev_priv->num_shared_dpll); +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; -- cgit v1.2.3 From 46edb027df0d4bd423f7430dd473609caad4674b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:12 +0200 Subject: drm/i915: metadata for shared dplls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An id to match the idx (useful for register access macros) and a name fore neater debug output. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 19 ++++++++------ drivers/gpu/drm/i915/intel_display.c | 48 +++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d83c80a9c0b9..0fc8d616cefb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -132,23 +132,26 @@ enum hpd_pin { list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ if ((intel_encoder)->base.crtc == (__crtc)) +enum intel_dpll_id { + DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ + /* real shared dpll ids must be >= 0 */ + DPLL_ID_PCH_PLL_A, + DPLL_ID_PCH_PLL_B, +}; +#define I915_NUM_PLLS 2 + struct intel_shared_dpll { int refcount; /* count of number of CRTCs sharing this PLL */ int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ + const char *name; + /* should match the index in the dev_priv->shared_dplls array */ + enum intel_dpll_id id; int pll_reg; int fp0_reg; int fp1_reg; }; -enum intel_dpll_id { - DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ - /* real shared dpll ids must be >= 0 */ - DPLL_ID_PCH_PLL_A, - DPLL_ID_PCH_PLL_B, -}; -#define I915_NUM_PLLS 2 - /* Used by dp and fdi links */ struct intel_link_m_n { uint32_t tu; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 665602a13ea4..1ee16e9195b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -935,14 +935,14 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, } if (WARN (!pll, - "asserting PCH PLL %s with no PLL\n", state_string(state))) + "asserting DPLL %s with no DPLL\n", state_string(state))) return; val = I915_READ(pll->pll_reg); cur_state = !!(val & DPLL_VCO_ENABLE); WARN(cur_state != state, - "PCH PLL state for reg %x assertion failure (expected %s, current %s), val=%08x\n", - pll->pll_reg, state_string(state), state_string(cur_state), val); + "%s assertion failure (expected %s, current %s), val=%08x\n", + pll->name, state_string(state), state_string(cur_state), val); /* Make sure the selected PLL is correctly attached to the transcoder */ if (crtc && HAS_PCH_CPT(dev_priv->dev)) { @@ -1430,8 +1430,8 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll->refcount == 0)) return; - DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n", - pll->pll_reg, pll->active, pll->on, + DRM_DEBUG_KMS("enable %s (active %d, on? %d)for crtc %d\n", + pll->name, pll->active, pll->on, crtc->base.base.id); /* PCH refclock must be enabled first */ @@ -1444,7 +1444,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) } WARN_ON(pll->on); - DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg); + DRM_DEBUG_KMS("enabling %s\n", pll->name); reg = pll->pll_reg; val = I915_READ(reg); @@ -1471,8 +1471,8 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) if (WARN_ON(pll->refcount == 0)) return; - DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n", - pll->pll_reg, pll->active, pll->on, + DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", + pll->name, pll->active, pll->on, crtc->base.base.id); if (WARN_ON(pll->active == 0)) { @@ -1485,7 +1485,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) if (--pll->active) return; - DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg); + DRM_DEBUG_KMS("disabling %s\n", pll->name); /* Make sure transcoder isn't still depending on us */ assert_pch_transcoder_disabled(dev_priv, crtc->pipe); @@ -3065,7 +3065,7 @@ static void intel_put_shared_dpll(struct intel_crtc *crtc) return; if (pll->refcount == 0) { - WARN(1, "bad PCH PLL refcount\n"); + WARN(1, "bad %s refcount\n", pll->name); return; } @@ -3084,8 +3084,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, enum intel_dpll_id i; if (pll) { - DRM_DEBUG_KMS("CRTC:%d dropping existing PCH PLL %x\n", - crtc->base.base.id, pll->pll_reg); + DRM_DEBUG_KMS("CRTC:%d dropping existing %s\n", + crtc->base.base.id, pll->name); intel_put_shared_dpll(crtc); } @@ -3094,8 +3094,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, i = crtc->pipe; pll = &dev_priv->shared_dplls[i]; - DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n", - crtc->base.base.id, pll->pll_reg); + DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", + crtc->base.base.id, pll->name); goto found; } @@ -3109,9 +3109,9 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) && fp == I915_READ(pll->fp0_reg)) { - DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n", + DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n", crtc->base.base.id, - pll->pll_reg, pll->refcount, pll->active); + pll->name, pll->refcount, pll->active); goto found; } @@ -3121,8 +3121,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; if (pll->refcount == 0) { - DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n", - crtc->base.base.id, pll->pll_reg); + DRM_DEBUG_KMS("CRTC:%d allocated %s\n", + crtc->base.base.id, pll->name); goto found; } } @@ -3131,9 +3131,10 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, found: crtc->config.shared_dpll = i; - DRM_DEBUG_DRIVER("using pll %d for pipe %c\n", i, pipe_name(crtc->pipe)); + DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, + pipe_name(crtc->pipe)); if (pll->active == 0) { - DRM_DEBUG_DRIVER("setting up pll %d\n", i); + DRM_DEBUG_DRIVER("setting up %s\n", pll->name); WARN_ON(pll->on); assert_shared_dpll_disabled(dev_priv, pll, NULL); @@ -8728,6 +8729,11 @@ static void intel_cpu_pll_init(struct drm_device *dev) intel_ddi_pll_init(dev); } +static char *ibx_pch_dpll_names[] = { + "PCH DPLL A", + "PCH DPLL B", +}; + static void ibx_pch_dpll_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -8736,6 +8742,8 @@ static void ibx_pch_dpll_init(struct drm_device *dev) dev_priv->num_shared_dpll = 2; for (i = 0; i < dev_priv->num_shared_dpll; i++) { + dev_priv->shared_dplls[i].id = i; + dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; dev_priv->shared_dplls[i].pll_reg = _PCH_DPLL(i); dev_priv->shared_dplls[i].fp0_reg = _PCH_FP0(i); dev_priv->shared_dplls[i].fp1_reg = _PCH_FP1(i); -- cgit v1.2.3 From e9a632a578e0205c1fb015bb01af49c2ae71d6f2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:13 +0200 Subject: drm/i915: scrap register address storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using ids in register macros is much more common in our driver. Also this way we can reduce the platform specific stuff a bit. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/i915_ums.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++------------------- 4 files changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0fc8d616cefb..bb1ad20e39a1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -147,9 +147,6 @@ struct intel_shared_dpll { const char *name; /* should match the index in the dev_priv->shared_dplls array */ enum intel_dpll_id id; - int pll_reg; - int fp0_reg; - int fp1_reg; }; /* Used by dp and fdi links */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 99638fc6285b..01e8783f1a97 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3930,15 +3930,15 @@ #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 -#define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) +#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_FPA0 0xc6040 #define FP_CB_TUNE (0x3<<22) #define _PCH_FPA1 0xc6044 #define _PCH_FPB0 0xc6048 #define _PCH_FPB1 0xc604c -#define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0) -#define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1) +#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0) +#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1) #define PCH_DPLL_TEST 0xc606c diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c index 5ef30b2e6bc6..967da4772c44 100644 --- a/drivers/gpu/drm/i915/i915_ums.c +++ b/drivers/gpu/drm/i915/i915_ums.c @@ -41,7 +41,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) return false; if (HAS_PCH_SPLIT(dev)) - dpll_reg = _PCH_DPLL(pipe); + dpll_reg = PCH_DPLL(pipe); else dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1ee16e9195b9..1825ca5466e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -938,7 +938,7 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, "asserting DPLL %s with no DPLL\n", state_string(state))) return; - val = I915_READ(pll->pll_reg); + val = I915_READ(PCH_DPLL(pll->id)); cur_state = !!(val & DPLL_VCO_ENABLE); WARN(cur_state != state, "%s assertion failure (expected %s, current %s), val=%08x\n", @@ -949,14 +949,14 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, u32 pch_dpll; pch_dpll = I915_READ(PCH_DPLL_SEL); - cur_state = pll->pll_reg == _PCH_DPLL_B; + cur_state = pll->id == DPLL_ID_PCH_PLL_B; if (!WARN(((pch_dpll >> (4 * crtc->pipe)) & 1) != cur_state, "PLL[%d] not attached to this transcoder %c: %08x\n", cur_state, pipe_name(crtc->pipe), pch_dpll)) { cur_state = !!(val >> (4*crtc->pipe + 3)); WARN(cur_state != state, "PLL[%d] not %s on this transcoder %c: %08x\n", - pll->pll_reg == _PCH_DPLL_B, + pll->id == DPLL_ID_PCH_PLL_B, state_string(state), pipe_name(crtc->pipe), val); @@ -1446,7 +1446,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) DRM_DEBUG_KMS("enabling %s\n", pll->name); - reg = pll->pll_reg; + reg = PCH_DPLL(pll->id); val = I915_READ(reg); val |= DPLL_VCO_ENABLE; I915_WRITE(reg, val); @@ -1490,7 +1490,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) /* Make sure transcoder isn't still depending on us */ assert_pch_transcoder_disabled(dev_priv, crtc->pipe); - reg = pll->pll_reg; + reg = PCH_DPLL(pll->id); val = I915_READ(reg); val &= ~DPLL_VCO_ENABLE; I915_WRITE(reg, val); @@ -3107,8 +3107,8 @@ static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, if (pll->refcount == 0) continue; - if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) && - fp == I915_READ(pll->fp0_reg)) { + if (dpll == (I915_READ(PCH_DPLL(pll->id)) & 0x7fffffff) && + fp == I915_READ(PCH_FP0(pll->id))) { DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n", crtc->base.base.id, pll->name, pll->refcount, pll->active); @@ -3139,12 +3139,12 @@ found: assert_shared_dpll_disabled(dev_priv, pll, NULL); /* Wait for the clocks to stabilize before rewriting the regs */ - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); - POSTING_READ(pll->pll_reg); + I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE); + POSTING_READ(PCH_DPLL(pll->id)); udelay(150); - I915_WRITE(pll->fp0_reg, fp); - I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE); + I915_WRITE(PCH_FP0(pll->id), fp); + I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE); } pll->refcount++; @@ -5785,10 +5785,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (intel_crtc->config.has_pch_encoder) { pll = intel_crtc_to_shared_dpll(intel_crtc); - I915_WRITE(pll->pll_reg, dpll); + I915_WRITE(PCH_DPLL(pll->id), dpll); /* Wait for the clocks to stabilize. */ - POSTING_READ(pll->pll_reg); + POSTING_READ(PCH_DPLL(pll->id)); udelay(150); /* The pixel multiplier can only be updated once the @@ -5796,13 +5796,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * * So write it again. */ - I915_WRITE(pll->pll_reg, dpll); + I915_WRITE(PCH_DPLL(pll->id), dpll); if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(pll->fp1_reg, fp2); + I915_WRITE(PCH_FP1(pll->id), fp2); intel_crtc->lowfreq_avail = true; } else { - I915_WRITE(pll->fp1_reg, fp); + I915_WRITE(PCH_FP1(pll->id), fp); } } @@ -8744,9 +8744,6 @@ static void ibx_pch_dpll_init(struct drm_device *dev) for (i = 0; i < dev_priv->num_shared_dpll; i++) { dev_priv->shared_dplls[i].id = i; dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; - dev_priv->shared_dplls[i].pll_reg = _PCH_DPLL(i); - dev_priv->shared_dplls[i].fp0_reg = _PCH_FP0(i); - dev_priv->shared_dplls[i].fp1_reg = _PCH_FP1(i); } } -- cgit v1.2.3 From e7b903d2525fe3be12b6535a27915186529a51b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:14 +0200 Subject: drm/i915: enable/disable hooks for shared dplls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks at first like a bit of overkill, but - Haswell actually wants different enable/disable functions for different plls. - And once we have full dpll hw state tracking we can move the full register setup into the ->enable hook. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++- drivers/gpu/drm/i915/intel_display.c | 71 ++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 29 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index bb1ad20e39a1..eaa04a6808cb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -132,6 +132,8 @@ enum hpd_pin { list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ if ((intel_encoder)->base.crtc == (__crtc)) +struct drm_i915_private; + enum intel_dpll_id { DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */ /* real shared dpll ids must be >= 0 */ @@ -147,6 +149,10 @@ struct intel_shared_dpll { const char *name; /* should match the index in the dev_priv->shared_dplls array */ enum intel_dpll_id id; + void (*enable)(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll); + void (*disable)(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll); }; /* Used by dp and fdi links */ @@ -202,7 +208,6 @@ struct opregion_header; struct opregion_acpi; struct opregion_swsci; struct opregion_asle; -struct drm_i915_private; struct intel_opregion { struct opregion_header __iomem *header; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1825ca5466e8..85f8888afce9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1419,8 +1419,6 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); - int reg; - u32 val; /* PCH PLLs only available on ILK, SNB and IVB */ BUG_ON(dev_priv->info->gen < 5); @@ -1434,9 +1432,6 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) pll->name, pll->active, pll->on, crtc->base.base.id); - /* PCH refclock must be enabled first */ - assert_pch_refclk_enabled(dev_priv); - if (pll->active++) { WARN_ON(!pll->on); assert_shared_dpll_enabled(dev_priv, pll, NULL); @@ -1445,14 +1440,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) WARN_ON(pll->on); DRM_DEBUG_KMS("enabling %s\n", pll->name); - - reg = PCH_DPLL(pll->id); - val = I915_READ(reg); - val |= DPLL_VCO_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - udelay(200); - + pll->enable(dev_priv, pll); pll->on = true; } @@ -1460,8 +1448,6 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); - int reg; - u32 val; /* PCH only available on ILK+ */ BUG_ON(dev_priv->info->gen < 5); @@ -1486,17 +1472,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) return; DRM_DEBUG_KMS("disabling %s\n", pll->name); - - /* Make sure transcoder isn't still depending on us */ - assert_pch_transcoder_disabled(dev_priv, crtc->pipe); - - reg = PCH_DPLL(pll->id); - val = I915_READ(reg); - val &= ~DPLL_VCO_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - udelay(200); - + pll->disable(dev_priv, pll); pll->on = false; } @@ -8729,6 +8705,43 @@ static void intel_cpu_pll_init(struct drm_device *dev) intel_ddi_pll_init(dev); } +static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + uint32_t reg, val; + + /* PCH refclock must be enabled first */ + assert_pch_refclk_enabled(dev_priv); + + reg = PCH_DPLL(pll->id); + val = I915_READ(reg); + val |= DPLL_VCO_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(200); +} + +static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *crtc; + uint32_t reg, val; + + /* Make sure no transcoder isn't still depending on us. */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (intel_crtc_to_shared_dpll(crtc) == pll) + assert_pch_transcoder_disabled(dev_priv, crtc->pipe); + } + + reg = PCH_DPLL(pll->id); + val = I915_READ(reg); + val &= ~DPLL_VCO_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(200); +} + static char *ibx_pch_dpll_names[] = { "PCH DPLL A", "PCH DPLL B", @@ -8736,7 +8749,7 @@ static char *ibx_pch_dpll_names[] = { static void ibx_pch_dpll_init(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int i; dev_priv->num_shared_dpll = 2; @@ -8744,12 +8757,14 @@ static void ibx_pch_dpll_init(struct drm_device *dev) for (i = 0; i < dev_priv->num_shared_dpll; i++) { dev_priv->shared_dplls[i].id = i; dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; + dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable; + dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable; } } static void intel_shared_dpll_init(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) ibx_pch_dpll_init(dev); -- cgit v1.2.3 From e9d6944ed75dbf16ae34bb73bd1eeca7cb183b67 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:15 +0200 Subject: drm/i915: drop crtc checking from assert_shared_dpll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hw state readout code for the pipe config will now check this for us, so rip out this hand-rolled complexity. Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 85f8888afce9..bef9086bf542 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -923,7 +923,6 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc) /* For ILK+ */ static void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, - struct intel_crtc *crtc, bool state) { u32 val; @@ -943,28 +942,9 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, WARN(cur_state != state, "%s assertion failure (expected %s, current %s), val=%08x\n", pll->name, state_string(state), state_string(cur_state), val); - - /* Make sure the selected PLL is correctly attached to the transcoder */ - if (crtc && HAS_PCH_CPT(dev_priv->dev)) { - u32 pch_dpll; - - pch_dpll = I915_READ(PCH_DPLL_SEL); - cur_state = pll->id == DPLL_ID_PCH_PLL_B; - if (!WARN(((pch_dpll >> (4 * crtc->pipe)) & 1) != cur_state, - "PLL[%d] not attached to this transcoder %c: %08x\n", - cur_state, pipe_name(crtc->pipe), pch_dpll)) { - cur_state = !!(val >> (4*crtc->pipe + 3)); - WARN(cur_state != state, - "PLL[%d] not %s on this transcoder %c: %08x\n", - pll->id == DPLL_ID_PCH_PLL_B, - state_string(state), - pipe_name(crtc->pipe), - val); - } - } } -#define assert_shared_dpll_enabled(d, p, c) assert_shared_dpll(d, p, c, true) -#define assert_shared_dpll_disabled(d, p, c) assert_shared_dpll(d, p, c, false) +#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) +#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum pipe pipe, bool state) @@ -1434,7 +1414,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) if (pll->active++) { WARN_ON(!pll->on); - assert_shared_dpll_enabled(dev_priv, pll, NULL); + assert_shared_dpll_enabled(dev_priv, pll); return; } WARN_ON(pll->on); @@ -1462,11 +1442,11 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) crtc->base.base.id); if (WARN_ON(pll->active == 0)) { - assert_shared_dpll_disabled(dev_priv, pll, NULL); + assert_shared_dpll_disabled(dev_priv, pll); return; } - assert_shared_dpll_enabled(dev_priv, pll, NULL); + assert_shared_dpll_enabled(dev_priv, pll); WARN_ON(!pll->on); if (--pll->active) return; @@ -1489,8 +1469,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, /* Make sure PCH DPLL is enabled */ assert_shared_dpll_enabled(dev_priv, - intel_crtc_to_shared_dpll(intel_crtc), - intel_crtc); + intel_crtc_to_shared_dpll(intel_crtc)); /* FDI must be feeding us bits for PCH ports */ assert_fdi_tx_enabled(dev_priv, pipe); @@ -3112,7 +3091,7 @@ found: if (pll->active == 0) { DRM_DEBUG_DRIVER("setting up %s\n", pll->name); WARN_ON(pll->on); - assert_shared_dpll_disabled(dev_priv, pll, NULL); + assert_shared_dpll_disabled(dev_priv, pll); /* Wait for the clocks to stabilize before rewriting the regs */ I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE); -- cgit v1.2.3 From 19d415a25e9078dba26adb54396d4e5b30d3b572 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 10 Jun 2013 13:28:42 +0100 Subject: drm/i915: Fix old reference to i830_sdvo_get_capabilities() It's now intel_sdvo_get_capabilities(). Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ac923b74924a..e77ffadb1779 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -80,7 +80,7 @@ struct intel_sdvo { /* * Capabilities of the SDVO device returned by - * i830_sdvo_get_capabilities() + * intel_sdvo_get_capabilities() */ struct intel_sdvo_caps caps; -- cgit v1.2.3 From 2f28c50bb3881f11afee8f8c9041dad2c96653aa Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 10 Jun 2013 13:49:25 +0100 Subject: drm/i915: Initialize active_outputs to never read unitialized values In case of intel_sdvo_get_active_outputs() failing, we end up reading a value from the stack. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e77ffadb1779..97d3099aea23 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1277,7 +1277,7 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(&connector->base); struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base); - u16 active_outputs; + u16 active_outputs = 0; intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); @@ -1293,7 +1293,7 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); - u16 active_outputs; + u16 active_outputs = 0; u32 tmp; tmp = I915_READ(intel_sdvo->sdvo_reg); -- cgit v1.2.3 From 4ee62c7669be1a6f1dd407e5ba7e38c0e2204e92 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 7 Jun 2013 15:43:05 +0000 Subject: drm/i915: Print pretty names for pixel formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use drm_get_format_name to print more readable pixel format names in debug output. Also unify the debug messages to say "unsupported pixel format", which better describes what is going on. Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e81eb20e2c88..a4c9f56afb38 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8945,7 +8945,8 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XRGB1555: case DRM_FORMAT_ARGB1555: if (INTEL_INFO(dev)->gen > 3) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; @@ -8956,7 +8957,8 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: if (INTEL_INFO(dev)->gen < 4) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; @@ -8965,12 +8967,14 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_YVYU: case DRM_FORMAT_VYUY: if (INTEL_INFO(dev)->gen < 5) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; default: - DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } -- cgit v1.2.3 From 50f018dff180942dc40e601de6e97145a4aaeaa9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jun 2013 11:20:19 +0100 Subject: drm/i915: Initialize ring->hangcheck upon ring init When we reset and restart a ring, we also want to clear any existing hangcheck. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1ef081cd1706..a3cfa35b0573 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -453,6 +453,8 @@ static int init_ring_common(struct intel_ring_buffer *ring) ring->last_retired_head = -1; } + memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); + out: if (HAS_FORCE_WAKE(dev)) gen6_gt_force_wake_put(dev_priv); -- cgit v1.2.3 From 9107e9d227e3b0893829baee4ac59feb874d4c23 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jun 2013 11:20:20 +0100 Subject: drm/i915: Only slightly increment hangcheck score if we succesfully kick a ring After kicking a ring, it should be free to make progress again and so should not be accused of being stuck until hangcheck fires once more. In order to catch a denial-of-service within a batch or across multiple batches, we still do increment the hangcheck score - just not as severely so that it takes multiple kicks to fail. This should address part of Ben's justified criticism of commit 05407ff889ceebe383aa5907219f86582ef96b72 Author: Mika Kuoppala Date: Thu May 30 09:04:29 2013 +0300 drm/i915: detect hang using per ring hangcheck_score "There's also another corner case on the kick. If the seqno = 2 (though not stuck), and on the 3rd hangcheck, the ring is stuck, and we try to kick it... we don't actually try to find out if the kick helped." v2: Make sure we catch DoS attempts with batches full of invalid WAITs. v3: Preserve the ability to detect loops by always charging the ring if it is busy on the same request. v4: Make sure we queue another check if on a new batch References: https://bugs.freedesktop.org/show_bug.cgi?id=65394 Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Ben Widawsky Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 110 +++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 52 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c482e8ae58dc..6a757691488e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2314,21 +2314,11 @@ ring_last_seqno(struct intel_ring_buffer *ring) struct drm_i915_gem_request, list)->seqno; } -static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, - u32 ring_seqno, bool *err) -{ - if (list_empty(&ring->request_list) || - i915_seqno_passed(ring_seqno, ring_last_seqno(ring))) { - /* Issue a wake-up to catch stuck h/w. */ - if (waitqueue_active(&ring->irq_queue)) { - DRM_ERROR("Hangcheck timer elapsed... %s idle\n", - ring->name); - wake_up_all(&ring->irq_queue); - *err = true; - } - return true; - } - return false; +static bool +ring_idle(struct intel_ring_buffer *ring, u32 seqno) +{ + return (list_empty(&ring->request_list) || + i915_seqno_passed(seqno, ring_last_seqno(ring))); } static bool semaphore_passed(struct intel_ring_buffer *ring) @@ -2362,16 +2352,26 @@ static bool semaphore_passed(struct intel_ring_buffer *ring) ioread32(ring->virtual_start+acthd+4)+1); } -static bool kick_ring(struct intel_ring_buffer *ring) +static bool ring_hung(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 tmp = I915_READ_CTL(ring); + u32 tmp; + + if (IS_GEN2(dev)) + return true; + + /* Is the chip hanging on a WAIT_FOR_EVENT? + * If so we can simply poke the RB_WAIT bit + * and break the hang. This should work on + * all but the second generation chipsets. + */ + tmp = I915_READ_CTL(ring); if (tmp & RING_WAIT) { DRM_ERROR("Kicking stuck wait on %s\n", ring->name); I915_WRITE_CTL(ring, tmp); - return true; + return false; } if (INTEL_INFO(dev)->gen >= 6 && @@ -2380,22 +2380,10 @@ static bool kick_ring(struct intel_ring_buffer *ring) DRM_ERROR("Kicking stuck semaphore on %s\n", ring->name); I915_WRITE_CTL(ring, tmp); - return true; - } - return false; -} - -static bool i915_hangcheck_ring_hung(struct intel_ring_buffer *ring) -{ - if (IS_GEN2(ring->dev)) return false; + } - /* Is the chip hanging on a WAIT_FOR_EVENT? - * If so we can simply poke the RB_WAIT bit - * and break the hang. This should work on - * all but the second generation chipsets. - */ - return !kick_ring(ring); + return true; } /** @@ -2413,45 +2401,63 @@ void i915_hangcheck_elapsed(unsigned long data) struct intel_ring_buffer *ring; int i; int busy_count = 0, rings_hung = 0; - bool stuck[I915_NUM_RINGS]; + bool stuck[I915_NUM_RINGS] = { 0 }; +#define BUSY 1 +#define KICK 5 +#define HUNG 20 +#define FIRE 30 if (!i915_enable_hangcheck) return; for_each_ring(ring, dev_priv, i) { u32 seqno, acthd; - bool idle, err = false; + bool busy = true; seqno = ring->get_seqno(ring, false); acthd = intel_ring_get_active_head(ring); - idle = i915_hangcheck_ring_idle(ring, seqno, &err); - stuck[i] = ring->hangcheck.acthd == acthd; - - if (idle) { - if (err) - ring->hangcheck.score += 2; - else - ring->hangcheck.score = 0; - } else { - busy_count++; - if (ring->hangcheck.seqno == seqno) { - ring->hangcheck.score++; - - /* Kick ring if stuck*/ - if (stuck[i]) - i915_hangcheck_ring_hung(ring); + if (ring->hangcheck.seqno == seqno) { + if (ring_idle(ring, seqno)) { + if (waitqueue_active(&ring->irq_queue)) { + /* Issue a wake-up to catch stuck h/w. */ + DRM_ERROR("Hangcheck timer elapsed... %s idle\n", + ring->name); + wake_up_all(&ring->irq_queue); + ring->hangcheck.score += HUNG; + } else + busy = false; } else { - ring->hangcheck.score = 0; + int score; + + stuck[i] = ring->hangcheck.acthd == acthd; + if (stuck[i]) { + /* Every time we kick the ring, add a + * small increment to the hangcheck + * score so that we can catch a + * batch that is repeatedly kicked. + */ + score = ring_hung(ring) ? HUNG : KICK; + } else + score = BUSY; + + ring->hangcheck.score += score; } + } else { + /* Gradually reduce the count so that we catch DoS + * attempts across multiple batches. + */ + if (ring->hangcheck.score > 0) + ring->hangcheck.score--; } ring->hangcheck.seqno = seqno; ring->hangcheck.acthd = acthd; + busy_count += busy; } for_each_ring(ring, dev_priv, i) { - if (ring->hangcheck.score > 2) { + if (ring->hangcheck.score > FIRE) { rings_hung++; DRM_ERROR("%s: %s on %s 0x%x\n", ring->name, stuck[i] ? "stuck" : "no progress", -- cgit v1.2.3 From 6274f2126a0454d3c3df1bc9cc6f5e18302696f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jun 2013 11:20:21 +0100 Subject: drm/i915: Don't count semaphore waits towards a stuck ring If we detect a ring is in a valid wait for another, just let it be. Eventually it will either begin to progress again, or the entire system will come grinding to a halt and then hangcheck will fire as soon as the deadlock is detected. This error was foretold by Ben in commit 05407ff889ceebe383aa5907219f86582ef96b72 Author: Mika Kuoppala Date: Thu May 30 09:04:29 2013 +0300 drm/i915: detect hang using per ring hangcheck_score "If ring B is waiting on ring A via semaphore, and ring A is making progress, albeit slowly - the hangcheck will fire. The check will determine that A is moving, however ring B will appear hung because the ACTHD doesn't move. I honestly can't say if that's actually a realistic problem to hit it probably implies the timeout value is too low." v2: Make sure we don't even incur the KICK cost whilst waiting. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65394 Signed-off-by: Chris Wilson Cc: Mika Kuoppala Cc: Ben Widawsky Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 121 +++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 2 files changed, 90 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6a757691488e..563abe79bb20 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2321,21 +2321,21 @@ ring_idle(struct intel_ring_buffer *ring, u32 seqno) i915_seqno_passed(seqno, ring_last_seqno(ring))); } -static bool semaphore_passed(struct intel_ring_buffer *ring) +static struct intel_ring_buffer * +semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; - struct intel_ring_buffer *signaller; - u32 cmd, ipehr, acthd_min; + u32 cmd, ipehr, acthd, acthd_min; ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); if ((ipehr & ~(0x3 << 16)) != (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) - return false; + return NULL; /* ACTHD is likely pointing to the dword after the actual command, * so scan backwards until we find the MBOX. */ + acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; acthd_min = max((int)acthd - 3 * 4, 0); do { cmd = ioread32(ring->virtual_start + acthd); @@ -2344,22 +2344,53 @@ static bool semaphore_passed(struct intel_ring_buffer *ring) acthd -= 4; if (acthd < acthd_min) - return false; + return NULL; } while (1); - signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; - return i915_seqno_passed(signaller->get_seqno(signaller, false), - ioread32(ring->virtual_start+acthd+4)+1); + *seqno = ioread32(ring->virtual_start+acthd+4)+1; + return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; +} + +static int semaphore_passed(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_ring_buffer *signaller; + u32 seqno, ctl; + + ring->hangcheck.deadlock = true; + + signaller = semaphore_waits_for(ring, &seqno); + if (signaller == NULL || signaller->hangcheck.deadlock) + return -1; + + /* cursory check for an unkickable deadlock */ + ctl = I915_READ_CTL(signaller); + if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0) + return -1; + + return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno); +} + +static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) +{ + struct intel_ring_buffer *ring; + int i; + + for_each_ring(ring, dev_priv, i) + ring->hangcheck.deadlock = false; } -static bool ring_hung(struct intel_ring_buffer *ring) +static enum { wait, active, kick, hung } ring_stuck(struct intel_ring_buffer *ring, u32 acthd) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; + if (ring->hangcheck.acthd != acthd) + return active; + if (IS_GEN2(dev)) - return true; + return hung; /* Is the chip hanging on a WAIT_FOR_EVENT? * If so we can simply poke the RB_WAIT bit @@ -2371,19 +2402,24 @@ static bool ring_hung(struct intel_ring_buffer *ring) DRM_ERROR("Kicking stuck wait on %s\n", ring->name); I915_WRITE_CTL(ring, tmp); - return false; - } - - if (INTEL_INFO(dev)->gen >= 6 && - tmp & RING_WAIT_SEMAPHORE && - semaphore_passed(ring)) { - DRM_ERROR("Kicking stuck semaphore on %s\n", - ring->name); - I915_WRITE_CTL(ring, tmp); - return false; + return kick; + } + + if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) { + switch (semaphore_passed(ring)) { + default: + return hung; + case 1: + DRM_ERROR("Kicking stuck semaphore on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + return kick; + case 0: + return wait; + } } - return true; + return hung; } /** @@ -2414,6 +2450,8 @@ void i915_hangcheck_elapsed(unsigned long data) u32 seqno, acthd; bool busy = true; + semaphore_clear_deadlocks(dev_priv); + seqno = ring->get_seqno(ring, false); acthd = intel_ring_get_active_head(ring); @@ -2430,17 +2468,36 @@ void i915_hangcheck_elapsed(unsigned long data) } else { int score; - stuck[i] = ring->hangcheck.acthd == acthd; - if (stuck[i]) { - /* Every time we kick the ring, add a - * small increment to the hangcheck - * score so that we can catch a - * batch that is repeatedly kicked. - */ - score = ring_hung(ring) ? HUNG : KICK; - } else + /* We always increment the hangcheck score + * if the ring is busy and still processing + * the same request, so that no single request + * can run indefinitely (such as a chain of + * batches). The only time we do not increment + * the hangcheck score on this ring, if this + * ring is in a legitimate wait for another + * ring. In that case the waiting ring is a + * victim and we want to be sure we catch the + * right culprit. Then every time we do kick + * the ring, add a small increment to the + * score so that we can catch a batch that is + * being repeatedly kicked and so responsible + * for stalling the machine. + */ + switch (ring_stuck(ring, acthd)) { + case wait: + score = 0; + break; + case active: score = BUSY; - + break; + case kick: + score = KICK; + break; + case hung: + score = HUNG; + stuck[i] = true; + break; + } ring->hangcheck.score += score; } } else { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index efc403d1e3e0..a3e96103dbe5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -38,6 +38,7 @@ struct intel_hw_status_page { #define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base)) struct intel_ring_hangcheck { + bool deadlock; u32 seqno; u32 acthd; int score; -- cgit v1.2.3 From a43adf0747ecde0d211f29adcbebf067f92e9cbb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 10 Jun 2013 11:20:22 +0100 Subject: drm/i915: Eliminate the addr/seqno from the hangcheck warning This is of no value to the developer reading the report, let alone the bamboozled user. Signed-off-by: Chris Wilson Acked-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 563abe79bb20..b26243f09c91 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2515,12 +2515,10 @@ void i915_hangcheck_elapsed(unsigned long data) for_each_ring(ring, dev_priv, i) { if (ring->hangcheck.score > FIRE) { - rings_hung++; - DRM_ERROR("%s: %s on %s 0x%x\n", ring->name, + DRM_ERROR("%s on %s ring\n", stuck[i] ? "stuck" : "no progress", - stuck[i] ? "addr" : "seqno", - stuck[i] ? ring->hangcheck.acthd & HEAD_ADDR : - ring->hangcheck.seqno); + ring->name); + rings_hung++; } } -- cgit v1.2.3 From b8c3af766b7f9350c581bb44e6ffaaabc8c1c198 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 12 Jun 2013 11:29:47 +0100 Subject: drm/i915: WARN if the fence pin_count is invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stéphane Marchesin found a bug where the fences were not being restored, and in particular the fence pin_count was incorrect. Had we had a warning in place, this bug would have come to light much earlier. Better late than never? Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Stéphane Marchesin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eaa04a6808cb..e5b8ae42859a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1703,6 +1703,7 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) { if (obj->fence_reg != I915_FENCE_REG_NONE) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0); dev_priv->fence_regs[obj->fence_reg].pin_count--; } } -- cgit v1.2.3 From fdafa9e276235225ce087695984cf1e52dd0c159 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 12 Jun 2013 11:47:24 +0200 Subject: drm/i915: disable sdvo pixel multiplier cross-check for HAS_PCH_SPLIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't (yet) have proper pixel multiplier readout support on pch split platforms, so the cross check will naturally fail. v2: Fix spelling in the comment, spotted by Ville. v3: Since the ordering constraint is pretty tricky between the crtc get_pipe_config callback and the encoder->get_config callback add a few comments about it. Prompted by a discussion with Chris Wilson on irc about why this does work anywhere else than on i915g/gm. Reported-by: Chris Wilson Acked-by: Chris Wilson Cc: Chris Wilson Cc: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_sdvo.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b77df049b773..4a69bdc4f8ca 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -140,7 +140,8 @@ struct intel_encoder { * it is connected to in the pipe parameter. */ bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); /* Reconstructs the equivalent mode flags for the current hardware - * state. */ + * state. This must be called _after_ display->get_pipe_config has + * pre-filled the pipe config. */ void (*get_config)(struct intel_encoder *, struct intel_crtc_config *pipe_config); int crtc_mask; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 97d3099aea23..b8e1623be30d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1342,6 +1342,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, pipe_config->adjusted_mode.flags |= flags; + /* + * pixel multiplier readout is tricky: Only on i915g/gm it is stored in + * the sdvo port register, on all other platforms it is part of the dpll + * state. Since the general pipe state readout happens before the + * encoder->get_config we so already have a valid pixel multplier on all + * other platfroms. + */ if (IS_I915G(dev) || IS_I915GM(dev)) { sdvox = I915_READ(intel_sdvo->sdvo_reg); pipe_config->pixel_multiplier = @@ -1362,6 +1369,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, encoder_pixel_multiplier = 4; break; } + + if(HAS_PCH_SPLIT(dev)) + return; /* no pixel multiplier readout support yet */ + WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier, "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n", pipe_config->pixel_multiplier, encoder_pixel_multiplier); -- cgit v1.2.3 From 7df00d7adb080122502a30ec48f237d2f90d36ad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 May 2013 21:54:55 +0200 Subject: drm/i915: pnv dpll doesn't use m1! So don't try to store it in the DPLL_FP register. Otherwise it looks like the limits for pineview are correct: It has it's own clock computation code, which doesn't use an offset for n divisors, and the register value based m limits look sane enough. v2: Rebase on top of the pineview clock refactor and fixup up the commit message: It's m1 pnv doens't care about, not m2! Quoting Damien's review: - "n can vary between 2 and 6, but we declare the 3-6 as limits. - "p1 seems to be able to go up to 9 - "the m upper limit seems a bit big, but the docs are a bit shy on that values for pnv. "Otherwise, the change itself seems good:" Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bef9086bf542..1dfaa1c5fa41 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4240,7 +4240,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) static uint32_t pnv_dpll_compute_fp(struct dpll *dpll) { - return (1 << dpll->n) << 16 | dpll->m1 << 8 | dpll->m2; + return (1 << dpll->n) << 16 | dpll->m2; } static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll) -- cgit v1.2.3 From 5358901f99153085db59c3644db00b8753b50ac1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:16 +0200 Subject: drm/i915: display pll hw state readout and checking Currently still with an empty register state, this will follow in a next step. This one here just creates the new vfunc and uses it for cross-checking, initial state takeover and the dpll assert function. And add a FIXME for the ddi pll readout code, which still needs to be converted over. v2: - Add some hw state readout debug output. - Also cross check the enabled crtc counting. Note that I've botched up the patch ordering, and before this patch we've read out the pll selection correctly, but did not reconstruct the refcounts properly. See the bug link. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65673 Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++++ drivers/gpu/drm/i915/intel_display.c | 77 +++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e5b8ae42859a..7b998dcae089 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -142,6 +142,9 @@ enum intel_dpll_id { }; #define I915_NUM_PLLS 2 +struct intel_dpll_hw_state { +}; + struct intel_shared_dpll { int refcount; /* count of number of CRTCs sharing this PLL */ int active; /* count of number of active CRTCs (i.e. DPMS on) */ @@ -149,10 +152,14 @@ struct intel_shared_dpll { const char *name; /* should match the index in the dev_priv->shared_dplls array */ enum intel_dpll_id id; + struct intel_dpll_hw_state hw_state; void (*enable)(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll); void (*disable)(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll); + bool (*get_hw_state)(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state); }; /* Used by dp and fdi links */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1dfaa1c5fa41..79a1081ed7c9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -925,8 +925,8 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll, bool state) { - u32 val; bool cur_state; + struct intel_dpll_hw_state hw_state; if (HAS_PCH_LPT(dev_priv->dev)) { DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n"); @@ -937,11 +937,10 @@ static void assert_shared_dpll(struct drm_i915_private *dev_priv, "asserting DPLL %s with no DPLL\n", state_string(state))) return; - val = I915_READ(PCH_DPLL(pll->id)); - cur_state = !!(val & DPLL_VCO_ENABLE); + cur_state = pll->get_hw_state(dev_priv, pll, &hw_state); WARN(cur_state != state, - "%s assertion failure (expected %s, current %s), val=%08x\n", - pll->name, state_string(state), state_string(cur_state), val); + "%s assertion failure (expected %s, current %s)\n", + pll->name, state_string(state), state_string(cur_state)); } #define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true) #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) @@ -8147,6 +8146,8 @@ intel_modeset_check_state(struct drm_device *dev) struct intel_encoder *encoder; struct intel_connector *connector; struct intel_crtc_config pipe_config; + struct intel_dpll_hw_state dpll_hw_state; + int i; list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { @@ -8261,6 +8262,41 @@ intel_modeset_check_state(struct drm_device *dev) "[sw state]"); } } + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + int enabled_crtcs = 0, active_crtcs = 0; + bool active; + + memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); + + DRM_DEBUG_KMS("%s\n", pll->name); + + active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state); + + WARN(pll->active > pll->refcount, + "more active pll users than references: %i vs %i\n", + pll->active, pll->refcount); + WARN(pll->active && !pll->on, + "pll in active use but not on in sw tracking\n"); + WARN(pll->on != active, + "pll on state mismatch (expected %i, found %i)\n", + pll->on, active); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->base.enabled && intel_crtc_to_shared_dpll(crtc) == pll) + enabled_crtcs++; + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) + active_crtcs++; + } + WARN(pll->active != active_crtcs, + "pll active crtcs mismatch (expected %i, found %i)\n", + pll->active, active_crtcs); + WARN(pll->refcount != enabled_crtcs, + "pll enabled crtcs mismatch (expected %i, found %i)\n", + pll->refcount, enabled_crtcs); + } } static int __intel_set_mode(struct drm_crtc *crtc, @@ -8684,6 +8720,17 @@ static void intel_cpu_pll_init(struct drm_device *dev) intel_ddi_pll_init(dev); } +static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + uint32_t val; + + val = I915_READ(PCH_DPLL(pll->id)); + + return val & DPLL_VCO_ENABLE; +} + static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv, struct intel_shared_dpll *pll) { @@ -8738,6 +8785,8 @@ static void ibx_pch_dpll_init(struct drm_device *dev) dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i]; dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable; dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable; + dev_priv->shared_dplls[i].get_hw_state = + ibx_pch_dpll_get_hw_state; } } @@ -9655,6 +9704,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; + int i; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { @@ -9670,9 +9720,26 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, crtc->active ? "enabled" : "disabled"); } + /* FIXME: Smash this into the new shared dpll infrastructure. */ if (HAS_DDI(dev)) intel_ddi_setup_hw_pll_state(dev); + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + + pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state); + pll->active = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, + base.head) { + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) + pll->active++; + } + pll->refcount = pll->active; + + DRM_DEBUG_KMS("%s hw state readout: refcount %i\n", + pll->name, pll->refcount); + } + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { pipe = 0; -- cgit v1.2.3 From 30e984df4c5633363b45108473b0561e7d89476d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:17 +0200 Subject: drm/i915: extract readout_hw_state from setup_hw_state Simply grew too big. This also makes the fixup and restore logic in setup_hw_state stand out a bit more clearly. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 79a1081ed7c9..34ddd6f7c31d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9693,14 +9693,10 @@ void i915_redisable_vga(struct drm_device *dev) } } -/* Scan out the current hw modeset state, sanitizes it and maps it into the drm - * and i915 state tracking structures. */ -void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore) +static void intel_modeset_readout_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; - struct drm_plane *plane; struct intel_crtc *crtc; struct intel_encoder *encoder; struct intel_connector *connector; @@ -9776,6 +9772,20 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, drm_get_connector_name(&connector->base), connector->base.encoder ? "enabled" : "disabled"); } +} + +/* Scan out the current hw modeset state, sanitizes it and maps it into the drm + * and i915 state tracking structures. */ +void intel_modeset_setup_hw_state(struct drm_device *dev, + bool force_restore) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct drm_plane *plane; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + + intel_modeset_readout_hw_state(dev); /* HW state is read out, now we need to sanitize this mess. */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, -- cgit v1.2.3 From 91d1b4bd14fd0bfe87e91a0fd115fcc15c9c9cc5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:18 +0200 Subject: drm/i915: split up intel_modeset_check_state Simply grew too large and needed to be split up into parts. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 44 +++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 34ddd6f7c31d..0eea23a21f86 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8138,16 +8138,10 @@ intel_pipe_config_compare(struct drm_device *dev, return true; } -void -intel_modeset_check_state(struct drm_device *dev) +static void +check_connector_state(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_crtc *crtc; - struct intel_encoder *encoder; struct intel_connector *connector; - struct intel_crtc_config pipe_config; - struct intel_dpll_hw_state dpll_hw_state; - int i; list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { @@ -8158,6 +8152,13 @@ intel_modeset_check_state(struct drm_device *dev) WARN(&connector->new_encoder->base != connector->base.encoder, "connector's staged encoder doesn't match current encoder\n"); } +} + +static void +check_encoder_state(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_connector *connector; list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { @@ -8209,6 +8210,15 @@ intel_modeset_check_state(struct drm_device *dev) tracked_pipe, pipe); } +} + +static void +check_crtc_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_crtc_config pipe_config; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { @@ -8262,6 +8272,15 @@ intel_modeset_check_state(struct drm_device *dev) "[sw state]"); } } +} + +static void +check_shared_dpll_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct intel_dpll_hw_state dpll_hw_state; + int i; for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; @@ -8299,6 +8318,15 @@ intel_modeset_check_state(struct drm_device *dev) } } +void +intel_modeset_check_state(struct drm_device *dev) +{ + check_connector_state(dev); + check_encoder_state(dev); + check_crtc_state(dev); + check_shared_dpll_state(dev); +} + static int __intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) -- cgit v1.2.3 From 87a875bbffcfac7cb7c9a106fda40f04de1f60a2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:19 +0200 Subject: drm/i915: WARN on lack of shared dpll Now that we have proper hw state reconstruction we should never have a case where we don't have the software dpll state properly set up. So add WARNs to the respective !pll cases in enable/disabel_shared_dpll. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0eea23a21f86..cb724b6f8833 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1401,7 +1401,7 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc) /* PCH PLLs only available on ILK, SNB and IVB */ BUG_ON(dev_priv->info->gen < 5); - if (pll == NULL) + if (WARN_ON(pll == NULL)) return; if (WARN_ON(pll->refcount == 0)) @@ -1430,7 +1430,7 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) /* PCH only available on ILK+ */ BUG_ON(dev_priv->info->gen < 5); - if (pll == NULL) + if (WARN_ON(pll == NULL)) return; if (WARN_ON(pll->refcount == 0)) -- cgit v1.2.3 From 66e985c035f4554939b8b63a8e21418271160ab0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:20 +0200 Subject: drm/i915: hw state readout and cross-checking for shared dplls Just the plumbing, all the modeset and enable code has not yet been switched over to use the new state. It seems to be decently broken anyway, at least wrt to handling of the special pixel mutliplier enabling sequence. Follow-up patches will clean up that mess. Another missing piece is more careful handling (and fixup) of the fp1 alternate divisor state. The BIOS most likely doesn't bother to program that one to what we expect. So we need to be more careful with comparing that state, both for cross checking but also when checking for dpll sharing when acquiring shared dpll. Otherwise fastboot will deny a few shared dpll configurations which would otherwise work. v2: We need to memcpy the pipe config dpll hw state into the pll, for otherwise the cross-check code will get angry. v3: Don't forget to read the pch pll state in the crtc get_pipe_config function for ibx/ilk platforms. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 3 +++ 3 files changed, 44 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b998dcae089..42ef7cb39e62 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -143,6 +143,9 @@ enum intel_dpll_id { #define I915_NUM_PLLS 2 struct intel_dpll_hw_state { + uint32_t dpll; + uint32_t fp0; + uint32_t fp1; }; struct intel_shared_dpll { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cb724b6f8833..5b2fd9063a2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3087,7 +3087,11 @@ found: crtc->config.shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); + if (pll->active == 0) { + memcpy(&pll->hw_state, &crtc->config.dpll_hw_state, + sizeof(pll->hw_state)); + DRM_DEBUG_DRIVER("setting up %s\n", pll->name); WARN_ON(pll->on); assert_shared_dpll_disabled(dev_priv, pll); @@ -5718,6 +5722,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); + intel_crtc->config.dpll_hw_state.dpll = dpll | DPLL_VCO_ENABLE; + intel_crtc->config.dpll_hw_state.fp0 = fp; + if (has_reduced_clock) + intel_crtc->config.dpll_hw_state.fp1 = fp2; + else + intel_crtc->config.dpll_hw_state.fp1 = fp; + pll = intel_get_shared_dpll(intel_crtc, dpll, fp); if (pll == NULL) { DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", @@ -5837,6 +5848,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, return false; if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { + struct intel_shared_dpll *pll; + pipe_config->has_pch_encoder = true; tmp = I915_READ(FDI_RX_CTL(crtc->pipe)); @@ -5858,6 +5871,11 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, else pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A; } + + pll = &dev_priv->shared_dplls[pipe_config->shared_dpll]; + + WARN_ON(!pll->get_hw_state(dev_priv, pll, + &pipe_config->dpll_hw_state)); } else { pipe_config->pixel_multiplier = 1; } @@ -8054,6 +8072,15 @@ intel_pipe_config_compare(struct drm_device *dev, struct intel_crtc_config *current_config, struct intel_crtc_config *pipe_config) { +#define PIPE_CONF_CHECK_X(name) \ + if (current_config->name != pipe_config->name) { \ + DRM_ERROR("mismatch in " #name " " \ + "(expected 0x%08x, found 0x%08x)\n", \ + current_config->name, \ + pipe_config->name); \ + return false; \ + } + #define PIPE_CONF_CHECK_I(name) \ if (current_config->name != pipe_config->name) { \ DRM_ERROR("mismatch in " #name " " \ @@ -8130,7 +8157,11 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(ips_enabled); PIPE_CONF_CHECK_I(shared_dpll); + PIPE_CONF_CHECK_X(dpll_hw_state.dpll); + PIPE_CONF_CHECK_X(dpll_hw_state.fp0); + PIPE_CONF_CHECK_X(dpll_hw_state.fp1); +#undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_QUIRK @@ -8315,6 +8346,10 @@ check_shared_dpll_state(struct drm_device *dev) WARN(pll->refcount != enabled_crtcs, "pll enabled crtcs mismatch (expected %i, found %i)\n", pll->refcount, enabled_crtcs); + + WARN(pll->on && memcmp(&pll->hw_state, &dpll_hw_state, + sizeof(dpll_hw_state)), + "pll hw state mismatch\n"); } } @@ -8755,6 +8790,9 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv, uint32_t val; val = I915_READ(PCH_DPLL(pll->id)); + hw_state->dpll = val; + hw_state->fp0 = I915_READ(PCH_FP0(pll->id)); + hw_state->fp1 = I915_READ(PCH_FP1(pll->id)); return val & DPLL_VCO_ENABLE; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4a69bdc4f8ca..02e5d6557066 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -256,6 +256,9 @@ struct intel_crtc_config { /* Selected dpll when shared or DPLL_ID_PRIVATE. */ enum intel_dpll_id shared_dpll; + /* Actual register state of the dpll, for shared dpll cross-checking. */ + struct intel_dpll_hw_state dpll_hw_state; + int pipe_bpp; struct intel_link_m_n dp_m_n; -- cgit v1.2.3 From 959e16d65d808602cd88b82530626f964f684c05 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:21 +0200 Subject: drm/i915: fix up pch pll enabling for pixel multipliers We have a nice comment saying that the pixel multiplier only sticks once the vco is on and stable. The only problem is that the enable bit wasn't set at all. This patch fixes this and so brings the ilk+ pch pll code in line with the i8xx/i9xx pll code. Or at least improves matters a lot. This should fix sdvo on ilk-ivb for low-res modes. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5b2fd9063a2d..015614fb04d9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5660,7 +5660,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, else dpll |= PLL_REF_INPUT_DREFCLK; - return dpll; + return dpll | DPLL_VCO_ENABLE; } static int ironlake_crtc_mode_set(struct drm_crtc *crtc, @@ -5722,7 +5722,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, &fp, &reduced_clock, has_reduced_clock ? &fp2 : NULL); - intel_crtc->config.dpll_hw_state.dpll = dpll | DPLL_VCO_ENABLE; + intel_crtc->config.dpll_hw_state.dpll = dpll; intel_crtc->config.dpll_hw_state.fp0 = fp; if (has_reduced_clock) intel_crtc->config.dpll_hw_state.fp1 = fp2; -- cgit v1.2.3 From e0d8d59b0831523da61739c9d5e3bc3c77d7b5db Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 12 Jun 2013 22:11:18 +0300 Subject: drm/i915: Try harder to disable trickle feed on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specs are a bit unclear whether the per-plane trickle feed disable control exists on VLV. There is another trickle feed disable control in the MI_ARB register. After some experimentation it turns out both the DSPCNTR trickle feed bits and the MI_ARB bit can be toggled. However the DSPCNTR bits don't seem to have any effect. The MI_ARB bit, on the other hand, has a noticable effect. I performed an experiment where I reduced the FIFO size via DSPARB and observed the effect of the MI_ARB trickle feed bit on the display. Using a 1920x1080-60 mode, with MI_ARB=0x4 the display started to have problems with DSPARB=0x42424242, whereas with MI_ARB=0x0 the problems didn't start until DSPARB=0x09090909. This seems to confirm that the MI_ARB trickle feed bit actually does work. So replace the use of the DSPCNTR trickle feed bits with MI_ARB on VLV. v2: Amend commit message with results from experimentation Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 01e8783f1a97..4058eaa19894 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1367,6 +1367,8 @@ #define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) #define FW_CSPWRDWNEN (1<<15) +#define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504) + /* * Palette regs */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index adc44e42b23c..b27bda07f4ae 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4873,7 +4873,7 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE); - g4x_disable_trickle_feed(dev); + I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE); I915_WRITE(CACHE_MODE_1, _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE)); -- cgit v1.2.3 From e59ec13de40ed1edd19940322ebd009423fd716d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 12:35:28 +0300 Subject: drm/i915: add struct i915_ctx_hang_stats To count context losses, add struct i915_ctx_hang_stats for both i915_hw_context and drm_i915_file_private. drm_i915_file_private is used when there is no context. v2: renamed and cleaned up the struct (Chris Wilson, Ian Romanick) Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index fd8898c8f8e3..8e628dc43a5f 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1814,7 +1814,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file) struct drm_i915_file_private *file_priv; DRM_DEBUG_DRIVER("\n"); - file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL); + file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 42ef7cb39e62..124eb1a9e9c3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -508,6 +508,13 @@ struct i915_hw_ppgtt { void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; +struct i915_ctx_hang_stats { + /* This context had batch pending when hang was declared */ + unsigned batch_pending; + + /* This context had batch active when hang was declared */ + unsigned batch_active; +}; /* This must match up with the value previously used for execbuf2.rsvd1. */ #define DEFAULT_CONTEXT_ID 0 @@ -518,6 +525,7 @@ struct i915_hw_context { struct drm_i915_file_private *file_priv; struct intel_ring_buffer *ring; struct drm_i915_gem_object *obj; + struct i915_ctx_hang_stats hang_stats; }; enum no_fbc_reason { @@ -1377,6 +1385,8 @@ struct drm_i915_file_private { struct list_head request_list; } mm; struct idr context_idr; + + struct i915_ctx_hang_stats hang_stats; }; #define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info) -- cgit v1.2.3 From c0bb617a70c94d660001f06f9810d53085e2c88d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 12:35:29 +0300 Subject: drm/i915: add i915_gem_context_get_hang_stats() To get context hang statistics for specified context, add i915_gem_context_get_hang_stats(). For arb-robustness, every context needs to have its own hang statistics tracking. Added function will return the user specified context statistics or in case of default context, statistics from drm_i915_file_private. v2: handle default context inside get_reset_state v3: return struct pointer instead of passing it in as param (Chris Wilson) Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gem_context.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 124eb1a9e9c3..cfa928643651 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1812,6 +1812,10 @@ static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) kref_put(&ctx->ref, i915_gem_context_free); } +struct i915_ctx_hang_stats * __must_check +i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring, + struct drm_file *file, + u32 id); int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 39bcc087db96..f5ea3c1351f8 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -303,6 +303,34 @@ static int context_idr_cleanup(int id, void *p, void *data) return 0; } +struct i915_ctx_hang_stats * +i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring, + struct drm_file *file, + u32 id) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; + struct i915_hw_context *to; + + if (dev_priv->hw_contexts_disabled) + return ERR_PTR(-ENOENT); + + if (ring->id != RCS) + return ERR_PTR(-EINVAL); + + if (file == NULL) + return ERR_PTR(-EINVAL); + + if (id == DEFAULT_CONTEXT_ID) + return &file_priv->hang_stats; + + to = i915_gem_context_get(file->driver_priv, id); + if (to == NULL) + return ERR_PTR(-ENOENT); + + return &to->hang_stats; +} + void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; -- cgit v1.2.3 From 0025c0772de7451c2302fa628f038b213a0783bf Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 12:35:30 +0300 Subject: drm/i915: change i915_add_request to macro Only execbuffer needed all the parameters on i915_add_request(). By putting __i915_add_request behind macro, all current callsites become cleaner. Following patch will introduce a new parameter for __i915_add_request. With this patch, only the relevant callsite will reflect the change making commit smaller and easier to understand. v2: _i915_add_request as function name (Chris Wilson) v3: change name __i915_add_request and fix ordering of params (Ben Widawsky) Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 +++++--- drivers/gpu/drm/i915/i915_gem.c | 11 +++++------ drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 4 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cfa928643651..425200bc1e44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1756,9 +1756,11 @@ void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); -int i915_add_request(struct intel_ring_buffer *ring, - struct drm_file *file, - u32 *seqno); +int __i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + u32 *seqno); +#define i915_add_request(ring, seqno) \ + __i915_add_request(ring, NULL, seqno); int __must_check i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 58048d49256c..38e20875c255 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -959,7 +959,7 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) ret = 0; if (seqno == ring->outstanding_lazy_request) - ret = i915_add_request(ring, NULL, NULL); + ret = i915_add_request(ring, NULL); return ret; } @@ -2000,10 +2000,9 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) return 0; } -int -i915_add_request(struct intel_ring_buffer *ring, - struct drm_file *file, - u32 *out_seqno) +int __i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + u32 *out_seqno) { drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2280,7 +2279,7 @@ i915_gem_retire_work_handler(struct work_struct *work) idle = true; for_each_ring(ring, dev_priv, i) { if (ring->gpu_caches_dirty) - i915_add_request(ring, NULL, NULL); + i915_add_request(ring, NULL); idle &= list_empty(&ring->request_list); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index f5ea3c1351f8..ff471454968d 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -455,7 +455,7 @@ static int do_switch(struct i915_hw_context *to) from->obj->dirty = 1; BUG_ON(from->obj->ring != ring); - ret = i915_add_request(ring, NULL, NULL); + ret = i915_add_request(ring, NULL); if (ret) { /* Too late, we've already scheduled a context switch. * Try to undo the change so that the hw state is diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c98333d74111..d79ac7aa55d4 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -802,7 +802,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - (void)i915_add_request(ring, file, NULL); + (void)__i915_add_request(ring, file, NULL); } static int diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 836794b68fc6..a3698812e9c7 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -217,7 +217,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; BUG_ON(overlay->last_flip_req); - ret = i915_add_request(ring, NULL, &overlay->last_flip_req); + ret = i915_add_request(ring, &overlay->last_flip_req); if (ret) return ret; @@ -286,7 +286,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, intel_ring_emit(ring, flip_addr); intel_ring_advance(ring); - return i915_add_request(ring, NULL, &overlay->last_flip_req); + return i915_add_request(ring, &overlay->last_flip_req); } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a3cfa35b0573..e51ab552046c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1512,7 +1512,7 @@ int intel_ring_idle(struct intel_ring_buffer *ring) /* We need to add any requests required to flush the objects and ring */ if (ring->outstanding_lazy_request) { - ret = i915_add_request(ring, NULL, NULL); + ret = i915_add_request(ring, NULL); if (ret) return ret; } -- cgit v1.2.3 From 7d736f4f0b405b1421d280632ef077eb8135e5c6 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 15:01:39 +0300 Subject: drm/i915: add batch bo to i915_add_request() In order to track down a batch buffer and context which caused the ring to hang, store reference to bo into the request struct. Request can also cause gpu to hang after the batch in the flush section in the ring. To detect this add start of the flush portion offset into the request. v2: Included comment about request vs batch_obj lifetimes (Chris Wilson) Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 11 +++++++++-- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++++++- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 ++++--- 3 files changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 425200bc1e44..5ce3751ddb3c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1362,12 +1362,18 @@ struct drm_i915_gem_request { /** GEM sequence number associated with this request. */ uint32_t seqno; - /** Postion in the ringbuffer of the end of the request */ + /** Position in the ringbuffer of the start of the request */ + u32 head; + + /** Position in the ringbuffer of the end of the request */ u32 tail; /** Context related to this request */ struct i915_hw_context *ctx; + /** Batch buffer related to this request if any */ + struct drm_i915_gem_object *batch_obj; + /** Time at which this request was emitted, in jiffies. */ unsigned long emitted_jiffies; @@ -1758,9 +1764,10 @@ int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); int __i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, + struct drm_i915_gem_object *batch_obj, u32 *seqno); #define i915_add_request(ring, seqno) \ - __i915_add_request(ring, NULL, seqno); + __i915_add_request(ring, NULL, NULL, seqno); int __must_check i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 38e20875c255..dc32faecd9fc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2002,14 +2002,16 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) int __i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, + struct drm_i915_gem_object *obj, u32 *out_seqno) { drm_i915_private_t *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; - u32 request_ring_position; + u32 request_ring_position, request_start; int was_empty; int ret; + request_start = intel_ring_get_tail(ring); /* * Emit any outstanding flushes - execbuf can fail to emit the flush * after having emitted the batchbuffer command. Hence we need to fix @@ -2041,8 +2043,17 @@ int __i915_add_request(struct intel_ring_buffer *ring, request->seqno = intel_ring_get_seqno(ring); request->ring = ring; + request->head = request_start; request->tail = request_ring_position; request->ctx = ring->last_context; + request->batch_obj = obj; + + /* Whilst this request exists, batch_obj will be on the + * active_list, and so will hold the active reference. Only when this + * request is retired will the the batch_obj be moved onto the + * inactive_list and lose its active reference. Hence we do not need + * to explicitly hold another reference here. + */ if (request->ctx) i915_gem_context_reference(request->ctx); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d79ac7aa55d4..87a3227e5179 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -796,13 +796,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, static void i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct drm_file *file, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + struct drm_i915_gem_object *obj) { /* Unconditionally force add_request to emit a full flush. */ ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - (void)__i915_add_request(ring, file, NULL); + (void)__i915_add_request(ring, file, obj, NULL); } static int @@ -1083,7 +1084,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); i915_gem_execbuffer_move_to_active(&eb->objects, ring); - i915_gem_execbuffer_retire_commands(dev, file, ring); + i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); err: eb_destroy(eb); -- cgit v1.2.3 From ad8beaeada276b4b2d31e1c3422346e8829a67d6 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 12:35:32 +0300 Subject: drm/i915: store ring hangcheck action For guilty batchbuffer analysis later on when rings are reset, store what state the ring was on when hang was declared. This helps to weed out the waiting rings from the active ones. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 8 ++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b26243f09c91..208e6753aec5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2380,7 +2380,8 @@ static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv) ring->hangcheck.deadlock = false; } -static enum { wait, active, kick, hung } ring_stuck(struct intel_ring_buffer *ring, u32 acthd) +static enum intel_ring_hangcheck_action +ring_stuck(struct intel_ring_buffer *ring, u32 acthd) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2483,7 +2484,10 @@ void i915_hangcheck_elapsed(unsigned long data) * being repeatedly kicked and so responsible * for stalling the machine. */ - switch (ring_stuck(ring, acthd)) { + ring->hangcheck.action = ring_stuck(ring, + acthd); + + switch (ring->hangcheck.action) { case wait: score = 0; break; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index a3e96103dbe5..799f04c9da45 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -37,11 +37,14 @@ struct intel_hw_status_page { #define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base)) #define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base)) +enum intel_ring_hangcheck_action { wait, active, kick, hung }; + struct intel_ring_hangcheck { bool deadlock; u32 seqno; u32 acthd; int score; + enum intel_ring_hangcheck_action action; }; struct intel_ring_buffer { -- cgit v1.2.3 From aa60c664e6df502578454621c3a9b1f087ff8d25 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 12 Jun 2013 15:13:20 +0300 Subject: drm/i915: find guilty batch buffer on ring resets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After hang check timer has declared gpu to be hung, rings are reset. In ring reset, when clearing request list, do post mortem analysis to find out the guilty batch buffer. Select requests for further analysis by inspecting the completed sequence number which has been updated into the HWS page. If request was completed, it can't be related to the hang. For noncompleted requests mark the batch as guilty if the ring was not waiting and the ring head was stuck inside the buffer object or in the flush region right after the batch. For everything else, mark them as innocents. v2: Fixed a typo in commit message (Ville Syrjälä) v3: - more descriptive function parameters (Chris Wilson) - use masked head address when inspecting if request is in ring - s/hangcheck.last_action/hangcheck.action - added comment about unmasked head hitting batch_obj range Reviewed-by: Chris Wilson Signed-off-by: Mika Kuoppala Acked-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index dc32faecd9fc..9b20fbbfd338 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2110,6 +2110,94 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) spin_unlock(&file_priv->mm.lock); } +static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj) +{ + if (acthd >= obj->gtt_offset && + acthd < obj->gtt_offset + obj->base.size) + return true; + + return false; +} + +static bool i915_head_inside_request(const u32 acthd_unmasked, + const u32 request_start, + const u32 request_end) +{ + const u32 acthd = acthd_unmasked & HEAD_ADDR; + + if (request_start < request_end) { + if (acthd >= request_start && acthd < request_end) + return true; + } else if (request_start > request_end) { + if (acthd >= request_start || acthd < request_end) + return true; + } + + return false; +} + +static bool i915_request_guilty(struct drm_i915_gem_request *request, + const u32 acthd, bool *inside) +{ + /* There is a possibility that unmasked head address + * pointing inside the ring, matches the batch_obj address range. + * However this is extremely unlikely. + */ + + if (request->batch_obj) { + if (i915_head_inside_object(acthd, request->batch_obj)) { + *inside = true; + return true; + } + } + + if (i915_head_inside_request(acthd, request->head, request->tail)) { + *inside = false; + return true; + } + + return false; +} + +static void i915_set_reset_status(struct intel_ring_buffer *ring, + struct drm_i915_gem_request *request, + u32 acthd) +{ + struct i915_ctx_hang_stats *hs = NULL; + bool inside, guilty; + + /* Innocent until proven guilty */ + guilty = false; + + if (ring->hangcheck.action != wait && + i915_request_guilty(request, acthd, &inside)) { + DRM_ERROR("%s hung %s bo (0x%x ctx %d) at 0x%x\n", + ring->name, + inside ? "inside" : "flushing", + request->batch_obj ? + request->batch_obj->gtt_offset : 0, + request->ctx ? request->ctx->id : 0, + acthd); + + guilty = true; + } + + /* If contexts are disabled or this is the default context, use + * file_priv->reset_state + */ + if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID) + hs = &request->ctx->hang_stats; + else if (request->file_priv) + hs = &request->file_priv->hang_stats; + + if (hs) { + if (guilty) + hs->batch_active++; + else + hs->batch_pending++; + } +} + static void i915_gem_free_request(struct drm_i915_gem_request *request) { list_del(&request->list); @@ -2124,6 +2212,12 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request) static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct intel_ring_buffer *ring) { + u32 completed_seqno; + u32 acthd; + + acthd = intel_ring_get_active_head(ring); + completed_seqno = ring->get_seqno(ring, false); + while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; @@ -2131,6 +2225,9 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv, struct drm_i915_gem_request, list); + if (request->seqno > completed_seqno) + i915_set_reset_status(ring, request, acthd); + i915_gem_free_request(request); } -- cgit v1.2.3 From b72447cdf1298b46af87d754bfb5d3db6eb7dbfe Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 3 Jun 2013 16:11:41 +0300 Subject: drm/i915: Drop bogus fbdev sprite disable code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plane->enabled is never set, so this code didn't do anything. Also drm_fb_helper_restore_fbdev_mode() will now disable all cursors and sprites for us, so we don't have to bother anymore. Signed-off-by: Ville Syrjälä Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_fb.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 6b7c3ca2c035..3b03c3c6cc5d 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -292,8 +292,6 @@ void intel_fb_restore_mode(struct drm_device *dev) { int ret; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_mode_config *config = &dev->mode_config; - struct drm_plane *plane; if (INTEL_INFO(dev)->num_pipes == 0) return; @@ -304,10 +302,5 @@ void intel_fb_restore_mode(struct drm_device *dev) if (ret) DRM_DEBUG("failed to restore crtc mode\n"); - /* Be sure to shut off any planes that may be active */ - list_for_each_entry(plane, &config->plane_list, head) - if (plane->enabled) - plane->funcs->disable_plane(plane); - drm_modeset_unlock_all(dev); } -- cgit v1.2.3 From 78114071ff9e3c2f6c1715bfb01ac8c0b3618e72 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Jun 2013 00:54:57 +0200 Subject: drm/i915: set up PIPECONF explicitly on ilk-ivb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dragging random garbage along from the BIOS isn't a good idea, since we really only support exactly what we've set up. In the specific case for the bug reporter the BIOS used the 10bit gamma table, but since we only support an 8bit table the dark colors ended up all wrong and the light ones all unadjusted. Note that this has a nice implication for fastboot, it essentially means that we have quite a bit more state to check and compare before we can decide whether fastboot is possible. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65593 Reported-and-Tested-by: Thomas Hebb Cc: stable@vger.kernel.org Reviewed-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 015614fb04d9..3097fb164fd8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5342,9 +5342,8 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; uint32_t val; - val = I915_READ(PIPECONF(pipe)); + val = 0; - val &= ~PIPECONF_BPC_MASK; switch (intel_crtc->config.pipe_bpp) { case 18: val |= PIPECONF_6BPC; @@ -5363,11 +5362,9 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc) BUG(); } - val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); - val &= ~PIPECONF_INTERLACE_MASK; if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) val |= PIPECONF_INTERLACED_ILK; else @@ -5375,8 +5372,6 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc) if (intel_crtc->config.limited_color_range) val |= PIPECONF_COLOR_RANGE_SELECT; - else - val &= ~PIPECONF_COLOR_RANGE_SELECT; I915_WRITE(PIPECONF(pipe), val); POSTING_READ(PIPECONF(pipe)); -- cgit v1.2.3 From 9f11a9e4e50006b615ba94722dfc33ced89664cf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Jun 2013 00:54:58 +0200 Subject: drm/i915: set up PIPECONF explicitly for i9xx/vlv platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same reasons as for the previous patch, just no bug report about anything going wrong yet: We only support exactly the mode we program, so don't leave any stale BIOS state behind. Again this will be fun to properly track for fastboot. Reviewed-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3097fb164fd8..a6b4bee9034c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4736,7 +4736,7 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t pipeconf; - pipeconf = I915_READ(PIPECONF(intel_crtc->pipe)); + pipeconf = 0; if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) { /* Enable pixel doubling when the dot clock is > 90% of the (display) @@ -4748,15 +4748,10 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) if (intel_crtc->config.requested_mode.clock > dev_priv->display.get_display_clock_speed(dev) * 9 / 10) pipeconf |= PIPECONF_DOUBLE_WIDE; - else - pipeconf &= ~PIPECONF_DOUBLE_WIDE; } /* only g4x and later have fancy bpc/dither controls */ if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { - pipeconf &= ~(PIPECONF_BPC_MASK | - PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); - /* Bspec claims that we can't use dithering for 30bpp pipes. */ if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30) pipeconf |= PIPECONF_DITHER_EN | @@ -4784,23 +4779,17 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) pipeconf |= PIPECONF_CXSR_DOWNCLOCK; } else { DRM_DEBUG_KMS("disabling CxSR downclocking\n"); - pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK; } } - pipeconf &= ~PIPECONF_INTERLACE_MASK; if (!IS_GEN2(dev) && intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION; else pipeconf |= PIPECONF_PROGRESSIVE; - if (IS_VALLEYVIEW(dev)) { - if (intel_crtc->config.limited_color_range) - pipeconf |= PIPECONF_COLOR_RANGE_SELECT; - else - pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT; - } + if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range) + pipeconf |= PIPECONF_COLOR_RANGE_SELECT; I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf); POSTING_READ(PIPECONF(intel_crtc->pipe)); -- cgit v1.2.3 From 3eff4faa9f59c581538663e3f42b9e16210cafd0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 13 Jun 2013 00:54:59 +0200 Subject: drm/i915: explicitly set up PIPECONF (and gamma table) on haswell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again we don't really support different settings, so don't let the BIOS sneak stuff through. Since the motivation for this patch series is to ensure we have the correct gamma table mode selected also add the required write to the GAMMA_MODE register to select the 8bit legacy table. And since I find lowercase letters in #defines offensive, also bikeshed those. Reviewed-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_display.c | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4058eaa19894..2102ff32ee20 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3672,9 +3672,9 @@ #define _GAMMA_MODE_B 0x4ac80 #define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) #define GAMMA_MODE_MODE_MASK (3 << 0) -#define GAMMA_MODE_MODE_8bit (0 << 0) -#define GAMMA_MODE_MODE_10bit (1 << 0) -#define GAMMA_MODE_MODE_12bit (2 << 0) +#define GAMMA_MODE_MODE_8BIT (0 << 0) +#define GAMMA_MODE_MODE_10BIT (1 << 0) +#define GAMMA_MODE_MODE_12BIT (2 << 0) #define GAMMA_MODE_MODE_SPLIT (3 << 0) /* interrupts */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a6b4bee9034c..06b1180c4c16 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5437,13 +5437,11 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc) enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; uint32_t val; - val = I915_READ(PIPECONF(cpu_transcoder)); + val = 0; - val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK); if (intel_crtc->config.dither) val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP); - val &= ~PIPECONF_INTERLACE_MASK_HSW; if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) val |= PIPECONF_INTERLACED_ILK; else @@ -5451,6 +5449,9 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc) I915_WRITE(PIPECONF(cpu_transcoder), val); POSTING_READ(PIPECONF(cpu_transcoder)); + + I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT); + POSTING_READ(GAMMA_MODE(intel_crtc->pipe)); } static bool ironlake_compute_clocks(struct drm_crtc *crtc, -- cgit v1.2.3 From c9093354a1e839be057aee66bac37bd3b2f44d0e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Jun 2013 22:22:47 +0200 Subject: drm/i915: stop killing pfit on i9xx Nowadays (i.e. with Valleyview) we also have edp on non-PCH_SPLIT platforms, so just checking for LVDS is not good enough. Secondly we have full pfit pipe config tracking, so we'll correctly disable the pfit as part of the initial modeset. For fastboot we need a bit of work here to correctly kill unsupported configs (if e.g. the pfit is used on anything else than the built-in panel). But since that's not yet supported we don't need to worry. Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +------ drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_lvds.c | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 06b1180c4c16..d617a72cc5c8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8959,13 +8959,8 @@ static void intel_setup_outputs(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *encoder; bool dpd_is_edp = false; - bool has_lvds; - has_lvds = intel_lvds_init(dev); - if (!has_lvds && !HAS_PCH_SPLIT(dev)) { - /* disable the panel fitter on everything but LVDS */ - I915_WRITE(PFIT_CONTROL, 0); - } + intel_lvds_init(dev); if (!IS_ULT(dev)) intel_crt_init(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02e5d6557066..ffe9d35b37b4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -582,7 +582,7 @@ extern void intel_mark_busy(struct drm_device *dev); extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring); extern void intel_mark_idle(struct drm_device *dev); -extern bool intel_lvds_init(struct drm_device *dev); +extern void intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 10c3d56332f5..eeff28ec2ff4 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -877,7 +877,7 @@ static bool intel_lvds_supported(struct drm_device *dev) * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present). */ -bool intel_lvds_init(struct drm_device *dev) +void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_lvds_encoder *lvds_encoder; @@ -895,35 +895,35 @@ bool intel_lvds_init(struct drm_device *dev) u8 pin; if (!intel_lvds_supported(dev)) - return false; + return; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) - return false; + return; pin = GMBUS_PORT_PANEL; if (!lvds_is_present_in_vbt(dev, &pin)) { DRM_DEBUG_KMS("LVDS is not present in VBT\n"); - return false; + return; } if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) - return false; + return; if (dev_priv->vbt.edp_support) { DRM_DEBUG_KMS("disable LVDS for eDP support\n"); - return false; + return; } } lvds_encoder = kzalloc(sizeof(struct intel_lvds_encoder), GFP_KERNEL); if (!lvds_encoder) - return false; + return; lvds_connector = kzalloc(sizeof(struct intel_lvds_connector), GFP_KERNEL); if (!lvds_connector) { kfree(lvds_encoder); - return false; + return; } lvds_encoder->attached_connector = lvds_connector; @@ -1094,7 +1094,7 @@ out: intel_panel_init(&intel_connector->panel, fixed_mode); intel_panel_setup_backlight(connector); - return true; + return; failed: DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); @@ -1104,5 +1104,5 @@ failed: drm_mode_destroy(dev, fixed_mode); kfree(lvds_encoder); kfree(lvds_connector); - return false; + return; } -- cgit v1.2.3 From bcd644e046d97b317255ee75f0ebd289b9bcd9ba Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 5 Jun 2013 13:34:22 +0200 Subject: drm/i915: simplify the reduced clock handling for pch plls Just move the lowfreq_avail logic out of the register writing as a prep step for the next patch, which will coalesce all the pch pll enabling into one spot. Note that writing the reduced clock dividers to FP1 in a few more cases (as this patch ends up doing) isn't really relevant since the FP1 value only matters when we enable the low lock. Which despite can only happen if we've actually enabled the reduced dotclock and furthermore isn't even properly implemented on ilk+: Despite claims to the contrary in the code switching between frequencies if fully manual. v2: Explain matters around the FP1 change to answer a question Damien raised in his review. Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d617a72cc5c8..b23937bbbcd8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5730,7 +5730,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, if (encoder->pre_pll_enable) encoder->pre_pll_enable(encoder); - intel_crtc->lowfreq_avail = false; + if (is_lvds && has_reduced_clock && i915_powersave) + intel_crtc->lowfreq_avail = true; + else + intel_crtc->lowfreq_avail = false; if (intel_crtc->config.has_pch_encoder) { pll = intel_crtc_to_shared_dpll(intel_crtc); @@ -5748,12 +5751,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, */ I915_WRITE(PCH_DPLL(pll->id), dpll); - if (is_lvds && has_reduced_clock && i915_powersave) { + if (has_reduced_clock) I915_WRITE(PCH_FP1(pll->id), fp2); - intel_crtc->lowfreq_avail = true; - } else { + else I915_WRITE(PCH_FP1(pll->id), fp); - } } intel_set_pipe_timings(intel_crtc); -- cgit v1.2.3 From acd78c117f0ac6960dc9e51801adb59810e49e75 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 13 Jun 2013 21:33:33 -0700 Subject: drm/i915: Remove extra "ring" from error message The ring names already have "ring" in it. CC: Chris Wilson Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 208e6753aec5..7857430943ec 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2519,7 +2519,7 @@ void i915_hangcheck_elapsed(unsigned long data) for_each_ring(ring, dev_priv, i) { if (ring->hangcheck.score > FIRE) { - DRM_ERROR("%s on %s ring\n", + DRM_ERROR("%s on %s\n", stuck[i] ? "stuck" : "no progress", ring->name); rings_hung++; -- cgit v1.2.3 From 05d62b831367cece58363dfe5768a00d2a1faaf5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 14 Jun 2013 00:51:23 +0200 Subject: drm/i915: Kill useless "Enable panel fitter" comments Now that we have this all nicely abstract into separate functions with self-documenting names this is pointless. And as Yuly Novikov spotted in the case of ilk-ivb also wrong since we use the pfit both for lvds and eDP Reported-By: Yuly Novikov Cc: Jesse Barnes Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b23937bbbcd8..218bc938936e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3209,7 +3209,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_enable) encoder->pre_enable(encoder); - /* Enable panel fitting for LVDS */ ironlake_pfit_enable(intel_crtc); /* @@ -3315,7 +3314,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_clock(intel_crtc); - /* Enable panel fitting for eDP */ ironlake_pfit_enable(intel_crtc); /* @@ -3611,7 +3609,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); - /* Enable panel fitting for eDP */ i9xx_pfit_enable(intel_crtc); intel_crtc_load_lut(crtc); @@ -3649,7 +3646,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) if (encoder->pre_enable) encoder->pre_enable(encoder); - /* Enable panel fitting for LVDS */ i9xx_pfit_enable(intel_crtc); intel_crtc_load_lut(crtc); -- cgit v1.2.3 From 854c94a7854a4fabdd7db451cf1774e6dcba6bab Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Jun 2013 10:29:58 +0300 Subject: drm/i915: remove a superflous semi-colon This macro doesn't need a semi-colon. Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5ce3751ddb3c..4b5ee47b4995 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1767,7 +1767,7 @@ int __i915_add_request(struct intel_ring_buffer *ring, struct drm_i915_gem_object *batch_obj, u32 *seqno); #define i915_add_request(ring, seqno) \ - __i915_add_request(ring, NULL, NULL, seqno); + __i915_add_request(ring, NULL, NULL, seqno) int __must_check i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -- cgit v1.2.3 From acd8db100ed5220fe8043f91cdc20155325542a9 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:23 -0300 Subject: drm/i915: don't check encoder at DP connector destroy() By the time we call intel_dp_destroy (which destroys the connector) the encoder may have been destroyed already, so if we use it we may be reading some free memory. That happens in drm_mode_config_cleanup() and also inside intel_dp_init_connector() when we detect a ghost eDP. I also hope this may solve some random memory bugs. Reported by kmemcheck. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 98686005dcf6..6975d4bdad6b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2683,13 +2683,14 @@ done: static void intel_dp_destroy(struct drm_connector *connector) { - struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_connector *intel_connector = to_intel_connector(connector); if (!IS_ERR_OR_NULL(intel_connector->edid)) kfree(intel_connector->edid); - if (is_edp(intel_dp)) + /* Can't call is_edp() since the encoder may have been destroyed + * already. */ + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) intel_panel_fini(&intel_connector->panel); drm_sysfs_connector_remove(connector); -- cgit v1.2.3 From ed92f0b239ac971edc509169ae3d6955fbe0a188 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:24 -0300 Subject: drm/i915: extract intel_edp_init_connector Because intel_dp_init_connector is too big for my poor little brain. No functional changes. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 151 ++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 69 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6975d4bdad6b..30514e58269b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2955,6 +2955,86 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_READ(pp_div_reg)); } +static bool intel_edp_init_connector(struct intel_dp *intel_dp, + struct intel_connector *intel_connector) +{ + struct drm_connector *connector = &intel_connector->base; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_display_mode *fixed_mode = NULL; + struct edp_power_seq power_seq = { 0 }; + bool has_dpcd; + struct drm_display_mode *scan; + struct edid *edid; + + if (!is_edp(intel_dp)) + return true; + + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + + /* Cache DPCD and EDID for edp. */ + ironlake_edp_panel_vdd_on(intel_dp); + has_dpcd = intel_dp_get_dpcd(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, false); + + if (has_dpcd) { + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) + dev_priv->no_aux_handshake = + intel_dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_NO_AUX_HANDSHAKE_LINK_TRAINING; + } else { + /* if this fails, presume the device is a ghost */ + DRM_INFO("failed to retrieve link info, disabling eDP\n"); + intel_dp_encoder_destroy(&intel_dig_port->base.base); + intel_dp_destroy(connector); + return false; + } + + /* We now know it's not a ghost, init power sequence regs. */ + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, + &power_seq); + + ironlake_edp_panel_vdd_on(intel_dp); + edid = drm_get_edid(connector, &intel_dp->adapter); + if (edid) { + if (drm_add_edid_modes(connector, edid)) { + drm_mode_connector_update_edid_property(connector, + edid); + drm_edid_to_eld(connector, edid); + } else { + kfree(edid); + edid = ERR_PTR(-EINVAL); + } + } else { + edid = ERR_PTR(-ENOENT); + } + intel_connector->edid = edid; + + /* prefer fixed mode from EDID if available */ + list_for_each_entry(scan, &connector->probed_modes, head) { + if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { + fixed_mode = drm_mode_duplicate(dev, scan); + break; + } + } + + /* fallback to VBT if available for eDP */ + if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { + fixed_mode = drm_mode_duplicate(dev, + dev_priv->vbt.lfp_lvds_vbt_mode); + if (fixed_mode) + fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; + } + + ironlake_edp_panel_vdd_off(intel_dp, false); + + intel_panel_init(&intel_connector->panel, fixed_mode); + intel_panel_setup_backlight(connector); + + return true; +} + void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector) @@ -2964,8 +3044,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *fixed_mode = NULL; - struct edp_power_seq power_seq = { 0 }; enum port port = intel_dig_port->port; const char *name = NULL; int type; @@ -3066,75 +3144,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - if (is_edp(intel_dp)) - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_i2c_init(intel_dp, intel_connector, name); - /* Cache DPCD and EDID for edp. */ - if (is_edp(intel_dp)) { - bool ret; - struct drm_display_mode *scan; - struct edid *edid; - - ironlake_edp_panel_vdd_on(intel_dp); - ret = intel_dp_get_dpcd(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, false); - - if (ret) { - if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) - dev_priv->no_aux_handshake = - intel_dp->dpcd[DP_MAX_DOWNSPREAD] & - DP_NO_AUX_HANDSHAKE_LINK_TRAINING; - } else { - /* if this fails, presume the device is a ghost */ - DRM_INFO("failed to retrieve link info, disabling eDP\n"); - intel_dp_encoder_destroy(&intel_encoder->base); - intel_dp_destroy(connector); - return; - } - - /* We now know it's not a ghost, init power sequence regs. */ - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); - - ironlake_edp_panel_vdd_on(intel_dp); - edid = drm_get_edid(connector, &intel_dp->adapter); - if (edid) { - if (drm_add_edid_modes(connector, edid)) { - drm_mode_connector_update_edid_property(connector, edid); - drm_edid_to_eld(connector, edid); - } else { - kfree(edid); - edid = ERR_PTR(-EINVAL); - } - } else { - edid = ERR_PTR(-ENOENT); - } - intel_connector->edid = edid; - - /* prefer fixed mode from EDID if available */ - list_for_each_entry(scan, &connector->probed_modes, head) { - if ((scan->type & DRM_MODE_TYPE_PREFERRED)) { - fixed_mode = drm_mode_duplicate(dev, scan); - break; - } - } - - /* fallback to VBT if available for eDP */ - if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) { - fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode); - if (fixed_mode) - fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; - } - - ironlake_edp_panel_vdd_off(intel_dp, false); - } - - if (is_edp(intel_dp)) { - intel_panel_init(&intel_connector->panel, fixed_mode); - intel_panel_setup_backlight(connector); - } + if (!intel_edp_init_connector(intel_dp, intel_connector)) + return; intel_dp_add_properties(intel_dp, connector); -- cgit v1.2.3 From 16c255335b0ec39b4e5e976f4b260978aeed5a68 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:25 -0300 Subject: drm/i915: propagate errors from intel_dp_init_connector In case we detect a "ghost eDP", intel_edp_init_connector frees both the connector and encoder and then returns. On Haswell, intel_ddi_init then tries to use the freed encoder on the HDMI initialization path since the following commit: commit 21a8e6a4853b2ed39fa4c5188a710f2cf1b92026 Author: Daniel Vetter Date: Wed Apr 10 23:28:35 2013 +0200 drm/i915: don't setup hdmi for port D edp in ddi_init So now on intel_ddi_init we check for the "ghost eDP" case and return without trying to initialize HDMI. This way we won't try to read the freed "intel_encoder" struct in the next "if" statement. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 ++- drivers/gpu/drm/i915/intel_dp.c | 6 ++++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 224ce25129ce..0f835d15c18b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1356,7 +1356,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_ddi_hot_plug; - intel_dp_init_connector(intel_dig_port, dp_connector); + if (!intel_dp_init_connector(intel_dig_port, dp_connector)) + return; if (intel_encoder->type != INTEL_OUTPUT_EDP) { hdmi_connector = kzalloc(sizeof(struct intel_connector), diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 30514e58269b..1a429cf55291 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3035,7 +3035,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, return true; } -void +bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector) { @@ -3147,7 +3147,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_i2c_init(intel_dp, intel_connector, name); if (!intel_edp_init_connector(intel_dp, intel_connector)) - return; + return false; intel_dp_add_properties(intel_dp, connector); @@ -3159,6 +3159,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, u32 temp = I915_READ(PEG_BAND_GAP_DATA); I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } + + return true; } void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ffe9d35b37b4..9ddbe3b49fef 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -586,7 +586,7 @@ extern void intel_lvds_init(struct drm_device *dev); extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); -extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, +extern bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_start_link_train(struct intel_dp *intel_dp); -- cgit v1.2.3 From b2f246a8998ccf9e00477c8829a62139804e9857 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:26 -0300 Subject: drm/i915: fix the "ghost eDP" connector unwind path Because calling intel_dp_destroy inside intel_edp_init_connector is just wrong. This is the initialization path, so we should properly unwind all the initialization through the whole caller stack. On the intel_dp_destroy function we do the following: 1 - Free edid if it exists 2 - Call intel_panel_fini in case it's eDP 3 - Call drm_sysfs_connector_remove 4 - Call drm_connector_cleanup 5 - Free the connector And here is how we unwind each specific step: 1 - No need as we still didn't assign anything 2 - No need as we still didn't call intel_panel_init 3 - Call it in the same function that called drm_sysfs_connector_add 4 - Call it in the same function that called drm_connector_init 5 - Free it in the same function that allocated it Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 4 +++- drivers/gpu/drm/i915/intel_dp.c | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0f835d15c18b..aed363cabe07 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1356,8 +1356,10 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_ddi_hot_plug; - if (!intel_dp_init_connector(intel_dig_port, dp_connector)) + if (!intel_dp_init_connector(intel_dig_port, dp_connector)) { + kfree(dp_connector); return; + } if (intel_encoder->type != INTEL_OUTPUT_EDP) { hdmi_connector = kzalloc(sizeof(struct intel_connector), diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1a429cf55291..5ba0a612d463 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2987,7 +2987,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, /* if this fails, presume the device is a ghost */ DRM_INFO("failed to retrieve link info, disabling eDP\n"); intel_dp_encoder_destroy(&intel_dig_port->base.base); - intel_dp_destroy(connector); return false; } @@ -3146,8 +3145,11 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_i2c_init(intel_dp, intel_connector, name); - if (!intel_edp_init_connector(intel_dp, intel_connector)) + if (!intel_edp_init_connector(intel_dp, intel_connector)) { + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); return false; + } intel_dp_add_properties(intel_dp, connector); @@ -3206,5 +3208,6 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_dp_hot_plug; - intel_dp_init_connector(intel_dig_port, intel_connector); + if (!intel_dp_init_connector(intel_dig_port, intel_connector)) + kfree(intel_connector); } -- cgit v1.2.3 From 15b1d171d87e86366266255462e6b11d21b61c1c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:27 -0300 Subject: drm/i915: fix the "ghost eDP" encoder unwind path Because calling intel_dp_encoder_destroy inside intel_edp_init_connector is just wrong. This is the initialization path, so we should properly unwind all the initialization through the whole caller stack. On the intel_dp_encoder_destroy function we do the following: 1 - Call i2c_del_adapter 2 - Call drm_encoder_cleanup 3 - If edp: 3.1 - Cancel panel_vdd_work 3.2 - Call ironlake_panel_vdd_of_sync 4 - Free the encoder And here is how we unwind each specific step: 1 - We have intel_dp_init_connector -> intel_dp_i2c_init -> i2c_dp_aux_add_bus -> i2c_add_adapter, so we call i2c_del_dapter at intel_dp_init_connector 2 - Call it in the same function that called drm_encoder_init 3 - Call it in the same function that called INIT_DELAYED_WORK 4 - Free it in the same function that allocated it Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 ++ drivers/gpu/drm/i915/intel_dp.c | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index aed363cabe07..324211ac9c55 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1357,6 +1357,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->hot_plug = intel_ddi_hot_plug; if (!intel_dp_init_connector(intel_dig_port, dp_connector)) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); kfree(dp_connector); return; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ba0a612d463..ed1d34680125 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2986,7 +2986,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, } else { /* if this fails, presume the device is a ghost */ DRM_INFO("failed to retrieve link info, disabling eDP\n"); - intel_dp_encoder_destroy(&intel_dig_port->base.base); return false; } @@ -3146,6 +3145,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_i2c_init(intel_dp, intel_connector, name); if (!intel_edp_init_connector(intel_dp, intel_connector)) { + i2c_del_adapter(&intel_dp->adapter); + if (is_edp(intel_dp)) { + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + mutex_lock(&dev->mode_config.mutex); + ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->mode_config.mutex); + } drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); return false; @@ -3208,6 +3214,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->cloneable = false; intel_encoder->hot_plug = intel_dp_hot_plug; - if (!intel_dp_init_connector(intel_dig_port, intel_connector)) + if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { + drm_encoder_cleanup(encoder); + kfree(intel_dig_port); kfree(intel_connector); + } } -- cgit v1.2.3 From b2a1475561d59e8d182ba8cc4b7e78b662a3f533 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:28 -0300 Subject: drm/i915: check the return value of intel_dp_i2c_init We've been ignoring this return value, so print a nice backtrace in case it's not what we expected. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ed1d34680125..591502c6f34c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3044,7 +3044,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; const char *name = NULL; - int type; + int type, error; /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); @@ -3142,7 +3142,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, BUG(); } - intel_dp_i2c_init(intel_dp, intel_connector, name); + error = intel_dp_i2c_init(intel_dp, intel_connector, name); + WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n", + error, port_name(port)); if (!intel_edp_init_connector(intel_dp, intel_connector)) { i2c_del_adapter(&intel_dp->adapter); -- cgit v1.2.3 From 73845adf3357c3c71da25e18f44e5a9924d666d5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 12 Jun 2013 17:27:30 -0300 Subject: drm/i915: rename intel_dp_destroy to intel_dp_connector_destroy Because it's the function that destroys the connector, not the encoder. And we already have intel_dp_encoder_destroy. This has annoyed me for a long time. Signed-off-by: Paulo Zanoni Reviewed-by: Zoltan Nyul Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 591502c6f34c..24a44ede867d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2681,7 +2681,7 @@ done: } static void -intel_dp_destroy(struct drm_connector *connector) +intel_dp_connector_destroy(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); @@ -2724,7 +2724,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { .detect = intel_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = intel_dp_set_property, - .destroy = intel_dp_destroy, + .destroy = intel_dp_connector_destroy, }; static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { -- cgit v1.2.3 From 6a9c4b35e6696a63805b6da5e4889c6986e9ee1b Mon Sep 17 00:00:00 2001 From: Rui Guo Date: Wed, 19 Jun 2013 21:10:23 +0800 Subject: drm/i915: Fix PCH detect with multiple ISA bridges in VM In some virtualized environments (e.g. XEN), there is irrelevant ISA bridge in the system. To work reliably, we should scan trhough all the ISA bridge devices and check for the first match, instead of only checking the first one. Signed-off-by: Rui Guo [danvet: Fixup conflict with the num_pch_pll removal. And add subsystem header to the commit message headline.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index deaa32e8113b..062cbda1bf4a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -465,9 +465,15 @@ void intel_detect_pch(struct drm_device *dev) * make graphics device passthrough work easy for VMM, that only * need to expose ISA bridge to let driver know the real hardware * underneath. This is a requirement from virtualization team. + * + * In some virtualized environments (e.g. XEN), there is irrelevant + * ISA bridge in the system. To work reliably, we should scan trhough + * all the ISA bridge devices and check for the first match, instead + * of only checking the first one. */ pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - if (pch) { + while (pch) { + struct pci_dev *curr = pch; if (pch->vendor == PCI_VENDOR_ID_INTEL) { unsigned short id; id = pch->device & INTEL_PCH_DEVICE_ID_MASK; @@ -496,10 +502,18 @@ void intel_detect_pch(struct drm_device *dev) DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); WARN_ON(!IS_ULT(dev)); + } else { + goto check_next; } + pci_dev_put(pch); + break; } - pci_dev_put(pch); +check_next: + pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr); + pci_dev_put(curr); } + if (!pch) + DRM_DEBUG_KMS("No PCH found?\n"); } bool i915_semaphore_is_enabled(struct drm_device *dev) -- cgit v1.2.3 From 1625e7e549c50fb57a1e1ab1cb0f5735c84c9029 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 24 Jun 2013 11:47:48 -0400 Subject: drm/i915: make compact dma scatter lists creation work with SWIOTLB backend. Git commit 90797e6d1ec0dfde6ba62a48b9ee3803887d6ed4 ("drm/i915: create compact dma scatter lists for gem objects") makes certain assumptions about the under laying DMA API that are not always correct. On a ThinkPad X230 with an Intel HD 4000 with Xen during the bootup I see: [drm:intel_pipe_set_base] *ERROR* pin & fence failed [drm:intel_crtc_set_config] *ERROR* failed to set mode on [CRTC:3], err = -28 Bit of debugging traced it down to dma_map_sg failing (in i915_gem_gtt_prepare_object) as some of the SG entries were huge (3MB). That unfortunately are sizes that the SWIOTLB is incapable of handling - the maximum it can handle is a an entry of 512KB of virtual contiguous memory for its bounce buffer. (See IO_TLB_SEGSIZE). Previous to the above mention git commit the SG entries were of 4KB, and the code introduced by above git commit squashed the CPU contiguous PFNs in one big virtual address provided to DMA API. This patch is a simple semi-revert - were we emulate the old behavior if we detect that SWIOTLB is online. If it is not online then we continue on with the new compact scatter gather mechanism. An alternative solution would be for the the '.get_pages' and the i915_gem_gtt_prepare_object to retry with smaller max gap of the amount of PFNs that can be combined together - but with this issue discovered during rc7 that might be too risky. Reported-and-Tested-by: Konrad Rzeszutek Wilk CC: Chris Wilson CC: Imre Deak CC: Daniel Vetter CC: David Airlie CC: Signed-off-by: Konrad Rzeszutek Wilk Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a6178baccb56..e31eeb1d7fd6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1802,7 +1802,14 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); } - +#ifdef CONFIG_SWIOTLB + if (swiotlb_nr_tbl()) { + st->nents++; + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + continue; + } +#endif if (!i || page_to_pfn(page) != last_pfn + 1) { if (i) sg = sg_next(sg); @@ -1813,8 +1820,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) } last_pfn = page_to_pfn(page); } - - sg_mark_end(sg); +#ifdef CONFIG_SWIOTLB + if (!swiotlb_nr_tbl()) +#endif + sg_mark_end(sg); obj->pages = st; if (i915_gem_object_needs_bit17_swizzle(obj)) -- cgit v1.2.3 From 0f4f7b57954dda93b10e3b46594b0bfe24bba22c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 24 Jun 2013 18:32:36 +0200 Subject: drm/i915: tune down DIDL warning about too many outputs Nothing the user (nor we) really can do about this, but upsets a nice quiet boot. Note that this happens mostly on SDVs where OEMs obviously haven't had a chance yet to appropriately trim the output list. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65988 Reviewed-by: Damien Lespiau [danvet: Amend commit message a bit to clarify a question from Paulo.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 79be7cfd3152..cfb8fb68f09c 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -311,8 +311,8 @@ static void intel_didl_outputs(struct drm_device *dev) list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { if (i >= 8) { - dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs detected via ACPI\n"); + dev_dbg(&dev->pdev->dev, + "More than 8 outputs detected via ACPI\n"); return; } status = @@ -338,8 +338,8 @@ blind_set: list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { - dev_printk(KERN_ERR, &dev->pdev->dev, - "More than 8 outputs in connector list\n"); + dev_dbg(&dev->pdev->dev, + "More than 8 outputs in connector list\n"); return; } switch (connector->connector_type) { -- cgit v1.2.3 From 3765f3048651586e2617793e9efe184ff8c79a97 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 7 Jun 2013 16:03:50 +0300 Subject: drm/i915: fix build warning on format specifier mismatch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/i915_gem.c: In function ‘i915_gem_object_bind_to_gtt’: drivers/gpu/drm/i915/i915_gem.c:3002:3: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 5 has type ‘size_t’ [-Wformat] v2: Use %zu instead of %d. Two char patch, and 100% wrong. (Ville) Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e31eeb1d7fd6..fa074cec8587 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3112,7 +3112,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, * before evicting everything in a vain attempt to find space. */ if (obj->base.size > gtt_max) { - DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%ld\n", + DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n", obj->base.size, map_and_fenceable ? "mappable" : "total", gtt_max); -- cgit v1.2.3 From f5adf94e5fed2468eef4f0c094b66bf834770d7b Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Mon, 24 Jun 2013 18:29:34 +0100 Subject: drm/i915: Introduce an HAS_IPS() macro Follow the trend and don't code conditions with platforms but with features. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d4e78b64ca87..f72d5a3fdfba 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1483,7 +1483,7 @@ static int i915_ips_status(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_ULT(dev)) { + if (!HAS_IPS(dev)) { seq_puts(m, "not supported\n"); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9e1bf6dcbb2a..cc1d6056ab70 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1474,6 +1474,8 @@ struct drm_i915_file_private { #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) +#define HAS_IPS(dev) (IS_ULT(dev)) + #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b08d1f9ce0de..17d5c7a3468b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3250,7 +3250,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) /* IPS only exists on ULT machines and is tied to pipe A. */ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) { - return IS_ULT(crtc->base.dev) && crtc->pipe == PIPE_A; + return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } static void hsw_enable_ips(struct intel_crtc *crtc) @@ -4069,7 +4069,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, pipe_config->pipe_bpp = 8*3; } - if (IS_HASWELL(dev)) + if (HAS_IPS(dev)) hsw_compute_ips_config(crtc, pipe_config); /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old -- cgit v1.2.3 From 4f7fd7095d85cd31c86cb9ba87bc301319630ccc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 24 Jun 2013 21:33:28 +0200 Subject: drm/i915: Fix up sdvo hpd pins for i965g/gm Bspec seems to be full of lies, at least it disagress with reality: Two systems corrobated that SDVO hpd bits are the same as on gen3. v2: Update comment a bit. Cc: Arthur Ranyan Cc: Chris Wilson Tested-by: Chris Wilson Reported-and-tested-by: Alex Fiestas Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=58405 Cc: stable@vger.kernel.org Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 13 ++----------- drivers/gpu/drm/i915/i915_reg.h | 13 ++++++------- 2 files changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7857430943ec..611da3a74479 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -70,15 +70,6 @@ static const u32 hpd_status_gen4[] = { [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; -static const u32 hpd_status_i965[] = { - [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, - [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965, - [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965, - [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS, - [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS, - [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS -}; - static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_CRT] = CRT_HOTPLUG_INT_STATUS, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915, @@ -3449,13 +3440,13 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? HOTPLUG_INT_STATUS_G4X : - HOTPLUG_INT_STATUS_I965); + HOTPLUG_INT_STATUS_I915); DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { if (hotplug_irq_storm_detect(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915)) i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2102ff32ee20..137be4c1abd1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1874,6 +1874,12 @@ /* SDVO is different across gen3/4 */ #define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3) #define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2) +/* + * Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm, + * since reality corrobates that they're the same as on gen3. But keep these + * bits here (and the comment!) to help any other lost wanderers back onto the + * right tracks. + */ #define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4) #define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2) #define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7) @@ -1885,13 +1891,6 @@ PORTC_HOTPLUG_INT_STATUS | \ PORTD_HOTPLUG_INT_STATUS) -#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \ - SDVOB_HOTPLUG_INT_STATUS_I965 | \ - SDVOC_HOTPLUG_INT_STATUS_I965 | \ - PORTB_HOTPLUG_INT_STATUS | \ - PORTC_HOTPLUG_INT_STATUS | \ - PORTD_HOTPLUG_INT_STATUS) - #define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \ SDVOB_HOTPLUG_INT_STATUS_I915 | \ SDVOC_HOTPLUG_INT_STATUS_I915 | \ -- cgit v1.2.3 From bf67dfeb6899e140710d2138535b519dd8e46417 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 25 Jun 2013 11:06:52 +0200 Subject: drm/i915: don't scream into dmesg when a modeset fails There are legit cases, e.g. when userspace asks for something impossible. So tune it down to debug output like we do with all other userspace-triggerable warnings. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66111#c5 Reviewed-by: Chris Wilson [danvet: Rebased.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17d5c7a3468b..623acf49358e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8753,8 +8753,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } if (ret) { - DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", - set->crtc->base.id, ret); + DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); fail: intel_set_config_restore_state(dev, config); -- cgit v1.2.3 From e4e9222d4b5e041c3b5a54ee21d6c62e7cc56609 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 16:38:21 +0300 Subject: drm/i915: Remove duplicated WaForceL3Serialization:vlv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to apply WaForceL3Serialization:vlv twice. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b27bda07f4ae..159254ffdb1d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4834,10 +4834,6 @@ static void valleyview_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_ROW_CHICKEN2, _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE)); - /* WaForceL3Serialization:vlv */ - I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) & - ~L3SQ_URB_READ_CAM_MATCH_DISABLE); - /* This is required by WaCatErrorRejectionIssue:vlv */ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | -- cgit v1.2.3 From a35cdaa0e13e24f3fccc518bfef1516aa8a8a665 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 25 Jun 2013 17:26:45 +0100 Subject: drm/i915: Detect invalid scanout pitches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Report back the user error of attempting to setup a CRTC with an invalid framebuffer pitch. This is trickier than it should be as on gen4, there is a restriction that tiled surfaces must have a stride less than 16k - which is less than the largest supported CRTC size. v2: Fix the limits for gen3 v3: Move check into intel_framebuffer_init() and fix VLV limits. (vsyrjala) v4: Use idiomatic '>=' for generation checks References: https://bugs.freedesktop.org/show_bug.cgi?id=65099 Signed-off-by: Chris Wilson Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 623acf49358e..d723819a450c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9121,6 +9121,7 @@ int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj) { + int pitch_limit; int ret; if (obj->tiling_mode == I915_TILING_Y) { @@ -9134,10 +9135,26 @@ int intel_framebuffer_init(struct drm_device *dev, return -EINVAL; } - /* FIXME <= Gen4 stride limits are bit unclear */ - if (mode_cmd->pitches[0] > 32768) { - DRM_DEBUG("pitch (%d) must be at less than 32768\n", - mode_cmd->pitches[0]); + if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) { + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 4) { + if (obj->tiling_mode) + pitch_limit = 16*1024; + else + pitch_limit = 32*1024; + } else if (INTEL_INFO(dev)->gen >= 3) { + if (obj->tiling_mode) + pitch_limit = 8*1024; + else + pitch_limit = 16*1024; + } else + /* XXX DSPC is limited to 4k tiled */ + pitch_limit = 8*1024; + + if (mode_cmd->pitches[0] > pitch_limit) { + DRM_DEBUG("%s pitch (%d) must be at less than %d\n", + obj->tiling_mode ? "tiled" : "linear", + mode_cmd->pitches[0], pitch_limit); return -EINVAL; } -- cgit v1.2.3 From 73008b989faf4200907a858f9b902ee29d6edbea Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 19:21:01 +0300 Subject: drm/i915: Clean up VLV rps code a bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always print both the MHz value and raw register value for rps stuff. Also kill a somewhat pointless local 'rpe' variable and just use dev_priv->rps.rpe_delay. While at it clean up the caps in "GPU" and "Punit" debug messages. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 50 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 159254ffdb1d..33aa2d6674e5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3080,10 +3080,11 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); - DRM_DEBUG_DRIVER("gpu freq request from %d to %d\n", + DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), - vlv_gpu_freq(dev_priv->mem_freq, val)); + dev_priv->rps.cur_delay, + vlv_gpu_freq(dev_priv->mem_freq, val), val); if (val == dev_priv->rps.cur_delay) return; @@ -3101,8 +3102,9 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); if ((pval >> 8) != val) - DRM_DEBUG_DRIVER("punit overrode freq: %d requested, but got %d\n", - val, pval >> 8); + DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, val), val, + vlv_gpu_freq(dev_priv->mem_freq, pval >> 8), pval >> 8); /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. @@ -3496,7 +3498,7 @@ static void valleyview_enable_rps(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - u32 gtfifodbg, val, rpe; + u32 gtfifodbg, val; int i; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -3557,31 +3559,39 @@ static void valleyview_enable_rps(struct drm_device *dev) DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no"); DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val); - DRM_DEBUG_DRIVER("current GPU freq: %d\n", - vlv_gpu_freq(dev_priv->mem_freq, (val >> 8) & 0xff)); dev_priv->rps.cur_delay = (val >> 8) & 0xff; + DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.cur_delay), + dev_priv->rps.cur_delay); dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv); dev_priv->rps.hw_max = dev_priv->rps.max_delay; - DRM_DEBUG_DRIVER("max GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, - dev_priv->rps.max_delay)); + DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.max_delay), + dev_priv->rps.max_delay); - rpe = valleyview_rps_rpe_freq(dev_priv); - DRM_DEBUG_DRIVER("RPe GPU freq: %d\n", - vlv_gpu_freq(dev_priv->mem_freq, rpe)); - dev_priv->rps.rpe_delay = rpe; + dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv); + DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.rpe_delay), + dev_priv->rps.rpe_delay); - val = valleyview_rps_min_freq(dev_priv); - DRM_DEBUG_DRIVER("min GPU freq: %d\n", vlv_gpu_freq(dev_priv->mem_freq, - val)); - dev_priv->rps.min_delay = val; + dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv); + DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.min_delay), + dev_priv->rps.min_delay); - DRM_DEBUG_DRIVER("setting GPU freq to %d\n", - vlv_gpu_freq(dev_priv->mem_freq, rpe)); + DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, + dev_priv->rps.rpe_delay), + dev_priv->rps.rpe_delay); INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work); - valleyview_set_rps(dev_priv->dev, rpe); + valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS); -- cgit v1.2.3 From 80814ae4dae5d2070b1ca848df728feb6a10e6f2 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 19:21:02 +0300 Subject: drm/i915: Don't wait for Punit after each freq change on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that even though Punit reports the frequency change to have been completed, it still reports the old frequency in the status register for some time. So rather than polling for Punit to complete the frequency change after each request, poll before. This gets rid of the spurious "Punit overrode GPU freq" messages. This also lets us continue working while Punit is performing the actual frequency change. As a result, openarena demo088-test1 timedemo average fps is increased by ~5 fps, and the slowest frame duration is reduced by ~25%. The sysfs cur_freq file always reads the current frequency from Punit anyway, so having rps.cur_delay be slightly off at times doesn't matter. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 53 +++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 33aa2d6674e5..909dbe1e39fc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3069,17 +3069,49 @@ void gen6_set_rps(struct drm_device *dev, u8 val) trace_intel_gpu_freq_change(val * 50); } +/* + * Wait until the previous freq change has completed, + * or the timeout elapsed, and then update our notion + * of the current GPU frequency. + */ +static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 pval; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + + do { + pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); + if (time_after(jiffies, timeout)) { + DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); + break; + } + udelay(10); + } while (pval & 1); + + pval >>= 8; + + if (pval != dev_priv->rps.cur_delay) + DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", + vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), + dev_priv->rps.cur_delay, + vlv_gpu_freq(dev_priv->mem_freq, pval), pval); + + dev_priv->rps.cur_delay = pval; +} + void valleyview_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(10); u32 limits = gen6_rps_limits(dev_priv, &val); - u32 pval; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); + vlv_update_rps_cur_delay(dev_priv); + DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n", vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay), @@ -3091,27 +3123,12 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); - do { - pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - if (time_after(jiffies, timeout)) { - DRM_DEBUG_DRIVER("timed out waiting for Punit\n"); - break; - } - udelay(10); - } while (pval & 1); - - pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); - if ((pval >> 8) != val) - DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n", - vlv_gpu_freq(dev_priv->mem_freq, val), val, - vlv_gpu_freq(dev_priv->mem_freq, pval >> 8), pval >> 8); - /* Make sure we continue to get interrupts * until we hit the minimum or maximum frequencies. */ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - dev_priv->rps.cur_delay = pval >> 8; + dev_priv->rps.cur_delay = val; trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); } -- cgit v1.2.3 From d8289c9e7bb34b136433a44937e3ebe3a7beea1c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 19:21:05 +0300 Subject: drm/i915: Make the rps new_delay comparison more readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate the weird inverted logic from the rps new_delay comparison. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 611da3a74479..62f8b2d8809c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -707,8 +707,8 @@ static void gen6_pm_rps_work(struct work_struct *work) /* sysfs frequency interfaces may have snuck in while servicing the * interrupt */ - if (!(new_delay > dev_priv->rps.max_delay || - new_delay < dev_priv->rps.min_delay)) { + if (new_delay >= dev_priv->rps.min_delay && + new_delay <= dev_priv->rps.max_delay) { if (IS_VALLEYVIEW(dev_priv->dev)) valleyview_set_rps(dev_priv->dev, new_delay); else -- cgit v1.2.3 From 7a67092a25d854a4f5c53a6495d33e250896f9db Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 19:21:06 +0300 Subject: drm/i915: GEN6_RP_INTERRUPT_LIMITS doesn't seem to exist on VLV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I can't find GEN6_RP_INTERRUPT_LIMITS (0xA014) anywhere in VLV docs. Reading it always returns zero from what I can tell, and eliminating it doesn't seem to make any difference to the behaviour of the system. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 909dbe1e39fc..ed929667c5ba 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3104,7 +3104,8 @@ static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv) void valleyview_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits = gen6_rps_limits(dev_priv, &val); + + gen6_rps_limits(dev_priv, &val); WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); @@ -3123,11 +3124,6 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); - /* Make sure we continue to get interrupts - * until we hit the minimum or maximum frequencies. - */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - dev_priv->rps.cur_delay = val; trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val)); -- cgit v1.2.3 From 6dc5848899a7ddbf1d02f104a97dde7ba0200693 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 21:38:10 +0300 Subject: drm/i915: Don't increase the GPU frequency from the delayed VLV rps timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's little point in increasing the GPU frequency from the delayed rps work on VLV. Now when the GPU is idle, the GPU frequency actually keeps dropping gradually until it hits the minimum, whereas previously it just ping-ponged constantly between RPe and RPe-1. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ed929667c5ba..ccbdd83f5220 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3461,7 +3461,8 @@ static void vlv_rps_timer_work(struct work_struct *work) * min freq available. */ mutex_lock(&dev_priv->rps.hw_lock); - valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); + if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay) + valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay); mutex_unlock(&dev_priv->rps.hw_lock); } -- cgit v1.2.3 From 7425034a3361145c109510892d1e5154af2cdfed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 21:38:11 +0300 Subject: drm/i915: Jump to at least RPe on VLV when increasing the GPU frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the current GPU frquency is below RPe, and we're asked to increase it, just go directly to RPe. This should provide better performance faster than letting the frequency trickle up in response to the up threshold interrupts. For now just do it for VLV, since that matches quite closely how VLV used to operate when the rps delayed timer kept things at RPe always. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 62f8b2d8809c..d6bd0d7a7486 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -699,9 +699,17 @@ static void gen6_pm_rps_work(struct work_struct *work) mutex_lock(&dev_priv->rps.hw_lock); - if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { new_delay = dev_priv->rps.cur_delay + 1; - else + + /* + * For better performance, jump directly + * to RPe if we're below it. + */ + if (IS_VALLEYVIEW(dev_priv->dev) && + dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay) + new_delay = dev_priv->rps.rpe_delay; + } else new_delay = dev_priv->rps.cur_delay - 1; /* sysfs frequency interfaces may have snuck in while servicing the -- cgit v1.2.3 From 99750bd46f6ad3816fe2045a34fac432114c8196 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 14 Jun 2013 14:02:52 +0300 Subject: drm/i915: Fix VLV PLL LPF coefficients for DAC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current PLL settings produce a rather unstable picture when I hook up a VLV to my HP ZR24w display via a VGA cable. According to VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_9, we should use the the same LPF coefficients for DAC as we do for HDMI and RBR DP. And indeed that seems to cure the shivers. v2: Add the name of the relevant document to the commit message Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d723819a450c..749d4282f5ad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4404,6 +4404,7 @@ static void vlv_update_pll(struct intel_crtc *crtc) /* Set HBR and RBR LPF coefficients */ if (crtc->config.port_clock == 162000 || + intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f0021); -- cgit v1.2.3 From 4abb2c39811eb81a653461d5ed8c75c528cb2245 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 14 Jun 2013 14:02:53 +0300 Subject: drm/i915: s/LFP/LPF in DPIO PLL register names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LPF is short for "low pass filter". Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 8 ++++---- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f72d5a3fdfba..04cf6c09710a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1862,10 +1862,10 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n", vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B)); - seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n", - vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_A)); - seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n", - vlv_dpio_read(dev_priv, _DPIO_LFP_COEFF_B)); + seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n", + vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_A)); + seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n", + vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_B)); seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 137be4c1abd1..b6f1fd988df5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -448,9 +448,9 @@ #define _DPIO_PLL_CML_B 0x806c #define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B) -#define _DPIO_LFP_COEFF_A 0x8048 -#define _DPIO_LFP_COEFF_B 0x8068 -#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B) +#define _DPIO_LPF_COEFF_A 0x8048 +#define _DPIO_LPF_COEFF_B 0x8068 +#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B) #define DPIO_CALIBRATION 0x80ac diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 749d4282f5ad..85f3eb74d2b7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4406,10 +4406,10 @@ static void vlv_update_pll(struct intel_crtc *crtc) if (crtc->config.port_clock == 162000 || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), 0x005f0021); else - vlv_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), + vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe), 0x00d0000f); if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) || -- cgit v1.2.3 From 2af2c4909b7c8bc76beef25941b2218b3bd8e4fc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 14:16:34 +0300 Subject: Revert "drm/i915: Don't use the HDMI port color range bit on Valleyview" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PIPECONF color range bit doesn't appear to be effective, on HDMI outputs at least. The color range bit in the port register works though, so let's use it. I have not yet verified whether the PIPECONF bit works on DP outputs. This reverts commit 83a2af88f80ebf8104c9e083b786668b00f5b9ce. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index bc12518a21b4..98df2a0c85bd 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -602,7 +602,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, u32 hdmi_val; hdmi_val = SDVO_ENCODING_HDMI; - if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev)) + if (!HAS_PCH_SPLIT(dev)) hdmi_val |= intel_hdmi->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH; -- cgit v1.2.3 From 921c3b677bf6340cd92800fb99350532674dea29 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 25 Jun 2013 14:16:35 +0300 Subject: drm/i915: Fix VLV sprite register offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We forgot to add VLV_DISPLAY_BASE to the VLV sprite registers, which caused the sprites to not work at all. Signed-off-by: Ville Syrjälä Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b6f1fd988df5..e1df06d1917f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3487,7 +3487,7 @@ #define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) #define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) -#define _SPACNTR 0x72180 +#define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) #define SP_ENABLE (1<<31) #define SP_GEAMMA_ENABLE (1<<30) #define SP_PIXFORMAT_MASK (0xf<<26) @@ -3506,30 +3506,30 @@ #define SP_YUV_ORDER_YVYU (2<<16) #define SP_YUV_ORDER_VYUY (3<<16) #define SP_TILED (1<<10) -#define _SPALINOFF 0x72184 -#define _SPASTRIDE 0x72188 -#define _SPAPOS 0x7218c -#define _SPASIZE 0x72190 -#define _SPAKEYMINVAL 0x72194 -#define _SPAKEYMSK 0x72198 -#define _SPASURF 0x7219c -#define _SPAKEYMAXVAL 0x721a0 -#define _SPATILEOFF 0x721a4 -#define _SPACONSTALPHA 0x721a8 -#define _SPAGAMC 0x721f4 - -#define _SPBCNTR 0x72280 -#define _SPBLINOFF 0x72284 -#define _SPBSTRIDE 0x72288 -#define _SPBPOS 0x7228c -#define _SPBSIZE 0x72290 -#define _SPBKEYMINVAL 0x72294 -#define _SPBKEYMSK 0x72298 -#define _SPBSURF 0x7229c -#define _SPBKEYMAXVAL 0x722a0 -#define _SPBTILEOFF 0x722a4 -#define _SPBCONSTALPHA 0x722a8 -#define _SPBGAMC 0x722f4 +#define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184) +#define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188) +#define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c) +#define _SPASIZE (VLV_DISPLAY_BASE + 0x72190) +#define _SPAKEYMINVAL (VLV_DISPLAY_BASE + 0x72194) +#define _SPAKEYMSK (VLV_DISPLAY_BASE + 0x72198) +#define _SPASURF (VLV_DISPLAY_BASE + 0x7219c) +#define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0) +#define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) +#define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) +#define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) + +#define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) +#define _SPBLINOFF (VLV_DISPLAY_BASE + 0x72284) +#define _SPBSTRIDE (VLV_DISPLAY_BASE + 0x72288) +#define _SPBPOS (VLV_DISPLAY_BASE + 0x7228c) +#define _SPBSIZE (VLV_DISPLAY_BASE + 0x72290) +#define _SPBKEYMINVAL (VLV_DISPLAY_BASE + 0x72294) +#define _SPBKEYMSK (VLV_DISPLAY_BASE + 0x72298) +#define _SPBSURF (VLV_DISPLAY_BASE + 0x7229c) +#define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0) +#define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4) +#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) +#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) #define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR) #define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF) -- cgit v1.2.3 From a0de80a0e07032a111230ec92eca563f9d93648d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 25 Jun 2013 21:53:40 -0700 Subject: drm/i915: Fix context sizes on HSW With updates to the spec, we can actually see the context layout, and how many dwords are allocated. That table suggests we need 70720 bytes per HW context. Rounded up, this is 18 pages. Looking at what lives after the current 4 pages we use, I can't see too much important (mostly it's d3d related), but there are a couple of things which look scary. I am hopeful this can explain some of our odd HSW failures. v2: Make the context only 17 pages. The power context space isn't used ever, and execlists aren't used in our driver, making the actual total 66944 bytes. v3: Add a comment to the code. (Jesse & Paulo) Reported-by: "Azad, Vinit" Cc: stable@vger.kernel.org Reviewed-by: Jesse Barnes Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_reg.h | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ff471454968d..51b7a2171cae 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -113,7 +113,7 @@ static int get_context_size(struct drm_device *dev) case 7: reg = I915_READ(GEN7_CXT_SIZE); if (IS_HASWELL(dev)) - ret = HSW_CXT_TOTAL_SIZE(reg) * 64; + ret = HSW_CXT_TOTAL_SIZE; else ret = GEN7_CXT_TOTAL_SIZE(reg) * 64; break; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e1df06d1917f..f2326fc60ac9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1718,14 +1718,13 @@ GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \ GEN7_CXT_GT1_SIZE(ctx_reg) + \ GEN7_CXT_VFSTATE_SIZE(ctx_reg)) -#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f) -#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7) -#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff) -#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \ - HSW_CXT_RING_SIZE(ctx_reg) + \ - HSW_CXT_RENDER_SIZE(ctx_reg) + \ - GEN7_CXT_VFSTATE_SIZE(ctx_reg)) - +/* Haswell does have the CXT_SIZE register however it does not appear to be + * valid. Now, docs explain in dwords what is in the context object. The full + * size is 70720 bytes, however, the power context and execlist context will + * never be saved (power context is stored elsewhere, and execlists don't work + * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages. + */ +#define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) /* * Overlay regs -- cgit v1.2.3 From 4bc9d4301573403c578e545b34dceac61891f39c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 13:44:58 +0200 Subject: drm/i915: fix locking around ironlake_enable|disable_display_irq The haswell unclaimed register handling code forgot to take the spinlock. Since this is in the context of the non-rentrant interupt handler and we only have one interrupt handler it is sufficient to just grab the spinlock - we do not need to exclude any other interrupts from running on the same cpu. To prevent such gaffles in the future sprinkle assert_spin_locked over these functions. Unfornately this requires us to hold the spinlock in the ironlake postinstall hook where it is not strictly required: Currently that is run in single-threaded context and with userspace exlcuded from running concurrent ioctls. Add a comment explaining this. v2: ivb_can_enable_err_int also needs to be protected by the spinlock. To ensure this won't happen in the future again also sprinkle a spinlock assert in there. v3: Kill the 2nd call to ivb_can_enable_err_int I've accidentally left behind, spotted by Paulo. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d6bd0d7a7486..61cd87999df3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -86,6 +86,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev); static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { + assert_spin_locked(&dev_priv->irq_lock); + if ((dev_priv->irq_mask & mask) != 0) { dev_priv->irq_mask &= ~mask; I915_WRITE(DEIMR, dev_priv->irq_mask); @@ -96,6 +98,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) static void ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) { + assert_spin_locked(&dev_priv->irq_lock); + if ((dev_priv->irq_mask & mask) != mask) { dev_priv->irq_mask |= mask; I915_WRITE(DEIMR, dev_priv->irq_mask); @@ -109,6 +113,8 @@ static bool ivb_can_enable_err_int(struct drm_device *dev) struct intel_crtc *crtc; enum pipe pipe; + assert_spin_locked(&dev_priv->irq_lock); + for_each_pipe(pipe) { crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -1217,8 +1223,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) /* On Haswell, also mask ERR_INT because we don't want to risk * generating "unclaimed register" interrupts from inside the interrupt * handler. */ - if (IS_HASWELL(dev)) + if (IS_HASWELL(dev)) { + spin_lock(&dev_priv->irq_lock); ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB); + spin_unlock(&dev_priv->irq_lock); + } gt_iir = I915_READ(GTIIR); if (gt_iir) { @@ -1271,8 +1280,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) ret = IRQ_HANDLED; } - if (IS_HASWELL(dev) && ivb_can_enable_err_int(dev)) - ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + if (IS_HASWELL(dev)) { + spin_lock(&dev_priv->irq_lock); + if (ivb_can_enable_err_int(dev)) + ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB); + spin_unlock(&dev_priv->irq_lock); + } I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); @@ -2697,6 +2710,8 @@ static void ibx_irq_postinstall(struct drm_device *dev) static int ironlake_irq_postinstall(struct drm_device *dev) { + unsigned long irqflags; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | @@ -2735,7 +2750,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* Clear & enable PCU event interrupts */ I915_WRITE(DEIIR, DE_PCU_EVENT); I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); + + /* spinlocking not required here for correctness since interrupt + * setup is guaranteed to run in single-threaded context. But we + * need it to make the assert_spin_locked happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } return 0; -- cgit v1.2.3 From 6005ce42433df3f69de99d7e730383a6adb852ef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 13:44:59 +0200 Subject: drm/i915: close tiny race in the ilk pcu even interrupt setup By the time we write DEIER in the postinstall hook the interrupt handler could run any time. And it does modify DEIER to handle interrupts. Hence the DEIER read-modify-write cycle for enabling the PCU event source is racy. Close this races the same way we handle vblank interrupts: Unconditionally enable the interrupt in the IER register, but conditionally mask it in IMR. The later poses no such race since the interrupt handler does not touch DEIMR. Also update the comment, the clearing has already happened unconditionally above. v2: Actually shove the updated comment into the right train^W commit, as spotted by Paulo. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 61cd87999df3..bff9abda81c6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2725,7 +2725,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* should always can generate irq */ I915_WRITE(DEIIR, I915_READ(DEIIR)); I915_WRITE(DEIMR, dev_priv->irq_mask); - I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK); + I915_WRITE(DEIER, display_mask | + DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT); POSTING_READ(DEIER); dev_priv->gt_irq_mask = ~0; @@ -2747,11 +2748,9 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ibx_irq_postinstall(dev); if (IS_IRONLAKE_M(dev)) { - /* Clear & enable PCU event interrupts */ - I915_WRITE(DEIIR, DE_PCU_EVENT); - I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT); - - /* spinlocking not required here for correctness since interrupt + /* Enable PCU event interrupts + * + * spinlocking not required here for correctness since interrupt * setup is guaranteed to run in single-threaded context. But we * need it to make the assert_spin_locked happy. */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); -- cgit v1.2.3 From 22062dbacf7ccc325c8b0ccc3fb90bf487be5c5c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:11 +0200 Subject: drm/i915: s/hotplug_irq_storm_detect/intel_hpd_irq_handler/ The combination of Paulo's fifo underrun detection code and Egbert's hpd storm handling code unfortunately made the hpd storm handling code racy. To avoid duplicating tricky interrupt locking code over all platforms start with a bit of refactoring. This patch is the very first step since in the end the irq storm handling code will handle all hotplug logic (and so also encapsulate the locking nicely). v2: Rebase on top of the i965g/gm sdvo hpd fix. Cc: Egbert Eich Reviewed-by: Egbert Eich Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bff9abda81c6..378ade0d8c9f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -875,9 +875,9 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static inline bool hotplug_irq_storm_detect(struct drm_device *dev, - u32 hotplug_trigger, - const u32 *hpd) +static inline bool intel_hpd_irq_handler(struct drm_device *dev, + u32 hotplug_trigger, + const u32 *hpd) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; @@ -1018,7 +1018,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915)) i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); @@ -1049,7 +1049,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx)) + if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx)) ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -1154,7 +1154,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt)) + if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt)) ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -3232,7 +3232,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915)) i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); @@ -3473,7 +3473,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (hotplug_irq_storm_detect(dev, hotplug_trigger, + if (intel_hpd_irq_handler(dev, hotplug_trigger, IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915)) i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, -- cgit v1.2.3 From 10a504de56f0451c828a9207e36c5610d5b0209a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:12 +0200 Subject: drm/i915: fold the hpd_irq_setup call into intel_hpd_irq_handler We already have a vfunc for this (and other parts of the hpd storm handling code already use it). v2: Rebase on top of the i965g/gm sdvo hpd fix. Cc: Egbert Eich Reviewed-by: Egbert Eich Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 378ade0d8c9f..c1e9b0a0861c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -79,9 +79,6 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; -static void ibx_hpd_irq_setup(struct drm_device *dev); -static void i915_hpd_irq_setup(struct drm_device *dev); - /* For display hotplug interrupt */ static void ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) @@ -875,14 +872,14 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static inline bool intel_hpd_irq_handler(struct drm_device *dev, +static inline void intel_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger, const u32 *hpd) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; int i; - bool ret = false; + bool storm_detected = false; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); @@ -902,7 +899,7 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev, dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; dev_priv->hpd_event_bits &= ~(1 << i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); - ret = true; + storm_detected = true; } else { dev_priv->hpd_stats[i].hpd_cnt++; } @@ -910,7 +907,8 @@ static inline bool intel_hpd_irq_handler(struct drm_device *dev, spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - return ret; + if (storm_detected) + dev_priv->display.hpd_irq_setup(dev); } static void gmbus_irq_handler(struct drm_device *dev) @@ -1018,8 +1016,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915)) - i915_hpd_irq_setup(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -1049,8 +1046,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; if (hotplug_trigger) { - if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx)) - ibx_hpd_irq_setup(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK) { @@ -1154,8 +1150,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; if (hotplug_trigger) { - if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt)) - ibx_hpd_irq_setup(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { @@ -3232,8 +3227,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915)) - i915_hpd_irq_setup(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -3473,9 +3467,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - if (intel_hpd_irq_handler(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915)) - i915_hpd_irq_setup(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } -- cgit v1.2.3 From 5876fa0d9e9097d980a72152f4967a52b1adaaac Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:13 +0200 Subject: drm/i915: fold the queue_work into intel_hpd_irq_handler Everywhere the same. Note that this patch leaves unnecessary braces behind, but the next patch will kill those all anyway (including the if itself) so I've figured I can keep the diff a bit smaller. v2: Rebase on top of the i965g/gm sdvo hpd fix. Cc: Egbert Eich Reviewed-by: Egbert Eich Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c1e9b0a0861c..531df31075d2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -909,6 +909,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, if (storm_detected) dev_priv->display.hpd_irq_setup(dev); + + queue_work(dev_priv->wq, + &dev_priv->hotplug_work); } static void gmbus_irq_handler(struct drm_device *dev) @@ -1017,8 +1020,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) hotplug_status); if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); @@ -1047,7 +1048,6 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); - queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -1151,7 +1151,6 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); - queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> @@ -3228,8 +3227,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) hotplug_status); if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); @@ -3469,8 +3466,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) if (hotplug_trigger) { intel_hpd_irq_handler(dev, hotplug_trigger, IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); - queue_work(dev_priv->wq, - &dev_priv->hotplug_work); } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); -- cgit v1.2.3 From 91d131d21e4916f84e5957cc25bea6dd355dfe77 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:14 +0200 Subject: drm/i915: fold the no-irq check into intel_hpd_irq_handler The usual pattern for our sub-function irq_handlers is that they check for the no-irq case themselves. This results in more streamlined code in the upper irq handlers. v2: Rebase on top of the i965g/gm sdvo hpd fix. Cc: Egbert Eich Reviewed-by: Egbert Eich Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 531df31075d2..b29b76fe1123 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -881,6 +881,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, int i; bool storm_detected = false; + if (!hotplug_trigger) + return; + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); for (i = 1; i < HPD_NUM_PINS; i++) { @@ -1018,9 +1021,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -1046,9 +1049,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - if (hotplug_trigger) { - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); - } + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx); + if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> SDE_AUDIO_POWER_SHIFT); @@ -1149,9 +1151,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - if (hotplug_trigger) { - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); - } + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt); + if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> SDE_AUDIO_POWER_SHIFT_CPT); @@ -3225,9 +3226,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); } @@ -3463,10 +3464,10 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_trigger) { - intel_hpd_irq_handler(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); - } + + intel_hpd_irq_handler(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915); + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } -- cgit v1.2.3 From b5ea2d5681522f1b8ef886b5ac039903bf1d39fe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 27 Jun 2013 17:52:15 +0200 Subject: drm/i915: fix hpd interrupt register locking Our interrupt handler (in hardirq context) could race with the timer (in softirq context), hence we need to hold the spinlock around the call to ->hdp_irq_setup in intel_hpd_irq_handler, too. But as an optimization (and more so to clarify things) we don't need to do the irqsave/restore dance in the hardirq context. Note also that on ilk+ the race isn't just against the hotplug reenable timer, but also against the fifo underrun reporting. That one also modifies the SDEIMR register (again protected by the same dev_priv->irq_lock). To lock things down again sprinkle a assert_spin_locked. But exclude the functions touching SDEIMR for now, I want to extract them all into a new helper function (like we do already for pipestate, display interrupts and all the various gt interrupts). v2: Add the missing 't' Egbert spotted in a comment. v3: Actually fix the right misspelled comment (Paulo). Cc: Egbert Eich Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b29b76fe1123..3d92a7cef154 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -877,15 +877,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, const u32 *hpd) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long irqflags; int i; bool storm_detected = false; if (!hotplug_trigger) return; - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - + spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { if (!(hpd[i] & hotplug_trigger) || @@ -908,10 +906,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, } } - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - if (storm_detected) dev_priv->display.hpd_irq_setup(dev); + spin_unlock(&dev_priv->irq_lock); queue_work(dev_priv->wq, &dev_priv->hotplug_work); @@ -3380,6 +3377,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev) struct intel_encoder *intel_encoder; u32 hotplug_en; + assert_spin_locked(&dev_priv->irq_lock); + if (I915_HAS_HOTPLUG(dev)) { hotplug_en = I915_READ(PORT_HOTPLUG_EN); hotplug_en &= ~HOTPLUG_INT_EN_MASK; @@ -3663,6 +3662,7 @@ void intel_hpd_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_connector *connector; + unsigned long irqflags; int i; for (i = 1; i < HPD_NUM_PINS; i++) { @@ -3675,6 +3675,11 @@ void intel_hpd_init(struct drm_device *dev) if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) connector->polled = DRM_CONNECTOR_POLL_HPD; } + + /* Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked checks happy. */ + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -- cgit v1.2.3 From 63000ef656190b65a8ae4d00acd7f22b6d92415d Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Fri, 28 Jun 2013 12:59:06 +0800 Subject: drm/i915: correct intel_dp_get_config() function for DevCPT On DevCPT, the control register for Transcoder DP Sync Polarity is TRANS_DP_CTL, not DP_CTL. Without this patch, Many call trace occur on CPT machine with DP monitor. The call trace is like: *ERROR* mismatch in adjusted_mode.flags(expected X,found X) v2: use intel-crtc to simple patch, suggested by Daniel. Signed-off-by: Xiong Zhang [danvet: Extend the encoder->get_config comment to specify that we now also depend upon intel_encoder->base.crtc being correct. Also bikeshed s/intel_crtc/crtc/.] Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65287 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 35 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_drv.h | 3 ++- 2 files changed, 27 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 24a44ede867d..b73971234013 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1324,20 +1324,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; u32 tmp, flags = 0; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum port port = dp_to_dig_port(intel_dp)->port; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - tmp = I915_READ(intel_dp->output_reg); + if ((port == PORT_A) || !HAS_PCH_CPT(dev)) { + tmp = I915_READ(intel_dp->output_reg); + if (tmp & DP_SYNC_HS_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; - if (tmp & DP_SYNC_HS_HIGH) - flags |= DRM_MODE_FLAG_PHSYNC; - else - flags |= DRM_MODE_FLAG_NHSYNC; + if (tmp & DP_SYNC_VS_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } else { + tmp = I915_READ(TRANS_DP_CTL(crtc->pipe)); + if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; - if (tmp & DP_SYNC_VS_HIGH) - flags |= DRM_MODE_FLAG_PVSYNC; - else - flags |= DRM_MODE_FLAG_NVSYNC; + if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + } pipe_config->adjusted_mode.flags |= flags; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9ddbe3b49fef..c8c9b6f48230 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -141,7 +141,8 @@ struct intel_encoder { bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe); /* Reconstructs the equivalent mode flags for the current hardware * state. This must be called _after_ display->get_pipe_config has - * pre-filled the pipe config. */ + * pre-filled the pipe config. Note that intel_encoder->base.crtc must + * be set correctly before calling this function. */ void (*get_config)(struct intel_encoder *, struct intel_crtc_config *pipe_config); int crtc_mask; -- cgit v1.2.3 From daa13e1ca587bc773c1aae415ed1af6554117bd4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 28 Jun 2013 16:54:08 +0100 Subject: drm/i915: Only clear write-domains after a successful wait-seqno In the introduction of the non-blocking wait, I cut'n'pasted the wait completion code from normal locked path. Unfortunately, this neglected that the normal path returned early if the wait returned early. The result is that read-only waits may return whilst the GPU is still writing to the bo. Fixes regression from commit 3236f57a0162391f84b93f39fc1882c49a8998c7 [v3.7] Author: Chris Wilson Date: Fri Aug 24 09:35:09 2012 +0100 drm/i915: Use a non-blocking wait for set-to-domain ioctl Signed-off-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66163 Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fa074cec8587..18025fd45d40 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1160,7 +1160,8 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, /* Manually manage the write flush as we may have not yet * retired the buffer. */ - if (obj->last_write_seqno && + if (ret == 0 && + obj->last_write_seqno && i915_seqno_passed(seqno, obj->last_write_seqno)) { obj->last_write_seqno = 0; obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; -- cgit v1.2.3 From d26e3af842023603747f1566caff5f471508bbd4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 29 Jun 2013 22:05:26 +0100 Subject: drm/i915: Refactor the wait_rendering completion into a common routine Harmonise the completion logic between the non-blocking and normal wait_rendering paths, and move that logic into a common function. In the process, we note that the last_write_seqno is by definition the earlier of the two read/write seqnos and so all successful waits will have passed the last_write_seqno. Therefore we can unconditionally clear the write seqno and its domains in the completion logic. v2: Add the missing ring parameter, because sometimes it is good to have things compile. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 18025fd45d40..769f75262feb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1087,6 +1087,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) interruptible, NULL); } +static int +i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *ring) +{ + i915_gem_retire_requests_ring(ring); + + /* Manually manage the write flush as we may have not yet + * retired the buffer. + * + * Note that the last_write_seqno is always the earlier of + * the two (read/write) seqno, so if we haved successfully waited, + * we know we have passed the last write. + */ + obj->last_write_seqno = 0; + obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; + + return 0; +} + /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -1107,18 +1126,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, if (ret) return ret; - i915_gem_retire_requests_ring(ring); - - /* Manually manage the write flush as we may have not yet - * retired the buffer. - */ - if (obj->last_write_seqno && - i915_seqno_passed(seqno, obj->last_write_seqno)) { - obj->last_write_seqno = 0; - obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; - } - - return 0; + return i915_gem_object_wait_rendering__tail(obj, ring); } /* A nonblocking variant of the above wait. This is a highly dangerous routine @@ -1154,20 +1162,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, mutex_unlock(&dev->struct_mutex); ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); mutex_lock(&dev->struct_mutex); + if (ret) + return ret; - i915_gem_retire_requests_ring(ring); - - /* Manually manage the write flush as we may have not yet - * retired the buffer. - */ - if (ret == 0 && - obj->last_write_seqno && - i915_seqno_passed(seqno, obj->last_write_seqno)) { - obj->last_write_seqno = 0; - obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; - } - - return ret; + return i915_gem_object_wait_rendering__tail(obj, ring); } /** -- cgit v1.2.3 From baf27f9b17bf2f369f3865e38c41d2163e8d815d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 29 Jun 2013 23:26:50 +0100 Subject: drm/i915: Break up the large vsnprintf() in print_error_buffers() So it appears that I have encountered some bogosity when trying to call i915_error_printf() with many arguments from print_error_buffers(). The symptom is that the vsnprintf parser tries to interpret an integer arg as a character string, the resulting OOPS indicating stack corruption. Replacing the single call with its 13 format specifiers and arguments with multiple calls to i915_error_printf() worked fine. This patch goes one step further and introduced i915_error_puts() to pass the strings simply. It may not fix the root cause, but it does prevent my box from dying and I think helps make print_error_buffers() more friendly. Signed-off-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66077 Cc: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 109 ++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 30 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 04cf6c09710a..47d6c748057e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -647,41 +647,44 @@ static const char *purgeable_flag(int purgeable) return purgeable ? " purgeable" : ""; } -static void i915_error_vprintf(struct drm_i915_error_state_buf *e, - const char *f, va_list args) +static bool __i915_error_ok(struct drm_i915_error_state_buf *e) { - unsigned len; if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) { e->err = -ENOSPC; - return; + return false; } if (e->bytes == e->size - 1 || e->err) - return; + return false; - /* Seek the first printf which is hits start position */ - if (e->pos < e->start) { - len = vsnprintf(NULL, 0, f, args); - if (e->pos + len <= e->start) { - e->pos += len; - return; - } + return true; +} - /* First vsnprintf needs to fit in full for memmove*/ - if (len >= e->size) { - e->err = -EIO; - return; - } +static bool __i915_error_seek(struct drm_i915_error_state_buf *e, + unsigned len) +{ + if (e->pos + len <= e->start) { + e->pos += len; + return false; } - len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); - if (len >= e->size - e->bytes) - len = e->size - e->bytes - 1; + /* First vsnprintf needs to fit in its entirety for memmove */ + if (len >= e->size) { + e->err = -EIO; + return false; + } + return true; +} + +static void __i915_error_advance(struct drm_i915_error_state_buf *e, + unsigned len) +{ /* If this is first printf in this window, adjust it so that * start position matches start of the buffer */ + if (e->pos < e->start) { const size_t off = e->start - e->pos; @@ -701,6 +704,51 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, e->pos += len; } +static void i915_error_vprintf(struct drm_i915_error_state_buf *e, + const char *f, va_list args) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + len = vsnprintf(NULL, 0, f, args); + if (!__i915_error_seek(e, len)) + return; + } + + len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args); + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + + __i915_error_advance(e, len); +} + +static void i915_error_puts(struct drm_i915_error_state_buf *e, + const char *str) +{ + unsigned len; + + if (!__i915_error_ok(e)) + return; + + len = strlen(str); + + /* Seek the first printf which is hits start position */ + if (e->pos < e->start) { + if (!__i915_error_seek(e, len)) + return; + } + + if (len >= e->size - e->bytes) + len = e->size - e->bytes - 1; + memcpy(e->buf + e->bytes, str, len); + + __i915_error_advance(e, len); +} + void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) { va_list args; @@ -711,6 +759,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) } #define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__) +#define err_puts(e, s) i915_error_puts(e, s) static void print_error_buffers(struct drm_i915_error_state_buf *m, const char *name, @@ -720,26 +769,26 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m, err_printf(m, "%s [%d]:\n", name, count); while (count--) { - err_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", + err_printf(m, " %08x %8u %02x %02x %x %x", err->gtt_offset, err->size, err->read_domains, err->write_domain, - err->rseqno, err->wseqno, - pin_flag(err->pinned), - tiling_flag(err->tiling), - dirty_flag(err->dirty), - purgeable_flag(err->purgeable), - err->ring != -1 ? " " : "", - ring_str(err->ring), - cache_level_str(err->cache_level)); + err->rseqno, err->wseqno); + err_puts(m, pin_flag(err->pinned)); + err_puts(m, tiling_flag(err->tiling)); + err_puts(m, dirty_flag(err->dirty)); + err_puts(m, purgeable_flag(err->purgeable)); + err_puts(m, err->ring != -1 ? " " : ""); + err_puts(m, ring_str(err->ring)); + err_puts(m, cache_level_str(err->cache_level)); if (err->name) err_printf(m, " (name: %d)", err->name); if (err->fence_reg != I915_FENCE_REG_NONE) err_printf(m, " (fence: %d)", err->fence_reg); - err_printf(m, "\n"); + err_puts(m, "\n"); err++; } } -- cgit v1.2.3 From 446f8d81ca2d9cefb614e87f2fabcc996a9e4e7e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 2 Jul 2013 10:48:31 +0200 Subject: drm/i915: Don't try to tear down the stolen drm_mm if it's not there Every other place properly checks whether we've managed to set up the stolen allocator at boot-up properly, with the exception of the cleanup code. Which results in an ugly *ERROR* Memory manager not clean. Delaying takedown at module unload time since the drm_mm isn't initialized at all. v2: While at it check whether the stolen drm_mm is initialized instead of the more obscure stolen_base == 0 check. v3: Fix up the logic. Also we need to keep the stolen_base check in i915_gem_object_create_stolen_for_preallocated since that can be called before stolen memory is fully set up. Spotted by Chris Wilson. v4: Readd the conversion in i915_gem_object_create_stolen_for_preallocated, the check is for the dev_priv->mm.gtt_space drm_mm, the stolen allocatot must already be initialized when calling that function (if we indeed have stolen memory). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=65953 Cc: Chris Wilson Tested-by: lu hua (v3) Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_stolen.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index f713294618fe..982d4732cecf 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -147,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return -ENODEV; if (size < dev_priv->cfb_size) @@ -179,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return; + i915_gem_stolen_cleanup_compression(dev); drm_mm_takedown(&dev_priv->mm.stolen); } @@ -300,7 +303,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) struct drm_i915_gem_object *obj; struct drm_mm_node *stolen; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return NULL; DRM_DEBUG_KMS("creating stolen object: size=%x\n", size); @@ -331,7 +334,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, struct drm_i915_gem_object *obj; struct drm_mm_node *stolen; - if (dev_priv->mm.stolen_base == 0) + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return NULL; DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n", -- cgit v1.2.3