Commit fabf6e51 authored by Daniel Vetter's avatar Daniel Vetter

drm/i915: Support pf CRC source on haswell transcoder edp

The always-on power well pixel path on haswell is routed such that it
bypasses the panel fitter when we use is. Which means the pfit CRC
source won't work in that configuration.

Add a new disallow-bypass flags to the pfit pipe config state and set
it when we want to use the pf CRC. Results in a bit of flicker, but
should get the job done. We'll also undo do it afterwards to make sure
other tests arent' negatively affected.

Totally untested due to lack of hsw laptops around here.

v2: s/disallow_bypass/force_power_well_on/ to avoid a double negative
(Damien).

v3: force_thru because roadsigns.

v4: Don't forget the power wells! Also note that until the runtime pm
for DPMS series is fully merged the simple disable/enable trick won't
work since the ->crtc_mode_set callback is still required to do nasty
things. This stuff is tricky, but I think by both fixing up
get_crtc_power_domains and the debugfs wa code we should always
grab/drop the additional power well correctly.

v5: Wrap in () as suggested by Damien to avoid setting reserved values
for the edp transcoder path on bdw+

References: https://bugs.freedesktop.org/show_bug.cgi?id=72864
Cc: Damien Lespiau <damien.lespiau@intel.com>
Reviewed-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
Tested-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent b3f9ad93
...@@ -2867,7 +2867,60 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, ...@@ -2867,7 +2867,60 @@ static int ilk_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
return 0; return 0;
} }
static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]);
drm_modeset_lock_all(dev);
/*
* If we use the eDP transcoder we need to make sure that we don't
* bypass the pfit, since otherwise the pipe CRC source won't work. Only
* relevant on hsw with pipe A when using the always-on power well
* routing.
*/
if (crtc->config.cpu_transcoder == TRANSCODER_EDP &&
!crtc->config.pch_pfit.enabled) {
crtc->config.pch_pfit.force_thru = true;
intel_display_power_get(dev_priv,
POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
dev_priv->display.crtc_disable(&crtc->base);
dev_priv->display.crtc_enable(&crtc->base);
}
drm_modeset_unlock_all(dev);
}
static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]);
drm_modeset_lock_all(dev);
/*
* If we use the eDP transcoder we need to make sure that we don't
* bypass the pfit, since otherwise the pipe CRC source won't work. Only
* relevant on hsw with pipe A when using the always-on power well
* routing.
*/
if (crtc->config.pch_pfit.force_thru) {
crtc->config.pch_pfit.force_thru = false;
dev_priv->display.crtc_disable(&crtc->base);
dev_priv->display.crtc_enable(&crtc->base);
intel_display_power_put(dev_priv,
POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
}
drm_modeset_unlock_all(dev);
}
static int ivb_pipe_crc_ctl_reg(struct drm_device *dev,
enum pipe pipe,
enum intel_pipe_crc_source *source,
uint32_t *val) uint32_t *val)
{ {
if (*source == INTEL_PIPE_CRC_SOURCE_AUTO) if (*source == INTEL_PIPE_CRC_SOURCE_AUTO)
...@@ -2881,6 +2934,9 @@ static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source, ...@@ -2881,6 +2934,9 @@ static int ivb_pipe_crc_ctl_reg(enum intel_pipe_crc_source *source,
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB; *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_SPRITE_IVB;
break; break;
case INTEL_PIPE_CRC_SOURCE_PF: case INTEL_PIPE_CRC_SOURCE_PF:
if (IS_HASWELL(dev) && pipe == PIPE_A)
hsw_trans_edp_pipe_A_crc_wa(dev);
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB; *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_PF_IVB;
break; break;
case INTEL_PIPE_CRC_SOURCE_NONE: case INTEL_PIPE_CRC_SOURCE_NONE:
...@@ -2913,11 +2969,11 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, ...@@ -2913,11 +2969,11 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
else if (INTEL_INFO(dev)->gen < 5) else if (INTEL_INFO(dev)->gen < 5)
ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val); ret = i9xx_pipe_crc_ctl_reg(dev, pipe, &source, &val);
else if (IS_VALLEYVIEW(dev)) else if (IS_VALLEYVIEW(dev))
ret = vlv_pipe_crc_ctl_reg(dev,pipe, &source, &val); ret = vlv_pipe_crc_ctl_reg(dev, pipe, &source, &val);
else if (IS_GEN5(dev) || IS_GEN6(dev)) else if (IS_GEN5(dev) || IS_GEN6(dev))
ret = ilk_pipe_crc_ctl_reg(&source, &val); ret = ilk_pipe_crc_ctl_reg(&source, &val);
else else
ret = ivb_pipe_crc_ctl_reg(&source, &val); ret = ivb_pipe_crc_ctl_reg(dev, pipe, &source, &val);
if (ret != 0) if (ret != 0)
return ret; return ret;
...@@ -2969,6 +3025,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, ...@@ -2969,6 +3025,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
g4x_undo_pipe_scramble_reset(dev, pipe); g4x_undo_pipe_scramble_reset(dev, pipe);
else if (IS_VALLEYVIEW(dev)) else if (IS_VALLEYVIEW(dev))
vlv_undo_pipe_scramble_reset(dev, pipe); vlv_undo_pipe_scramble_reset(dev, pipe);
else if (IS_HASWELL(dev) && pipe == PIPE_A)
hsw_undo_trans_edp_pipe_A_crc_wa(dev);
} }
return 0; return 0;
......
...@@ -995,7 +995,9 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) ...@@ -995,7 +995,9 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
* eDP when not using the panel fitter, and when not * eDP when not using the panel fitter, and when not
* using motion blur mitigation (which we don't * using motion blur mitigation (which we don't
* support). */ * support). */
if (IS_HASWELL(dev) && intel_crtc->config.pch_pfit.enabled) if (IS_HASWELL(dev) &&
(intel_crtc->config.pch_pfit.enabled ||
intel_crtc->config.pch_pfit.force_thru))
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
else else
temp |= TRANS_DDI_EDP_INPUT_A_ON; temp |= TRANS_DDI_EDP_INPUT_A_ON;
......
...@@ -4350,7 +4350,6 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) ...@@ -4350,7 +4350,6 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe; enum pipe pipe = intel_crtc->pipe;
bool pfit_enabled = intel_crtc->config.pch_pfit.enabled;
unsigned long mask; unsigned long mask;
enum transcoder transcoder; enum transcoder transcoder;
...@@ -4358,7 +4357,8 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) ...@@ -4358,7 +4357,8 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
mask = BIT(POWER_DOMAIN_PIPE(pipe)); mask = BIT(POWER_DOMAIN_PIPE(pipe));
mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
if (pfit_enabled) if (intel_crtc->config.pch_pfit.enabled ||
intel_crtc->config.pch_pfit.force_thru)
mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe)); mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
for_each_encoder_on_crtc(dev, crtc, intel_encoder) for_each_encoder_on_crtc(dev, crtc, intel_encoder)
......
...@@ -338,6 +338,7 @@ struct intel_crtc_config { ...@@ -338,6 +338,7 @@ struct intel_crtc_config {
u32 pos; u32 pos;
u32 size; u32 size;
bool enabled; bool enabled;
bool force_thru;
} pch_pfit; } pch_pfit;
/* FDI configuration, only valid if has_pch_encoder is set. */ /* FDI configuration, only valid if has_pch_encoder is set. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment