diff options
author | Maarten Lankhorst | 2015-06-01 12:50:09 +0200 |
---|---|---|
committer | Jani Nikula | 2015-06-12 12:19:34 +0200 |
commit | 99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1 (patch) | |
tree | e2e400cb0dc8f8b4146db7cd3a4ae30f5827bbed /drivers/gpu/drm/i915/intel_display.c | |
parent | drm/i915: Remove use of crtc->config from i915_debugfs.c (diff) | |
download | kernel-qcow2-linux-99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1.tar.gz kernel-qcow2-linux-99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1.tar.xz kernel-qcow2-linux-99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1.zip |
drm/i915: Calculate haswell plane workaround, v5.
This needs to be done last after all modesets have been calculated.
A modeset first disables all crtc's, so any crtc that undergoes a
modeset counts as inactive.
If no modeset's done, or > 1 crtc's stay w/a doesn't apply.
Apply workaround on the first crtc if 1 crtc stays active.
Apply workaround on the second crtc if no crtc was active.
Changes since v1:
- Use intel_crtc->atomic as a place to put hsw_workaround_pipe.
- Make sure quirk only applies to haswell.
- Use first loop to iterate over newly enabled crtc's only.
This increases readability.
Changes since v2:
- Move hsw_workaround_pipe back to crtc_state.
Changes since v3:
- Return errors from haswell_mode_set_planes_workaround.
Changes since v4:
- Clean up commit message.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Matt Roper <matthew.d.roper@intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 113 |
1 files changed, 81 insertions, 32 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e2bbd7e6210..cd9a7545b0d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4864,42 +4864,15 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } -/* - * This implements the workaround described in the "notes" section of the mode - * set sequence documentation. When going from no pipes or single pipe to - * multiple pipes, and planes are enabled after the pipe, we need to wait at - * least 2 vblanks on the first pipe before enabling planes on the second pipe. - */ -static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc) -{ - struct drm_device *dev = crtc->base.dev; - struct intel_crtc *crtc_it, *other_active_crtc = NULL; - - /* We want to get the other_active_crtc only if there's only 1 other - * active crtc. */ - for_each_intel_crtc(dev, crtc_it) { - if (!crtc_it->active || crtc_it == crtc) - continue; - - if (other_active_crtc) - return; - - other_active_crtc = crtc_it; - } - if (!other_active_crtc) - return; - - intel_wait_for_vblank(dev, other_active_crtc->pipe); - intel_wait_for_vblank(dev, other_active_crtc->pipe); -} - static void haswell_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 pipe = intel_crtc->pipe, hsw_workaround_pipe; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->state); if (WARN_ON(intel_crtc->active)) return; @@ -4976,7 +4949,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ - haswell_mode_set_planes_workaround(intel_crtc); + hsw_workaround_pipe = pipe_config->hsw_workaround_pipe; + if (IS_HASWELL(dev) && hsw_workaround_pipe != INVALID_PIPE) { + intel_wait_for_vblank(dev, hsw_workaround_pipe); + intel_wait_for_vblank(dev, hsw_workaround_pipe); + } } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -12818,6 +12795,71 @@ static int intel_modeset_setup_plls(struct drm_atomic_state *state) return ret; } +/* + * This implements the workaround described in the "notes" section of the mode + * set sequence documentation. When going from no pipes or single pipe to + * multiple pipes, and planes are enabled after the pipe, we need to wait at + * least 2 vblanks on the first pipe before enabling planes on the second pipe. + */ +static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + struct intel_crtc_state *first_crtc_state = NULL; + struct intel_crtc_state *other_crtc_state = NULL; + enum pipe first_pipe = INVALID_PIPE, enabled_pipe = INVALID_PIPE; + int i; + + /* look at all crtc's that are going to be enabled in during modeset */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + intel_crtc = to_intel_crtc(crtc); + + if (!crtc_state->active || !needs_modeset(crtc_state)) + continue; + + if (first_crtc_state) { + other_crtc_state = to_intel_crtc_state(crtc_state); + break; + } else { + first_crtc_state = to_intel_crtc_state(crtc_state); + first_pipe = intel_crtc->pipe; + } + } + + /* No workaround needed? */ + if (!first_crtc_state) + return 0; + + /* w/a possibly needed, check how many crtc's are already enabled. */ + for_each_intel_crtc(state->dev, intel_crtc) { + struct intel_crtc_state *pipe_config; + + pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(pipe_config)) + return PTR_ERR(pipe_config); + + pipe_config->hsw_workaround_pipe = INVALID_PIPE; + + if (!pipe_config->base.active || + needs_modeset(&pipe_config->base)) + continue; + + /* 2 or more enabled crtcs means no need for w/a */ + if (enabled_pipe != INVALID_PIPE) + return 0; + + enabled_pipe = intel_crtc->pipe; + } + + if (enabled_pipe != INVALID_PIPE) + first_crtc_state->hsw_workaround_pipe = enabled_pipe; + else if (other_crtc_state) + other_crtc_state->hsw_workaround_pipe = first_pipe; + + return 0; +} + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { @@ -12841,7 +12883,14 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; } - return intel_modeset_setup_plls(state); + ret = intel_modeset_setup_plls(state); + if (ret) + return ret; + + if (IS_HASWELL(dev)) + ret = haswell_mode_set_planes_workaround(state); + + return ret; } static int |