As part of moving the modesetting code out of drm_fb_helper and into
drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
Replace it with a drm_driver->initial_client_display callback that can
work for all in-kernel clients.

TODO:
- Add a patch that moves the function out of intel_fbdev.c since it's not
  fbdev specific anymore.

Signed-off-by: Noralf Trønnes <nor...@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c    |  19 +++++--
 drivers/gpu/drm/i915/i915_drv.c    |   1 +
 drivers/gpu/drm/i915/intel_drv.h   |  11 ++++
 drivers/gpu/drm/i915/intel_fbdev.c | 113 ++++++++++++++++++-------------------
 include/drm/drm_drv.h              |  21 +++++++
 5 files changed, 104 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b992f59dad30..5407bf6dc8c0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2103,6 +2103,20 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
        /* prevent concurrent modification of connector_count by hotplug */
        lockdep_assert_held(&fb_helper->lock);
 
+       mutex_lock(&dev->mode_config.mutex);
+       if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
+               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) {
+                       drm_client_display_free(fb_helper->display);
+                       fb_helper->display = display;
+                       mutex_unlock(&dev->mode_config.mutex);
+                       return;
+               }
+       }
+
        crtcs = kcalloc(fb_helper->connector_count,
                        sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
        modes = kcalloc(fb_helper->connector_count,
@@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
        if (IS_ERR(display))
                goto out;
 
-       mutex_lock(&fb_helper->dev->mode_config.mutex);
-       if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
-               DRM_DEBUG_KMS("No connectors reported connected with modes\n");
        drm_enable_connectors(fb_helper, enabled);
 
        if (!(fb_helper->funcs->initial_config &&
@@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
 
                drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
        }
-       mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
        /* need to set the modesets up here for use later */
        /* fill out the connector<->crtc mappings into the modesets */
@@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper,
        drm_client_display_free(fb_helper->display);
        fb_helper->display = display;
 out:
+       mutex_unlock(&dev->mode_config.mutex);
        kfree(crtcs);
        kfree(modes);
        kfree(offsets);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 07c07d55398b..b746c0cbaa4b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
 
        .dumb_create = i915_gem_dumb_create,
        .dumb_map_offset = i915_gem_mmap_gtt,
+       .initial_client_display = i915_initial_client_display,
        .ioctls = i915_ioctls,
        .num_ioctls = ARRAY_SIZE(i915_ioctls),
        .fops = &i915_driver_fops,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d4368589b355..f77f510617c5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private 
*dev_priv);
 extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool 
synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
 extern void intel_fbdev_restore_mode(struct drm_device *dev);
+struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+                           unsigned int height);
 #else
 static inline int intel_fbdev_init(struct drm_device *dev)
 {
@@ -1749,6 +1752,14 @@ static inline void 
intel_fbdev_output_poll_changed(struct drm_device *dev)
 static inline void intel_fbdev_restore_mode(struct drm_device *dev)
 {
 }
+
+static inline struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+                           unsigned int height)
+{
+       return NULL;
+}
+
 #endif
 
 /* intel_fbc.c */
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c 
b/drivers/gpu/drm/i915/intel_fbdev.c
index a4ab8575a72e..b7f44c9475a8 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -38,6 +38,7 @@
 #include <linux/vga_switcheroo.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
 #include "intel_drv.h"
@@ -287,18 +288,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
        return ret;
 }
 
-static struct drm_fb_helper_crtc *
-intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
-{
-       int i;
-
-       for (i = 0; i < fb_helper->crtc_count; i++)
-               if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
-                       return &fb_helper->crtc_info[i];
-
-       return NULL;
-}
-
 /*
  * Try to read the BIOS display configuration and use it for the initial
  * fb configuration.
@@ -326,44 +315,48 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, 
struct drm_crtc *crtc)
  * is in VGA mode we need to recalculate watermarks and set a new high-res
  * framebuffer anyway.
  */
