LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_crtc_helper.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 378 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 15 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2006-2008 Intel Corporation
       3             :  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
       4             :  *
       5             :  * DRM core CRTC related functions
       6             :  *
       7             :  * Permission to use, copy, modify, distribute, and sell this software and its
       8             :  * documentation for any purpose is hereby granted without fee, provided that
       9             :  * the above copyright notice appear in all copies and that both that copyright
      10             :  * notice and this permission notice appear in supporting documentation, and
      11             :  * that the name of the copyright holders not be used in advertising or
      12             :  * publicity pertaining to distribution of the software without specific,
      13             :  * written prior permission.  The copyright holders make no representations
      14             :  * about the suitability of this software for any purpose.  It is provided "as
      15             :  * is" without express or implied warranty.
      16             :  *
      17             :  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
      18             :  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
      19             :  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
      20             :  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
      21             :  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      22             :  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      23             :  * OF THIS SOFTWARE.
      24             :  *
      25             :  * Authors:
      26             :  *      Keith Packard
      27             :  *      Eric Anholt <eric@anholt.net>
      28             :  *      Dave Airlie <airlied@linux.ie>
      29             :  *      Jesse Barnes <jesse.barnes@intel.com>
      30             :  */
      31             : 
      32             : #include <linux/export.h>
      33             : #include <linux/kernel.h>
      34             : #include <linux/moduleparam.h>
      35             : 
      36             : #include <drm/drm_atomic.h>
      37             : #include <drm/drm_atomic_helper.h>
      38             : #include <drm/drm_atomic_uapi.h>
      39             : #include <drm/drm_bridge.h>
      40             : #include <drm/drm_crtc.h>
      41             : #include <drm/drm_crtc_helper.h>
      42             : #include <drm/drm_drv.h>
      43             : #include <drm/drm_edid.h>
      44             : #include <drm/drm_encoder.h>
      45             : #include <drm/drm_fb_helper.h>
      46             : #include <drm/drm_fourcc.h>
      47             : #include <drm/drm_plane_helper.h>
      48             : #include <drm/drm_print.h>
      49             : #include <drm/drm_vblank.h>
      50             : 
      51             : #include "drm_crtc_helper_internal.h"
      52             : 
      53             : /**
      54             :  * DOC: overview
      55             :  *
      56             :  * The CRTC modeset helper library provides a default set_config implementation
      57             :  * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
      58             :  * the same callbacks which drivers can use to e.g. restore the modeset
      59             :  * configuration on resume with drm_helper_resume_force_mode().
      60             :  *
      61             :  * Note that this helper library doesn't track the current power state of CRTCs
      62             :  * and encoders. It can call callbacks like &drm_encoder_helper_funcs.dpms even
      63             :  * though the hardware is already in the desired state. This deficiency has been
      64             :  * fixed in the atomic helpers.
      65             :  *
      66             :  * The driver callbacks are mostly compatible with the atomic modeset helpers,
      67             :  * except for the handling of the primary plane: Atomic helpers require that the
      68             :  * primary plane is implemented as a real standalone plane and not directly tied
      69             :  * to the CRTC state. For easier transition this library provides functions to
      70             :  * implement the old semantics required by the CRTC helpers using the new plane
      71             :  * and atomic helper callbacks.
      72             :  *
      73             :  * Drivers are strongly urged to convert to the atomic helpers (by way of first
      74             :  * converting to the plane helpers). New drivers must not use these functions
      75             :  * but need to implement the atomic interface instead, potentially using the
      76             :  * atomic helpers for that.
      77             :  *
      78             :  * These legacy modeset helpers use the same function table structures as
      79             :  * all other modesetting helpers. See the documentation for struct
      80             :  * &drm_crtc_helper_funcs, &struct drm_encoder_helper_funcs and struct
      81             :  * &drm_connector_helper_funcs.
      82             :  */
      83             : 
      84             : /**
      85             :  * drm_helper_encoder_in_use - check if a given encoder is in use
      86             :  * @encoder: encoder to check
      87             :  *
      88             :  * Checks whether @encoder is with the current mode setting output configuration
      89             :  * in use by any connector. This doesn't mean that it is actually enabled since
      90             :  * the DPMS state is tracked separately.
      91             :  *
      92             :  * Returns:
      93             :  * True if @encoder is used, false otherwise.
      94             :  */
      95           0 : bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
      96             : {
      97             :         struct drm_connector *connector;
      98             :         struct drm_connector_list_iter conn_iter;
      99           0 :         struct drm_device *dev = encoder->dev;
     100             : 
     101           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     102             : 
     103             :         /*
     104             :          * We can expect this mutex to be locked if we are not panicking.
     105             :          * Locking is currently fubar in the panic handler.
     106             :          */
     107           0 :         if (!oops_in_progress) {
     108           0 :                 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
     109           0 :                 WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
     110             :         }
     111             : 
     112             : 
     113           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     114           0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     115           0 :                 if (connector->encoder == encoder) {
     116           0 :                         drm_connector_list_iter_end(&conn_iter);
     117           0 :                         return true;
     118             :                 }
     119             :         }
     120           0 :         drm_connector_list_iter_end(&conn_iter);
     121           0 :         return false;
     122             : }
     123             : EXPORT_SYMBOL(drm_helper_encoder_in_use);
     124             : 
     125             : /**
     126             :  * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
     127             :  * @crtc: CRTC to check
     128             :  *
     129             :  * Checks whether @crtc is with the current mode setting output configuration
     130             :  * in use by any connector. This doesn't mean that it is actually enabled since
     131             :  * the DPMS state is tracked separately.
     132             :  *
     133             :  * Returns:
     134             :  * True if @crtc is used, false otherwise.
     135             :  */
     136           0 : bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
     137             : {
     138             :         struct drm_encoder *encoder;
     139           0 :         struct drm_device *dev = crtc->dev;
     140             : 
     141           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     142             : 
     143             :         /*
     144             :          * We can expect this mutex to be locked if we are not panicking.
     145             :          * Locking is currently fubar in the panic handler.
     146             :          */
     147           0 :         if (!oops_in_progress)
     148           0 :                 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
     149             : 
     150           0 :         drm_for_each_encoder(encoder, dev)
     151           0 :                 if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
     152             :                         return true;
     153             :         return false;
     154             : }
     155             : EXPORT_SYMBOL(drm_helper_crtc_in_use);
     156             : 
     157             : static void
     158           0 : drm_encoder_disable(struct drm_encoder *encoder)
     159             : {
     160           0 :         const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
     161             : 
     162           0 :         if (!encoder_funcs)
     163             :                 return;
     164             : 
     165           0 :         if (encoder_funcs->disable)
     166           0 :                 (*encoder_funcs->disable)(encoder);
     167           0 :         else if (encoder_funcs->dpms)
     168           0 :                 (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
     169             : }
     170             : 
     171           0 : static void __drm_helper_disable_unused_functions(struct drm_device *dev)
     172             : {
     173             :         struct drm_encoder *encoder;
     174             :         struct drm_crtc *crtc;
     175             : 
     176           0 :         drm_warn_on_modeset_not_all_locked(dev);
     177             : 
     178           0 :         drm_for_each_encoder(encoder, dev) {
     179           0 :                 if (!drm_helper_encoder_in_use(encoder)) {
     180           0 :                         drm_encoder_disable(encoder);
     181             :                         /* disconnect encoder from any connector */
     182           0 :                         encoder->crtc = NULL;
     183             :                 }
     184             :         }
     185             : 
     186           0 :         drm_for_each_crtc(crtc, dev) {
     187           0 :                 const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     188             : 
     189           0 :                 crtc->enabled = drm_helper_crtc_in_use(crtc);
     190           0 :                 if (!crtc->enabled) {
     191           0 :                         if (crtc_funcs->disable)
     192           0 :                                 (*crtc_funcs->disable)(crtc);
     193             :                         else
     194           0 :                                 (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
     195           0 :                         crtc->primary->fb = NULL;
     196             :                 }
     197             :         }
     198           0 : }
     199             : 
     200             : /**
     201             :  * drm_helper_disable_unused_functions - disable unused objects
     202             :  * @dev: DRM device
     203             :  *
     204             :  * This function walks through the entire mode setting configuration of @dev. It
     205             :  * will remove any CRTC links of unused encoders and encoder links of
     206             :  * disconnected connectors. Then it will disable all unused encoders and CRTCs
     207             :  * either by calling their disable callback if available or by calling their
     208             :  * dpms callback with DRM_MODE_DPMS_OFF.
     209             :  *
     210             :  * NOTE:
     211             :  *
     212             :  * This function is part of the legacy modeset helper library and will cause
     213             :  * major confusion with atomic drivers. This is because atomic helpers guarantee
     214             :  * to never call ->disable() hooks on a disabled function, or ->enable() hooks
     215             :  * on an enabled functions. drm_helper_disable_unused_functions() on the other
     216             :  * hand throws such guarantees into the wind and calls disable hooks
     217             :  * unconditionally on unused functions.
     218             :  */
     219           0 : void drm_helper_disable_unused_functions(struct drm_device *dev)
     220             : {
     221           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     222             : 
     223           0 :         drm_modeset_lock_all(dev);
     224           0 :         __drm_helper_disable_unused_functions(dev);
     225           0 :         drm_modeset_unlock_all(dev);
     226           0 : }
     227             : EXPORT_SYMBOL(drm_helper_disable_unused_functions);
     228             : 
     229             : /*
     230             :  * Check the CRTC we're going to map each output to vs. its current
     231             :  * CRTC.  If they don't match, we have to disable the output and the CRTC
     232             :  * since the driver will have to re-route things.
     233             :  */
     234             : static void
     235           0 : drm_crtc_prepare_encoders(struct drm_device *dev)
     236             : {
     237             :         const struct drm_encoder_helper_funcs *encoder_funcs;
     238             :         struct drm_encoder *encoder;
     239             : 
     240           0 :         drm_for_each_encoder(encoder, dev) {
     241           0 :                 encoder_funcs = encoder->helper_private;
     242           0 :                 if (!encoder_funcs)
     243           0 :                         continue;
     244             : 
     245             :                 /* Disable unused encoders */
     246           0 :                 if (encoder->crtc == NULL)
     247           0 :                         drm_encoder_disable(encoder);
     248             :         }
     249           0 : }
     250             : 
     251             : /**
     252             :  * drm_crtc_helper_set_mode - internal helper to set a mode
     253             :  * @crtc: CRTC to program
     254             :  * @mode: mode to use
     255             :  * @x: horizontal offset into the surface
     256             :  * @y: vertical offset into the surface
     257             :  * @old_fb: old framebuffer, for cleanup
     258             :  *
     259             :  * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
     260             :  * to fixup or reject the mode prior to trying to set it. This is an internal
     261             :  * helper that drivers could e.g. use to update properties that require the
     262             :  * entire output pipe to be disabled and re-enabled in a new configuration. For
     263             :  * example for changing whether audio is enabled on a hdmi link or for changing
     264             :  * panel fitter or dither attributes. It is also called by the
     265             :  * drm_crtc_helper_set_config() helper function to drive the mode setting
     266             :  * sequence.
     267             :  *
     268             :  * Returns:
     269             :  * True if the mode was set successfully, false otherwise.
     270             :  */
     271           0 : bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
     272             :                               struct drm_display_mode *mode,
     273             :                               int x, int y,
     274             :                               struct drm_framebuffer *old_fb)
     275             : {
     276           0 :         struct drm_device *dev = crtc->dev;
     277             :         struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
     278           0 :         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     279             :         const struct drm_encoder_helper_funcs *encoder_funcs;
     280             :         int saved_x, saved_y;
     281             :         bool saved_enabled;
     282             :         struct drm_encoder *encoder;
     283           0 :         bool ret = true;
     284             : 
     285           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     286             : 
     287           0 :         drm_warn_on_modeset_not_all_locked(dev);
     288             : 
     289           0 :         saved_enabled = crtc->enabled;
     290           0 :         crtc->enabled = drm_helper_crtc_in_use(crtc);
     291           0 :         if (!crtc->enabled)
     292             :                 return true;
     293             : 
     294           0 :         adjusted_mode = drm_mode_duplicate(dev, mode);
     295           0 :         if (!adjusted_mode) {
     296           0 :                 crtc->enabled = saved_enabled;
     297           0 :                 return false;
     298             :         }
     299             : 
     300           0 :         drm_mode_init(&saved_mode, &crtc->mode);
     301           0 :         drm_mode_init(&saved_hwmode, &crtc->hwmode);
     302           0 :         saved_x = crtc->x;
     303           0 :         saved_y = crtc->y;
     304             : 
     305             :         /* Update crtc values up front so the driver can rely on them for mode
     306             :          * setting.
     307             :          */
     308           0 :         drm_mode_copy(&crtc->mode, mode);
     309           0 :         crtc->x = x;
     310           0 :         crtc->y = y;
     311             : 
     312             :         /* Pass our mode to the connectors and the CRTC to give them a chance to
     313             :          * adjust it according to limitations or connector properties, and also
     314             :          * a chance to reject the mode entirely.
     315             :          */
     316           0 :         drm_for_each_encoder(encoder, dev) {
     317             : 
     318           0 :                 if (encoder->crtc != crtc)
     319           0 :                         continue;
     320             : 
     321           0 :                 encoder_funcs = encoder->helper_private;
     322           0 :                 if (!encoder_funcs)
     323           0 :                         continue;
     324             : 
     325           0 :                 encoder_funcs = encoder->helper_private;
     326           0 :                 if (encoder_funcs->mode_fixup) {
     327           0 :                         if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
     328             :                                                               adjusted_mode))) {
     329           0 :                                 DRM_DEBUG_KMS("Encoder fixup failed\n");
     330           0 :                                 goto done;
     331             :                         }
     332             :                 }
     333             :         }
     334             : 
     335           0 :         if (crtc_funcs->mode_fixup) {
     336           0 :                 if (!(ret = crtc_funcs->mode_fixup(crtc, mode,
     337             :                                                 adjusted_mode))) {
     338           0 :                         DRM_DEBUG_KMS("CRTC fixup failed\n");
     339           0 :                         goto done;
     340             :                 }
     341             :         }
     342           0 :         DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
     343             : 
     344           0 :         drm_mode_copy(&crtc->hwmode, adjusted_mode);
     345             : 
     346             :         /* Prepare the encoders and CRTCs before setting the mode. */
     347           0 :         drm_for_each_encoder(encoder, dev) {
     348             : 
     349           0 :                 if (encoder->crtc != crtc)
     350           0 :                         continue;
     351             : 
     352           0 :                 encoder_funcs = encoder->helper_private;
     353           0 :                 if (!encoder_funcs)
     354           0 :                         continue;
     355             : 
     356             :                 /* Disable the encoders as the first thing we do. */
     357           0 :                 if (encoder_funcs->prepare)
     358           0 :                         encoder_funcs->prepare(encoder);
     359             :         }
     360             : 
     361           0 :         drm_crtc_prepare_encoders(dev);
     362             : 
     363           0 :         crtc_funcs->prepare(crtc);
     364             : 
     365             :         /* Set up the DPLL and any encoders state that needs to adjust or depend
     366             :          * on the DPLL.
     367             :          */
     368           0 :         ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
     369           0 :         if (!ret)
     370             :             goto done;
     371             : 
     372           0 :         drm_for_each_encoder(encoder, dev) {
     373             : 
     374           0 :                 if (encoder->crtc != crtc)
     375           0 :                         continue;
     376             : 
     377           0 :                 encoder_funcs = encoder->helper_private;
     378           0 :                 if (!encoder_funcs)
     379           0 :                         continue;
     380             : 
     381           0 :                 DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%s]\n",
     382             :                         encoder->base.id, encoder->name, mode->name);
     383           0 :                 if (encoder_funcs->mode_set)
     384           0 :                         encoder_funcs->mode_set(encoder, mode, adjusted_mode);
     385             :         }
     386             : 
     387             :         /* Now enable the clocks, plane, pipe, and connectors that we set up. */
     388           0 :         crtc_funcs->commit(crtc);
     389             : 
     390           0 :         drm_for_each_encoder(encoder, dev) {
     391             : 
     392           0 :                 if (encoder->crtc != crtc)
     393           0 :                         continue;
     394             : 
     395           0 :                 encoder_funcs = encoder->helper_private;
     396           0 :                 if (!encoder_funcs)
     397           0 :                         continue;
     398             : 
     399           0 :                 if (encoder_funcs->commit)
     400           0 :                         encoder_funcs->commit(encoder);
     401             :         }
     402             : 
     403             :         /* Calculate and store various constants which
     404             :          * are later needed by vblank and swap-completion
     405             :          * timestamping. They are derived from true hwmode.
     406             :          */
     407           0 :         drm_calc_timestamping_constants(crtc, &crtc->hwmode);
     408             : 
     409             :         /* FIXME: add subpixel order */
     410             : done:
     411           0 :         drm_mode_destroy(dev, adjusted_mode);
     412           0 :         if (!ret) {
     413           0 :                 crtc->enabled = saved_enabled;
     414           0 :                 drm_mode_copy(&crtc->mode, &saved_mode);
     415           0 :                 drm_mode_copy(&crtc->hwmode, &saved_hwmode);
     416           0 :                 crtc->x = saved_x;
     417           0 :                 crtc->y = saved_y;
     418             :         }
     419             : 
     420             :         return ret;
     421             : }
     422             : EXPORT_SYMBOL(drm_crtc_helper_set_mode);
     423             : 
     424             : static void
     425           0 : drm_crtc_helper_disable(struct drm_crtc *crtc)
     426             : {
     427           0 :         struct drm_device *dev = crtc->dev;
     428             :         struct drm_connector *connector;
     429             :         struct drm_encoder *encoder;
     430             : 
     431             :         /* Decouple all encoders and their attached connectors from this crtc */
     432           0 :         drm_for_each_encoder(encoder, dev) {
     433             :                 struct drm_connector_list_iter conn_iter;
     434             : 
     435           0 :                 if (encoder->crtc != crtc)
     436           0 :                         continue;
     437             : 
     438           0 :                 drm_connector_list_iter_begin(dev, &conn_iter);
     439           0 :                 drm_for_each_connector_iter(connector, &conn_iter) {
     440           0 :                         if (connector->encoder != encoder)
     441           0 :                                 continue;
     442             : 
     443           0 :                         connector->encoder = NULL;
     444             : 
     445             :                         /*
     446             :                          * drm_helper_disable_unused_functions() ought to be
     447             :                          * doing this, but since we've decoupled the encoder
     448             :                          * from the connector above, the required connection
     449             :                          * between them is henceforth no longer available.
     450             :                          */
     451           0 :                         connector->dpms = DRM_MODE_DPMS_OFF;
     452             : 
     453             :                         /* we keep a reference while the encoder is bound */
     454             :                         drm_connector_put(connector);
     455             :                 }
     456           0 :                 drm_connector_list_iter_end(&conn_iter);
     457             :         }
     458             : 
     459           0 :         __drm_helper_disable_unused_functions(dev);
     460           0 : }
     461             : 
     462             : /*
     463             :  * For connectors that support multiple encoders, either the
     464             :  * .atomic_best_encoder() or .best_encoder() operation must be implemented.
     465             :  */
     466             : struct drm_encoder *
     467           0 : drm_connector_get_single_encoder(struct drm_connector *connector)
     468             : {
     469             :         struct drm_encoder *encoder;
     470             : 
     471           0 :         WARN_ON(hweight32(connector->possible_encoders) > 1);
     472           0 :         drm_connector_for_each_possible_encoder(connector, encoder)
     473             :                 return encoder;
     474             : 
     475             :         return NULL;
     476             : }
     477             : 
     478             : /**
     479             :  * drm_crtc_helper_set_config - set a new config from userspace
     480             :  * @set: mode set configuration
     481             :  * @ctx: lock acquire context, not used here
     482             :  *
     483             :  * The drm_crtc_helper_set_config() helper function implements the of
     484             :  * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC
     485             :  * helpers.
     486             :  *
     487             :  * It first tries to locate the best encoder for each connector by calling the
     488             :  * connector @drm_connector_helper_funcs.best_encoder helper operation.
     489             :  *
     490             :  * After locating the appropriate encoders, the helper function will call the
     491             :  * mode_fixup encoder and CRTC helper operations to adjust the requested mode,
     492             :  * or reject it completely in which case an error will be returned to the
     493             :  * application. If the new configuration after mode adjustment is identical to
     494             :  * the current configuration the helper function will return without performing
     495             :  * any other operation.
     496             :  *
     497             :  * If the adjusted mode is identical to the current mode but changes to the
     498             :  * frame buffer need to be applied, the drm_crtc_helper_set_config() function
     499             :  * will call the CRTC &drm_crtc_helper_funcs.mode_set_base helper operation.
     500             :  *
     501             :  * If the adjusted mode differs from the current mode, or if the
     502             :  * ->mode_set_base() helper operation is not provided, the helper function
     503             :  * performs a full mode set sequence by calling the ->prepare(), ->mode_set()
     504             :  * and ->commit() CRTC and encoder helper operations, in that order.
     505             :  * Alternatively it can also use the dpms and disable helper operations. For
     506             :  * details see &struct drm_crtc_helper_funcs and struct
     507             :  * &drm_encoder_helper_funcs.
     508             :  *
     509             :  * This function is deprecated.  New drivers must implement atomic modeset
     510             :  * support, for which this function is unsuitable. Instead drivers should use
     511             :  * drm_atomic_helper_set_config().
     512             :  *
     513             :  * Returns:
     514             :  * Returns 0 on success, negative errno numbers on failure.
     515             :  */
     516           0 : int drm_crtc_helper_set_config(struct drm_mode_set *set,
     517             :                                struct drm_modeset_acquire_ctx *ctx)
     518             : {
     519             :         struct drm_device *dev;
     520             :         struct drm_crtc **save_encoder_crtcs, *new_crtc;
     521             :         struct drm_encoder **save_connector_encoders, *new_encoder, *encoder;
     522           0 :         bool mode_changed = false; /* if true do a full mode set */
     523           0 :         bool fb_changed = false; /* if true and !mode_changed just do a flip */
     524             :         struct drm_connector *connector;
     525             :         struct drm_connector_list_iter conn_iter;
     526           0 :         int count = 0, ro, fail = 0;
     527             :         const struct drm_crtc_helper_funcs *crtc_funcs;
     528             :         struct drm_mode_set save_set;
     529             :         int ret;
     530             :         int i;
     531             : 
     532           0 :         DRM_DEBUG_KMS("\n");
     533             : 
     534           0 :         BUG_ON(!set);
     535           0 :         BUG_ON(!set->crtc);
     536           0 :         BUG_ON(!set->crtc->helper_private);
     537             : 
     538             :         /* Enforce sane interface api - has been abused by the fb helper. */
     539           0 :         BUG_ON(!set->mode && set->fb);
     540           0 :         BUG_ON(set->fb && set->num_connectors == 0);
     541             : 
     542           0 :         crtc_funcs = set->crtc->helper_private;
     543             : 
     544           0 :         dev = set->crtc->dev;
     545           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     546             : 
     547           0 :         if (!set->mode)
     548           0 :                 set->fb = NULL;
     549             : 
     550           0 :         if (set->fb) {
     551           0 :                 DRM_DEBUG_KMS("[CRTC:%d:%s] [FB:%d] #connectors=%d (x y) (%i %i)\n",
     552             :                               set->crtc->base.id, set->crtc->name,
     553             :                               set->fb->base.id,
     554             :                               (int)set->num_connectors, set->x, set->y);
     555             :         } else {
     556           0 :                 DRM_DEBUG_KMS("[CRTC:%d:%s] [NOFB]\n",
     557             :                               set->crtc->base.id, set->crtc->name);
     558           0 :                 drm_crtc_helper_disable(set->crtc);
     559           0 :                 return 0;
     560             :         }
     561             : 
     562           0 :         drm_warn_on_modeset_not_all_locked(dev);
     563             : 
     564             :         /*
     565             :          * Allocate space for the backup of all (non-pointer) encoder and
     566             :          * connector data.
     567             :          */
     568           0 :         save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder,
     569             :                                 sizeof(struct drm_crtc *), GFP_KERNEL);
     570           0 :         if (!save_encoder_crtcs)
     571             :                 return -ENOMEM;
     572             : 
     573           0 :         save_connector_encoders = kcalloc(dev->mode_config.num_connector,
     574             :                                 sizeof(struct drm_encoder *), GFP_KERNEL);
     575           0 :         if (!save_connector_encoders) {
     576           0 :                 kfree(save_encoder_crtcs);
     577           0 :                 return -ENOMEM;
     578             :         }
     579             : 
     580             :         /*
     581             :          * Copy data. Note that driver private data is not affected.
     582             :          * Should anything bad happen only the expected state is
     583             :          * restored, not the drivers personal bookkeeping.
     584             :          */
     585           0 :         count = 0;
     586           0 :         drm_for_each_encoder(encoder, dev) {
     587           0 :                 save_encoder_crtcs[count++] = encoder->crtc;
     588             :         }
     589             : 
     590           0 :         count = 0;
     591           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     592           0 :         drm_for_each_connector_iter(connector, &conn_iter)
     593           0 :                 save_connector_encoders[count++] = connector->encoder;
     594           0 :         drm_connector_list_iter_end(&conn_iter);
     595             : 
     596           0 :         save_set.crtc = set->crtc;
     597           0 :         save_set.mode = &set->crtc->mode;
     598           0 :         save_set.x = set->crtc->x;
     599           0 :         save_set.y = set->crtc->y;
     600           0 :         save_set.fb = set->crtc->primary->fb;
     601             : 
     602             :         /* We should be able to check here if the fb has the same properties
     603             :          * and then just flip_or_move it */
     604           0 :         if (set->crtc->primary->fb != set->fb) {
     605             :                 /* If we have no fb then treat it as a full mode set */
     606           0 :                 if (set->crtc->primary->fb == NULL) {
     607           0 :                         DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
     608           0 :                         mode_changed = true;
     609           0 :                 } else if (set->fb->format != set->crtc->primary->fb->format) {
     610             :                         mode_changed = true;
     611             :                 } else
     612           0 :                         fb_changed = true;
     613             :         }
     614             : 
     615           0 :         if (set->x != set->crtc->x || set->y != set->crtc->y)
     616           0 :                 fb_changed = true;
     617             : 
     618           0 :         if (!drm_mode_equal(set->mode, &set->crtc->mode)) {
     619           0 :                 DRM_DEBUG_KMS("modes are different, full mode set\n");
     620           0 :                 drm_mode_debug_printmodeline(&set->crtc->mode);
     621           0 :                 drm_mode_debug_printmodeline(set->mode);
     622           0 :                 mode_changed = true;
     623             :         }
     624             : 
     625             :         /* take a reference on all unbound connectors in set, reuse the
     626             :          * already taken reference for bound connectors
     627             :          */
     628           0 :         for (ro = 0; ro < set->num_connectors; ro++) {
     629           0 :                 if (set->connectors[ro]->encoder)
     630           0 :                         continue;
     631           0 :                 drm_connector_get(set->connectors[ro]);
     632             :         }
     633             : 
     634             :         /* a) traverse passed in connector list and get encoders for them */
     635           0 :         count = 0;
     636           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     637           0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     638           0 :                 const struct drm_connector_helper_funcs *connector_funcs =
     639             :                         connector->helper_private;
     640           0 :                 new_encoder = connector->encoder;
     641           0 :                 for (ro = 0; ro < set->num_connectors; ro++) {
     642           0 :                         if (set->connectors[ro] == connector) {
     643           0 :                                 if (connector_funcs->best_encoder)
     644           0 :                                         new_encoder = connector_funcs->best_encoder(connector);
     645             :                                 else
     646           0 :                                         new_encoder = drm_connector_get_single_encoder(connector);
     647             : 
     648             :                                 /* if we can't get an encoder for a connector
     649             :                                    we are setting now - then fail */
     650           0 :                                 if (new_encoder == NULL)
     651             :                                         /* don't break so fail path works correct */
     652           0 :                                         fail = 1;
     653             : 
     654           0 :                                 if (connector->dpms != DRM_MODE_DPMS_ON) {
     655           0 :                                         DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
     656           0 :                                         mode_changed = true;
     657             :                                 }
     658             : 
     659             :                                 break;
     660             :                         }
     661             :                 }
     662             : 
     663           0 :                 if (new_encoder != connector->encoder) {
     664           0 :                         DRM_DEBUG_KMS("encoder changed, full mode switch\n");
     665           0 :                         mode_changed = true;
     666             :                         /* If the encoder is reused for another connector, then
     667             :                          * the appropriate crtc will be set later.
     668             :                          */
     669           0 :                         if (connector->encoder)
     670           0 :                                 connector->encoder->crtc = NULL;
     671           0 :                         connector->encoder = new_encoder;
     672             :                 }
     673             :         }
     674           0 :         drm_connector_list_iter_end(&conn_iter);
     675             : 
     676           0 :         if (fail) {
     677             :                 ret = -EINVAL;
     678             :                 goto fail;
     679             :         }
     680             : 
     681           0 :         count = 0;
     682           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     683           0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     684           0 :                 if (!connector->encoder)
     685           0 :                         continue;
     686             : 
     687           0 :                 if (connector->encoder->crtc == set->crtc)
     688             :                         new_crtc = NULL;
     689             :                 else
     690           0 :                         new_crtc = connector->encoder->crtc;
     691             : 
     692           0 :                 for (ro = 0; ro < set->num_connectors; ro++) {
     693           0 :                         if (set->connectors[ro] == connector)
     694           0 :                                 new_crtc = set->crtc;
     695             :                 }
     696             : 
     697             :                 /* Make sure the new CRTC will work with the encoder */
     698           0 :                 if (new_crtc &&
     699           0 :                     !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
     700           0 :                         ret = -EINVAL;
     701           0 :                         drm_connector_list_iter_end(&conn_iter);
     702           0 :                         goto fail;
     703             :                 }
     704           0 :                 if (new_crtc != connector->encoder->crtc) {
     705           0 :                         DRM_DEBUG_KMS("crtc changed, full mode switch\n");
     706           0 :                         mode_changed = true;
     707           0 :                         connector->encoder->crtc = new_crtc;
     708             :                 }
     709           0 :                 if (new_crtc) {
     710           0 :                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d:%s]\n",
     711             :                                       connector->base.id, connector->name,
     712             :                                       new_crtc->base.id, new_crtc->name);
     713             :                 } else {
     714           0 :                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
     715             :                                       connector->base.id, connector->name);
     716             :                 }
     717             :         }
     718           0 :         drm_connector_list_iter_end(&conn_iter);
     719             : 
     720             :         /* mode_set_base is not a required function */
     721           0 :         if (fb_changed && !crtc_funcs->mode_set_base)
     722           0 :                 mode_changed = true;
     723             : 
     724           0 :         if (mode_changed) {
     725           0 :                 if (drm_helper_crtc_in_use(set->crtc)) {
     726           0 :                         DRM_DEBUG_KMS("attempting to set mode from"
     727             :                                         " userspace\n");
     728           0 :                         drm_mode_debug_printmodeline(set->mode);
     729           0 :                         set->crtc->primary->fb = set->fb;
     730           0 :                         if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
     731           0 :                                                       set->x, set->y,
     732             :                                                       save_set.fb)) {
     733           0 :                                 DRM_ERROR("failed to set mode on [CRTC:%d:%s]\n",
     734             :                                           set->crtc->base.id, set->crtc->name);
     735           0 :                                 set->crtc->primary->fb = save_set.fb;
     736           0 :                                 ret = -EINVAL;
     737           0 :                                 goto fail;
     738             :                         }
     739           0 :                         DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
     740           0 :                         for (i = 0; i < set->num_connectors; i++) {
     741           0 :                                 DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
     742             :                                               set->connectors[i]->name);
     743           0 :                                 set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
     744             :                         }
     745             :                 }
     746           0 :                 __drm_helper_disable_unused_functions(dev);
     747           0 :         } else if (fb_changed) {
     748           0 :                 set->crtc->x = set->x;
     749           0 :                 set->crtc->y = set->y;
     750           0 :                 set->crtc->primary->fb = set->fb;
     751           0 :                 ret = crtc_funcs->mode_set_base(set->crtc,
     752           0 :                                                 set->x, set->y, save_set.fb);
     753           0 :                 if (ret != 0) {
     754           0 :                         set->crtc->x = save_set.x;
     755           0 :                         set->crtc->y = save_set.y;
     756           0 :                         set->crtc->primary->fb = save_set.fb;
     757           0 :                         goto fail;
     758             :                 }
     759             :         }
     760             : 
     761           0 :         kfree(save_connector_encoders);
     762           0 :         kfree(save_encoder_crtcs);
     763           0 :         return 0;
     764             : 
     765             : fail:
     766             :         /* Restore all previous data. */
     767           0 :         count = 0;
     768           0 :         drm_for_each_encoder(encoder, dev) {
     769           0 :                 encoder->crtc = save_encoder_crtcs[count++];
     770             :         }
     771             : 
     772           0 :         count = 0;
     773           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     774           0 :         drm_for_each_connector_iter(connector, &conn_iter)
     775           0 :                 connector->encoder = save_connector_encoders[count++];
     776           0 :         drm_connector_list_iter_end(&conn_iter);
     777             : 
     778             :         /* after fail drop reference on all unbound connectors in set, let
     779             :          * bound connectors keep their reference
     780             :          */
     781           0 :         for (ro = 0; ro < set->num_connectors; ro++) {
     782           0 :                 if (set->connectors[ro]->encoder)
     783           0 :                         continue;
     784           0 :                 drm_connector_put(set->connectors[ro]);
     785             :         }
     786             : 
     787             :         /* Try to restore the config */
     788           0 :         if (mode_changed &&
     789           0 :             !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
     790             :                                       save_set.y, save_set.fb))
     791           0 :                 DRM_ERROR("failed to restore config after modeset failure\n");
     792             : 
     793           0 :         kfree(save_connector_encoders);
     794           0 :         kfree(save_encoder_crtcs);
     795           0 :         return ret;
     796             : }
     797             : EXPORT_SYMBOL(drm_crtc_helper_set_config);
     798             : 
     799           0 : static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
     800             : {
     801           0 :         int dpms = DRM_MODE_DPMS_OFF;
     802             :         struct drm_connector *connector;
     803             :         struct drm_connector_list_iter conn_iter;
     804           0 :         struct drm_device *dev = encoder->dev;
     805             : 
     806           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     807           0 :         drm_for_each_connector_iter(connector, &conn_iter)
     808           0 :                 if (connector->encoder == encoder)
     809           0 :                         if (connector->dpms < dpms)
     810           0 :                                 dpms = connector->dpms;
     811           0 :         drm_connector_list_iter_end(&conn_iter);
     812             : 
     813           0 :         return dpms;
     814             : }
     815             : 
     816             : /* Helper which handles bridge ordering around encoder dpms */
     817             : static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
     818             : {
     819             :         const struct drm_encoder_helper_funcs *encoder_funcs;
     820             : 
     821           0 :         encoder_funcs = encoder->helper_private;
     822           0 :         if (!encoder_funcs)
     823             :                 return;
     824             : 
     825           0 :         if (encoder_funcs->dpms)
     826           0 :                 encoder_funcs->dpms(encoder, mode);
     827             : }
     828             : 
     829           0 : static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
     830             : {
     831           0 :         int dpms = DRM_MODE_DPMS_OFF;
     832             :         struct drm_connector *connector;
     833             :         struct drm_connector_list_iter conn_iter;
     834           0 :         struct drm_device *dev = crtc->dev;
     835             : 
     836           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     837           0 :         drm_for_each_connector_iter(connector, &conn_iter)
     838           0 :                 if (connector->encoder && connector->encoder->crtc == crtc)
     839           0 :                         if (connector->dpms < dpms)
     840           0 :                                 dpms = connector->dpms;
     841           0 :         drm_connector_list_iter_end(&conn_iter);
     842             : 
     843           0 :         return dpms;
     844             : }
     845             : 
     846             : /**
     847             :  * drm_helper_connector_dpms() - connector dpms helper implementation
     848             :  * @connector: affected connector
     849             :  * @mode: DPMS mode
     850             :  *
     851             :  * The drm_helper_connector_dpms() helper function implements the
     852             :  * &drm_connector_funcs.dpms callback for drivers using the legacy CRTC
     853             :  * helpers.
     854             :  *
     855             :  * This is the main helper function provided by the CRTC helper framework for
     856             :  * implementing the DPMS connector attribute. It computes the new desired DPMS
     857             :  * state for all encoders and CRTCs in the output mesh and calls the
     858             :  * &drm_crtc_helper_funcs.dpms and &drm_encoder_helper_funcs.dpms callbacks
     859             :  * provided by the driver.
     860             :  *
     861             :  * This function is deprecated.  New drivers must implement atomic modeset
     862             :  * support, where DPMS is handled in the DRM core.
     863             :  *
     864             :  * Returns:
     865             :  * Always returns 0.
     866             :  */
     867           0 : int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
     868             : {
     869           0 :         struct drm_encoder *encoder = connector->encoder;
     870           0 :         struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
     871           0 :         int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
     872             : 
     873           0 :         WARN_ON(drm_drv_uses_atomic_modeset(connector->dev));
     874             : 
     875           0 :         if (mode == connector->dpms)
     876             :                 return 0;
     877             : 
     878           0 :         old_dpms = connector->dpms;
     879           0 :         connector->dpms = mode;
     880             : 
     881           0 :         if (encoder)
     882           0 :                 encoder_dpms = drm_helper_choose_encoder_dpms(encoder);
     883             : 
     884             :         /* from off to on, do crtc then encoder */
     885           0 :         if (mode < old_dpms) {
     886           0 :                 if (crtc) {
     887           0 :                         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     888             : 
     889           0 :                         if (crtc_funcs->dpms)
     890           0 :                                 (*crtc_funcs->dpms) (crtc,
     891             :                                                      drm_helper_choose_crtc_dpms(crtc));
     892             :                 }
     893           0 :                 if (encoder)
     894             :                         drm_helper_encoder_dpms(encoder, encoder_dpms);
     895             :         }
     896             : 
     897             :         /* from on to off, do encoder then crtc */
     898           0 :         if (mode > old_dpms) {
     899           0 :                 if (encoder)
     900             :                         drm_helper_encoder_dpms(encoder, encoder_dpms);
     901           0 :                 if (crtc) {
     902           0 :                         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     903             : 
     904           0 :                         if (crtc_funcs->dpms)
     905           0 :                                 (*crtc_funcs->dpms) (crtc,
     906             :                                                      drm_helper_choose_crtc_dpms(crtc));
     907             :                 }
     908             :         }
     909             : 
     910             :         return 0;
     911             : }
     912             : EXPORT_SYMBOL(drm_helper_connector_dpms);
     913             : 
     914             : /**
     915             :  * drm_helper_resume_force_mode - force-restore mode setting configuration
     916             :  * @dev: drm_device which should be restored
     917             :  *
     918             :  * Drivers which use the mode setting helpers can use this function to
     919             :  * force-restore the mode setting configuration e.g. on resume or when something
     920             :  * else might have trampled over the hw state (like some overzealous old BIOSen
     921             :  * tended to do).
     922             :  *
     923             :  * This helper doesn't provide a error return value since restoring the old
     924             :  * config should never fail due to resource allocation issues since the driver
     925             :  * has successfully set the restored configuration already. Hence this should
     926             :  * boil down to the equivalent of a few dpms on calls, which also don't provide
     927             :  * an error code.
     928             :  *
     929             :  * Drivers where simply restoring an old configuration again might fail (e.g.
     930             :  * due to slight differences in allocating shared resources when the
     931             :  * configuration is restored in a different order than when userspace set it up)
     932             :  * need to use their own restore logic.
     933             :  *
     934             :  * This function is deprecated. New drivers should implement atomic mode-
     935             :  * setting and use the atomic suspend/resume helpers.
     936             :  *
     937             :  * See also:
     938             :  * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
     939             :  */
     940           0 : void drm_helper_resume_force_mode(struct drm_device *dev)
     941             : {
     942             :         struct drm_crtc *crtc;
     943             :         struct drm_encoder *encoder;
     944             :         const struct drm_crtc_helper_funcs *crtc_funcs;
     945             :         int encoder_dpms;
     946             :         bool ret;
     947             : 
     948           0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     949             : 
     950           0 :         drm_modeset_lock_all(dev);
     951           0 :         drm_for_each_crtc(crtc, dev) {
     952             : 
     953           0 :                 if (!crtc->enabled)
     954           0 :                         continue;
     955             : 
     956           0 :                 ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
     957           0 :                                                crtc->x, crtc->y, crtc->primary->fb);
     958             : 
     959             :                 /* Restoring the old config should never fail! */
     960           0 :                 if (ret == false)
     961           0 :                         DRM_ERROR("failed to set mode on crtc %p\n", crtc);
     962             : 
     963             :                 /* Turn off outputs that were already powered off */
     964           0 :                 if (drm_helper_choose_crtc_dpms(crtc)) {
     965           0 :                         drm_for_each_encoder(encoder, dev) {
     966             : 
     967           0 :                                 if(encoder->crtc != crtc)
     968           0 :                                         continue;
     969             : 
     970           0 :                                 encoder_dpms = drm_helper_choose_encoder_dpms(
     971             :                                                         encoder);
     972             : 
     973             :                                 drm_helper_encoder_dpms(encoder, encoder_dpms);
     974             :                         }
     975             : 
     976           0 :                         crtc_funcs = crtc->helper_private;
     977           0 :                         if (crtc_funcs->dpms)
     978           0 :                                 (*crtc_funcs->dpms) (crtc,
     979             :                                                      drm_helper_choose_crtc_dpms(crtc));
     980             :                 }
     981             :         }
     982             : 
     983             :         /* disable the unused connectors while restoring the modesetting */
     984           0 :         __drm_helper_disable_unused_functions(dev);
     985           0 :         drm_modeset_unlock_all(dev);
     986           0 : }
     987             : EXPORT_SYMBOL(drm_helper_resume_force_mode);
     988             : 
     989             : /**
     990             :  * drm_helper_force_disable_all - Forcibly turn off all enabled CRTCs
     991             :  * @dev: DRM device whose CRTCs to turn off
     992             :  *
     993             :  * Drivers may want to call this on unload to ensure that all displays are
     994             :  * unlit and the GPU is in a consistent, low power state. Takes modeset locks.
     995             :  *
     996             :  * Note: This should only be used by non-atomic legacy drivers. For an atomic
     997             :  * version look at drm_atomic_helper_shutdown().
     998             :  *
     999             :  * Returns:
    1000             :  * Zero on success, error code on failure.
    1001             :  */
    1002           0 : int drm_helper_force_disable_all(struct drm_device *dev)
    1003             : {
    1004             :         struct drm_crtc *crtc;
    1005           0 :         int ret = 0;
    1006             : 
    1007           0 :         drm_modeset_lock_all(dev);
    1008           0 :         drm_for_each_crtc(crtc, dev)
    1009           0 :                 if (crtc->enabled) {
    1010           0 :                         struct drm_mode_set set = {
    1011             :                                 .crtc = crtc,
    1012             :                         };
    1013             : 
    1014           0 :                         ret = drm_mode_set_config_internal(&set);
    1015           0 :                         if (ret)
    1016             :                                 goto out;
    1017             :                 }
    1018             : out:
    1019           0 :         drm_modeset_unlock_all(dev);
    1020           0 :         return ret;
    1021             : }
    1022             : EXPORT_SYMBOL(drm_helper_force_disable_all);

Generated by: LCOV version 1.14