Skip to content

Commit

Permalink
drm/i915: Keep track of the cdclk as if all crtc's were active.
Browse files Browse the repository at this point in the history
On skylake when calculating plane visibility with the crtc in
dpms off mode the real cdclk may be different from what it would be
if the crtc was active. This may result in a WARN_ON(cdclk < crtc_clock)
from skl_max_scale. The fix is to keep a atomic_cdclk that would be true
if all crtc's were active.

This is required to get the same calculations done correctly regardless
of dpms mode.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Mika Kahola <mika.kahola@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1447945645-32005-12-git-send-email-maarten.lankhorst@linux.intel.com
  • Loading branch information
Maarten Lankhorst committed Dec 22, 2015
1 parent 565602d commit 1a617b7
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 19 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1774,7 +1774,7 @@ struct drm_i915_private {

unsigned int fsb_freq, mem_freq, is_ddr3;
unsigned int skl_boot_cdclk;
unsigned int cdclk_freq, max_cdclk_freq;
unsigned int cdclk_freq, max_cdclk_freq, atomic_cdclk_freq;
unsigned int max_dotclk_freq;
unsigned int hpll_freq;
unsigned int czclk_freq;
Expand Down
55 changes: 37 additions & 18 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -5370,6 +5370,7 @@ static void modeset_put_power_domains(struct drm_i915_private *dev_priv,

static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long put_domains[I915_MAX_PIPES] = {};
Expand All @@ -5383,13 +5384,9 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
modeset_get_crtc_power_domains(crtc);
}

if (dev_priv->display.modeset_commit_cdclk) {
unsigned int cdclk = to_intel_atomic_state(state)->cdclk;

if (cdclk != dev_priv->cdclk_freq &&
!WARN_ON(!state->allow_modeset))
dev_priv->display.modeset_commit_cdclk(state);
}
if (dev_priv->display.modeset_commit_cdclk &&
intel_state->dev_cdclk != dev_priv->cdclk_freq)
dev_priv->display.modeset_commit_cdclk(state);

for (i = 0; i < I915_MAX_PIPES; i++)
if (put_domains[i])
Expand Down Expand Up @@ -6096,13 +6093,18 @@ static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state)
struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int max_pixclk = intel_mode_max_pixclk(dev, state);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);

if (max_pixclk < 0)
return max_pixclk;

to_intel_atomic_state(state)->cdclk =
intel_state->cdclk = intel_state->dev_cdclk =
valleyview_calc_cdclk(dev_priv, max_pixclk);

if (!intel_state->active_crtcs)
intel_state->dev_cdclk = valleyview_calc_cdclk(dev_priv, 0);

return 0;
}

Expand All @@ -6111,13 +6113,18 @@ static int broxton_modeset_calc_cdclk(struct drm_atomic_state *state)
struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int max_pixclk = intel_mode_max_pixclk(dev, state);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);

if (max_pixclk < 0)
return max_pixclk;

to_intel_atomic_state(state)->cdclk =
intel_state->cdclk = intel_state->dev_cdclk =
broxton_calc_cdclk(dev_priv, max_pixclk);

if (!intel_state->active_crtcs)
intel_state->dev_cdclk = broxton_calc_cdclk(dev_priv, 0);

return 0;
}

Expand Down Expand Up @@ -6160,8 +6167,10 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;
unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned req_cdclk = old_intel_state->dev_cdclk;

/*
* FIXME: We can end up here with all power domains off, yet
Expand Down Expand Up @@ -9683,7 +9692,9 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;
unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned int req_cdclk = old_intel_state->dev_cdclk;

broxton_set_cdclk(dev, req_cdclk);
}
Expand Down Expand Up @@ -9809,6 +9820,7 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->dev);
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
int max_pixclk = ilk_max_pixel_rate(state);
int cdclk;

Expand All @@ -9831,15 +9843,19 @@ static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
return -EINVAL;
}

to_intel_atomic_state(state)->cdclk = cdclk;
intel_state->cdclk = intel_state->dev_cdclk = cdclk;
if (!intel_state->active_crtcs)
intel_state->dev_cdclk = 337500;

return 0;
}

static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;
unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk;
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned req_cdclk = old_intel_state->dev_cdclk;

broadwell_set_cdclk(dev, req_cdclk);
}
Expand Down Expand Up @@ -13261,18 +13277,15 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
* adjusted_mode bits in the crtc directly.
*/
if (dev_priv->display.modeset_calc_cdclk) {
unsigned int cdclk;

ret = dev_priv->display.modeset_calc_cdclk(state);

cdclk = to_intel_atomic_state(state)->cdclk;
if (!ret && cdclk != dev_priv->cdclk_freq)
if (!ret && intel_state->dev_cdclk != dev_priv->cdclk_freq)
ret = intel_modeset_all_pipes(state);

if (ret < 0)
return ret;
} else
to_intel_atomic_state(state)->cdclk = dev_priv->cdclk_freq;
to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;

intel_modeset_clear_plls(state);

Expand Down Expand Up @@ -13514,6 +13527,7 @@ static int intel_atomic_commit(struct drm_device *dev,
memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
sizeof(intel_state->min_pixclk));
dev_priv->active_crtcs = intel_state->active_crtcs;
dev_priv->atomic_cdclk_freq = intel_state->cdclk;
}

for_each_crtc_in_state(state, crtc, crtc_state, i) {
Expand Down Expand Up @@ -15235,7 +15249,12 @@ static void i915_disable_vga(struct drm_device *dev)

void intel_modeset_init_hw(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;

intel_update_cdclk(dev);

dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;

intel_prepare_ddi(dev);
intel_init_clock_gating(dev);
intel_enable_gt_powersave(dev);
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ struct intel_atomic_state {

unsigned int cdclk;

/*
* Calculated device cdclk, can be different from cdclk
* only when all crtc's are DPMS off.
*/
unsigned int dev_cdclk;

bool dpll_set, modeset;

unsigned int active_crtcs;
Expand Down

0 comments on commit 1a617b7

Please sign in to comment.