-static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
-                                   struct drm_fb_helper_crtc **crtcs,
-                                   struct drm_display_mode **modes,
-                                   struct drm_fb_offset *offsets,
-                                   bool *enabled, int width, int height)
+struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+                           unsigned int height)
 {
-       struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
+       struct drm_i915_private *dev_priv = to_i915(dev);
        unsigned long conn_configured, conn_seq, mask;
-       unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
-       int i, j;
-       bool *save_enabled;
-       bool fallback = true, ret = true;
+       bool fallback = true, *enabled = NULL;
+       struct drm_client_display *display;
+       struct drm_connector **connectors;
+       int i, connector_count;
+       unsigned int count;
        int num_connectors_enabled = 0;
        int num_connectors_detected = 0;
        struct drm_modeset_acquire_ctx ctx;
 
-       save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
-       if (!save_enabled)
-               return false;
+       display = drm_client_display_create(dev);
+       if (IS_ERR(display))
+               return NULL;
 
        drm_modeset_acquire_init(&ctx, 0);
 
-       while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
+       while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
                drm_modeset_backoff(&ctx);
 
-       memcpy(save_enabled, enabled, count);
+       connector_count = drm_connector_get_all(dev, &connectors);
+       if (connector_count < 1)
+               goto bail;
+
+       enabled = drm_connector_get_enabled_status(connectors, connector_count);
+       if (!enabled)
+               goto bail;
+
+       count = min(connector_count, BITS_PER_LONG);
        mask = GENMASK(count - 1, 0);
        conn_configured = 0;
 retry:
        conn_seq = conn_configured;
        for (i = 0; i < count; i++) {
-               struct drm_fb_helper_connector *fb_conn;
-               struct drm_connector *connector;
+               struct drm_connector *connector = connectors[i];
+               struct drm_display_mode *mode;
+               struct drm_mode_set *modeset;
                struct drm_encoder *encoder;
-               struct drm_fb_helper_crtc *new_crtc;
-
-               fb_conn = fb_helper->connector_info[i];
-               connector = fb_conn->connector;
 
                if (conn_configured & BIT(i))
                        continue;
@@ -402,16 +395,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
 
                num_connectors_enabled++;
 
-               new_crtc = intel_fb_helper_crtc(fb_helper,
-                                               connector->state->crtc);
-
                /*
                 * Make sure we're not trying to drive multiple connectors
                 * with a single CRTC, since our cloning support may not
                 * match the BIOS.
                 */
-               for (j = 0; j < count; j++) {
-                       if (crtcs[j] == new_crtc) {
+               drm_client_display_for_each_modeset(modeset, display) {
+                       if (modeset->connectors[0] == connector) {
                                DRM_DEBUG_KMS("fallback: cloned 
configuration\n");
                                goto bail;
                        }
@@ -421,28 +411,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
                              connector->name);
 
                /* go for command line mode first */
-               modes[i] = drm_connector_pick_cmdline_mode(connector);
+               mode = drm_connector_pick_cmdline_mode(connector);
 
                /* try for preferred next */
-               if (!modes[i]) {
+               if (!mode) {
                        DRM_DEBUG_KMS("looking for preferred mode on connector 
%s %d\n",
                                      connector->name, connector->has_tile);
-                       modes[i] = drm_connector_has_preferred_mode(connector,
-                                                                   width,
-                                                                   height);
+                       mode = drm_connector_has_preferred_mode(connector,
+                                                               width, height);
                }
 
                /* No preferred mode marked by the EDID? Are there any modes? */
-               if (!modes[i] && !list_empty(&connector->modes)) {
+               if (!mode && !list_empty(&connector->modes)) {
                        DRM_DEBUG_KMS("using first mode listed on connector 
%s\n",
                                      connector->name);
-                       modes[i] = list_first_entry(&connector->modes,
-                                                   struct drm_display_mode,
-                                                   head);
+                       mode = list_first_entry(&connector->modes,
+                                               struct drm_display_mode, head);
                }
 
                /* last resort: use current mode */
-               if (!modes[i]) {
+               if (!mode) {
                        /*
                         * IMPORTANT: We want to use the adjusted mode (i.e.
                         * after the panel fitter upscaling) as the initial
@@ -458,16 +446,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
                         */
                        DRM_DEBUG_KMS("looking for current mode on connector 
%s\n",
                                      connector->name);
-                       modes[i] = &connector->state->crtc->mode;
+                       mode = &connector->state->crtc->mode;
                }
-               crtcs[i] = new_crtc;
+
+               modeset = drm_client_display_find_modeset(display, 
connector->state->crtc);
+               if (WARN_ON(!modeset))
+                       goto bail;
+
+               modeset->mode = drm_mode_duplicate(dev, mode);
+               drm_connector_get(connector);
+               modeset->connectors[0] = connector;
+               modeset->num_connectors = 1;
+               modeset->x = 0;
+               modeset->y = 0;
 
                DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
                              connector->name,
                              connector->state->crtc->base.id,
                              connector->state->crtc->name,
-                             modes[i]->hdisplay, modes[i]->vdisplay,
-                             modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" 
:"");
+                             mode->hdisplay, mode->vdisplay,
+                             mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
 
                fallback = false;
                conn_configured |= BIT(i);
@@ -492,19 +490,20 @@ static bool intel_fb_initial_config(struct drm_fb_helper 
*fb_helper,
        if (fallback) {
 bail:
                DRM_DEBUG_KMS("Not using firmware configuration\n");
-               memcpy(enabled, save_enabled, count);
-               ret = false;
+               drm_client_display_free(display);
+               display = NULL;
        }
 
        drm_modeset_drop_locks(&ctx);
        drm_modeset_acquire_fini(&ctx);
 
-       kfree(save_enabled);
-       return ret;
+       drm_connector_put_all(connectors, connector_count);
+       kfree(enabled);
+
+       return display;
 }
 
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
-       .initial_config = intel_fb_initial_config,
        .fb_probe = intelfb_create,
 };
 
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 7e545f5f94d3..13356e6fd40c 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -32,6 +32,7 @@
 
 #include <drm/drm_device.h>
 
+struct drm_client_display;
 struct drm_file;
 struct drm_gem_object;
 struct drm_master;
@@ -553,6 +554,26 @@ struct drm_driver {
                            struct drm_device *dev,
                            uint32_t handle);
 
+       /**
+        * @initial_client_config:
+        *
+        * Driver callback to setup an initial fbdev display configuration.
+        * Drivers can use this callback to tell the fbdev emulation what the
+        * preferred initial configuration is. This is useful to implement
+        * smooth booting where the fbdev (and subsequently all userspace) never
+        * changes the mode, but always inherits the existing configuration.
+        *
+        * This callback is optional.
+        *
+        * RETURNS:
+        *
+        * The driver should return true if a suitable initial configuration has
+        * been filled out and false when the fbdev helper should fall back to
+        * the default probing logic.
+        */
+       struct drm_client_display *(*initial_client_display)(struct drm_device 
*dev,
+                                       unsigned int width, unsigned int 
height);
+
        /**
         * @gem_vm_ops: Driver private ops for this object
         */
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to