The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/drm_crtc_helper.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <dev/drm2/drmP.h>
   36 #include <dev/drm2/drm_crtc.h>
   37 #include <dev/drm2/drm_fourcc.h>
   38 #include <dev/drm2/drm_crtc_helper.h>
   39 #include <dev/drm2/drm_fb_helper.h>
   40 #include <dev/drm2/drm_edid.h>
   41 
   42 /**
   43  * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
   44  *                                              connector list
   45  * @dev: drm device to operate on
   46  *
   47  * Some userspace presumes that the first connected connector is the main
   48  * display, where it's supposed to display e.g. the login screen. For
   49  * laptops, this should be the main panel. Use this function to sort all
   50  * (eDP/LVDS) panels to the front of the connector list, instead of
   51  * painstakingly trying to initialize them in the right order.
   52  */
   53 void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
   54 {
   55         struct drm_connector *connector, *tmp;
   56         struct list_head panel_list;
   57 
   58         INIT_LIST_HEAD(&panel_list);
   59 
   60         list_for_each_entry_safe(connector, tmp,
   61                                  &dev->mode_config.connector_list, head) {
   62                 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
   63                     connector->connector_type == DRM_MODE_CONNECTOR_eDP)
   64                         list_move_tail(&connector->head, &panel_list);
   65         }
   66 
   67         list_splice(&panel_list, &dev->mode_config.connector_list);
   68 }
   69 EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
   70 
   71 static bool drm_kms_helper_poll = true;
   72 module_param_named(poll, drm_kms_helper_poll, bool, 0600);
   73 
   74 static void drm_mode_validate_flag(struct drm_connector *connector,
   75                                    int flags)
   76 {
   77         struct drm_display_mode *mode;
   78 
   79         if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
   80                 return;
   81 
   82         list_for_each_entry(mode, &connector->modes, head) {
   83                 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
   84                                 !(flags & DRM_MODE_FLAG_INTERLACE))
   85                         mode->status = MODE_NO_INTERLACE;
   86                 if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
   87                                 !(flags & DRM_MODE_FLAG_DBLSCAN))
   88                         mode->status = MODE_NO_DBLESCAN;
   89         }
   90 
   91         return;
   92 }
   93 
   94 /**
   95  * drm_helper_probe_single_connector_modes - get complete set of display modes
   96  * @connector: connector to probe
   97  * @maxX: max width for modes
   98  * @maxY: max height for modes
   99  *
  100  * LOCKING:
  101  * Caller must hold mode config lock.
  102  *
  103  * Based on the helper callbacks implemented by @connector try to detect all
  104  * valid modes.  Modes will first be added to the connector's probed_modes list,
  105  * then culled (based on validity and the @maxX, @maxY parameters) and put into
  106  * the normal modes list.
  107  *
  108  * Intended to be use as a generic implementation of the ->probe() @connector
  109  * callback for drivers that use the crtc helpers for output mode filtering and
  110  * detection.
  111  *
  112  * RETURNS:
  113  * Number of modes found on @connector.
  114  */
  115 int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
  116                                             uint32_t maxX, uint32_t maxY)
  117 {
  118         struct drm_device *dev = connector->dev;
  119         struct drm_display_mode *mode;
  120         struct drm_connector_helper_funcs *connector_funcs =
  121                 connector->helper_private;
  122         int count = 0;
  123         int mode_flags = 0;
  124 
  125         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
  126                         drm_get_connector_name(connector));
  127         /* set all modes to the unverified state */
  128         list_for_each_entry(mode, &connector->modes, head)
  129                 mode->status = MODE_UNVERIFIED;
  130 
  131         if (connector->force) {
  132                 if (connector->force == DRM_FORCE_ON)
  133                         connector->status = connector_status_connected;
  134                 else
  135                         connector->status = connector_status_disconnected;
  136                 if (connector->funcs->force)
  137                         connector->funcs->force(connector);
  138         } else {
  139                 connector->status = connector->funcs->detect(connector, true);
  140         }
  141 
  142         /* Re-enable polling in case the global poll config changed. */
  143         if (drm_kms_helper_poll != dev->mode_config.poll_running)
  144                 drm_kms_helper_poll_enable(dev);
  145 
  146         dev->mode_config.poll_running = drm_kms_helper_poll;
  147 
  148         if (connector->status == connector_status_disconnected) {
  149                 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
  150                         connector->base.id, drm_get_connector_name(connector));
  151                 drm_mode_connector_update_edid_property(connector, NULL);
  152                 goto prune;
  153         }
  154 
  155 #ifdef FREEBSD_NOTYET
  156 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
  157         count = drm_load_edid_firmware(connector);
  158         if (count == 0)
  159 #endif
  160 #endif /* FREEBSD_NOTYET */
  161                 count = (*connector_funcs->get_modes)(connector);
  162 
  163         if (count == 0 && connector->status == connector_status_connected)
  164                 count = drm_add_modes_noedid(connector, 1024, 768);
  165         if (count == 0)
  166                 goto prune;
  167 
  168         drm_mode_connector_list_update(connector);
  169 
  170         if (maxX && maxY)
  171                 drm_mode_validate_size(dev, &connector->modes, maxX,
  172                                        maxY, 0);
  173 
  174         if (connector->interlace_allowed)
  175                 mode_flags |= DRM_MODE_FLAG_INTERLACE;
  176         if (connector->doublescan_allowed)
  177                 mode_flags |= DRM_MODE_FLAG_DBLSCAN;
  178         drm_mode_validate_flag(connector, mode_flags);
  179 
  180         list_for_each_entry(mode, &connector->modes, head) {
  181                 if (mode->status == MODE_OK)
  182                         mode->status = connector_funcs->mode_valid(connector,
  183                                                                    mode);
  184         }
  185 
  186 prune:
  187         drm_mode_prune_invalid(dev, &connector->modes, true);
  188 
  189         if (list_empty(&connector->modes))
  190                 return 0;
  191 
  192         list_for_each_entry(mode, &connector->modes, head)
  193                 mode->vrefresh = drm_mode_vrefresh(mode);
  194 
  195         drm_mode_sort(&connector->modes);
  196 
  197         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
  198                         drm_get_connector_name(connector));
  199         list_for_each_entry(mode, &connector->modes, head) {
  200                 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
  201                 drm_mode_debug_printmodeline(mode);
  202         }
  203 
  204         return count;
  205 }
  206 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
  207 
  208 /**
  209  * drm_helper_encoder_in_use - check if a given encoder is in use
  210  * @encoder: encoder to check
  211  *
  212  * LOCKING:
  213  * Caller must hold mode config lock.
  214  *
  215  * Walk @encoders's DRM device's mode_config and see if it's in use.
  216  *
  217  * RETURNS:
  218  * True if @encoder is part of the mode_config, false otherwise.
  219  */
  220 bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
  221 {
  222         struct drm_connector *connector;
  223         struct drm_device *dev = encoder->dev;
  224         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
  225                 if (connector->encoder == encoder)
  226                         return true;
  227         return false;
  228 }
  229 EXPORT_SYMBOL(drm_helper_encoder_in_use);
  230 
  231 /**
  232  * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
  233  * @crtc: CRTC to check
  234  *
  235  * LOCKING:
  236  * Caller must hold mode config lock.
  237  *
  238  * Walk @crtc's DRM device's mode_config and see if it's in use.
  239  *
  240  * RETURNS:
  241  * True if @crtc is part of the mode_config, false otherwise.
  242  */
  243 bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
  244 {
  245         struct drm_encoder *encoder;
  246         struct drm_device *dev = crtc->dev;
  247         /* FIXME: Locking around list access? */
  248         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
  249                 if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
  250                         return true;
  251         return false;
  252 }
  253 EXPORT_SYMBOL(drm_helper_crtc_in_use);
  254 
  255 static void
  256 drm_encoder_disable(struct drm_encoder *encoder)
  257 {
  258         struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
  259 
  260         if (encoder_funcs->disable)
  261                 (*encoder_funcs->disable)(encoder);
  262         else
  263                 (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
  264 }
  265 
  266 /**
  267  * drm_helper_disable_unused_functions - disable unused objects
  268  * @dev: DRM device
  269  *
  270  * LOCKING:
  271  * Caller must hold mode config lock.
  272  *
  273  * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
  274  * by calling its dpms function, which should power it off.
  275  */
  276 void drm_helper_disable_unused_functions(struct drm_device *dev)
  277 {
  278         struct drm_encoder *encoder;
  279         struct drm_connector *connector;
  280         struct drm_crtc *crtc;
  281 
  282         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  283                 if (!connector->encoder)
  284                         continue;
  285                 if (connector->status == connector_status_disconnected)
  286                         connector->encoder = NULL;
  287         }
  288 
  289         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  290                 if (!drm_helper_encoder_in_use(encoder)) {
  291                         drm_encoder_disable(encoder);
  292                         /* disconnector encoder from any connector */
  293                         encoder->crtc = NULL;
  294                 }
  295         }
  296 
  297         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  298                 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
  299                 crtc->enabled = drm_helper_crtc_in_use(crtc);
  300                 if (!crtc->enabled) {
  301                         if (crtc_funcs->disable)
  302                                 (*crtc_funcs->disable)(crtc);
  303                         else
  304                                 (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
  305                         crtc->fb = NULL;
  306                 }
  307         }
  308 }
  309 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
  310 
  311 /**
  312  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  313  * @encoder: encoder to test
  314  * @crtc: crtc to test
  315  *
  316  * Return false if @encoder can't be driven by @crtc, true otherwise.
  317  */
  318 static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
  319                                 struct drm_crtc *crtc)
  320 {
  321         struct drm_device *dev;
  322         struct drm_crtc *tmp;
  323         int crtc_mask = 1;
  324 
  325         if (crtc == NULL)
  326                 printf("checking null crtc?\n");
  327 
  328         dev = crtc->dev;
  329 
  330         list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
  331                 if (tmp == crtc)
  332                         break;
  333                 crtc_mask <<= 1;
  334         }
  335 
  336         if (encoder->possible_crtcs & crtc_mask)
  337                 return true;
  338         return false;
  339 }
  340 
  341 /*
  342  * Check the CRTC we're going to map each output to vs. its current
  343  * CRTC.  If they don't match, we have to disable the output and the CRTC
  344  * since the driver will have to re-route things.
  345  */
  346 static void
  347 drm_crtc_prepare_encoders(struct drm_device *dev)
  348 {
  349         struct drm_encoder_helper_funcs *encoder_funcs;
  350         struct drm_encoder *encoder;
  351 
  352         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  353                 encoder_funcs = encoder->helper_private;
  354                 /* Disable unused encoders */
  355                 if (encoder->crtc == NULL)
  356                         drm_encoder_disable(encoder);
  357                 /* Disable encoders whose CRTC is about to change */
  358                 if (encoder_funcs->get_crtc &&
  359                     encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
  360                         drm_encoder_disable(encoder);
  361         }
  362 }
  363 
  364 /**
  365  * drm_crtc_helper_set_mode - internal helper to set a mode
  366  * @crtc: CRTC to program
  367  * @mode: mode to use
  368  * @x: horizontal offset into the surface
  369  * @y: vertical offset into the surface
  370  * @old_fb: old framebuffer, for cleanup
  371  *
  372  * LOCKING:
  373  * Caller must hold mode config lock.
  374  *
  375  * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
  376  * to fixup or reject the mode prior to trying to set it. This is an internal
  377  * helper that drivers could e.g. use to update properties that require the
  378  * entire output pipe to be disabled and re-enabled in a new configuration. For
  379  * example for changing whether audio is enabled on a hdmi link or for changing
  380  * panel fitter or dither attributes. It is also called by the
  381  * drm_crtc_helper_set_config() helper function to drive the mode setting
  382  * sequence.
  383  *
  384  * RETURNS:
  385  * True if the mode was set successfully, or false otherwise.
  386  */
  387 bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
  388                               struct drm_display_mode *mode,
  389                               int x, int y,
  390                               struct drm_framebuffer *old_fb)
  391 {
  392         struct drm_device *dev = crtc->dev;
  393         struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
  394         struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
  395         struct drm_encoder_helper_funcs *encoder_funcs;
  396         int saved_x, saved_y;
  397         struct drm_encoder *encoder;
  398         bool ret = true;
  399 
  400         crtc->enabled = drm_helper_crtc_in_use(crtc);
  401         if (!crtc->enabled)
  402                 return true;
  403 
  404         adjusted_mode = drm_mode_duplicate(dev, mode);
  405         if (!adjusted_mode)
  406                 return false;
  407 
  408         saved_hwmode = crtc->hwmode;
  409         saved_mode = crtc->mode;
  410         saved_x = crtc->x;
  411         saved_y = crtc->y;
  412 
  413         /* Update crtc values up front so the driver can rely on them for mode
  414          * setting.
  415          */
  416         crtc->mode = *mode;
  417         crtc->x = x;
  418         crtc->y = y;
  419 
  420         /* Pass our mode to the connectors and the CRTC to give them a chance to
  421          * adjust it according to limitations or connector properties, and also
  422          * a chance to reject the mode entirely.
  423          */
  424         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  425 
  426                 if (encoder->crtc != crtc)
  427                         continue;
  428                 encoder_funcs = encoder->helper_private;
  429                 if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
  430                                                       adjusted_mode))) {
  431                         DRM_DEBUG_KMS("Encoder fixup failed\n");
  432                         goto done;
  433                 }
  434         }
  435 
  436         if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
  437                 DRM_DEBUG_KMS("CRTC fixup failed\n");
  438                 goto done;
  439         }
  440         DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
  441 
  442         /* Prepare the encoders and CRTCs before setting the mode. */
  443         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  444 
  445                 if (encoder->crtc != crtc)
  446                         continue;
  447                 encoder_funcs = encoder->helper_private;
  448                 /* Disable the encoders as the first thing we do. */
  449                 encoder_funcs->prepare(encoder);
  450         }
  451 
  452         drm_crtc_prepare_encoders(dev);
  453 
  454         crtc_funcs->prepare(crtc);
  455 
  456         /* Set up the DPLL and any encoders state that needs to adjust or depend
  457          * on the DPLL.
  458          */
  459         ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
  460         if (!ret)
  461             goto done;
  462 
  463         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  464 
  465                 if (encoder->crtc != crtc)
  466                         continue;
  467 
  468                 DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
  469                         encoder->base.id, drm_get_encoder_name(encoder),
  470                         mode->base.id, mode->name);
  471                 encoder_funcs = encoder->helper_private;
  472                 encoder_funcs->mode_set(encoder, mode, adjusted_mode);
  473         }
  474 
  475         /* Now enable the clocks, plane, pipe, and connectors that we set up. */
  476         crtc_funcs->commit(crtc);
  477 
  478         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  479 
  480                 if (encoder->crtc != crtc)
  481                         continue;
  482 
  483                 encoder_funcs = encoder->helper_private;
  484                 encoder_funcs->commit(encoder);
  485 
  486         }
  487 
  488         /* Store real post-adjustment hardware mode. */
  489         crtc->hwmode = *adjusted_mode;
  490 
  491         /* Calculate and store various constants which
  492          * are later needed by vblank and swap-completion
  493          * timestamping. They are derived from true hwmode.
  494          */
  495         drm_calc_timestamping_constants(crtc);
  496 
  497         /* FIXME: add subpixel order */
  498 done:
  499         drm_mode_destroy(dev, adjusted_mode);
  500         if (!ret) {
  501                 crtc->hwmode = saved_hwmode;
  502                 crtc->mode = saved_mode;
  503                 crtc->x = saved_x;
  504                 crtc->y = saved_y;
  505         }
  506 
  507         return ret;
  508 }
  509 EXPORT_SYMBOL(drm_crtc_helper_set_mode);
  510 
  511 
  512 static int
  513 drm_crtc_helper_disable(struct drm_crtc *crtc)
  514 {
  515         struct drm_device *dev = crtc->dev;
  516         struct drm_connector *connector;
  517         struct drm_encoder *encoder;
  518 
  519         /* Decouple all encoders and their attached connectors from this crtc */
  520         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  521                 if (encoder->crtc != crtc)
  522                         continue;
  523 
  524                 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  525                         if (connector->encoder != encoder)
  526                                 continue;
  527 
  528                         connector->encoder = NULL;
  529                 }
  530         }
  531 
  532         drm_helper_disable_unused_functions(dev);
  533         return 0;
  534 }
  535 
  536 /**
  537  * drm_crtc_helper_set_config - set a new config from userspace
  538  * @set: mode set configuration
  539  *
  540  * LOCKING:
  541  * Caller must hold mode config lock.
  542  *
  543  * Setup a new configuration, provided by the upper layers (either an ioctl call
  544  * from userspace or internally e.g. from the fbdev suppport code) in @set, and
  545  * enable it. This is the main helper functions for drivers that implement
  546  * kernel mode setting with the crtc helper functions and the assorted
  547  * ->prepare(), ->modeset() and ->commit() helper callbacks.
  548  *
  549  * RETURNS:
  550  * Returns 0 on success, -ERRNO on failure.
  551  */
  552 int drm_crtc_helper_set_config(struct drm_mode_set *set)
  553 {
  554         struct drm_device *dev;
  555         struct drm_crtc *save_crtcs, *new_crtc, *crtc;
  556         struct drm_encoder *save_encoders, *new_encoder, *encoder;
  557         struct drm_framebuffer *old_fb = NULL;
  558         bool mode_changed = false; /* if true do a full mode set */
  559         bool fb_changed = false; /* if true and !mode_changed just do a flip */
  560         struct drm_connector *save_connectors, *connector;
  561         int count = 0, ro, fail = 0;
  562         struct drm_crtc_helper_funcs *crtc_funcs;
  563         struct drm_mode_set save_set;
  564         int ret;
  565         int i;
  566 
  567         DRM_DEBUG_KMS("\n");
  568 
  569         if (!set)
  570                 return -EINVAL;
  571 
  572         if (!set->crtc)
  573                 return -EINVAL;
  574 
  575         if (!set->crtc->helper_private)
  576                 return -EINVAL;
  577 
  578         crtc_funcs = set->crtc->helper_private;
  579 
  580         if (!set->mode)
  581                 set->fb = NULL;
  582 
  583         if (set->fb) {
  584                 DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
  585                                 set->crtc->base.id, set->fb->base.id,
  586                                 (int)set->num_connectors, set->x, set->y);
  587         } else {
  588                 DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
  589                 return drm_crtc_helper_disable(set->crtc);
  590         }
  591 
  592         dev = set->crtc->dev;
  593 
  594         /* Allocate space for the backup of all (non-pointer) crtc, encoder and
  595          * connector data. */
  596         save_crtcs = malloc(dev->mode_config.num_crtc *
  597                              sizeof(struct drm_crtc), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
  598         if (!save_crtcs)
  599                 return -ENOMEM;
  600 
  601         save_encoders = malloc(dev->mode_config.num_encoder *
  602                                 sizeof(struct drm_encoder), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
  603         if (!save_encoders) {
  604                 free(save_crtcs, DRM_MEM_KMS);
  605                 return -ENOMEM;
  606         }
  607 
  608         save_connectors = malloc(dev->mode_config.num_connector *
  609                                 sizeof(struct drm_connector), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
  610         if (!save_connectors) {
  611                 free(save_crtcs, DRM_MEM_KMS);
  612                 free(save_encoders, DRM_MEM_KMS);
  613                 return -ENOMEM;
  614         }
  615 
  616         /* Copy data. Note that driver private data is not affected.
  617          * Should anything bad happen only the expected state is
  618          * restored, not the drivers personal bookkeeping.
  619          */
  620         count = 0;
  621         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  622                 save_crtcs[count++] = *crtc;
  623         }
  624 
  625         count = 0;
  626         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  627                 save_encoders[count++] = *encoder;
  628         }
  629 
  630         count = 0;
  631         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  632                 save_connectors[count++] = *connector;
  633         }
  634 
  635         save_set.crtc = set->crtc;
  636         save_set.mode = &set->crtc->mode;
  637         save_set.x = set->crtc->x;
  638         save_set.y = set->crtc->y;
  639         save_set.fb = set->crtc->fb;
  640 
  641         /* We should be able to check here if the fb has the same properties
  642          * and then just flip_or_move it */
  643         if (set->crtc->fb != set->fb) {
  644                 /* If we have no fb then treat it as a full mode set */
  645                 if (set->crtc->fb == NULL) {
  646                         DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
  647                         mode_changed = true;
  648                 } else if (set->fb == NULL) {
  649                         mode_changed = true;
  650                 } else if (set->fb->depth != set->crtc->fb->depth) {
  651                         mode_changed = true;
  652                 } else if (set->fb->bits_per_pixel !=
  653                            set->crtc->fb->bits_per_pixel) {
  654                         mode_changed = true;
  655                 } else
  656                         fb_changed = true;
  657         }
  658 
  659         if (set->x != set->crtc->x || set->y != set->crtc->y)
  660                 fb_changed = true;
  661 
  662         if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
  663                 DRM_DEBUG_KMS("modes are different, full mode set\n");
  664                 drm_mode_debug_printmodeline(&set->crtc->mode);
  665                 drm_mode_debug_printmodeline(set->mode);
  666                 mode_changed = true;
  667         }
  668 
  669         /* a) traverse passed in connector list and get encoders for them */
  670         count = 0;
  671         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  672                 struct drm_connector_helper_funcs *connector_funcs =
  673                         connector->helper_private;
  674                 new_encoder = connector->encoder;
  675                 for (ro = 0; ro < set->num_connectors; ro++) {
  676                         if (set->connectors[ro] == connector) {
  677                                 new_encoder = connector_funcs->best_encoder(connector);
  678                                 /* if we can't get an encoder for a connector
  679                                    we are setting now - then fail */
  680                                 if (new_encoder == NULL)
  681                                         /* don't break so fail path works correct */
  682                                         fail = 1;
  683                                 break;
  684                         }
  685                 }
  686 
  687                 if (new_encoder != connector->encoder) {
  688                         DRM_DEBUG_KMS("encoder changed, full mode switch\n");
  689                         mode_changed = true;
  690                         /* If the encoder is reused for another connector, then
  691                          * the appropriate crtc will be set later.
  692                          */
  693                         if (connector->encoder)
  694                                 connector->encoder->crtc = NULL;
  695                         connector->encoder = new_encoder;
  696                 }
  697         }
  698 
  699         if (fail) {
  700                 ret = -EINVAL;
  701                 goto fail;
  702         }
  703 
  704         count = 0;
  705         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  706                 if (!connector->encoder)
  707                         continue;
  708 
  709                 if (connector->encoder->crtc == set->crtc)
  710                         new_crtc = NULL;
  711                 else
  712                         new_crtc = connector->encoder->crtc;
  713 
  714                 for (ro = 0; ro < set->num_connectors; ro++) {
  715                         if (set->connectors[ro] == connector)
  716                                 new_crtc = set->crtc;
  717                 }
  718 
  719                 /* Make sure the new CRTC will work with the encoder */
  720                 if (new_crtc &&
  721                     !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
  722                         ret = -EINVAL;
  723                         goto fail;
  724                 }
  725                 if (new_crtc != connector->encoder->crtc) {
  726                         DRM_DEBUG_KMS("crtc changed, full mode switch\n");
  727                         mode_changed = true;
  728                         connector->encoder->crtc = new_crtc;
  729                 }
  730                 if (new_crtc) {
  731                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
  732                                 connector->base.id, drm_get_connector_name(connector),
  733                                 new_crtc->base.id);
  734                 } else {
  735                         DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
  736                                 connector->base.id, drm_get_connector_name(connector));
  737                 }
  738         }
  739 
  740         /* mode_set_base is not a required function */
  741         if (fb_changed && !crtc_funcs->mode_set_base)
  742                 mode_changed = true;
  743 
  744         if (mode_changed) {
  745                 set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
  746                 if (set->crtc->enabled) {
  747                         DRM_DEBUG_KMS("attempting to set mode from"
  748                                         " userspace\n");
  749                         drm_mode_debug_printmodeline(set->mode);
  750                         old_fb = set->crtc->fb;
  751                         set->crtc->fb = set->fb;
  752                         if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
  753                                                       set->x, set->y,
  754                                                       old_fb)) {
  755                                 DRM_ERROR("failed to set mode on [CRTC:%d]\n",
  756                                           set->crtc->base.id);
  757                                 set->crtc->fb = old_fb;
  758                                 ret = -EINVAL;
  759                                 goto fail;
  760                         }
  761                         DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
  762                         for (i = 0; i < set->num_connectors; i++) {
  763                                 DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
  764                                               drm_get_connector_name(set->connectors[i]));
  765                                 set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
  766                         }
  767                 }
  768                 drm_helper_disable_unused_functions(dev);
  769         } else if (fb_changed) {
  770                 set->crtc->x = set->x;
  771                 set->crtc->y = set->y;
  772 
  773                 old_fb = set->crtc->fb;
  774                 if (set->crtc->fb != set->fb)
  775                         set->crtc->fb = set->fb;
  776                 ret = crtc_funcs->mode_set_base(set->crtc,
  777                                                 set->x, set->y, old_fb);
  778                 if (ret != 0) {
  779                         set->crtc->fb = old_fb;
  780                         goto fail;
  781                 }
  782         }
  783 
  784         free(save_connectors, DRM_MEM_KMS);
  785         free(save_encoders, DRM_MEM_KMS);
  786         free(save_crtcs, DRM_MEM_KMS);
  787         return 0;
  788 
  789 fail:
  790         /* Restore all previous data. */
  791         count = 0;
  792         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  793                 *crtc = save_crtcs[count++];
  794         }
  795 
  796         count = 0;
  797         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  798                 *encoder = save_encoders[count++];
  799         }
  800 
  801         count = 0;
  802         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  803                 *connector = save_connectors[count++];
  804         }
  805 
  806         /* Try to restore the config */
  807         if (mode_changed &&
  808             !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
  809                                       save_set.y, save_set.fb))
  810                 DRM_ERROR("failed to restore config after modeset failure\n");
  811 
  812         free(save_connectors, DRM_MEM_KMS);
  813         free(save_encoders, DRM_MEM_KMS);
  814         free(save_crtcs, DRM_MEM_KMS);
  815         return ret;
  816 }
  817 EXPORT_SYMBOL(drm_crtc_helper_set_config);
  818 
  819 static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
  820 {
  821         int dpms = DRM_MODE_DPMS_OFF;
  822         struct drm_connector *connector;
  823         struct drm_device *dev = encoder->dev;
  824 
  825         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
  826                 if (connector->encoder == encoder)
  827                         if (connector->dpms < dpms)
  828                                 dpms = connector->dpms;
  829         return dpms;
  830 }
  831 
  832 static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
  833 {
  834         int dpms = DRM_MODE_DPMS_OFF;
  835         struct drm_connector *connector;
  836         struct drm_device *dev = crtc->dev;
  837 
  838         list_for_each_entry(connector, &dev->mode_config.connector_list, head)
  839                 if (connector->encoder && connector->encoder->crtc == crtc)
  840                         if (connector->dpms < dpms)
  841                                 dpms = connector->dpms;
  842         return dpms;
  843 }
  844 
  845 /**
  846  * drm_helper_connector_dpms() - connector dpms helper implementation
  847  * @connector: affected connector
  848  * @mode: DPMS mode
  849  *
  850  * This is the main helper function provided by the crtc helper framework for
  851  * implementing the DPMS connector attribute. It computes the new desired DPMS
  852  * state for all encoders and crtcs in the output mesh and calls the ->dpms()
  853  * callback provided by the driver appropriately.
  854  */
  855 void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
  856 {
  857         struct drm_encoder *encoder = connector->encoder;
  858         struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
  859         int old_dpms;
  860 
  861         if (mode == connector->dpms)
  862                 return;
  863 
  864         old_dpms = connector->dpms;
  865         connector->dpms = mode;
  866 
  867         /* from off to on, do crtc then encoder */
  868         if (mode < old_dpms) {
  869                 if (crtc) {
  870                         struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
  871                         if (crtc_funcs->dpms)
  872                                 (*crtc_funcs->dpms) (crtc,
  873                                                      drm_helper_choose_crtc_dpms(crtc));
  874                 }
  875                 if (encoder) {
  876                         struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
  877                         if (encoder_funcs->dpms)
  878                                 (*encoder_funcs->dpms) (encoder,
  879                                                         drm_helper_choose_encoder_dpms(encoder));
  880                 }
  881         }
  882 
  883         /* from on to off, do encoder then crtc */
  884         if (mode > old_dpms) {
  885                 if (encoder) {
  886                         struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
  887                         if (encoder_funcs->dpms)
  888                                 (*encoder_funcs->dpms) (encoder,
  889                                                         drm_helper_choose_encoder_dpms(encoder));
  890                 }
  891                 if (crtc) {
  892                         struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
  893                         if (crtc_funcs->dpms)
  894                                 (*crtc_funcs->dpms) (crtc,
  895                                                      drm_helper_choose_crtc_dpms(crtc));
  896                 }
  897         }
  898 
  899         return;
  900 }
  901 EXPORT_SYMBOL(drm_helper_connector_dpms);
  902 
  903 int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
  904                                    struct drm_mode_fb_cmd2 *mode_cmd)
  905 {
  906         int i;
  907 
  908         fb->width = mode_cmd->width;
  909         fb->height = mode_cmd->height;
  910         for (i = 0; i < 4; i++) {
  911                 fb->pitches[i] = mode_cmd->pitches[i];
  912                 fb->offsets[i] = mode_cmd->offsets[i];
  913         }
  914         drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
  915                                     &fb->bits_per_pixel);
  916         fb->pixel_format = mode_cmd->pixel_format;
  917 
  918         return 0;
  919 }
  920 EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
  921 
  922 int drm_helper_resume_force_mode(struct drm_device *dev)
  923 {
  924         struct drm_crtc *crtc;
  925         struct drm_encoder *encoder;
  926         struct drm_encoder_helper_funcs *encoder_funcs;
  927         struct drm_crtc_helper_funcs *crtc_funcs;
  928         int ret;
  929 
  930         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
  931 
  932                 if (!crtc->enabled)
  933                         continue;
  934 
  935                 ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
  936                                                crtc->x, crtc->y, crtc->fb);
  937 
  938                 if (ret == false)
  939                         DRM_ERROR("failed to set mode on crtc %p\n", crtc);
  940 
  941                 /* Turn off outputs that were already powered off */
  942                 if (drm_helper_choose_crtc_dpms(crtc)) {
  943                         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
  944 
  945                                 if(encoder->crtc != crtc)
  946                                         continue;
  947 
  948                                 encoder_funcs = encoder->helper_private;
  949                                 if (encoder_funcs->dpms)
  950                                         (*encoder_funcs->dpms) (encoder,
  951                                                                 drm_helper_choose_encoder_dpms(encoder));
  952                         }
  953 
  954                         crtc_funcs = crtc->helper_private;
  955                         if (crtc_funcs->dpms)
  956                                 (*crtc_funcs->dpms) (crtc,
  957                                                      drm_helper_choose_crtc_dpms(crtc));
  958                 }
  959         }
  960         /* disable the unused connectors while restoring the modesetting */
  961         drm_helper_disable_unused_functions(dev);
  962         return 0;
  963 }
  964 EXPORT_SYMBOL(drm_helper_resume_force_mode);
  965 
  966 void drm_kms_helper_hotplug_event(struct drm_device *dev)
  967 {
  968         /* send a uevent + call fbdev */
  969 #ifdef FREEBSD_NOTYET
  970         drm_sysfs_hotplug_event(dev);
  971 #endif /* FREEBSD_NOTYET */
  972         if (dev->mode_config.funcs->output_poll_changed)
  973                 dev->mode_config.funcs->output_poll_changed(dev);
  974 }
  975 EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
  976 
  977 #define DRM_OUTPUT_POLL_PERIOD (10*HZ)
  978 static void output_poll_execute(void *ctx, int pending)
  979 {
  980         struct drm_device *dev = ctx;
  981         struct drm_connector *connector;
  982         enum drm_connector_status old_status;
  983         bool repoll = false, changed = false;
  984 
  985         if (!drm_kms_helper_poll)
  986                 return;
  987 
  988         sx_xlock(&dev->mode_config.mutex);
  989         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  990 
  991                 /* Ignore forced connectors. */
  992                 if (connector->force)
  993                         continue;
  994 
  995                 /* Ignore HPD capable connectors and connectors where we don't
  996                  * want any hotplug detection at all for polling. */
  997                 if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
  998                         continue;
  999 
 1000                 repoll = true;
 1001 
 1002                 old_status = connector->status;
 1003                 /* if we are connected and don't want to poll for disconnect
 1004                    skip it */
 1005                 if (old_status == connector_status_connected &&
 1006                     !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
 1007                         continue;
 1008 
 1009                 connector->status = connector->funcs->detect(connector, false);
 1010                 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
 1011                               connector->base.id,
 1012                               drm_get_connector_name(connector),
 1013                               old_status, connector->status);
 1014                 if (old_status != connector->status)
 1015                         changed = true;
 1016         }
 1017 
 1018         sx_xunlock(&dev->mode_config.mutex);
 1019 
 1020         if (changed)
 1021                 drm_kms_helper_hotplug_event(dev);
 1022 
 1023         if (repoll)
 1024                 taskqueue_enqueue_timeout(taskqueue_thread,
 1025                     &dev->mode_config.output_poll_work,
 1026                     DRM_OUTPUT_POLL_PERIOD);
 1027 }
 1028 
 1029 void drm_kms_helper_poll_disable(struct drm_device *dev)
 1030 {
 1031         if (!dev->mode_config.poll_enabled)
 1032                 return;
 1033         taskqueue_cancel_timeout(taskqueue_thread,
 1034             &dev->mode_config.output_poll_work, NULL);
 1035 }
 1036 EXPORT_SYMBOL(drm_kms_helper_poll_disable);
 1037 
 1038 void drm_kms_helper_poll_enable(struct drm_device *dev)
 1039 {
 1040         bool poll = false;
 1041         struct drm_connector *connector;
 1042 
 1043         if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
 1044                 return;
 1045 
 1046         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 1047                 if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
 1048                                          DRM_CONNECTOR_POLL_DISCONNECT))
 1049                         poll = true;
 1050         }
 1051 
 1052         if (poll)
 1053                 taskqueue_enqueue_timeout(taskqueue_thread,
 1054                     &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
 1055 }
 1056 EXPORT_SYMBOL(drm_kms_helper_poll_enable);
 1057 
 1058 void drm_kms_helper_poll_init(struct drm_device *dev)
 1059 {
 1060         TIMEOUT_TASK_INIT(taskqueue_thread, &dev->mode_config.output_poll_work,
 1061             0, output_poll_execute, dev);
 1062         dev->mode_config.poll_enabled = true;
 1063 
 1064         drm_kms_helper_poll_enable(dev);
 1065 }
 1066 EXPORT_SYMBOL(drm_kms_helper_poll_init);
 1067 
 1068 void drm_kms_helper_poll_fini(struct drm_device *dev)
 1069 {
 1070         drm_kms_helper_poll_disable(dev);
 1071 }
 1072 EXPORT_SYMBOL(drm_kms_helper_poll_fini);
 1073 
 1074 void drm_helper_hpd_irq_event(struct drm_device *dev)
 1075 {
 1076         struct drm_connector *connector;
 1077         enum drm_connector_status old_status;
 1078         bool changed = false;
 1079 
 1080         if (!dev->mode_config.poll_enabled)
 1081                 return;
 1082 
 1083         sx_xlock(&dev->mode_config.mutex);
 1084         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 1085 
 1086                 /* Only handle HPD capable connectors. */
 1087                 if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
 1088                         continue;
 1089 
 1090                 old_status = connector->status;
 1091 
 1092                 connector->status = connector->funcs->detect(connector, false);
 1093                 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
 1094                               connector->base.id,
 1095                               drm_get_connector_name(connector),
 1096                               old_status, connector->status);
 1097                 if (old_status != connector->status)
 1098                         changed = true;
 1099         }
 1100 
 1101         sx_xunlock(&dev->mode_config.mutex);
 1102 
 1103         if (changed)
 1104                 drm_kms_helper_hotplug_event(dev);
 1105 }
 1106 EXPORT_SYMBOL(drm_helper_hpd_irq_event);

Cache object: 77667406c902f8b070a7c0b5bceb19bf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.