LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_crtc_helper.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 427 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 15 0.0 %
Branches: 0 306 0.0 %

           Branch data     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                 :          0 :         struct drm_connector *connector;
      98                 :          0 :         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                 :          0 :         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                 :          0 :         struct drm_encoder *encoder;
     174                 :          0 :         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                 :          0 :                 crtc->enabled = drm_helper_crtc_in_use(crtc);
     189         [ #  # ]:          0 :                 if (!crtc->enabled) {
     190         [ #  # ]:          0 :                         if (crtc_funcs->disable)
     191                 :          0 :                                 (*crtc_funcs->disable)(crtc);
     192                 :            :                         else
     193                 :          0 :                                 (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
     194                 :          0 :                         crtc->primary->fb = NULL;
     195                 :            :                 }
     196                 :            :         }
     197                 :          0 : }
     198                 :            : 
     199                 :            : /**
     200                 :            :  * drm_helper_disable_unused_functions - disable unused objects
     201                 :            :  * @dev: DRM device
     202                 :            :  *
     203                 :            :  * This function walks through the entire mode setting configuration of @dev. It
     204                 :            :  * will remove any CRTC links of unused encoders and encoder links of
     205                 :            :  * disconnected connectors. Then it will disable all unused encoders and CRTCs
     206                 :            :  * either by calling their disable callback if available or by calling their
     207                 :            :  * dpms callback with DRM_MODE_DPMS_OFF.
     208                 :            :  *
     209                 :            :  * NOTE:
     210                 :            :  *
     211                 :            :  * This function is part of the legacy modeset helper library and will cause
     212                 :            :  * major confusion with atomic drivers. This is because atomic helpers guarantee
     213                 :            :  * to never call ->disable() hooks on a disabled function, or ->enable() hooks
     214                 :            :  * on an enabled functions. drm_helper_disable_unused_functions() on the other
     215                 :            :  * hand throws such guarantees into the wind and calls disable hooks
     216                 :            :  * unconditionally on unused functions.
     217                 :            :  */
     218                 :          0 : void drm_helper_disable_unused_functions(struct drm_device *dev)
     219                 :            : {
     220   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     221                 :            : 
     222                 :          0 :         drm_modeset_lock_all(dev);
     223                 :          0 :         __drm_helper_disable_unused_functions(dev);
     224                 :          0 :         drm_modeset_unlock_all(dev);
     225                 :          0 : }
     226                 :            : EXPORT_SYMBOL(drm_helper_disable_unused_functions);
     227                 :            : 
     228                 :            : /*
     229                 :            :  * Check the CRTC we're going to map each output to vs. its current
     230                 :            :  * CRTC.  If they don't match, we have to disable the output and the CRTC
     231                 :            :  * since the driver will have to re-route things.
     232                 :            :  */
     233                 :            : static void
     234                 :          0 : drm_crtc_prepare_encoders(struct drm_device *dev)
     235                 :            : {
     236                 :          0 :         const struct drm_encoder_helper_funcs *encoder_funcs;
     237                 :          0 :         struct drm_encoder *encoder;
     238                 :            : 
     239         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     240                 :          0 :                 encoder_funcs = encoder->helper_private;
     241         [ #  # ]:          0 :                 if (!encoder_funcs)
     242                 :          0 :                         continue;
     243                 :            : 
     244                 :            :                 /* Disable unused encoders */
     245         [ #  # ]:          0 :                 if (encoder->crtc == NULL)
     246                 :          0 :                         drm_encoder_disable(encoder);
     247                 :            :                 /* Disable encoders whose CRTC is about to change */
     248   [ #  #  #  # ]:          0 :                 if (encoder_funcs->get_crtc &&
     249                 :          0 :                     encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
     250                 :          0 :                         drm_encoder_disable(encoder);
     251                 :            :         }
     252                 :          0 : }
     253                 :            : 
     254                 :            : /**
     255                 :            :  * drm_crtc_helper_set_mode - internal helper to set a mode
     256                 :            :  * @crtc: CRTC to program
     257                 :            :  * @mode: mode to use
     258                 :            :  * @x: horizontal offset into the surface
     259                 :            :  * @y: vertical offset into the surface
     260                 :            :  * @old_fb: old framebuffer, for cleanup
     261                 :            :  *
     262                 :            :  * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
     263                 :            :  * to fixup or reject the mode prior to trying to set it. This is an internal
     264                 :            :  * helper that drivers could e.g. use to update properties that require the
     265                 :            :  * entire output pipe to be disabled and re-enabled in a new configuration. For
     266                 :            :  * example for changing whether audio is enabled on a hdmi link or for changing
     267                 :            :  * panel fitter or dither attributes. It is also called by the
     268                 :            :  * drm_crtc_helper_set_config() helper function to drive the mode setting
     269                 :            :  * sequence.
     270                 :            :  *
     271                 :            :  * Returns:
     272                 :            :  * True if the mode was set successfully, false otherwise.
     273                 :            :  */
     274                 :          0 : bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
     275                 :            :                               struct drm_display_mode *mode,
     276                 :            :                               int x, int y,
     277                 :            :                               struct drm_framebuffer *old_fb)
     278                 :            : {
     279                 :          0 :         struct drm_device *dev = crtc->dev;
     280                 :          0 :         struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
     281                 :          0 :         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     282                 :          0 :         const struct drm_encoder_helper_funcs *encoder_funcs;
     283                 :          0 :         int saved_x, saved_y;
     284                 :          0 :         bool saved_enabled;
     285                 :          0 :         struct drm_encoder *encoder;
     286                 :          0 :         bool ret = true;
     287                 :            : 
     288   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     289                 :            : 
     290                 :          0 :         drm_warn_on_modeset_not_all_locked(dev);
     291                 :            : 
     292                 :          0 :         saved_enabled = crtc->enabled;
     293                 :          0 :         crtc->enabled = drm_helper_crtc_in_use(crtc);
     294         [ #  # ]:          0 :         if (!crtc->enabled)
     295                 :            :                 return true;
     296                 :            : 
     297                 :          0 :         adjusted_mode = drm_mode_duplicate(dev, mode);
     298         [ #  # ]:          0 :         if (!adjusted_mode) {
     299                 :          0 :                 crtc->enabled = saved_enabled;
     300                 :          0 :                 return false;
     301                 :            :         }
     302                 :            : 
     303                 :          0 :         saved_mode = crtc->mode;
     304                 :          0 :         saved_hwmode = crtc->hwmode;
     305                 :          0 :         saved_x = crtc->x;
     306                 :          0 :         saved_y = crtc->y;
     307                 :            : 
     308                 :            :         /* Update crtc values up front so the driver can rely on them for mode
     309                 :            :          * setting.
     310                 :            :          */
     311                 :          0 :         crtc->mode = *mode;
     312                 :          0 :         crtc->x = x;
     313                 :          0 :         crtc->y = y;
     314                 :            : 
     315                 :            :         /* Pass our mode to the connectors and the CRTC to give them a chance to
     316                 :            :          * adjust it according to limitations or connector properties, and also
     317                 :            :          * a chance to reject the mode entirely.
     318                 :            :          */
     319         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     320                 :            : 
     321         [ #  # ]:          0 :                 if (encoder->crtc != crtc)
     322                 :          0 :                         continue;
     323                 :            : 
     324                 :          0 :                 encoder_funcs = encoder->helper_private;
     325         [ #  # ]:          0 :                 if (!encoder_funcs)
     326                 :          0 :                         continue;
     327                 :            : 
     328                 :          0 :                 encoder_funcs = encoder->helper_private;
     329         [ #  # ]:          0 :                 if (encoder_funcs->mode_fixup) {
     330         [ #  # ]:          0 :                         if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
     331                 :            :                                                               adjusted_mode))) {
     332                 :          0 :                                 DRM_DEBUG_KMS("Encoder fixup failed\n");
     333                 :          0 :                                 goto done;
     334                 :            :                         }
     335                 :            :                 }
     336                 :            :         }
     337                 :            : 
     338         [ #  # ]:          0 :         if (crtc_funcs->mode_fixup) {
     339         [ #  # ]:          0 :                 if (!(ret = crtc_funcs->mode_fixup(crtc, mode,
     340                 :            :                                                 adjusted_mode))) {
     341                 :          0 :                         DRM_DEBUG_KMS("CRTC fixup failed\n");
     342                 :          0 :                         goto done;
     343                 :            :                 }
     344                 :            :         }
     345                 :          0 :         DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
     346                 :            : 
     347                 :          0 :         crtc->hwmode = *adjusted_mode;
     348                 :            : 
     349                 :            :         /* Prepare the encoders and CRTCs before setting the mode. */
     350         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     351                 :            : 
     352         [ #  # ]:          0 :                 if (encoder->crtc != crtc)
     353                 :          0 :                         continue;
     354                 :            : 
     355                 :          0 :                 encoder_funcs = encoder->helper_private;
     356         [ #  # ]:          0 :                 if (!encoder_funcs)
     357                 :          0 :                         continue;
     358                 :            : 
     359                 :            :                 /* Disable the encoders as the first thing we do. */
     360         [ #  # ]:          0 :                 if (encoder_funcs->prepare)
     361                 :          0 :                         encoder_funcs->prepare(encoder);
     362                 :            :         }
     363                 :            : 
     364                 :          0 :         drm_crtc_prepare_encoders(dev);
     365                 :            : 
     366                 :          0 :         crtc_funcs->prepare(crtc);
     367                 :            : 
     368                 :            :         /* Set up the DPLL and any encoders state that needs to adjust or depend
     369                 :            :          * on the DPLL.
     370                 :            :          */
     371                 :          0 :         ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
     372         [ #  # ]:          0 :         if (!ret)
     373                 :          0 :             goto done;
     374                 :            : 
     375         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     376                 :            : 
     377         [ #  # ]:          0 :                 if (encoder->crtc != crtc)
     378                 :          0 :                         continue;
     379                 :            : 
     380                 :          0 :                 encoder_funcs = encoder->helper_private;
     381         [ #  # ]:          0 :                 if (!encoder_funcs)
     382                 :          0 :                         continue;
     383                 :            : 
     384                 :          0 :                 DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%s]\n",
     385                 :            :                         encoder->base.id, encoder->name, mode->name);
     386         [ #  # ]:          0 :                 if (encoder_funcs->mode_set)
     387                 :          0 :                         encoder_funcs->mode_set(encoder, mode, adjusted_mode);
     388                 :            :         }
     389                 :            : 
     390                 :            :         /* Now enable the clocks, plane, pipe, and connectors that we set up. */
     391                 :          0 :         crtc_funcs->commit(crtc);
     392                 :            : 
     393         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     394                 :            : 
     395         [ #  # ]:          0 :                 if (encoder->crtc != crtc)
     396                 :          0 :                         continue;
     397                 :            : 
     398                 :          0 :                 encoder_funcs = encoder->helper_private;
     399         [ #  # ]:          0 :                 if (!encoder_funcs)
     400                 :          0 :                         continue;
     401                 :            : 
     402         [ #  # ]:          0 :                 if (encoder_funcs->commit)
     403                 :          0 :                         encoder_funcs->commit(encoder);
     404                 :            :         }
     405                 :            : 
     406                 :            :         /* Calculate and store various constants which
     407                 :            :          * are later needed by vblank and swap-completion
     408                 :            :          * timestamping. They are derived from true hwmode.
     409                 :            :          */
     410                 :          0 :         drm_calc_timestamping_constants(crtc, &crtc->hwmode);
     411                 :            : 
     412                 :            :         /* FIXME: add subpixel order */
     413                 :          0 : done:
     414                 :          0 :         drm_mode_destroy(dev, adjusted_mode);
     415         [ #  # ]:          0 :         if (!ret) {
     416                 :          0 :                 crtc->enabled = saved_enabled;
     417                 :          0 :                 crtc->mode = saved_mode;
     418                 :          0 :                 crtc->hwmode = saved_hwmode;
     419                 :          0 :                 crtc->x = saved_x;
     420                 :          0 :                 crtc->y = saved_y;
     421                 :            :         }
     422                 :            : 
     423                 :            :         return ret;
     424                 :            : }
     425                 :            : EXPORT_SYMBOL(drm_crtc_helper_set_mode);
     426                 :            : 
     427                 :            : static void
     428                 :          0 : drm_crtc_helper_disable(struct drm_crtc *crtc)
     429                 :            : {
     430                 :          0 :         struct drm_device *dev = crtc->dev;
     431                 :          0 :         struct drm_connector *connector;
     432                 :          0 :         struct drm_encoder *encoder;
     433                 :            : 
     434                 :            :         /* Decouple all encoders and their attached connectors from this crtc */
     435         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     436                 :          0 :                 struct drm_connector_list_iter conn_iter;
     437                 :            : 
     438         [ #  # ]:          0 :                 if (encoder->crtc != crtc)
     439                 :          0 :                         continue;
     440                 :            : 
     441                 :          0 :                 drm_connector_list_iter_begin(dev, &conn_iter);
     442         [ #  # ]:          0 :                 drm_for_each_connector_iter(connector, &conn_iter) {
     443         [ #  # ]:          0 :                         if (connector->encoder != encoder)
     444                 :          0 :                                 continue;
     445                 :            : 
     446                 :          0 :                         connector->encoder = NULL;
     447                 :            : 
     448                 :            :                         /*
     449                 :            :                          * drm_helper_disable_unused_functions() ought to be
     450                 :            :                          * doing this, but since we've decoupled the encoder
     451                 :            :                          * from the connector above, the required connection
     452                 :            :                          * between them is henceforth no longer available.
     453                 :            :                          */
     454                 :          0 :                         connector->dpms = DRM_MODE_DPMS_OFF;
     455                 :            : 
     456                 :            :                         /* we keep a reference while the encoder is bound */
     457                 :          0 :                         drm_connector_put(connector);
     458                 :            :                 }
     459                 :          0 :                 drm_connector_list_iter_end(&conn_iter);
     460                 :            :         }
     461                 :            : 
     462                 :          0 :         __drm_helper_disable_unused_functions(dev);
     463                 :          0 : }
     464                 :            : 
     465                 :            : /*
     466                 :            :  * For connectors that support multiple encoders, either the
     467                 :            :  * .atomic_best_encoder() or .best_encoder() operation must be implemented.
     468                 :            :  */
     469                 :            : struct drm_encoder *
     470                 :          0 : drm_connector_get_single_encoder(struct drm_connector *connector)
     471                 :            : {
     472                 :          0 :         struct drm_encoder *encoder;
     473                 :            : 
     474   [ #  #  #  # ]:          0 :         WARN_ON(hweight32(connector->possible_encoders) > 1);
     475   [ #  #  #  # ]:          0 :         drm_connector_for_each_possible_encoder(connector, encoder)
     476                 :          0 :                 return encoder;
     477                 :            : 
     478                 :            :         return NULL;
     479                 :            : }
     480                 :            : 
     481                 :            : /**
     482                 :            :  * drm_crtc_helper_set_config - set a new config from userspace
     483                 :            :  * @set: mode set configuration
     484                 :            :  * @ctx: lock acquire context, not used here
     485                 :            :  *
     486                 :            :  * The drm_crtc_helper_set_config() helper function implements the of
     487                 :            :  * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC
     488                 :            :  * helpers.
     489                 :            :  *
     490                 :            :  * It first tries to locate the best encoder for each connector by calling the
     491                 :            :  * connector @drm_connector_helper_funcs.best_encoder helper operation.
     492                 :            :  *
     493                 :            :  * After locating the appropriate encoders, the helper function will call the
     494                 :            :  * mode_fixup encoder and CRTC helper operations to adjust the requested mode,
     495                 :            :  * or reject it completely in which case an error will be returned to the
     496                 :            :  * application. If the new configuration after mode adjustment is identical to
     497                 :            :  * the current configuration the helper function will return without performing
     498                 :            :  * any other operation.
     499                 :            :  *
     500                 :            :  * If the adjusted mode is identical to the current mode but changes to the
     501                 :            :  * frame buffer need to be applied, the drm_crtc_helper_set_config() function
     502                 :            :  * will call the CRTC &drm_crtc_helper_funcs.mode_set_base helper operation.
     503                 :            :  *
     504                 :            :  * If the adjusted mode differs from the current mode, or if the
     505                 :            :  * ->mode_set_base() helper operation is not provided, the helper function
     506                 :            :  * performs a full mode set sequence by calling the ->prepare(), ->mode_set()
     507                 :            :  * and ->commit() CRTC and encoder helper operations, in that order.
     508                 :            :  * Alternatively it can also use the dpms and disable helper operations. For
     509                 :            :  * details see &struct drm_crtc_helper_funcs and struct
     510                 :            :  * &drm_encoder_helper_funcs.
     511                 :            :  *
     512                 :            :  * This function is deprecated.  New drivers must implement atomic modeset
     513                 :            :  * support, for which this function is unsuitable. Instead drivers should use
     514                 :            :  * drm_atomic_helper_set_config().
     515                 :            :  *
     516                 :            :  * Returns:
     517                 :            :  * Returns 0 on success, negative errno numbers on failure.
     518                 :            :  */
     519                 :          0 : int drm_crtc_helper_set_config(struct drm_mode_set *set,
     520                 :            :                                struct drm_modeset_acquire_ctx *ctx)
     521                 :            : {
     522                 :          0 :         struct drm_device *dev;
     523                 :          0 :         struct drm_crtc **save_encoder_crtcs, *new_crtc;
     524                 :          0 :         struct drm_encoder **save_connector_encoders, *new_encoder, *encoder;
     525                 :          0 :         bool mode_changed = false; /* if true do a full mode set */
     526                 :          0 :         bool fb_changed = false; /* if true and !mode_changed just do a flip */
     527                 :          0 :         struct drm_connector *connector;
     528                 :          0 :         struct drm_connector_list_iter conn_iter;
     529                 :          0 :         int count = 0, ro, fail = 0;
     530                 :          0 :         const struct drm_crtc_helper_funcs *crtc_funcs;
     531                 :          0 :         struct drm_mode_set save_set;
     532                 :          0 :         int ret;
     533                 :          0 :         int i;
     534                 :            : 
     535                 :          0 :         DRM_DEBUG_KMS("\n");
     536                 :            : 
     537         [ #  # ]:          0 :         BUG_ON(!set);
     538         [ #  # ]:          0 :         BUG_ON(!set->crtc);
     539         [ #  # ]:          0 :         BUG_ON(!set->crtc->helper_private);
     540                 :            : 
     541                 :            :         /* Enforce sane interface api - has been abused by the fb helper. */
     542   [ #  #  #  # ]:          0 :         BUG_ON(!set->mode && set->fb);
     543   [ #  #  #  # ]:          0 :         BUG_ON(set->fb && set->num_connectors == 0);
     544                 :            : 
     545                 :          0 :         crtc_funcs = set->crtc->helper_private;
     546                 :            : 
     547                 :          0 :         dev = set->crtc->dev;
     548   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     549                 :            : 
     550         [ #  # ]:          0 :         if (!set->mode)
     551                 :          0 :                 set->fb = NULL;
     552                 :            : 
     553         [ #  # ]:          0 :         if (set->fb) {
     554                 :          0 :                 DRM_DEBUG_KMS("[CRTC:%d:%s] [FB:%d] #connectors=%d (x y) (%i %i)\n",
     555                 :            :                               set->crtc->base.id, set->crtc->name,
     556                 :            :                               set->fb->base.id,
     557                 :            :                               (int)set->num_connectors, set->x, set->y);
     558                 :            :         } else {
     559                 :          0 :                 DRM_DEBUG_KMS("[CRTC:%d:%s] [NOFB]\n",
     560                 :            :                               set->crtc->base.id, set->crtc->name);
     561                 :          0 :                 drm_crtc_helper_disable(set->crtc);
     562                 :          0 :                 return 0;
     563                 :            :         }
     564                 :            : 
     565                 :          0 :         drm_warn_on_modeset_not_all_locked(dev);
     566                 :            : 
     567                 :            :         /*
     568                 :            :          * Allocate space for the backup of all (non-pointer) encoder and
     569                 :            :          * connector data.
     570                 :            :          */
     571                 :          0 :         save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder,
     572                 :            :                                 sizeof(struct drm_crtc *), GFP_KERNEL);
     573         [ #  # ]:          0 :         if (!save_encoder_crtcs)
     574                 :            :                 return -ENOMEM;
     575                 :            : 
     576                 :          0 :         save_connector_encoders = kcalloc(dev->mode_config.num_connector,
     577                 :            :                                 sizeof(struct drm_encoder *), GFP_KERNEL);
     578         [ #  # ]:          0 :         if (!save_connector_encoders) {
     579                 :          0 :                 kfree(save_encoder_crtcs);
     580                 :          0 :                 return -ENOMEM;
     581                 :            :         }
     582                 :            : 
     583                 :            :         /*
     584                 :            :          * Copy data. Note that driver private data is not affected.
     585                 :            :          * Should anything bad happen only the expected state is
     586                 :            :          * restored, not the drivers personal bookkeeping.
     587                 :            :          */
     588                 :          0 :         count = 0;
     589         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     590                 :          0 :                 save_encoder_crtcs[count++] = encoder->crtc;
     591                 :            :         }
     592                 :            : 
     593                 :          0 :         count = 0;
     594                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     595         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter)
     596                 :          0 :                 save_connector_encoders[count++] = connector->encoder;
     597                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     598                 :            : 
     599                 :          0 :         save_set.crtc = set->crtc;
     600                 :          0 :         save_set.mode = &set->crtc->mode;
     601                 :          0 :         save_set.x = set->crtc->x;
     602                 :          0 :         save_set.y = set->crtc->y;
     603                 :          0 :         save_set.fb = set->crtc->primary->fb;
     604                 :            : 
     605                 :            :         /* We should be able to check here if the fb has the same properties
     606                 :            :          * and then just flip_or_move it */
     607         [ #  # ]:          0 :         if (set->crtc->primary->fb != set->fb) {
     608                 :            :                 /* If we have no fb then treat it as a full mode set */
     609         [ #  # ]:          0 :                 if (set->crtc->primary->fb == NULL) {
     610                 :          0 :                         DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
     611                 :          0 :                         mode_changed = true;
     612         [ #  # ]:          0 :                 } else if (set->fb->format != set->crtc->primary->fb->format) {
     613                 :            :                         mode_changed = true;
     614                 :            :                 } else
     615                 :          0 :                         fb_changed = true;
     616                 :            :         }
     617                 :            : 
     618         [ #  # ]:          0 :         if (set->x != set->crtc->x || set->y != set->crtc->y)
     619                 :          0 :                 fb_changed = true;
     620                 :            : 
     621         [ #  # ]:          0 :         if (!drm_mode_equal(set->mode, &set->crtc->mode)) {
     622                 :          0 :                 DRM_DEBUG_KMS("modes are different, full mode set\n");
     623                 :          0 :                 drm_mode_debug_printmodeline(&set->crtc->mode);
     624                 :          0 :                 drm_mode_debug_printmodeline(set->mode);
     625                 :          0 :                 mode_changed = true;
     626                 :            :         }
     627                 :            : 
     628                 :            :         /* take a reference on all unbound connectors in set, reuse the
     629                 :            :          * already taken reference for bound connectors
     630                 :            :          */
     631         [ #  # ]:          0 :         for (ro = 0; ro < set->num_connectors; ro++) {
     632         [ #  # ]:          0 :                 if (set->connectors[ro]->encoder)
     633                 :          0 :                         continue;
     634                 :          0 :                 drm_connector_get(set->connectors[ro]);
     635                 :            :         }
     636                 :            : 
     637                 :            :         /* a) traverse passed in connector list and get encoders for them */
     638                 :          0 :         count = 0;
     639                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     640         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     641                 :          0 :                 const struct drm_connector_helper_funcs *connector_funcs =
     642                 :            :                         connector->helper_private;
     643                 :          0 :                 new_encoder = connector->encoder;
     644         [ #  # ]:          0 :                 for (ro = 0; ro < set->num_connectors; ro++) {
     645         [ #  # ]:          0 :                         if (set->connectors[ro] == connector) {
     646         [ #  # ]:          0 :                                 if (connector_funcs->best_encoder)
     647                 :          0 :                                         new_encoder = connector_funcs->best_encoder(connector);
     648                 :            :                                 else
     649                 :          0 :                                         new_encoder = drm_connector_get_single_encoder(connector);
     650                 :            : 
     651                 :            :                                 /* if we can't get an encoder for a connector
     652                 :            :                                    we are setting now - then fail */
     653         [ #  # ]:          0 :                                 if (new_encoder == NULL)
     654                 :            :                                         /* don't break so fail path works correct */
     655                 :          0 :                                         fail = 1;
     656                 :            : 
     657         [ #  # ]:          0 :                                 if (connector->dpms != DRM_MODE_DPMS_ON) {
     658                 :          0 :                                         DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
     659                 :          0 :                                         mode_changed = true;
     660                 :            :                                 }
     661                 :            : 
     662                 :            :                                 break;
     663                 :            :                         }
     664                 :            :                 }
     665                 :            : 
     666         [ #  # ]:          0 :                 if (new_encoder != connector->encoder) {
     667                 :          0 :                         DRM_DEBUG_KMS("encoder changed, full mode switch\n");
     668                 :          0 :                         mode_changed = true;
     669                 :            :                         /* If the encoder is reused for another connector, then
     670                 :            :                          * the appropriate crtc will be set later.
     671                 :            :                          */
     672         [ #  # ]:          0 :                         if (connector->encoder)
     673                 :          0 :                                 connector->encoder->crtc = NULL;
     674                 :          0 :                         connector->encoder = new_encoder;
     675                 :            :                 }
     676                 :            :         }
     677                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     678                 :            : 
     679         [ #  # ]:          0 :         if (fail) {
     680                 :          0 :                 ret = -EINVAL;
     681                 :          0 :                 goto fail;
     682                 :            :         }
     683                 :            : 
     684                 :          0 :         count = 0;
     685                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     686         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter) {
     687         [ #  # ]:          0 :                 if (!connector->encoder)
     688                 :          0 :                         continue;
     689                 :            : 
     690         [ #  # ]:          0 :                 if (connector->encoder->crtc == set->crtc)
     691                 :            :                         new_crtc = NULL;
     692                 :            :                 else
     693                 :          0 :                         new_crtc = connector->encoder->crtc;
     694                 :            : 
     695         [ #  # ]:          0 :                 for (ro = 0; ro < set->num_connectors; ro++) {
     696         [ #  # ]:          0 :                         if (set->connectors[ro] == connector)
     697                 :          0 :                                 new_crtc = set->crtc;
     698                 :            :                 }
     699                 :            : 
     700                 :            :                 /* Make sure the new CRTC will work with the encoder */
     701   [ #  #  #  # ]:          0 :                 if (new_crtc &&
     702         [ #  # ]:          0 :                     !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
     703                 :          0 :                         ret = -EINVAL;
     704                 :          0 :                         drm_connector_list_iter_end(&conn_iter);
     705                 :          0 :                         goto fail;
     706                 :            :                 }
     707         [ #  # ]:          0 :                 if (new_crtc != connector->encoder->crtc) {
     708                 :          0 :                         DRM_DEBUG_KMS("crtc changed, full mode switch\n");
     709                 :          0 :                         mode_changed = true;
     710                 :          0 :                         connector->encoder->crtc = new_crtc;
     711                 :            :                 }
     712         [ #  # ]:          0 :                 if (new_crtc) {
     713                 :          0 :                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d:%s]\n",
     714                 :            :                                       connector->base.id, connector->name,
     715                 :            :                                       new_crtc->base.id, new_crtc->name);
     716                 :            :                 } else {
     717                 :          0 :                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
     718                 :            :                                       connector->base.id, connector->name);
     719                 :            :                 }
     720                 :            :         }
     721                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     722                 :            : 
     723                 :            :         /* mode_set_base is not a required function */
     724   [ #  #  #  # ]:          0 :         if (fb_changed && !crtc_funcs->mode_set_base)
     725                 :            :                 mode_changed = true;
     726                 :            : 
     727         [ #  # ]:          0 :         if (mode_changed) {
     728         [ #  # ]:          0 :                 if (drm_helper_crtc_in_use(set->crtc)) {
     729                 :          0 :                         DRM_DEBUG_KMS("attempting to set mode from"
     730                 :            :                                         " userspace\n");
     731                 :          0 :                         drm_mode_debug_printmodeline(set->mode);
     732                 :          0 :                         set->crtc->primary->fb = set->fb;
     733         [ #  # ]:          0 :                         if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
     734                 :          0 :                                                       set->x, set->y,
     735                 :            :                                                       save_set.fb)) {
     736                 :          0 :                                 DRM_ERROR("failed to set mode on [CRTC:%d:%s]\n",
     737                 :            :                                           set->crtc->base.id, set->crtc->name);
     738                 :          0 :                                 set->crtc->primary->fb = save_set.fb;
     739                 :          0 :                                 ret = -EINVAL;
     740                 :          0 :                                 goto fail;
     741                 :            :                         }
     742                 :          0 :                         DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
     743         [ #  # ]:          0 :                         for (i = 0; i < set->num_connectors; i++) {
     744                 :          0 :                                 DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
     745                 :            :                                               set->connectors[i]->name);
     746                 :          0 :                                 set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
     747                 :            :                         }
     748                 :            :                 }
     749                 :          0 :                 __drm_helper_disable_unused_functions(dev);
     750         [ #  # ]:          0 :         } else if (fb_changed) {
     751                 :          0 :                 set->crtc->x = set->x;
     752                 :          0 :                 set->crtc->y = set->y;
     753                 :          0 :                 set->crtc->primary->fb = set->fb;
     754                 :          0 :                 ret = crtc_funcs->mode_set_base(set->crtc,
     755                 :          0 :                                                 set->x, set->y, save_set.fb);
     756         [ #  # ]:          0 :                 if (ret != 0) {
     757                 :          0 :                         set->crtc->x = save_set.x;
     758                 :          0 :                         set->crtc->y = save_set.y;
     759                 :          0 :                         set->crtc->primary->fb = save_set.fb;
     760                 :          0 :                         goto fail;
     761                 :            :                 }
     762                 :            :         }
     763                 :            : 
     764                 :          0 :         kfree(save_connector_encoders);
     765                 :          0 :         kfree(save_encoder_crtcs);
     766                 :          0 :         return 0;
     767                 :            : 
     768                 :          0 : fail:
     769                 :            :         /* Restore all previous data. */
     770                 :          0 :         count = 0;
     771         [ #  # ]:          0 :         drm_for_each_encoder(encoder, dev) {
     772                 :          0 :                 encoder->crtc = save_encoder_crtcs[count++];
     773                 :            :         }
     774                 :            : 
     775                 :          0 :         count = 0;
     776                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     777         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter)
     778                 :          0 :                 connector->encoder = save_connector_encoders[count++];
     779                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     780                 :            : 
     781                 :            :         /* after fail drop reference on all unbound connectors in set, let
     782                 :            :          * bound connectors keep their reference
     783                 :            :          */
     784         [ #  # ]:          0 :         for (ro = 0; ro < set->num_connectors; ro++) {
     785         [ #  # ]:          0 :                 if (set->connectors[ro]->encoder)
     786                 :          0 :                         continue;
     787                 :          0 :                 drm_connector_put(set->connectors[ro]);
     788                 :            :         }
     789                 :            : 
     790                 :            :         /* Try to restore the config */
     791   [ #  #  #  # ]:          0 :         if (mode_changed &&
     792                 :          0 :             !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
     793                 :            :                                       save_set.y, save_set.fb))
     794                 :          0 :                 DRM_ERROR("failed to restore config after modeset failure\n");
     795                 :            : 
     796                 :          0 :         kfree(save_connector_encoders);
     797                 :          0 :         kfree(save_encoder_crtcs);
     798                 :          0 :         return ret;
     799                 :            : }
     800                 :            : EXPORT_SYMBOL(drm_crtc_helper_set_config);
     801                 :            : 
     802                 :          0 : static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
     803                 :            : {
     804                 :          0 :         int dpms = DRM_MODE_DPMS_OFF;
     805                 :          0 :         struct drm_connector *connector;
     806                 :          0 :         struct drm_connector_list_iter conn_iter;
     807                 :          0 :         struct drm_device *dev = encoder->dev;
     808                 :            : 
     809                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     810         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter)
     811         [ #  # ]:          0 :                 if (connector->encoder == encoder)
     812                 :          0 :                         if (connector->dpms < dpms)
     813                 :            :                                 dpms = connector->dpms;
     814                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     815                 :            : 
     816                 :          0 :         return dpms;
     817                 :            : }
     818                 :            : 
     819                 :            : /* Helper which handles bridge ordering around encoder dpms */
     820                 :          0 : static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
     821                 :            : {
     822                 :          0 :         const struct drm_encoder_helper_funcs *encoder_funcs;
     823                 :            : 
     824                 :          0 :         encoder_funcs = encoder->helper_private;
     825                 :          0 :         if (!encoder_funcs)
     826                 :            :                 return;
     827                 :            : 
     828   [ #  #  #  #  :          0 :         if (encoder_funcs->dpms)
                   #  # ]
     829                 :          0 :                 encoder_funcs->dpms(encoder, mode);
     830                 :            : }
     831                 :            : 
     832                 :          0 : static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
     833                 :            : {
     834                 :          0 :         int dpms = DRM_MODE_DPMS_OFF;
     835                 :          0 :         struct drm_connector *connector;
     836                 :          0 :         struct drm_connector_list_iter conn_iter;
     837                 :          0 :         struct drm_device *dev = crtc->dev;
     838                 :            : 
     839                 :          0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     840         [ #  # ]:          0 :         drm_for_each_connector_iter(connector, &conn_iter)
     841   [ #  #  #  # ]:          0 :                 if (connector->encoder && connector->encoder->crtc == crtc)
     842                 :          0 :                         if (connector->dpms < dpms)
     843                 :            :                                 dpms = connector->dpms;
     844                 :          0 :         drm_connector_list_iter_end(&conn_iter);
     845                 :            : 
     846                 :          0 :         return dpms;
     847                 :            : }
     848                 :            : 
     849                 :            : /**
     850                 :            :  * drm_helper_connector_dpms() - connector dpms helper implementation
     851                 :            :  * @connector: affected connector
     852                 :            :  * @mode: DPMS mode
     853                 :            :  *
     854                 :            :  * The drm_helper_connector_dpms() helper function implements the
     855                 :            :  * &drm_connector_funcs.dpms callback for drivers using the legacy CRTC
     856                 :            :  * helpers.
     857                 :            :  *
     858                 :            :  * This is the main helper function provided by the CRTC helper framework for
     859                 :            :  * implementing the DPMS connector attribute. It computes the new desired DPMS
     860                 :            :  * state for all encoders and CRTCs in the output mesh and calls the
     861                 :            :  * &drm_crtc_helper_funcs.dpms and &drm_encoder_helper_funcs.dpms callbacks
     862                 :            :  * provided by the driver.
     863                 :            :  *
     864                 :            :  * This function is deprecated.  New drivers must implement atomic modeset
     865                 :            :  * support, where DPMS is handled in the DRM core.
     866                 :            :  *
     867                 :            :  * Returns:
     868                 :            :  * Always returns 0.
     869                 :            :  */
     870                 :          0 : int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
     871                 :            : {
     872                 :          0 :         struct drm_encoder *encoder = connector->encoder;
     873         [ #  # ]:          0 :         struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
     874                 :          0 :         int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
     875                 :            : 
     876   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(connector->dev));
     877                 :            : 
     878         [ #  # ]:          0 :         if (mode == connector->dpms)
     879                 :            :                 return 0;
     880                 :            : 
     881                 :          0 :         old_dpms = connector->dpms;
     882                 :          0 :         connector->dpms = mode;
     883                 :            : 
     884         [ #  # ]:          0 :         if (encoder)
     885                 :          0 :                 encoder_dpms = drm_helper_choose_encoder_dpms(encoder);
     886                 :            : 
     887                 :            :         /* from off to on, do crtc then encoder */
     888         [ #  # ]:          0 :         if (mode < old_dpms) {
     889         [ #  # ]:          0 :                 if (crtc) {
     890                 :          0 :                         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     891         [ #  # ]:          0 :                         if (crtc_funcs->dpms)
     892                 :          0 :                                 (*crtc_funcs->dpms) (crtc,
     893                 :            :                                                      drm_helper_choose_crtc_dpms(crtc));
     894                 :            :                 }
     895         [ #  # ]:          0 :                 if (encoder)
     896         [ #  # ]:          0 :                         drm_helper_encoder_dpms(encoder, encoder_dpms);
     897                 :            :         }
     898                 :            : 
     899                 :            :         /* from on to off, do encoder then crtc */
     900         [ #  # ]:          0 :         if (mode > old_dpms) {
     901         [ #  # ]:          0 :                 if (encoder)
     902         [ #  # ]:          0 :                         drm_helper_encoder_dpms(encoder, encoder_dpms);
     903         [ #  # ]:          0 :                 if (crtc) {
     904                 :          0 :                         const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
     905         [ #  # ]:          0 :                         if (crtc_funcs->dpms)
     906                 :          0 :                                 (*crtc_funcs->dpms) (crtc,
     907                 :            :                                                      drm_helper_choose_crtc_dpms(crtc));
     908                 :            :                 }
     909                 :            :         }
     910                 :            : 
     911                 :            :         return 0;
     912                 :            : }
     913                 :            : EXPORT_SYMBOL(drm_helper_connector_dpms);
     914                 :            : 
     915                 :            : /**
     916                 :            :  * drm_helper_resume_force_mode - force-restore mode setting configuration
     917                 :            :  * @dev: drm_device which should be restored
     918                 :            :  *
     919                 :            :  * Drivers which use the mode setting helpers can use this function to
     920                 :            :  * force-restore the mode setting configuration e.g. on resume or when something
     921                 :            :  * else might have trampled over the hw state (like some overzealous old BIOSen
     922                 :            :  * tended to do).
     923                 :            :  *
     924                 :            :  * This helper doesn't provide a error return value since restoring the old
     925                 :            :  * config should never fail due to resource allocation issues since the driver
     926                 :            :  * has successfully set the restored configuration already. Hence this should
     927                 :            :  * boil down to the equivalent of a few dpms on calls, which also don't provide
     928                 :            :  * an error code.
     929                 :            :  *
     930                 :            :  * Drivers where simply restoring an old configuration again might fail (e.g.
     931                 :            :  * due to slight differences in allocating shared resources when the
     932                 :            :  * configuration is restored in a different order than when userspace set it up)
     933                 :            :  * need to use their own restore logic.
     934                 :            :  *
     935                 :            :  * This function is deprecated. New drivers should implement atomic mode-
     936                 :            :  * setting and use the atomic suspend/resume helpers.
     937                 :            :  *
     938                 :            :  * See also:
     939                 :            :  * drm_atomic_helper_suspend(), drm_atomic_helper_resume()
     940                 :            :  */
     941                 :          0 : void drm_helper_resume_force_mode(struct drm_device *dev)
     942                 :            : {
     943                 :          0 :         struct drm_crtc *crtc;
     944                 :          0 :         struct drm_encoder *encoder;
     945                 :          0 :         const struct drm_crtc_helper_funcs *crtc_funcs;
     946                 :          0 :         int encoder_dpms;
     947                 :          0 :         bool ret;
     948                 :            : 
     949   [ #  #  #  # ]:          0 :         WARN_ON(drm_drv_uses_atomic_modeset(dev));
     950                 :            : 
     951                 :          0 :         drm_modeset_lock_all(dev);
     952         [ #  # ]:          0 :         drm_for_each_crtc(crtc, dev) {
     953                 :            : 
     954         [ #  # ]:          0 :                 if (!crtc->enabled)
     955                 :          0 :                         continue;
     956                 :            : 
     957                 :          0 :                 ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
     958                 :          0 :                                                crtc->x, crtc->y, crtc->primary->fb);
     959                 :            : 
     960                 :            :                 /* Restoring the old config should never fail! */
     961         [ #  # ]:          0 :                 if (ret == false)
     962                 :          0 :                         DRM_ERROR("failed to set mode on crtc %p\n", crtc);
     963                 :            : 
     964                 :            :                 /* Turn off outputs that were already powered off */
     965         [ #  # ]:          0 :                 if (drm_helper_choose_crtc_dpms(crtc)) {
     966         [ #  # ]:          0 :                         drm_for_each_encoder(encoder, dev) {
     967                 :            : 
     968         [ #  # ]:          0 :                                 if(encoder->crtc != crtc)
     969                 :          0 :                                         continue;
     970                 :            : 
     971                 :          0 :                                 encoder_dpms = drm_helper_choose_encoder_dpms(
     972                 :            :                                                         encoder);
     973                 :            : 
     974         [ #  # ]:          0 :                                 drm_helper_encoder_dpms(encoder, encoder_dpms);
     975                 :            :                         }
     976                 :            : 
     977                 :          0 :                         crtc_funcs = crtc->helper_private;
     978         [ #  # ]:          0 :                         if (crtc_funcs->dpms)
     979                 :          0 :                                 (*crtc_funcs->dpms) (crtc,
     980                 :            :                                                      drm_helper_choose_crtc_dpms(crtc));
     981                 :            :                 }
     982                 :            :         }
     983                 :            : 
     984                 :            :         /* disable the unused connectors while restoring the modesetting */
     985                 :          0 :         __drm_helper_disable_unused_functions(dev);
     986                 :          0 :         drm_modeset_unlock_all(dev);
     987                 :          0 : }
     988                 :            : EXPORT_SYMBOL(drm_helper_resume_force_mode);
     989                 :            : 
     990                 :            : /**
     991                 :            :  * drm_helper_force_disable_all - Forcibly turn off all enabled CRTCs
     992                 :            :  * @dev: DRM device whose CRTCs to turn off
     993                 :            :  *
     994                 :            :  * Drivers may want to call this on unload to ensure that all displays are
     995                 :            :  * unlit and the GPU is in a consistent, low power state. Takes modeset locks.
     996                 :            :  *
     997                 :            :  * Note: This should only be used by non-atomic legacy drivers. For an atomic
     998                 :            :  * version look at drm_atomic_helper_shutdown().
     999                 :            :  *
    1000                 :            :  * Returns:
    1001                 :            :  * Zero on success, error code on failure.
    1002                 :            :  */
    1003                 :          0 : int drm_helper_force_disable_all(struct drm_device *dev)
    1004                 :            : {
    1005                 :          0 :         struct drm_crtc *crtc;
    1006                 :          0 :         int ret = 0;
    1007                 :            : 
    1008                 :          0 :         drm_modeset_lock_all(dev);
    1009         [ #  # ]:          0 :         drm_for_each_crtc(crtc, dev)
    1010         [ #  # ]:          0 :                 if (crtc->enabled) {
    1011                 :          0 :                         struct drm_mode_set set = {
    1012                 :            :                                 .crtc = crtc,
    1013                 :            :                         };
    1014                 :            : 
    1015                 :          0 :                         ret = drm_mode_set_config_internal(&set);
    1016         [ #  # ]:          0 :                         if (ret)
    1017                 :          0 :                                 goto out;
    1018                 :            :                 }
    1019                 :          0 : out:
    1020                 :          0 :         drm_modeset_unlock_all(dev);
    1021                 :          0 :         return ret;
    1022                 :            : }
    1023                 :            : EXPORT_SYMBOL(drm_helper_force_disable_all);

Generated by: LCOV version 1.14