Give clients easy access to the display modes. Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx> --- 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 <airlied@xxxxxxxx> */ +#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(©->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(©->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(©->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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx