drm: Add crtc/encoder/bridge->mode_valid() callbacks
authorJose Abreu <Jose.Abreu@synopsys.com>
Mon, 15 May 2017 09:33:47 +0000 (11:33 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 23 May 2017 14:36:06 +0000 (16:36 +0200)
This adds a new callback to crtc, encoder and bridge helper functions
called mode_valid(). This callback shall be implemented if the
corresponding component has some sort of restriction in the modes
that can be displayed. A NULL callback implicates that the component
can display all the modes.

We also change the documentation so that the new and old callbacks
are correctly documented.

Only the callbacks were implemented to simplify review process,
following patches will make use of them.

Changes in v2 from Daniel:
- Update the warning about how modes aren't filtered in atomic_check -
  the heleprs help out a lot more now.
- Consistenly roll out that warning, crtc/encoder's atomic_check
  missed it.
- Sprinkle more links all over the place, so it's easier to see where
  this stuff is used and how the differen hooks are related.
- Note that ->mode_valid is optional everywhere.
- Explain why the connector's mode_valid is special and does _not_ get
  called in atomic_check.

v3: Document what can and cannot be checked in mode_valid a bit better
(Andrjez). Answer: Only allowed to look at the mode, nothing else.

Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
Cc: Jose Abreu <joabreu@synopsys.com>
Cc: Carlos Palminha <palminha@synopsys.com>
Cc: Alexey Brodkin <abrodkin@synopsys.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Dave Airlie <airlied@linux.ie>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> (v2)
Reviewed-by: Jose Abreu <joabreu@synopsys.com> (v2)
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170515093347.31098-1-daniel.vetter@ffwll.ch
include/drm/drm_bridge.h
include/drm/drm_modeset_helper_vtables.h

index fdd82fcbf1686482bbc3ea8bede6a8da688cea2e..f703bafc2e30bad658511720ec5af40327dd8ca0 100644 (file)
@@ -58,6 +58,40 @@ struct drm_bridge_funcs {
         */
        void (*detach)(struct drm_bridge *bridge);
 
+       /**
+        * @mode_valid:
+        *
+        * This callback is used to check if a specific mode is valid in this
+        * bridge. This should be implemented if the bridge has some sort of
+        * restriction in the modes it can display. For example, a given bridge
+        * may be responsible to set a clock value. If the clock can not
+        * produce all the values for the available modes then this callback
+        * can be used to restrict the number of modes to only the ones that
+        * can be displayed.
+        *
+        * This hook is used by the probe helpers to filter the mode list in
+        * drm_helper_probe_single_connector_modes(), and it is used by the
+        * atomic helpers to validate modes supplied by userspace in
+        * drm_atomic_helper_check_modeset().
+        *
+        * This function is optional.
+        *
+        * NOTE:
+        *
+        * Since this function is both called from the check phase of an atomic
+        * commit, and the mode validation in the probe paths it is not allowed
+        * to look at anything else but the passed-in mode, and validate it
+        * against configuration-invariant hardward constraints. Any further
+        * limits which depend upon the configuration can only be checked in
+        * @mode_fixup.
+        *
+        * RETURNS:
+        *
+        * drm_mode_status Enum
+        */
+       enum drm_mode_status (*mode_valid)(struct drm_bridge *crtc,
+                                          const struct drm_display_mode *mode);
+
        /**
         * @mode_fixup:
         *
@@ -82,6 +116,12 @@ struct drm_bridge_funcs {
         * NOT touch any persistent state (hardware or software) or data
         * structures except the passed in @state parameter.
         *
+        * Also beware that userspace can request its own custom modes, neither
+        * core nor helpers filter modes to the list of probe modes reported by
+        * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+        * that modes are filtered consistently put any bridge constraints and
+        * limits checks into @mode_valid.
+        *
         * RETURNS:
         *
         * True if an acceptable configuration is possible, false if the modeset
index c01c328f6cc80c1945b9f8355d89fd314bfb424a..739b832eb304bd1cd261076a2e4e44d90b841b6c 100644 (file)
@@ -105,6 +105,40 @@ struct drm_crtc_helper_funcs {
         */
        void (*commit)(struct drm_crtc *crtc);
 
+       /**
+        * @mode_valid:
+        *
+        * This callback is used to check if a specific mode is valid in this
+        * crtc. This should be implemented if the crtc has some sort of
+        * restriction in the modes it can display. For example, a given crtc
+        * may be responsible to set a clock value. If the clock can not
+        * produce all the values for the available modes then this callback
+        * can be used to restrict the number of modes to only the ones that
+        * can be displayed.
+        *
+        * This hook is used by the probe helpers to filter the mode list in
+        * drm_helper_probe_single_connector_modes(), and it is used by the
+        * atomic helpers to validate modes supplied by userspace in
+        * drm_atomic_helper_check_modeset().
+        *
+        * This function is optional.
+        *
+        * NOTE:
+        *
+        * Since this function is both called from the check phase of an atomic
+        * commit, and the mode validation in the probe paths it is not allowed
+        * to look at anything else but the passed-in mode, and validate it
+        * against configuration-invariant hardward constraints. Any further
+        * limits which depend upon the configuration can only be checked in
+        * @mode_fixup or @atomic_check.
+        *
+        * RETURNS:
+        *
+        * drm_mode_status Enum
+        */
+       enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
+                                          const struct drm_display_mode *mode);
+
        /**
         * @mode_fixup:
         *
@@ -132,20 +166,11 @@ struct drm_crtc_helper_funcs {
         * Atomic drivers which need to inspect and adjust more state should
         * instead use the @atomic_check callback.
         *
-        * Also beware that neither core nor helpers filter modes before
-        * passing them to the driver: While the list of modes that is
-        * advertised to userspace is filtered using the
-        * &drm_connector.mode_valid callback, neither the core nor the helpers
-        * do any filtering on modes passed in from userspace when setting a
-        * mode. It is therefore possible for userspace to pass in a mode that
-        * was previously filtered out using &drm_connector.mode_valid or add a
-        * custom mode that wasn't probed from EDID or similar to begin with.
-        * Even though this is an advanced feature and rarely used nowadays,
-        * some users rely on being able to specify modes manually so drivers
-        * must be prepared to deal with it. Specifically this means that all
-        * drivers need not only validate modes in &drm_connector.mode_valid but
-        * also in this or in the &drm_encoder_helper_funcs.mode_fixup callback
-        * to make sure invalid modes passed in from userspace are rejected.
+        * Also beware that userspace can request its own custom modes, neither
+        * core nor helpers filter modes to the list of probe modes reported by
+        * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+        * that modes are filtered consistently put any CRTC constraints and
+        * limits checks into @mode_valid.
         *
         * RETURNS:
         *
@@ -341,6 +366,12 @@ struct drm_crtc_helper_funcs {
         * state objects passed-in or assembled in the overall &drm_atomic_state
         * update tracking structure.
         *
+        * Also beware that userspace can request its own custom modes, neither
+        * core nor helpers filter modes to the list of probe modes reported by
+        * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+        * that modes are filtered consistently put any CRTC constraints and
+        * limits checks into @mode_valid.
+        *
         * RETURNS:
         *
         * 0 on success, -EINVAL if the state or the transition can't be
@@ -456,6 +487,40 @@ struct drm_encoder_helper_funcs {
         */
        void (*dpms)(struct drm_encoder *encoder, int mode);
 
+       /**
+        * @mode_valid:
+        *
+        * This callback is used to check if a specific mode is valid in this
+        * encoder. This should be implemented if the encoder has some sort
+        * of restriction in the modes it can display. For example, a given
+        * encoder may be responsible to set a clock value. If the clock can
+        * not produce all the values for the available modes then this callback
+        * can be used to restrict the number of modes to only the ones that
+        * can be displayed.
+        *
+        * This hook is used by the probe helpers to filter the mode list in
+        * drm_helper_probe_single_connector_modes(), and it is used by the
+        * atomic helpers to validate modes supplied by userspace in
+        * drm_atomic_helper_check_modeset().
+        *
+        * This function is optional.
+        *
+        * NOTE:
+        *
+        * Since this function is both called from the check phase of an atomic
+        * commit, and the mode validation in the probe paths it is not allowed
+        * to look at anything else but the passed-in mode, and validate it
+        * against configuration-invariant hardward constraints. Any further
+        * limits which depend upon the configuration can only be checked in
+        * @mode_fixup or @atomic_check.
+        *
+        * RETURNS:
+        *
+        * drm_mode_status Enum
+        */
+       enum drm_mode_status (*mode_valid)(struct drm_encoder *crtc,
+                                          const struct drm_display_mode *mode);
+
        /**
         * @mode_fixup:
         *
@@ -482,21 +547,11 @@ struct drm_encoder_helper_funcs {
         * Atomic drivers which need to inspect and adjust more state should
         * instead use the @atomic_check callback.
         *
-        * Also beware that neither core nor helpers filter modes before
-        * passing them to the driver: While the list of modes that is
-        * advertised to userspace is filtered using the connector's
-        * &drm_connector_helper_funcs.mode_valid callback, neither the core nor
-        * the helpers do any filtering on modes passed in from userspace when
-        * setting a mode. It is therefore possible for userspace to pass in a
-        * mode that was previously filtered out using
-        * &drm_connector_helper_funcs.mode_valid or add a custom mode that
-        * wasn't probed from EDID or similar to begin with.  Even though this
-        * is an advanced feature and rarely used nowadays, some users rely on
-        * being able to specify modes manually so drivers must be prepared to
-        * deal with it. Specifically this means that all drivers need not only
-        * validate modes in &drm_connector.mode_valid but also in this or in
-        * the &drm_crtc_helper_funcs.mode_fixup callback to make sure
-        * invalid modes passed in from userspace are rejected.
+        * Also beware that userspace can request its own custom modes, neither
+        * core nor helpers filter modes to the list of probe modes reported by
+        * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+        * that modes are filtered consistently put any encoder constraints and
+        * limits checks into @mode_valid.
         *
         * RETURNS:
         *
@@ -686,6 +741,12 @@ struct drm_encoder_helper_funcs {
         * state objects passed-in or assembled in the overall &drm_atomic_state
         * update tracking structure.
         *
+        * Also beware that userspace can request its own custom modes, neither
+        * core nor helpers filter modes to the list of probe modes reported by
+        * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+        * that modes are filtered consistently put any encoder constraints and
+        * limits checks into @mode_valid.
+        *
         * RETURNS:
         *
         * 0 on success, -EINVAL if the state or the transition can't be
@@ -795,13 +856,20 @@ struct drm_connector_helper_funcs {
         * (which is usually derived from the EDID data block from the sink).
         * See e.g. drm_helper_probe_single_connector_modes().
         *
+        * This function is optional.
+        *
         * NOTE:
         *
         * This only filters the mode list supplied to userspace in the
-        * GETCONNECOTR IOCTL. Userspace is free to create modes of its own and
-        * ask the kernel to use them. It this case the atomic helpers or legacy
-        * CRTC helpers will not call this function. Drivers therefore must
-        * still fully validate any mode passed in in a modeset request.
+        * GETCONNECTOR IOCTL. Compared to &drm_encoder_helper_funcs.mode_valid,
+        * &drm_crtc_helper_funcs.mode_valid and &drm_bridge_funcs.mode_valid,
+        * which are also called by the atomic helpers from
+        * drm_atomic_helper_check_modeset(). This allows userspace to force and
+        * ignore sink constraint (like the pixel clock limits in the screen's
+        * EDID), which is useful for e.g. testing, or working around a broken
+        * EDID. Any source hardware constraint (which always need to be
+        * enforced) therefore should be checked in one of the above callbacks,
+        * and not this one here.
         *
         * To avoid races with concurrent connector state updates, the helper
         * libraries always call this with the &drm_mode_config.connection_mutex