drm/probe_helper: Add drm_connector_helper_funcs.mode_valid_ctx
This is just an atomic version of mode_valid, which is intended to be used for situations where a driver might need to check the atomic state of objects other than the connector itself. One such example is with MST, where the maximum possible bandwidth on a connector can change dynamically irregardless of the display configuration. Changes since v1: * Use new drm logging functions * Make some corrections in the mode_valid_ctx kdoc * Return error codes or 0 from ->mode_valid_ctx() on fail, and store the drm_mode_status in an additional function parameter Changes since v2: * Don't accidentally assign ret to mode->status on success, or we'll squash legitimate mode validation results * Don't forget to assign MODE_OK to status in drm_connector_mode_valid() if we have no callbacks * Drop leftover hunk in drm_modes.h around enum drm_mode_status Changes since v3: * s/return ret/return 0/ in drm_mode_validate_pipeline() * Minor cleanup in drm_connector_mode_valid() Tested-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Cc: Lee Shawn C <shawn.c.lee@intel.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20200713170746.254388-2-lyude@redhat.com
This commit is contained in:
@@ -86,17 +86,19 @@ drm_mode_validate_flag(const struct drm_display_mode *mode,
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
static int
|
||||
drm_mode_validate_pipeline(struct drm_display_mode *mode,
|
||||
struct drm_connector *connector)
|
||||
struct drm_connector *connector,
|
||||
struct drm_modeset_acquire_ctx *ctx,
|
||||
enum drm_mode_status *status)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
enum drm_mode_status ret = MODE_OK;
|
||||
struct drm_encoder *encoder;
|
||||
int ret;
|
||||
|
||||
/* Step 1: Validate against connector */
|
||||
ret = drm_connector_mode_valid(connector, mode);
|
||||
if (ret != MODE_OK)
|
||||
ret = drm_connector_mode_valid(connector, mode, ctx, status);
|
||||
if (ret || *status != MODE_OK)
|
||||
return ret;
|
||||
|
||||
/* Step 2: Validate against encoders and crtcs */
|
||||
@@ -104,8 +106,8 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
ret = drm_encoder_mode_valid(encoder, mode);
|
||||
if (ret != MODE_OK) {
|
||||
*status = drm_encoder_mode_valid(encoder, mode);
|
||||
if (*status != MODE_OK) {
|
||||
/* No point in continuing for crtc check as this encoder
|
||||
* will not accept the mode anyway. If all encoders
|
||||
* reject the mode then, at exit, ret will not be
|
||||
@@ -114,8 +116,8 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
|
||||
}
|
||||
|
||||
bridge = drm_bridge_chain_get_first_bridge(encoder);
|
||||
ret = drm_bridge_chain_mode_valid(bridge, mode);
|
||||
if (ret != MODE_OK) {
|
||||
*status = drm_bridge_chain_mode_valid(bridge, mode);
|
||||
if (*status != MODE_OK) {
|
||||
/* There is also no point in continuing for crtc check
|
||||
* here. */
|
||||
continue;
|
||||
@@ -125,17 +127,17 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode,
|
||||
if (!drm_encoder_crtc_ok(encoder, crtc))
|
||||
continue;
|
||||
|
||||
ret = drm_crtc_mode_valid(crtc, mode);
|
||||
if (ret == MODE_OK) {
|
||||
*status = drm_crtc_mode_valid(crtc, mode);
|
||||
if (*status == MODE_OK) {
|
||||
/* If we get to this point there is at least
|
||||
* one combination of encoder+crtc that works
|
||||
* for this mode. Lets return now. */
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
|
||||
@@ -196,16 +198,27 @@ enum drm_mode_status drm_encoder_mode_valid(struct drm_encoder *encoder,
|
||||
return encoder_funcs->mode_valid(encoder, mode);
|
||||
}
|
||||
|
||||
enum drm_mode_status drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
int
|
||||
drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_modeset_acquire_ctx *ctx,
|
||||
enum drm_mode_status *status)
|
||||
{
|
||||
const struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
int ret = 0;
|
||||
|
||||
if (!connector_funcs || !connector_funcs->mode_valid)
|
||||
return MODE_OK;
|
||||
if (!connector_funcs)
|
||||
*status = MODE_OK;
|
||||
else if (connector_funcs->mode_valid_ctx)
|
||||
ret = connector_funcs->mode_valid_ctx(connector, mode, ctx,
|
||||
status);
|
||||
else if (connector_funcs->mode_valid)
|
||||
*status = connector_funcs->mode_valid(connector, mode);
|
||||
else
|
||||
*status = MODE_OK;
|
||||
|
||||
return connector_funcs->mode_valid(connector, mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
|
||||
@@ -375,8 +388,9 @@ EXPORT_SYMBOL(drm_helper_probe_detect);
|
||||
* (if specified)
|
||||
* - drm_mode_validate_flag() checks the modes against basic connector
|
||||
* capabilities (interlace_allowed,doublescan_allowed,stereo_allowed)
|
||||
* - the optional &drm_connector_helper_funcs.mode_valid helper can perform
|
||||
* driver and/or sink specific checks
|
||||
* - the optional &drm_connector_helper_funcs.mode_valid or
|
||||
* &drm_connector_helper_funcs.mode_valid_ctx helpers can perform driver
|
||||
* and/or sink specific checks
|
||||
* - the optional &drm_crtc_helper_funcs.mode_valid,
|
||||
* &drm_bridge_funcs.mode_valid and &drm_encoder_helper_funcs.mode_valid
|
||||
* helpers can perform driver and/or source specific checks which are also
|
||||
@@ -507,22 +521,39 @@ retry:
|
||||
mode_flags |= DRM_MODE_FLAG_3D_MASK;
|
||||
|
||||
list_for_each_entry(mode, &connector->modes, head) {
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_driver(dev, mode);
|
||||
if (mode->status != MODE_OK)
|
||||
continue;
|
||||
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_size(mode, maxX, maxY);
|
||||
mode->status = drm_mode_validate_driver(dev, mode);
|
||||
if (mode->status != MODE_OK)
|
||||
continue;
|
||||
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_flag(mode, mode_flags);
|
||||
mode->status = drm_mode_validate_size(mode, maxX, maxY);
|
||||
if (mode->status != MODE_OK)
|
||||
continue;
|
||||
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_pipeline(mode,
|
||||
connector);
|
||||
mode->status = drm_mode_validate_flag(mode, mode_flags);
|
||||
if (mode->status != MODE_OK)
|
||||
continue;
|
||||
|
||||
if (mode->status == MODE_OK)
|
||||
mode->status = drm_mode_validate_ycbcr420(mode,
|
||||
connector);
|
||||
ret = drm_mode_validate_pipeline(mode, connector, &ctx,
|
||||
&mode->status);
|
||||
if (ret) {
|
||||
drm_dbg_kms(dev,
|
||||
"drm_mode_validate_pipeline failed: %d\n",
|
||||
ret);
|
||||
|
||||
if (drm_WARN_ON_ONCE(dev, ret != -EDEADLK)) {
|
||||
mode->status = MODE_ERROR;
|
||||
} else {
|
||||
drm_modeset_backoff(&ctx);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode->status != MODE_OK)
|
||||
continue;
|
||||
mode->status = drm_mode_validate_ycbcr420(mode, connector);
|
||||
}
|
||||
|
||||
prune:
|
||||
|
Reference in New Issue
Block a user