drm/i915: Allow DBLSCAN user modes with eDP/LVDS/DSI
When encountering a connector with the scaling mode property both intel and modesetting ddxs sometimes add tons of DBLSCAN modes to the output's mode list. The idea presumably being that since the output will be going through the panel fitter anyway we can pretend to use any kind of mode. Sadly that means we can't reject user modes with the DBLSCAN flag until we know whether we're going to be using the panel's native mode or the user mode directly. Doing otherwise means X clients using xf86vidmode/xrandr will get a protocol error (and often self terminate as a result) when the kernel refuses to use the requested mode with the DBLSCAN flag. To undo the regression we'll move the DBLSCAN checks into the connector->mode_valid() and encoder->compute_config() hooks. Cc: stable@vger.kernel.org Cc: Vito Caputo <vcaputo@pengaru.com> Reported-by: Vito Caputo <vcaputo@pengaru.com> Fixes:e995ca0b81
("drm/i915: Provide a device level .mode_valid() hook") References: https://lkml.org/lkml/2018/5/21/715 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180524125403.23445-1-ville.syrjala@linux.intel.com Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106804 Tested-by: Arkadiusz Miskiewicz <arekm@maven.pl> (cherry picked from commite4dd27aadd
) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
This commit is contained in:
parent
a5bfcdf0e1
commit
541ab84d2b
|
@ -304,6 +304,9 @@ intel_crt_mode_valid(struct drm_connector *connector,
|
|||
int max_dotclk = dev_priv->max_dotclk_freq;
|
||||
int max_clock;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->clock < 25000)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
|
@ -337,6 +340,12 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
|
|||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -344,6 +353,12 @@ static bool pch_crt_compute_config(struct intel_encoder *encoder,
|
|||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
||||
return true;
|
||||
|
@ -354,6 +369,11 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder,
|
|||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
||||
|
|
|
@ -14469,12 +14469,22 @@ static enum drm_mode_status
|
|||
intel_mode_valid(struct drm_device *dev,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
/*
|
||||
* Can't reject DBLSCAN here because Xorg ddxen can add piles
|
||||
* of DBLSCAN modes to the output's mode list when they detect
|
||||
* the scaling mode property on the connector. And they don't
|
||||
* ask the kernel to validate those modes in any way until
|
||||
* modeset time at which point the client gets a protocol error.
|
||||
* So in order to not upset those clients we silently ignore the
|
||||
* DBLSCAN flag on such connectors. For other connectors we will
|
||||
* reject modes with the DBLSCAN flag in encoder->compute_config().
|
||||
* And we always reject DBLSCAN modes in connector->mode_valid()
|
||||
* as we never want such modes on the connector's mode list.
|
||||
*/
|
||||
|
||||
if (mode->vscan > 1)
|
||||
return MODE_NO_VSCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_HSKEW)
|
||||
return MODE_H_ILLEGAL;
|
||||
|
||||
|
|
|
@ -420,6 +420,9 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|||
int max_rate, mode_rate, max_lanes, max_link_clock;
|
||||
int max_dotclk;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
|
||||
|
||||
if (intel_dp_is_edp(intel_dp) && fixed_mode) {
|
||||
|
@ -1862,6 +1865,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
conn_state->scaling_mode);
|
||||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
|
||||
adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return false;
|
||||
|
|
|
@ -48,6 +48,9 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
|||
bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
|
||||
DP_DPCD_QUIRK_LIMITED_M_N);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
pipe_config->has_pch_encoder = false;
|
||||
bpp = 24;
|
||||
if (intel_dp->compliance.test_data.bpc) {
|
||||
|
@ -366,6 +369,9 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
|
|||
if (!intel_dp)
|
||||
return MODE_ERROR;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
max_link_clock = intel_dp_max_link_rate(intel_dp);
|
||||
max_lanes = intel_dp_max_lane_count(intel_dp);
|
||||
|
||||
|
|
|
@ -326,6 +326,9 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
|||
conn_state->scaling_mode);
|
||||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
/* DSI uses short packets for sync events, so clear mode flags for DSI */
|
||||
adjusted_mode->flags = 0;
|
||||
|
||||
|
@ -1266,6 +1269,9 @@ intel_dsi_mode_valid(struct drm_connector *connector,
|
|||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (fixed_mode) {
|
||||
if (mode->hdisplay > fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
|
|
|
@ -219,6 +219,9 @@ intel_dvo_mode_valid(struct drm_connector *connector,
|
|||
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
||||
int target_clock = mode->clock;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
/* XXX: Validate clock range */
|
||||
|
||||
if (fixed_mode) {
|
||||
|
@ -254,6 +257,9 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
|||
if (fixed_mode)
|
||||
intel_fixed_panel_mode(fixed_mode, adjusted_mode);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1557,6 +1557,9 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
|
|||
bool force_dvi =
|
||||
READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
clock = mode->clock;
|
||||
|
||||
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
|
||||
|
@ -1677,6 +1680,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
int desired_bpp;
|
||||
bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
|
||||
|
||||
if (pipe_config->has_hdmi_sink)
|
||||
|
|
|
@ -380,6 +380,8 @@ intel_lvds_mode_valid(struct drm_connector *connector,
|
|||
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
|
||||
int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
if (mode->hdisplay > fixed_mode->hdisplay)
|
||||
return MODE_PANEL;
|
||||
if (mode->vdisplay > fixed_mode->vdisplay)
|
||||
|
@ -429,6 +431,9 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
|||
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
|
||||
adjusted_mode);
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv)) {
|
||||
pipe_config->has_pch_encoder = true;
|
||||
|
||||
|
|
|
@ -1160,6 +1160,9 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
|||
adjusted_mode);
|
||||
}
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Make the CRTC code factor in the SDVO pixel multiplier. The
|
||||
* SDVO device will factor out the multiplier during mode_set.
|
||||
|
@ -1621,6 +1624,9 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
|
|||
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
|
||||
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (intel_sdvo->pixel_clock_min > mode->clock)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
|
|
|
@ -850,6 +850,9 @@ intel_tv_mode_valid(struct drm_connector *connector,
|
|||
const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
|
||||
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->clock > max_dotclk)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
|
@ -877,16 +880,21 @@ intel_tv_compute_config(struct intel_encoder *encoder,
|
|||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
|
||||
struct drm_display_mode *adjusted_mode =
|
||||
&pipe_config->base.adjusted_mode;
|
||||
|
||||
if (!tv_mode)
|
||||
return false;
|
||||
|
||||
pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return false;
|
||||
|
||||
adjusted_mode->crtc_clock = tv_mode->clock;
|
||||
DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
|
||||
pipe_config->pipe_bpp = 8*3;
|
||||
|
||||
/* TV has it's own notion of sync and other mode flags, so clear them. */
|
||||
pipe_config->base.adjusted_mode.flags = 0;
|
||||
adjusted_mode->flags = 0;
|
||||
|
||||
/*
|
||||
* FIXME: We don't check whether the input mode is actually what we want
|
||||
|
|
Loading…
Reference in New Issue