Give clients easy access to the display modes.

Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 drivers/gpu/drm/drm_client.c | 159 +++++++++++++++++++++++++++++++++----------
 include/drm/drm_client.h     |  25 +++++++
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 764c556630b8..bce1630a0db2 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,6 +8,7 @@
  * Copyright (c) 2007 Dave Airlie <airl...@linux.ie>
  */
 
+#include <linux/list.h>
 #include <linux/slab.h>
 
 #include <drm/drm_atomic.h>
@@ -54,6 +55,7 @@ struct drm_client_display *drm_client_display_create(struct 
drm_device *dev)
        }
 
        display->dev = dev;
+       INIT_LIST_HEAD(&display->modes);
        display->modeset_count = num_crtc;
 
        drm_for_each_crtc(crtc, dev)
@@ -84,12 +86,16 @@ EXPORT_SYMBOL(drm_client_display_create);
  */
 void drm_client_display_free(struct drm_client_display *display)
 {
+       struct drm_display_mode *mode, *tmp;
        struct drm_mode_set *modeset;
        unsigned int i;
 
        if (!display)
                return;
 
+       list_for_each_entry_safe(mode, tmp, &display->modes, head)
+               drm_mode_destroy(display->dev, mode);
+
        drm_client_display_for_each_modeset(modeset, display) {
                if (modeset->mode)
                        drm_mode_destroy(display->dev, modeset->mode);
@@ -670,22 +676,70 @@ static int drm_pick_crtcs(struct drm_client_display 
*display,
        return best_score;
 }
 
-/**
- * drm_client_find_display() - Find display
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function returns a display the client can use if available.
- *
- * Free resources by calling drm_client_display_free().
- *
- * Returns:
- * A &drm_client_display on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_client_display *
-drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned 
int height)
+/* Give the client a static list of display modes */
+static int drm_client_display_copy_modes(struct drm_client_display *display)
+{
+       int hdisplay = 0, vdisplay = 0, vrefresh;
+       struct drm_device *dev = display->dev;
+       struct drm_display_mode *mode, *copy;
+       struct drm_connector *connector;
+       struct drm_mode_set *modeset;
+       unsigned int count = 0;
+
+       drm_client_display_for_each_modeset(modeset, display) {
+               if (!modeset->num_connectors || !modeset->mode)
+                       continue;
+
+               connector = modeset->connectors[0];
+               mode = modeset->mode;
+               count++;
+
+               if (modeset->num_connectors == 2) {
+                       /* Cloned output */
+                       copy = drm_mode_duplicate(dev, modeset->mode);
+                       if (!copy)
+                               return -ENOMEM;
+                       list_add_tail(&copy->head, &display->modes);
+                       display->mode = copy;
+
+                       return 0;
+               }
+
+               if (!modeset->y)
+                       hdisplay += modeset->mode->hdisplay;
+               if (!modeset->x)
+                       vdisplay += modeset->mode->vdisplay;
+               vrefresh = modeset->mode->vrefresh;
+       }
+
+       if (!count)
+               return 0;
+
+       if (count == 1) {
+               struct drm_display_mode *iter;
+
+               list_for_each_entry(iter, &connector->modes, head) {
+                       copy = drm_mode_duplicate(dev, iter);
+                       if (!copy)
+                               return -ENOMEM;
+                       list_add_tail(&copy->head, &display->modes);
+                       if (!display->mode && drm_mode_equal(iter, mode))
+                               display->mode = copy;
+               }
+       } else {
+               /* Combined tile mode. Only the default one for now */
+               copy = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, 
false, false);
+               if (!copy)
+                       return -ENOMEM;
+               list_add_tail(&copy->head, &display->modes);
+               display->mode = copy;
+       }
+
+       return 0;
+}
+
+static struct drm_client_display *
+drm_client_find_display_default(struct drm_device *dev, unsigned int width, 
unsigned int height)
 {
        struct drm_client_display_offset *offsets;
        struct drm_client_display *display;
@@ -695,25 +749,6 @@ drm_client_find_display(struct drm_device *dev, unsigned 
int width, unsigned int
        int i, connector_count;
        bool *enabled;
 
-       DRM_DEBUG_KMS("\n");
-
-       if (!width)
-               width = dev->mode_config.max_width;
-       if (!height)
-               height = dev->mode_config.max_height;
-
-       mutex_lock(&dev->mode_config.mutex);
-       if (!drm_client_probe_connector_modes(dev, width, height))
-               DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-
-       if (dev->driver->initial_client_display) {
-               display = dev->driver->initial_client_display(dev, width, 
height);
-               if (display) {
-                       mutex_unlock(&dev->mode_config.mutex);
-                       return display;
-               }
-       }
-
        connector_count = drm_connector_get_all(dev, &connectors);
        if (connector_count < 1)
                return NULL;
@@ -772,7 +807,6 @@ drm_client_find_display(struct drm_device *dev, unsigned 
int width, unsigned int
                }
        }
 out:
-       mutex_unlock(&dev->mode_config.mutex);
        drm_connector_put_all(connectors, connector_count);
        kfree(crtcs);
        kfree(modes);
@@ -781,4 +815,57 @@ drm_client_find_display(struct drm_device *dev, unsigned 
int width, unsigned int
 
        return display;
 }
+
+/**
+ * drm_client_find_display() - Find display
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function returns a display the client can use if one is found.
+ *
+ * Free resources by calling drm_client_display_free().
+ *
+ * Returns:
+ * A &drm_client_display on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned 
int height)
+{
+       struct drm_client_display *display = NULL;
+       int ret;
+
+       DRM_DEBUG_KMS("\n");
+
+       if (!width)
+               width = dev->mode_config.max_width;
+       if (!height)
+               height = dev->mode_config.max_height;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       if (!drm_client_probe_connector_modes(dev, width, height))
+               DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+       if (dev->driver->initial_client_display)
+               display = dev->driver->initial_client_display(dev, width, 
height);
+
+       if (!display)
+               display = drm_client_find_display_default(dev, width, height);
+
+       if (IS_ERR_OR_NULL(display))
+               goto out_unlock;
+
+       ret = drm_client_display_copy_modes(display);
+       if (ret) {
+               drm_client_display_free(display);
+               display = ERR_PTR(ret);
+       }
+
+out_unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return display;
+}
 EXPORT_SYMBOL(drm_client_find_display);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 3befd879a0b0..524f793d6e7b 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,9 +3,12 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/types.h>
+
 struct drm_connector;
 struct drm_crtc;
 struct drm_device;
+struct drm_display_mode;
 struct drm_mode_set;
 struct drm_plane;
 
@@ -33,6 +36,20 @@ struct drm_client_display {
         * Number of modesets
         */
        unsigned int modeset_count;
+
+       /**
+        * @modes:
+        *
+        * Display modes available on this display.
+        */
+       struct list_head modes;
+
+       /**
+        * @mode:
+        *
+        * The current display mode.
+        */
+       struct drm_display_mode *mode;
 };
 
 struct drm_client_display *drm_client_display_create(struct drm_device *dev);
@@ -51,4 +68,12 @@ int drm_client_display_dpms(struct drm_client_display 
*display, int mode);
 struct drm_client_display *
 drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned 
int height);
 
+/**
+ * drm_client_display_for_each_mode - Iterate over the available display modes
+ * @mode: A @drm_display_mode loop cursor
+ * @display: Client display
+ */
+#define drm_client_display_for_each_mode(mode, display) \
+       list_for_each_entry(mode, &display->modes, head)
+
 #endif
-- 
2.15.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to