diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index b76d49218cf1de132be35d1ccb9226f8ba8a7704..51a848c553b93fc7a88dfe07c6f07ef46f4abacd 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -390,7 +390,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, if (blob) { if (blob->length != sizeof(struct drm_mode_modeinfo) || - drm_mode_convert_umode(&state->mode, + drm_mode_convert_umode(state->crtc->dev, &state->mode, (const struct drm_mode_modeinfo *) blob->data)) return -EINVAL; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5b4be382a1d7660046945e664f10970aa45c18a0..353e24fcde9e9b5cbbec60174615e30352b71601 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -614,7 +614,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } - ret = drm_mode_convert_umode(mode, &crtc_req->mode); + ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode); if (ret) { DRM_DEBUG_KMS("Invalid mode\n"); goto out; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index b35324a50fdfab9a2c7bd7cabc75d5705f8fb1d3..c397b523c9454b62ac54a30eb1cc3ce8a6c7517b 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1023,17 +1023,7 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, } EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo); -/** - * drm_mode_validate_basic - make sure the mode is somewhat sane - * @mode: mode to check - * - * Check that the mode timings are at least somewhat reasonable. - * Any hardware specific limits are left up for each driver to check. - * - * Returns: - * The mode status - */ -enum drm_mode_status +static enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode) { if (mode->type & ~DRM_MODE_TYPE_ALL) @@ -1062,7 +1052,35 @@ drm_mode_validate_basic(const struct drm_display_mode *mode) return MODE_OK; } -EXPORT_SYMBOL(drm_mode_validate_basic); + +/** + * drm_mode_validate_driver - make sure the mode is somewhat sane + * @dev: drm device + * @mode: mode to check + * + * First do basic validation on the mode, and then allow the driver + * to check for device/driver specific limitations via the optional + * &drm_mode_config_helper_funcs.mode_valid hook. + * + * Returns: + * The mode status + */ +enum drm_mode_status +drm_mode_validate_driver(struct drm_device *dev, + const struct drm_display_mode *mode) +{ + enum drm_mode_status status; + + status = drm_mode_validate_basic(mode); + if (status != MODE_OK) + return status; + + if (dev->mode_config.funcs->mode_valid) + return dev->mode_config.funcs->mode_valid(dev, mode); + else + return MODE_OK; +} +EXPORT_SYMBOL(drm_mode_validate_driver); /** * drm_mode_validate_size - make sure modes adhere to size constraints @@ -1564,6 +1582,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, /** * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode + * @dev: drm device * @out: drm_display_mode to return to the user * @in: drm_mode_modeinfo to use * @@ -1573,7 +1592,8 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, * Returns: * Zero on success, negative errno on failure. */ -int drm_mode_convert_umode(struct drm_display_mode *out, +int drm_mode_convert_umode(struct drm_device *dev, + struct drm_display_mode *out, const struct drm_mode_modeinfo *in) { int ret = -EINVAL; @@ -1600,7 +1620,7 @@ int drm_mode_convert_umode(struct drm_display_mode *out, strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; - out->status = drm_mode_validate_basic(out); + out->status = drm_mode_validate_driver(dev, out); if (out->status != MODE_OK) goto out; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 555fbe54d6e224e2b58a7d263353efac2d7e0104..2d1643bdae78b0e390672efc0d84396b9b9b17d4 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -499,7 +499,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, list_for_each_entry(mode, &connector->modes, head) { if (mode->status == MODE_OK) - mode->status = drm_mode_validate_basic(mode); + mode->status = drm_mode_validate_driver(dev, mode); if (mode->status == MODE_OK) mode->status = drm_mode_validate_size(mode, maxX, maxY); diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 2cb6f02df64ab562eed1d0b515e6da905bda0212..7569f22ffef6b648b7b7af82a8a78ba8ee36b79e 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -36,6 +36,7 @@ struct drm_device; struct drm_atomic_state; struct drm_mode_fb_cmd2; struct drm_format_info; +struct drm_display_mode; /** * struct drm_mode_config_funcs - basic driver provided mode setting functions @@ -101,6 +102,17 @@ struct drm_mode_config_funcs { */ void (*output_poll_changed)(struct drm_device *dev); + /** + * @mode_valid: + * + * Device specific validation of display modes. Can be used to reject + * modes that can never be supported. Only device wide constraints can + * be checked here. crtc/encoder/bridge/connector specific constraints + * should be checked in the .mode_valid() hook for each specific object. + */ + enum drm_mode_status (*mode_valid)(struct drm_device *dev, + const struct drm_display_mode *mode); + /** * @atomic_check: * diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 71cbb10e22dca8f9d59d13801de438bd509b027a..0d310beae6afd45bc3a74ec49aef1ca57849e864 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -444,7 +444,8 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev); void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, const struct drm_display_mode *in); -int drm_mode_convert_umode(struct drm_display_mode *out, +int drm_mode_convert_umode(struct drm_device *dev, + struct drm_display_mode *out, const struct drm_mode_modeinfo *in); void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); void drm_mode_debug_printmodeline(const struct drm_display_mode *mode); @@ -497,7 +498,8 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); /* for use by the crtc helper probe functions */ -enum drm_mode_status drm_mode_validate_basic(const struct drm_display_mode *mode); +enum drm_mode_status drm_mode_validate_driver(struct drm_device *dev, + const struct drm_display_mode *mode); enum drm_mode_status drm_mode_validate_size(const struct drm_display_mode *mode, int maxX, int maxY); enum drm_mode_status