]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/modes: Provide global mode_valid hook
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 14 Nov 2017 18:32:57 +0000 (20:32 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 29 Jan 2018 19:51:51 +0000 (21:51 +0200)
Allow drivers to provide a device wide .mode_valid() hook in addition to
the already existing crtc/encoder/bridge/connector hooks. This can be
used to validate device/driver wide constraings without having to add
those to the other hooks. And since we call this hook also for user
modes later on in the modeset we don't have to worry about anything the
hook has already rejected.

I also have some further ideas for this hook. Eg. we could replace the
drm_mode_set_crtcinfo(HALVE_V) call in drm_mode_convert_umode()/etc.
with a driver specific variant via this hook. At least on i915 we would
like to pass CRTC_STEREO_DOUBLE to that function instead, and then
we could safely use the crtc_ timings in all our .mode_valid() hooks,
which would allow us to reuse those hooks for validating the
adjusted_mode during a modeset.

v2: Fix the language fails in the kernel docs (Daniel)

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171114183258.16976-10-ville.syrjala@linux.intel.com
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_probe_helper.c
include/drm/drm_mode_config.h
include/drm/drm_modes.h

index b76d49218cf1de132be35d1ccb9226f8ba8a7704..51a848c553b93fc7a88dfe07c6f07ef46f4abacd 100644 (file)
@@ -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;
index 5b4be382a1d7660046945e664f10970aa45c18a0..353e24fcde9e9b5cbbec60174615e30352b71601 100644 (file)
@@ -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;
index b35324a50fdfab9a2c7bd7cabc75d5705f8fb1d3..c397b523c9454b62ac54a30eb1cc3ce8a6c7517b 100644 (file)
@@ -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;
 
index 555fbe54d6e224e2b58a7d263353efac2d7e0104..2d1643bdae78b0e390672efc0d84396b9b9b17d4 100644 (file)
@@ -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);
index 2cb6f02df64ab562eed1d0b515e6da905bda0212..7569f22ffef6b648b7b7af82a8a78ba8ee36b79e 100644 (file)
@@ -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:
         *
index 71cbb10e22dca8f9d59d13801de438bd509b027a..0d310beae6afd45bc3a74ec49aef1ca57849e864 100644 (file)
@@ -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