Skip to content

Commit

Permalink
drm/i915: Calculate haswell plane workaround, v5.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maarten Lankhorst authored and Jani Nikula committed Jun 12, 2015
1 parent f77076c commit 99d736a
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 32 deletions.
113 changes: 81 additions & 32 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ struct intel_crtc_state {
int pbn;

struct intel_crtc_scaler_state scaler_state;

/* w/a for waiting 2 vblanks during crtc enable */
enum pipe hsw_workaround_pipe;
};

struct intel_pipe_wm {
Expand Down

0 comments on commit 99d736a

Please sign in to comment.