LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_client_modeset.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 412 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 13 0.0 %
Branches: 0 290 0.0 %

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

Generated by: LCOV version 1.14