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

          Line data    Source code
       1             : // SPDX-License-Identifier: MIT
       2             : /*
       3             :  * Copyright 2018 Noralf Trønnes
       4             :  * Copyright (c) 2006-2009 Red Hat Inc.
       5             :  * Copyright (c) 2006-2008 Intel Corporation
       6             :  *   Jesse Barnes <jesse.barnes@intel.com>
       7             :  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
       8             :  */
       9             : 
      10             : #include "drm/drm_modeset_lock.h"
      11             : #include <linux/module.h>
      12             : #include <linux/mutex.h>
      13             : #include <linux/slab.h>
      14             : #include <linux/string_helpers.h>
      15             : 
      16             : #include <drm/drm_atomic.h>
      17             : #include <drm/drm_client.h>
      18             : #include <drm/drm_connector.h>
      19             : #include <drm/drm_crtc.h>
      20             : #include <drm/drm_device.h>
      21             : #include <drm/drm_drv.h>
      22             : #include <drm/drm_encoder.h>
      23             : #include <drm/drm_print.h>
      24             : 
      25             : #include "drm_crtc_internal.h"
      26             : #include "drm_internal.h"
      27             : 
      28             : #define DRM_CLIENT_MAX_CLONED_CONNECTORS        8
      29             : 
      30             : struct drm_client_offset {
      31             :         int x, y;
      32             : };
      33             : 
      34           0 : int drm_client_modeset_create(struct drm_client_dev *client)
      35             : {
      36           0 :         struct drm_device *dev = client->dev;
      37           0 :         unsigned int num_crtc = dev->mode_config.num_crtc;
      38           0 :         unsigned int max_connector_count = 1;
      39             :         struct drm_mode_set *modeset;
      40             :         struct drm_crtc *crtc;
      41           0 :         unsigned int i = 0;
      42             : 
      43             :         /* Add terminating zero entry to enable index less iteration */
      44           0 :         client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
      45           0 :         if (!client->modesets)
      46             :                 return -ENOMEM;
      47             : 
      48           0 :         mutex_init(&client->modeset_mutex);
      49             : 
      50           0 :         drm_for_each_crtc(crtc, dev)
      51           0 :                 client->modesets[i++].crtc = crtc;
      52             : 
      53             :         /* Cloning is only supported in the single crtc case. */
      54           0 :         if (num_crtc == 1)
      55           0 :                 max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
      56             : 
      57           0 :         for (modeset = client->modesets; modeset->crtc; modeset++) {
      58           0 :                 modeset->connectors = kcalloc(max_connector_count,
      59             :                                               sizeof(*modeset->connectors), GFP_KERNEL);
      60           0 :                 if (!modeset->connectors)
      61             :                         goto err_free;
      62             :         }
      63             : 
      64             :         return 0;
      65             : 
      66             : err_free:
      67           0 :         drm_client_modeset_free(client);
      68             : 
      69           0 :         return -ENOMEM;
      70             : }
      71             : 
      72           0 : static void drm_client_modeset_release(struct drm_client_dev *client)
      73             : {
      74             :         struct drm_mode_set *modeset;
      75             :         unsigned int i;
      76             : 
      77           0 :         drm_client_for_each_modeset(modeset, client) {
      78           0 :                 drm_mode_destroy(client->dev, modeset->mode);
      79           0 :                 modeset->mode = NULL;
      80           0 :                 modeset->fb = NULL;
      81             : 
      82           0 :                 for (i = 0; i < modeset->num_connectors; i++) {
      83           0 :                         drm_connector_put(modeset->connectors[i]);
      84           0 :                         modeset->connectors[i] = NULL;
      85             :                 }
      86           0 :                 modeset->num_connectors = 0;
      87             :         }
      88           0 : }
      89             : 
      90           0 : void drm_client_modeset_free(struct drm_client_dev *client)
      91             : {
      92             :         struct drm_mode_set *modeset;
      93             : 
      94           0 :         mutex_lock(&client->modeset_mutex);
      95             : 
      96           0 :         drm_client_modeset_release(client);
      97             : 
      98           0 :         drm_client_for_each_modeset(modeset, client)
      99           0 :                 kfree(modeset->connectors);
     100             : 
     101           0 :         mutex_unlock(&client->modeset_mutex);
     102             : 
     103           0 :         mutex_destroy(&client->modeset_mutex);
     104           0 :         kfree(client->modesets);
     105           0 : }
     106             : 
     107             : static struct drm_mode_set *
     108             : drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
     109             : {
     110             :         struct drm_mode_set *modeset;
     111             : 
     112           0 :         drm_client_for_each_modeset(modeset, client)
     113           0 :                 if (modeset->crtc == crtc)
     114             :                         return modeset;
     115             : 
     116             :         return NULL;
     117             : }
     118             : 
     119             : static struct drm_display_mode *
     120             : drm_connector_get_tiled_mode(struct drm_connector *connector)
     121             : {
     122             :         struct drm_display_mode *mode;
     123             : 
     124           0 :         list_for_each_entry(mode, &connector->modes, head) {
     125           0 :                 if (mode->hdisplay == connector->tile_h_size &&
     126           0 :                     mode->vdisplay == connector->tile_v_size)
     127             :                         return mode;
     128             :         }
     129             :         return NULL;
     130             : }
     131             : 
     132             : static struct drm_display_mode *
     133             : drm_connector_fallback_non_tiled_mode(struct drm_connector *connector)
     134             : {
     135             :         struct drm_display_mode *mode;
     136             : 
     137           0 :         list_for_each_entry(mode, &connector->modes, head) {
     138           0 :                 if (mode->hdisplay == connector->tile_h_size &&
     139           0 :                     mode->vdisplay == connector->tile_v_size)
     140           0 :                         continue;
     141             :                 return mode;
     142             :         }
     143             :         return NULL;
     144             : }
     145             : 
     146             : static struct drm_display_mode *
     147             : drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
     148             : {
     149             :         struct drm_display_mode *mode;
     150             : 
     151           0 :         list_for_each_entry(mode, &connector->modes, head) {
     152           0 :                 if (mode->hdisplay > width ||
     153           0 :                     mode->vdisplay > height)
     154           0 :                         continue;
     155           0 :                 if (mode->type & DRM_MODE_TYPE_PREFERRED)
     156             :                         return mode;
     157             :         }
     158             :         return NULL;
     159             : }
     160             : 
     161             : static struct drm_display_mode *
     162           0 : drm_connector_pick_cmdline_mode(struct drm_connector *connector)
     163             : {
     164             :         struct drm_cmdline_mode *cmdline_mode;
     165             :         struct drm_display_mode *mode;
     166             :         bool prefer_non_interlace;
     167             : 
     168           0 :         cmdline_mode = &connector->cmdline_mode;
     169           0 :         if (cmdline_mode->specified == false)
     170             :                 return NULL;
     171             : 
     172             :         /* attempt to find a matching mode in the list of modes
     173             :          *  we have gotten so far, if not add a CVT mode that conforms
     174             :          */
     175           0 :         if (cmdline_mode->rb || cmdline_mode->margins)
     176             :                 goto create_mode;
     177             : 
     178           0 :         prefer_non_interlace = !cmdline_mode->interlace;
     179             : again:
     180           0 :         list_for_each_entry(mode, &connector->modes, head) {
     181             :                 /* Check (optional) mode name first */
     182           0 :                 if (!strcmp(mode->name, cmdline_mode->name))
     183             :                         return mode;
     184             : 
     185             :                 /* check width/height */
     186           0 :                 if (mode->hdisplay != cmdline_mode->xres ||
     187           0 :                     mode->vdisplay != cmdline_mode->yres)
     188           0 :                         continue;
     189             : 
     190           0 :                 if (cmdline_mode->refresh_specified) {
     191           0 :                         if (drm_mode_vrefresh(mode) != cmdline_mode->refresh)
     192           0 :                                 continue;
     193             :                 }
     194             : 
     195           0 :                 if (cmdline_mode->interlace) {
     196           0 :                         if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
     197           0 :                                 continue;
     198           0 :                 } else if (prefer_non_interlace) {
     199           0 :                         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
     200           0 :                                 continue;
     201             :                 }
     202             :                 return mode;
     203             :         }
     204             : 
     205           0 :         if (prefer_non_interlace) {
     206             :                 prefer_non_interlace = false;
     207             :                 goto again;
     208             :         }
     209             : 
     210             : create_mode:
     211           0 :         mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
     212           0 :         if (mode)
     213           0 :                 list_add(&mode->head, &connector->modes);
     214             : 
     215             :         return mode;
     216             : }
     217             : 
     218             : static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
     219             : {
     220             :         bool enable;
     221             : 
     222           0 :         if (connector->display_info.non_desktop)
     223             :                 return false;
     224             : 
     225             :         if (strict)
     226           0 :                 enable = connector->status == connector_status_connected;
     227             :         else
     228           0 :                 enable = connector->status != connector_status_disconnected;
     229             : 
     230             :         return enable;
     231             : }
     232             : 
     233           0 : static void drm_client_connectors_enabled(struct drm_connector **connectors,
     234             :                                           unsigned int connector_count,
     235             :                                           bool *enabled)
     236             : {
     237           0 :         bool any_enabled = false;
     238             :         struct drm_connector *connector;
     239           0 :         int i = 0;
     240             : 
     241           0 :         for (i = 0; i < connector_count; i++) {
     242           0 :                 connector = connectors[i];
     243           0 :                 enabled[i] = drm_connector_enabled(connector, true);
     244           0 :                 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
     245             :                               connector->display_info.non_desktop ? "non desktop" : str_yes_no(enabled[i]));
     246             : 
     247           0 :                 any_enabled |= enabled[i];
     248             :         }
     249             : 
     250           0 :         if (any_enabled)
     251             :                 return;
     252             : 
     253           0 :         for (i = 0; i < connector_count; i++)
     254           0 :                 enabled[i] = drm_connector_enabled(connectors[i], false);
     255             : }
     256             : 
     257           0 : static bool drm_client_target_cloned(struct drm_device *dev,
     258             :                                      struct drm_connector **connectors,
     259             :                                      unsigned int connector_count,
     260             :                                      struct drm_display_mode **modes,
     261             :                                      struct drm_client_offset *offsets,
     262             :                                      bool *enabled, int width, int height)
     263             : {
     264             :         int count, i, j;
     265           0 :         bool can_clone = false;
     266             :         struct drm_display_mode *dmt_mode, *mode;
     267             : 
     268             :         /* only contemplate cloning in the single crtc case */
     269           0 :         if (dev->mode_config.num_crtc > 1)
     270             :                 return false;
     271             : 
     272             :         count = 0;
     273           0 :         for (i = 0; i < connector_count; i++) {
     274           0 :                 if (enabled[i])
     275           0 :                         count++;
     276             :         }
     277             : 
     278             :         /* only contemplate cloning if more than one connector is enabled */
     279           0 :         if (count <= 1)
     280             :                 return false;
     281             : 
     282             :         /* check the command line or if nothing common pick 1024x768 */
     283             :         can_clone = true;
     284           0 :         for (i = 0; i < connector_count; i++) {
     285           0 :                 if (!enabled[i])
     286           0 :                         continue;
     287           0 :                 modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
     288           0 :                 if (!modes[i]) {
     289             :                         can_clone = false;
     290             :                         break;
     291             :                 }
     292           0 :                 for (j = 0; j < i; j++) {
     293           0 :                         if (!enabled[j])
     294           0 :                                 continue;
     295           0 :                         if (!drm_mode_match(modes[j], modes[i],
     296             :                                             DRM_MODE_MATCH_TIMINGS |
     297             :                                             DRM_MODE_MATCH_CLOCK |
     298             :                                             DRM_MODE_MATCH_FLAGS |
     299             :                                             DRM_MODE_MATCH_3D_FLAGS))
     300           0 :                                 can_clone = false;
     301             :                 }
     302             :         }
     303             : 
     304           0 :         if (can_clone) {
     305           0 :                 DRM_DEBUG_KMS("can clone using command line\n");
     306             :                 return true;
     307             :         }
     308             : 
     309             :         /* try and find a 1024x768 mode on each connector */
     310           0 :         can_clone = true;
     311           0 :         dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
     312             : 
     313           0 :         for (i = 0; i < connector_count; i++) {
     314           0 :                 if (!enabled[i])
     315           0 :                         continue;
     316             : 
     317           0 :                 list_for_each_entry(mode, &connectors[i]->modes, head) {
     318           0 :                         if (drm_mode_match(mode, dmt_mode,
     319             :                                            DRM_MODE_MATCH_TIMINGS |
     320             :                                            DRM_MODE_MATCH_CLOCK |
     321             :                                            DRM_MODE_MATCH_FLAGS |
     322             :                                            DRM_MODE_MATCH_3D_FLAGS))
     323           0 :                                 modes[i] = mode;
     324             :                 }
     325           0 :                 if (!modes[i])
     326           0 :                         can_clone = false;
     327             :         }
     328             : 
     329           0 :         if (can_clone) {
     330           0 :                 DRM_DEBUG_KMS("can clone using 1024x768\n");
     331             :                 return true;
     332             :         }
     333           0 :         DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
     334             :         return false;
     335             : }
     336             : 
     337           0 : static int drm_client_get_tile_offsets(struct drm_connector **connectors,
     338             :                                        unsigned int connector_count,
     339             :                                        struct drm_display_mode **modes,
     340             :                                        struct drm_client_offset *offsets,
     341             :                                        int idx,
     342             :                                        int h_idx, int v_idx)
     343             : {
     344             :         struct drm_connector *connector;
     345             :         int i;
     346           0 :         int hoffset = 0, voffset = 0;
     347             : 
     348           0 :         for (i = 0; i < connector_count; i++) {
     349           0 :                 connector = connectors[i];
     350           0 :                 if (!connector->has_tile)
     351           0 :                         continue;
     352             : 
     353           0 :                 if (!modes[i] && (h_idx || v_idx)) {
     354           0 :                         DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
     355             :                                       connector->base.id);
     356           0 :                         continue;
     357             :                 }
     358           0 :                 if (connector->tile_h_loc < h_idx)
     359           0 :                         hoffset += modes[i]->hdisplay;
     360             : 
     361           0 :                 if (connector->tile_v_loc < v_idx)
     362           0 :                         voffset += modes[i]->vdisplay;
     363             :         }
     364           0 :         offsets[idx].x = hoffset;
     365           0 :         offsets[idx].y = voffset;
     366           0 :         DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
     367           0 :         return 0;
     368             : }
     369             : 
     370           0 : static bool drm_client_target_preferred(struct drm_connector **connectors,
     371             :                                         unsigned int connector_count,
     372             :                                         struct drm_display_mode **modes,
     373             :                                         struct drm_client_offset *offsets,
     374             :                                         bool *enabled, int width, int height)
     375             : {
     376           0 :         const u64 mask = BIT_ULL(connector_count) - 1;
     377             :         struct drm_connector *connector;
     378           0 :         u64 conn_configured = 0;
     379           0 :         int tile_pass = 0;
     380           0 :         int num_tiled_conns = 0;
     381             :         int i;
     382             : 
     383           0 :         for (i = 0; i < connector_count; i++) {
     384           0 :                 if (connectors[i]->has_tile &&
     385           0 :                     connectors[i]->status == connector_status_connected)
     386           0 :                         num_tiled_conns++;
     387             :         }
     388             : 
     389             : retry:
     390           0 :         for (i = 0; i < connector_count; i++) {
     391           0 :                 connector = connectors[i];
     392             : 
     393           0 :                 if (conn_configured & BIT_ULL(i))
     394           0 :                         continue;
     395             : 
     396           0 :                 if (enabled[i] == false) {
     397           0 :                         conn_configured |= BIT_ULL(i);
     398           0 :                         continue;
     399             :                 }
     400             : 
     401             :                 /* first pass over all the untiled connectors */
     402           0 :                 if (tile_pass == 0 && connector->has_tile)
     403           0 :                         continue;
     404             : 
     405           0 :                 if (tile_pass == 1) {
     406           0 :                         if (connector->tile_h_loc != 0 ||
     407             :                             connector->tile_v_loc != 0)
     408           0 :                                 continue;
     409             : 
     410             :                 } else {
     411           0 :                         if (connector->tile_h_loc != tile_pass - 1 &&
     412           0 :                             connector->tile_v_loc != tile_pass - 1)
     413             :                         /* if this tile_pass doesn't cover any of the tiles - keep going */
     414           0 :                                 continue;
     415             : 
     416             :                         /*
     417             :                          * find the tile offsets for this pass - need to find
     418             :                          * all tiles left and above
     419             :                          */
     420           0 :                         drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
     421           0 :                                                     connector->tile_h_loc, connector->tile_v_loc);
     422             :                 }
     423           0 :                 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
     424             :                               connector->base.id);
     425             : 
     426             :                 /* got for command line mode first */
     427           0 :                 modes[i] = drm_connector_pick_cmdline_mode(connector);
     428           0 :                 if (!modes[i]) {
     429           0 :                         DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
     430             :                                       connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
     431           0 :                         modes[i] = drm_connector_has_preferred_mode(connector, width, height);
     432             :                 }
     433             :                 /* No preferred modes, pick one off the list */
     434           0 :                 if (!modes[i] && !list_empty(&connector->modes)) {
     435           0 :                         list_for_each_entry(modes[i], &connector->modes, head)
     436             :                                 break;
     437             :                 }
     438             :                 /*
     439             :                  * In case of tiled mode if all tiles not present fallback to
     440             :                  * first available non tiled mode.
     441             :                  * After all tiles are present, try to find the tiled mode
     442             :                  * for all and if tiled mode not present due to fbcon size
     443             :                  * limitations, use first non tiled mode only for
     444             :                  * tile 0,0 and set to no mode for all other tiles.
     445             :                  */
     446           0 :                 if (connector->has_tile) {
     447           0 :                         if (num_tiled_conns <
     448           0 :                             connector->num_h_tile * connector->num_v_tile ||
     449           0 :                             (connector->tile_h_loc == 0 &&
     450           0 :                              connector->tile_v_loc == 0 &&
     451           0 :                              !drm_connector_get_tiled_mode(connector))) {
     452           0 :                                 DRM_DEBUG_KMS("Falling back to non tiled mode on Connector %d\n",
     453             :                                               connector->base.id);
     454           0 :                                 modes[i] = drm_connector_fallback_non_tiled_mode(connector);
     455             :                         } else {
     456           0 :                                 modes[i] = drm_connector_get_tiled_mode(connector);
     457             :                         }
     458             :                 }
     459             : 
     460           0 :                 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
     461             :                           "none");
     462           0 :                 conn_configured |= BIT_ULL(i);
     463             :         }
     464             : 
     465           0 :         if ((conn_configured & mask) != mask) {
     466           0 :                 tile_pass++;
     467           0 :                 goto retry;
     468             :         }
     469           0 :         return true;
     470             : }
     471             : 
     472             : static bool connector_has_possible_crtc(struct drm_connector *connector,
     473             :                                         struct drm_crtc *crtc)
     474             : {
     475             :         struct drm_encoder *encoder;
     476             : 
     477           0 :         drm_connector_for_each_possible_encoder(connector, encoder) {
     478           0 :                 if (encoder->possible_crtcs & drm_crtc_mask(crtc))
     479             :                         return true;
     480             :         }
     481             : 
     482             :         return false;
     483             : }
     484             : 
     485           0 : static int drm_client_pick_crtcs(struct drm_client_dev *client,
     486             :                                  struct drm_connector **connectors,
     487             :                                  unsigned int connector_count,
     488             :                                  struct drm_crtc **best_crtcs,
     489             :                                  struct drm_display_mode **modes,
     490             :                                  int n, int width, int height)
     491             : {
     492           0 :         struct drm_device *dev = client->dev;
     493             :         struct drm_connector *connector;
     494             :         int my_score, best_score, score;
     495             :         struct drm_crtc **crtcs, *crtc;
     496             :         struct drm_mode_set *modeset;
     497             :         int o;
     498             : 
     499           0 :         if (n == connector_count)
     500             :                 return 0;
     501             : 
     502           0 :         connector = connectors[n];
     503             : 
     504           0 :         best_crtcs[n] = NULL;
     505           0 :         best_score = drm_client_pick_crtcs(client, connectors, connector_count,
     506             :                                            best_crtcs, modes, n + 1, width, height);
     507           0 :         if (modes[n] == NULL)
     508             :                 return best_score;
     509             : 
     510           0 :         crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
     511           0 :         if (!crtcs)
     512             :                 return best_score;
     513             : 
     514           0 :         my_score = 1;
     515           0 :         if (connector->status == connector_status_connected)
     516           0 :                 my_score++;
     517           0 :         if (connector->cmdline_mode.specified)
     518           0 :                 my_score++;
     519           0 :         if (drm_connector_has_preferred_mode(connector, width, height))
     520           0 :                 my_score++;
     521             : 
     522             :         /*
     523             :          * select a crtc for this connector and then attempt to configure
     524             :          * remaining connectors
     525             :          */
     526           0 :         drm_client_for_each_modeset(modeset, client) {
     527           0 :                 crtc = modeset->crtc;
     528             : 
     529           0 :                 if (!connector_has_possible_crtc(connector, crtc))
     530           0 :                         continue;
     531             : 
     532           0 :                 for (o = 0; o < n; o++)
     533           0 :                         if (best_crtcs[o] == crtc)
     534             :                                 break;
     535             : 
     536           0 :                 if (o < n) {
     537             :                         /* ignore cloning unless only a single crtc */
     538           0 :                         if (dev->mode_config.num_crtc > 1)
     539           0 :                                 continue;
     540             : 
     541           0 :                         if (!drm_mode_equal(modes[o], modes[n]))
     542           0 :                                 continue;
     543             :                 }
     544             : 
     545           0 :                 crtcs[n] = crtc;
     546           0 :                 memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
     547           0 :                 score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
     548             :                                                          crtcs, modes, n + 1, width, height);
     549           0 :                 if (score > best_score) {
     550           0 :                         best_score = score;
     551           0 :                         memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
     552             :                 }
     553             :         }
     554             : 
     555           0 :         kfree(crtcs);
     556           0 :         return best_score;
     557             : }
     558             : 
     559             : /* Try to read the BIOS display configuration and use it for the initial config */
     560           0 : static bool drm_client_firmware_config(struct drm_client_dev *client,
     561             :                                        struct drm_connector **connectors,
     562             :                                        unsigned int connector_count,
     563             :                                        struct drm_crtc **crtcs,
     564             :                                        struct drm_display_mode **modes,
     565             :                                        struct drm_client_offset *offsets,
     566             :                                        bool *enabled, int width, int height)
     567             : {
     568           0 :         const int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
     569             :         unsigned long conn_configured, conn_seq, mask;
     570           0 :         struct drm_device *dev = client->dev;
     571             :         int i, j;
     572             :         bool *save_enabled;
     573           0 :         bool fallback = true, ret = true;
     574           0 :         int num_connectors_enabled = 0;
     575           0 :         int num_connectors_detected = 0;
     576           0 :         int num_tiled_conns = 0;
     577             :         struct drm_modeset_acquire_ctx ctx;
     578             : 
     579           0 :         if (!drm_drv_uses_atomic_modeset(dev))
     580             :                 return false;
     581             : 
     582           0 :         if (WARN_ON(count <= 0))
     583             :                 return false;
     584             : 
     585           0 :         save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
     586           0 :         if (!save_enabled)
     587             :                 return false;
     588             : 
     589           0 :         drm_modeset_acquire_init(&ctx, 0);
     590             : 
     591           0 :         while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
     592           0 :                 drm_modeset_backoff(&ctx);
     593             : 
     594           0 :         memcpy(save_enabled, enabled, count);
     595           0 :         mask = GENMASK(count - 1, 0);
     596           0 :         conn_configured = 0;
     597           0 :         for (i = 0; i < count; i++) {
     598           0 :                 if (connectors[i]->has_tile &&
     599           0 :                     connectors[i]->status == connector_status_connected)
     600           0 :                         num_tiled_conns++;
     601             :         }
     602             : retry:
     603           0 :         conn_seq = conn_configured;
     604           0 :         for (i = 0; i < count; i++) {
     605             :                 struct drm_connector *connector;
     606             :                 struct drm_encoder *encoder;
     607             :                 struct drm_crtc *new_crtc;
     608             : 
     609           0 :                 connector = connectors[i];
     610             : 
     611           0 :                 if (conn_configured & BIT(i))
     612           0 :                         continue;
     613             : 
     614           0 :                 if (conn_seq == 0 && !connector->has_tile)
     615           0 :                         continue;
     616             : 
     617           0 :                 if (connector->status == connector_status_connected)
     618           0 :                         num_connectors_detected++;
     619             : 
     620           0 :                 if (!enabled[i]) {
     621           0 :                         DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
     622             :                                       connector->name);
     623           0 :                         conn_configured |= BIT(i);
     624           0 :                         continue;
     625             :                 }
     626             : 
     627           0 :                 if (connector->force == DRM_FORCE_OFF) {
     628           0 :                         DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
     629             :                                       connector->name);
     630           0 :                         enabled[i] = false;
     631           0 :                         continue;
     632             :                 }
     633             : 
     634           0 :                 encoder = connector->state->best_encoder;
     635           0 :                 if (!encoder || WARN_ON(!connector->state->crtc)) {
     636           0 :                         if (connector->force > DRM_FORCE_OFF)
     637             :                                 goto bail;
     638             : 
     639           0 :                         DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
     640             :                                       connector->name);
     641           0 :                         enabled[i] = false;
     642           0 :                         conn_configured |= BIT(i);
     643           0 :                         continue;
     644             :                 }
     645             : 
     646           0 :                 num_connectors_enabled++;
     647             : 
     648           0 :                 new_crtc = connector->state->crtc;
     649             : 
     650             :                 /*
     651             :                  * Make sure we're not trying to drive multiple connectors
     652             :                  * with a single CRTC, since our cloning support may not
     653             :                  * match the BIOS.
     654             :                  */
     655           0 :                 for (j = 0; j < count; j++) {
     656           0 :                         if (crtcs[j] == new_crtc) {
     657           0 :                                 DRM_DEBUG_KMS("fallback: cloned configuration\n");
     658             :                                 goto bail;
     659             :                         }
     660             :                 }
     661             : 
     662           0 :                 DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
     663             :                               connector->name);
     664             : 
     665             :                 /* go for command line mode first */
     666           0 :                 modes[i] = drm_connector_pick_cmdline_mode(connector);
     667             : 
     668             :                 /* try for preferred next */
     669           0 :                 if (!modes[i]) {
     670           0 :                         DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
     671             :                                       connector->name, connector->has_tile);
     672           0 :                         modes[i] = drm_connector_has_preferred_mode(connector, width, height);
     673             :                 }
     674             : 
     675             :                 /* No preferred mode marked by the EDID? Are there any modes? */
     676           0 :                 if (!modes[i] && !list_empty(&connector->modes)) {
     677           0 :                         DRM_DEBUG_KMS("using first mode listed on connector %s\n",
     678             :                                       connector->name);
     679           0 :                         modes[i] = list_first_entry(&connector->modes,
     680             :                                                     struct drm_display_mode,
     681             :                                                     head);
     682             :                 }
     683             : 
     684             :                 /* last resort: use current mode */
     685           0 :                 if (!modes[i]) {
     686             :                         /*
     687             :                          * IMPORTANT: We want to use the adjusted mode (i.e.
     688             :                          * after the panel fitter upscaling) as the initial
     689             :                          * config, not the input mode, which is what crtc->mode
     690             :                          * usually contains. But since our current
     691             :                          * code puts a mode derived from the post-pfit timings
     692             :                          * into crtc->mode this works out correctly.
     693             :                          *
     694             :                          * This is crtc->mode and not crtc->state->mode for the
     695             :                          * fastboot check to work correctly.
     696             :                          */
     697           0 :                         DRM_DEBUG_KMS("looking for current mode on connector %s\n",
     698             :                                       connector->name);
     699           0 :                         modes[i] = &connector->state->crtc->mode;
     700             :                 }
     701             :                 /*
     702             :                  * In case of tiled modes, if all tiles are not present
     703             :                  * then fallback to a non tiled mode.
     704             :                  */
     705           0 :                 if (connector->has_tile &&
     706           0 :                     num_tiled_conns < connector->num_h_tile * connector->num_v_tile) {
     707           0 :                         DRM_DEBUG_KMS("Falling back to non tiled mode on Connector %d\n",
     708             :                                       connector->base.id);
     709           0 :                         modes[i] = drm_connector_fallback_non_tiled_mode(connector);
     710             :                 }
     711           0 :                 crtcs[i] = new_crtc;
     712             : 
     713           0 :                 DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
     714             :                               connector->name,
     715             :                               connector->state->crtc->base.id,
     716             :                               connector->state->crtc->name,
     717             :                               modes[i]->hdisplay, modes[i]->vdisplay,
     718             :                               modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
     719             : 
     720           0 :                 fallback = false;
     721           0 :                 conn_configured |= BIT(i);
     722             :         }
     723             : 
     724           0 :         if ((conn_configured & mask) != mask && conn_configured != conn_seq)
     725             :                 goto retry;
     726             : 
     727             :         /*
     728             :          * If the BIOS didn't enable everything it could, fall back to have the
     729             :          * same user experiencing of lighting up as much as possible like the
     730             :          * fbdev helper library.
     731             :          */
     732           0 :         if (num_connectors_enabled != num_connectors_detected &&
     733           0 :             num_connectors_enabled < dev->mode_config.num_crtc) {
     734           0 :                 DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
     735           0 :                 DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
     736             :                               num_connectors_detected);
     737           0 :                 fallback = true;
     738             :         }
     739             : 
     740           0 :         if (fallback) {
     741             : bail:
     742           0 :                 DRM_DEBUG_KMS("Not using firmware configuration\n");
     743           0 :                 memcpy(enabled, save_enabled, count);
     744           0 :                 ret = false;
     745             :         }
     746             : 
     747           0 :         drm_modeset_drop_locks(&ctx);
     748           0 :         drm_modeset_acquire_fini(&ctx);
     749             : 
     750           0 :         kfree(save_enabled);
     751             :         return ret;
     752             : }
     753             : 
     754             : /**
     755             :  * drm_client_modeset_probe() - Probe for displays
     756             :  * @client: DRM client
     757             :  * @width: Maximum display mode width (optional)
     758             :  * @height: Maximum display mode height (optional)
     759             :  *
     760             :  * This function sets up display pipelines for enabled connectors and stores the
     761             :  * config in the client's modeset array.
     762             :  *
     763             :  * Returns:
     764             :  * Zero on success or negative error code on failure.
     765             :  */
     766           0 : int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)
     767             : {
     768           0 :         struct drm_connector *connector, **connectors = NULL;
     769             :         struct drm_connector_list_iter conn_iter;
     770           0 :         struct drm_device *dev = client->dev;
     771           0 :         unsigned int total_modes_count = 0;
     772             :         struct drm_client_offset *offsets;
     773           0 :         unsigned int connector_count = 0;
     774             :         struct drm_display_mode **modes;
     775             :         struct drm_crtc **crtcs;
     776           0 :         int i, ret = 0;
     777             :         bool *enabled;
     778             : 
     779           0 :         DRM_DEBUG_KMS("\n");
     780             : 
     781           0 :         if (!width)
     782           0 :                 width = dev->mode_config.max_width;
     783           0 :         if (!height)
     784           0 :                 height = dev->mode_config.max_height;
     785             : 
     786           0 :         drm_connector_list_iter_begin(dev, &conn_iter);
     787           0 :         drm_client_for_each_connector_iter(connector, &conn_iter) {
     788             :                 struct drm_connector **tmp;
     789             : 
     790           0 :                 tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
     791           0 :                 if (!tmp) {
     792             :                         ret = -ENOMEM;
     793             :                         goto free_connectors;
     794             :                 }
     795             : 
     796           0 :                 connectors = tmp;
     797           0 :                 drm_connector_get(connector);
     798           0 :                 connectors[connector_count++] = connector;
     799             :         }
     800           0 :         drm_connector_list_iter_end(&conn_iter);
     801             : 
     802           0 :         if (!connector_count)
     803             :                 return 0;
     804             : 
     805           0 :         crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
     806           0 :         modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
     807           0 :         offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
     808           0 :         enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
     809           0 :         if (!crtcs || !modes || !enabled || !offsets) {
     810           0 :                 DRM_ERROR("Memory allocation failed\n");
     811           0 :                 ret = -ENOMEM;
     812           0 :                 goto out;
     813             :         }
     814             : 
     815           0 :         mutex_lock(&client->modeset_mutex);
     816             : 
     817           0 :         mutex_lock(&dev->mode_config.mutex);
     818           0 :         for (i = 0; i < connector_count; i++)
     819           0 :                 total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
     820           0 :         if (!total_modes_count)
     821           0 :                 DRM_DEBUG_KMS("No connectors reported connected with modes\n");
     822           0 :         drm_client_connectors_enabled(connectors, connector_count, enabled);
     823             : 
     824           0 :         if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
     825             :                                         modes, offsets, enabled, width, height)) {
     826           0 :                 memset(modes, 0, connector_count * sizeof(*modes));
     827           0 :                 memset(crtcs, 0, connector_count * sizeof(*crtcs));
     828           0 :                 memset(offsets, 0, connector_count * sizeof(*offsets));
     829             : 
     830           0 :                 if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
     831           0 :                                               offsets, enabled, width, height) &&
     832           0 :                     !drm_client_target_preferred(connectors, connector_count, modes,
     833             :                                                  offsets, enabled, width, height))
     834           0 :                         DRM_ERROR("Unable to find initial modes\n");
     835             : 
     836           0 :                 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
     837             :                               width, height);
     838             : 
     839           0 :                 drm_client_pick_crtcs(client, connectors, connector_count,
     840             :                                       crtcs, modes, 0, width, height);
     841             :         }
     842           0 :         mutex_unlock(&dev->mode_config.mutex);
     843             : 
     844           0 :         drm_client_modeset_release(client);
     845             : 
     846           0 :         for (i = 0; i < connector_count; i++) {
     847           0 :                 struct drm_display_mode *mode = modes[i];
     848           0 :                 struct drm_crtc *crtc = crtcs[i];
     849           0 :                 struct drm_client_offset *offset = &offsets[i];
     850             : 
     851           0 :                 if (mode && crtc) {
     852           0 :                         struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
     853           0 :                         struct drm_connector *connector = connectors[i];
     854             : 
     855           0 :                         DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
     856             :                                       mode->name, crtc->base.id, offset->x, offset->y);
     857             : 
     858           0 :                         if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
     859             :                                          (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {
     860             :                                 ret = -EINVAL;
     861             :                                 break;
     862             :                         }
     863             : 
     864           0 :                         modeset->mode = drm_mode_duplicate(dev, mode);
     865           0 :                         drm_connector_get(connector);
     866           0 :                         modeset->connectors[modeset->num_connectors++] = connector;
     867           0 :                         modeset->x = offset->x;
     868           0 :                         modeset->y = offset->y;
     869             :                 }
     870             :         }
     871             : 
     872           0 :         mutex_unlock(&client->modeset_mutex);
     873             : out:
     874           0 :         kfree(crtcs);
     875           0 :         kfree(modes);
     876           0 :         kfree(offsets);
     877           0 :         kfree(enabled);
     878             : free_connectors:
     879           0 :         for (i = 0; i < connector_count; i++)
     880           0 :                 drm_connector_put(connectors[i]);
     881           0 :         kfree(connectors);
     882             : 
     883           0 :         return ret;
     884             : }
     885             : EXPORT_SYMBOL(drm_client_modeset_probe);
     886             : 
     887             : /**
     888             :  * drm_client_rotation() - Check the initial rotation value
     889             :  * @modeset: DRM modeset
     890             :  * @rotation: Returned rotation value
     891             :  *
     892             :  * This function checks if the primary plane in @modeset can hw rotate
     893             :  * to match the rotation needed on its connector.
     894             :  *
     895             :  * Note: Currently only 0 and 180 degrees are supported.
     896             :  *
     897             :  * Return:
     898             :  * True if the plane can do the rotation, false otherwise.
     899             :  */
     900           0 : bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
     901             : {
     902           0 :         struct drm_connector *connector = modeset->connectors[0];
     903           0 :         struct drm_plane *plane = modeset->crtc->primary;
     904             :         struct drm_cmdline_mode *cmdline;
     905           0 :         u64 valid_mask = 0;
     906             :         unsigned int i;
     907             : 
     908           0 :         if (!modeset->num_connectors)
     909             :                 return false;
     910             : 
     911           0 :         switch (connector->display_info.panel_orientation) {
     912             :         case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
     913           0 :                 *rotation = DRM_MODE_ROTATE_180;
     914           0 :                 break;
     915             :         case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
     916           0 :                 *rotation = DRM_MODE_ROTATE_90;
     917           0 :                 break;
     918             :         case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
     919           0 :                 *rotation = DRM_MODE_ROTATE_270;
     920           0 :                 break;
     921             :         default:
     922           0 :                 *rotation = DRM_MODE_ROTATE_0;
     923             :         }
     924             : 
     925             :         /**
     926             :          * The panel already defined the default rotation
     927             :          * through its orientation. Whatever has been provided
     928             :          * on the command line needs to be added to that.
     929             :          *
     930             :          * Unfortunately, the rotations are at different bit
     931             :          * indices, so the math to add them up are not as
     932             :          * trivial as they could.
     933             :          *
     934             :          * Reflections on the other hand are pretty trivial to deal with, a
     935             :          * simple XOR between the two handle the addition nicely.
     936             :          */
     937           0 :         cmdline = &connector->cmdline_mode;
     938           0 :         if (cmdline->specified && cmdline->rotation_reflection) {
     939             :                 unsigned int cmdline_rest, panel_rest;
     940             :                 unsigned int cmdline_rot, panel_rot;
     941             :                 unsigned int sum_rot, sum_rest;
     942             : 
     943           0 :                 panel_rot = ilog2(*rotation & DRM_MODE_ROTATE_MASK);
     944           0 :                 cmdline_rot = ilog2(cmdline->rotation_reflection & DRM_MODE_ROTATE_MASK);
     945           0 :                 sum_rot = (panel_rot + cmdline_rot) % 4;
     946             : 
     947           0 :                 panel_rest = *rotation & ~DRM_MODE_ROTATE_MASK;
     948           0 :                 cmdline_rest = cmdline->rotation_reflection & ~DRM_MODE_ROTATE_MASK;
     949           0 :                 sum_rest = panel_rest ^ cmdline_rest;
     950             : 
     951           0 :                 *rotation = (1 << sum_rot) | sum_rest;
     952             :         }
     953             : 
     954             :         /*
     955             :          * TODO: support 90 / 270 degree hardware rotation,
     956             :          * depending on the hardware this may require the framebuffer
     957             :          * to be in a specific tiling format.
     958             :          */
     959           0 :         if (((*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0 &&
     960           0 :              (*rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_180) ||
     961           0 :             !plane->rotation_property)
     962             :                 return false;
     963             : 
     964           0 :         for (i = 0; i < plane->rotation_property->num_values; i++)
     965           0 :                 valid_mask |= (1ULL << plane->rotation_property->values[i]);
     966             : 
     967           0 :         if (!(*rotation & valid_mask))
     968             :                 return false;
     969             : 
     970           0 :         return true;
     971             : }
     972             : EXPORT_SYMBOL(drm_client_rotation);
     973             : 
     974           0 : static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active, bool check)
     975             : {
     976           0 :         struct drm_device *dev = client->dev;
     977             :         struct drm_plane *plane;
     978             :         struct drm_atomic_state *state;
     979             :         struct drm_modeset_acquire_ctx ctx;
     980             :         struct drm_mode_set *mode_set;
     981             :         int ret;
     982             : 
     983           0 :         drm_modeset_acquire_init(&ctx, 0);
     984             : 
     985           0 :         state = drm_atomic_state_alloc(dev);
     986           0 :         if (!state) {
     987             :                 ret = -ENOMEM;
     988             :                 goto out_ctx;
     989             :         }
     990             : 
     991           0 :         state->acquire_ctx = &ctx;
     992             : retry:
     993           0 :         drm_for_each_plane(plane, dev) {
     994             :                 struct drm_plane_state *plane_state;
     995             : 
     996           0 :                 plane_state = drm_atomic_get_plane_state(state, plane);
     997           0 :                 if (IS_ERR(plane_state)) {
     998           0 :                         ret = PTR_ERR(plane_state);
     999           0 :                         goto out_state;
    1000             :                 }
    1001             : 
    1002           0 :                 plane_state->rotation = DRM_MODE_ROTATE_0;
    1003             : 
    1004             :                 /* disable non-primary: */
    1005           0 :                 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
    1006           0 :                         continue;
    1007             : 
    1008           0 :                 ret = __drm_atomic_helper_disable_plane(plane, plane_state);
    1009           0 :                 if (ret != 0)
    1010             :                         goto out_state;
    1011             :         }
    1012             : 
    1013           0 :         drm_client_for_each_modeset(mode_set, client) {
    1014           0 :                 struct drm_plane *primary = mode_set->crtc->primary;
    1015             :                 unsigned int rotation;
    1016             : 
    1017           0 :                 if (drm_client_rotation(mode_set, &rotation)) {
    1018             :                         struct drm_plane_state *plane_state;
    1019             : 
    1020             :                         /* Cannot fail as we've already gotten the plane state above */
    1021           0 :                         plane_state = drm_atomic_get_new_plane_state(state, primary);
    1022           0 :                         plane_state->rotation = rotation;
    1023             :                 }
    1024             : 
    1025           0 :                 ret = __drm_atomic_helper_set_config(mode_set, state);
    1026           0 :                 if (ret != 0)
    1027             :                         goto out_state;
    1028             : 
    1029             :                 /*
    1030             :                  * __drm_atomic_helper_set_config() sets active when a
    1031             :                  * mode is set, unconditionally clear it if we force DPMS off
    1032             :                  */
    1033           0 :                 if (!active) {
    1034           0 :                         struct drm_crtc *crtc = mode_set->crtc;
    1035           0 :                         struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
    1036             : 
    1037           0 :                         crtc_state->active = false;
    1038             :                 }
    1039             :         }
    1040             : 
    1041           0 :         if (check)
    1042           0 :                 ret = drm_atomic_check_only(state);
    1043             :         else
    1044           0 :                 ret = drm_atomic_commit(state);
    1045             : 
    1046             : out_state:
    1047           0 :         if (ret == -EDEADLK)
    1048             :                 goto backoff;
    1049             : 
    1050             :         drm_atomic_state_put(state);
    1051             : out_ctx:
    1052           0 :         drm_modeset_drop_locks(&ctx);
    1053           0 :         drm_modeset_acquire_fini(&ctx);
    1054             : 
    1055           0 :         return ret;
    1056             : 
    1057             : backoff:
    1058           0 :         drm_atomic_state_clear(state);
    1059           0 :         drm_modeset_backoff(&ctx);
    1060             : 
    1061           0 :         goto retry;
    1062             : }
    1063             : 
    1064           0 : static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
    1065             : {
    1066           0 :         struct drm_device *dev = client->dev;
    1067             :         struct drm_mode_set *mode_set;
    1068             :         struct drm_plane *plane;
    1069           0 :         int ret = 0;
    1070             : 
    1071           0 :         drm_modeset_lock_all(dev);
    1072           0 :         drm_for_each_plane(plane, dev) {
    1073           0 :                 if (plane->type != DRM_PLANE_TYPE_PRIMARY)
    1074           0 :                         drm_plane_force_disable(plane);
    1075             : 
    1076           0 :                 if (plane->rotation_property)
    1077           0 :                         drm_mode_plane_set_obj_prop(plane,
    1078             :                                                     plane->rotation_property,
    1079             :                                                     DRM_MODE_ROTATE_0);
    1080             :         }
    1081             : 
    1082           0 :         drm_client_for_each_modeset(mode_set, client) {
    1083           0 :                 struct drm_crtc *crtc = mode_set->crtc;
    1084             : 
    1085           0 :                 if (crtc->funcs->cursor_set2) {
    1086           0 :                         ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
    1087           0 :                         if (ret)
    1088             :                                 goto out;
    1089           0 :                 } else if (crtc->funcs->cursor_set) {
    1090           0 :                         ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
    1091           0 :                         if (ret)
    1092             :                                 goto out;
    1093             :                 }
    1094             : 
    1095           0 :                 ret = drm_mode_set_config_internal(mode_set);
    1096           0 :                 if (ret)
    1097             :                         goto out;
    1098             :         }
    1099             : out:
    1100           0 :         drm_modeset_unlock_all(dev);
    1101             : 
    1102           0 :         return ret;
    1103             : }
    1104             : 
    1105             : /**
    1106             :  * drm_client_modeset_check() - Check modeset configuration
    1107             :  * @client: DRM client
    1108             :  *
    1109             :  * Check modeset configuration.
    1110             :  *
    1111             :  * Returns:
    1112             :  * Zero on success or negative error code on failure.
    1113             :  */
    1114           0 : int drm_client_modeset_check(struct drm_client_dev *client)
    1115             : {
    1116             :         int ret;
    1117             : 
    1118           0 :         if (!drm_drv_uses_atomic_modeset(client->dev))
    1119             :                 return 0;
    1120             : 
    1121           0 :         mutex_lock(&client->modeset_mutex);
    1122           0 :         ret = drm_client_modeset_commit_atomic(client, true, true);
    1123           0 :         mutex_unlock(&client->modeset_mutex);
    1124             : 
    1125           0 :         return ret;
    1126             : }
    1127             : EXPORT_SYMBOL(drm_client_modeset_check);
    1128             : 
    1129             : /**
    1130             :  * drm_client_modeset_commit_locked() - Force commit CRTC configuration
    1131             :  * @client: DRM client
    1132             :  *
    1133             :  * Commit modeset configuration to crtcs without checking if there is a DRM
    1134             :  * master. The assumption is that the caller already holds an internal DRM
    1135             :  * master reference acquired with drm_master_internal_acquire().
    1136             :  *
    1137             :  * Returns:
    1138             :  * Zero on success or negative error code on failure.
    1139             :  */
    1140           0 : int drm_client_modeset_commit_locked(struct drm_client_dev *client)
    1141             : {
    1142           0 :         struct drm_device *dev = client->dev;
    1143             :         int ret;
    1144             : 
    1145           0 :         mutex_lock(&client->modeset_mutex);
    1146           0 :         if (drm_drv_uses_atomic_modeset(dev))
    1147           0 :                 ret = drm_client_modeset_commit_atomic(client, true, false);
    1148             :         else
    1149           0 :                 ret = drm_client_modeset_commit_legacy(client);
    1150           0 :         mutex_unlock(&client->modeset_mutex);
    1151             : 
    1152           0 :         return ret;
    1153             : }
    1154             : EXPORT_SYMBOL(drm_client_modeset_commit_locked);
    1155             : 
    1156             : /**
    1157             :  * drm_client_modeset_commit() - Commit CRTC configuration
    1158             :  * @client: DRM client
    1159             :  *
    1160             :  * Commit modeset configuration to crtcs.
    1161             :  *
    1162             :  * Returns:
    1163             :  * Zero on success or negative error code on failure.
    1164             :  */
    1165           0 : int drm_client_modeset_commit(struct drm_client_dev *client)
    1166             : {
    1167           0 :         struct drm_device *dev = client->dev;
    1168             :         int ret;
    1169             : 
    1170           0 :         if (!drm_master_internal_acquire(dev))
    1171             :                 return -EBUSY;
    1172             : 
    1173           0 :         ret = drm_client_modeset_commit_locked(client);
    1174             : 
    1175           0 :         drm_master_internal_release(dev);
    1176             : 
    1177           0 :         return ret;
    1178             : }
    1179             : EXPORT_SYMBOL(drm_client_modeset_commit);
    1180             : 
    1181           0 : static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
    1182             : {
    1183           0 :         struct drm_device *dev = client->dev;
    1184             :         struct drm_connector *connector;
    1185             :         struct drm_mode_set *modeset;
    1186             :         struct drm_modeset_acquire_ctx ctx;
    1187             :         int j;
    1188             :         int ret;
    1189             : 
    1190           0 :         DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
    1191           0 :         drm_client_for_each_modeset(modeset, client) {
    1192           0 :                 if (!modeset->crtc->enabled)
    1193           0 :                         continue;
    1194             : 
    1195           0 :                 for (j = 0; j < modeset->num_connectors; j++) {
    1196           0 :                         connector = modeset->connectors[j];
    1197           0 :                         connector->funcs->dpms(connector, dpms_mode);
    1198           0 :                         drm_object_property_set_value(&connector->base,
    1199             :                                 dev->mode_config.dpms_property, dpms_mode);
    1200             :                 }
    1201             :         }
    1202           0 :         DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
    1203           0 : }
    1204             : 
    1205             : /**
    1206             :  * drm_client_modeset_dpms() - Set DPMS mode
    1207             :  * @client: DRM client
    1208             :  * @mode: DPMS mode
    1209             :  *
    1210             :  * Note: For atomic drivers @mode is reduced to on/off.
    1211             :  *
    1212             :  * Returns:
    1213             :  * Zero on success or negative error code on failure.
    1214             :  */
    1215           0 : int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
    1216             : {
    1217           0 :         struct drm_device *dev = client->dev;
    1218           0 :         int ret = 0;
    1219             : 
    1220           0 :         if (!drm_master_internal_acquire(dev))
    1221             :                 return -EBUSY;
    1222             : 
    1223           0 :         mutex_lock(&client->modeset_mutex);
    1224           0 :         if (drm_drv_uses_atomic_modeset(dev))
    1225           0 :                 ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON, false);
    1226             :         else
    1227           0 :                 drm_client_modeset_dpms_legacy(client, mode);
    1228           0 :         mutex_unlock(&client->modeset_mutex);
    1229             : 
    1230           0 :         drm_master_internal_release(dev);
    1231             : 
    1232           0 :         return ret;
    1233             : }
    1234             : EXPORT_SYMBOL(drm_client_modeset_dpms);

Generated by: LCOV version 1.14