LCOV - code coverage report
Current view: top level - dev/pci/drm - drm_crtc_helper.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 390 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13