drm: Add mode_config .get_format_info() hook
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 21 Mar 2017 18:12:16 +0000 (20:12 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 22 Mar 2017 17:45:00 +0000 (19:45 +0200)
Allow drivers to return a custom drm_format_info structure for special
fb layouts. We'll use this for the compression control surface in i915.

v2: Fix drm_get_format_info() kernel doc (Laurent)
    Don't pass 'dev' to the new hook (Laurent)
v3: s/compresssion/compression/ (Ben)

Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Ben Widawsky <ben@bwidawsk.net>
Cc: Jason Ekstrand <jason@jlekstrand.net>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
Link: http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-4-ville.syrjala@linux.intel.com
drivers/gpu/drm/drm_fb_cma_helper.c
drivers/gpu/drm/drm_fourcc.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_modeset_helper.c
include/drm/drm_fourcc.h
include/drm/drm_mode_config.h

index 74cd393a640778b69262b3a7f81443bc389e9edb..50abd1faf38f08681673cc09f2b290c6cf0d1aa3 100644 (file)
@@ -177,7 +177,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev,
        int ret;
        int i;
 
-       info = drm_format_info(mode_cmd->pixel_format);
+       info = drm_get_format_info(dev, mode_cmd);
        if (!info)
                return ERR_PTR(-EINVAL);
 
index 90d2cc8da8eb659cf59a1a0d1748cd88be36083b..f9b6445e846a558a8aa5c881ed8445da154f839a 100644 (file)
@@ -198,6 +198,31 @@ const struct drm_format_info *drm_format_info(u32 format)
 }
 EXPORT_SYMBOL(drm_format_info);
 
+/**
+ * drm_get_format_info - query information for a given framebuffer configuration
+ * @dev: DRM device
+ * @mode_cmd: metadata from the userspace fb creation request
+ *
+ * Returns:
+ * The instance of struct drm_format_info that describes the pixel format, or
+ * NULL if the format is unsupported.
+ */
+const struct drm_format_info *
+drm_get_format_info(struct drm_device *dev,
+                   const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       const struct drm_format_info *info = NULL;
+
+       if (dev->mode_config.funcs->get_format_info)
+               info = dev->mode_config.funcs->get_format_info(mode_cmd);
+
+       if (!info)
+               info = drm_format_info(mode_cmd->pixel_format);
+
+       return info;
+}
+EXPORT_SYMBOL(drm_get_format_info);
+
 /**
  * drm_format_num_planes - get the number of planes for format
  * @format: pixel format (DRM_FORMAT_*)
index 69e4c1487420a113c40a53d357f4c9678bb8e835..e8f9c13a0afd90cb2880f03ea057d4ea4a9ce406 100644 (file)
@@ -144,11 +144,13 @@ static int fb_plane_height(int height,
        return DIV_ROUND_UP(height, format->vsub);
 }
 
-static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
+static int framebuffer_check(struct drm_device *dev,
+                            const struct drm_mode_fb_cmd2 *r)
 {
        const struct drm_format_info *info;
        int i;
 
+       /* check if the format is supported at all */
        info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN);
        if (!info) {
                struct drm_format_name_buf format_name;
@@ -158,6 +160,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
                return -EINVAL;
        }
 
+       /* now let the driver pick its own format info */
+       info = drm_get_format_info(dev, r);
+
        if (r->width == 0) {
                DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
                return -EINVAL;
@@ -281,7 +286,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
                return ERR_PTR(-EINVAL);
        }
 
-       ret = framebuffer_check(r);
+       ret = framebuffer_check(dev, r);
        if (ret)
                return ERR_PTR(ret);
 
index cc44a9a4b004076e660154d7966f78ca2287d80d..2b33825f2f93138066b3593289bd076ad9f43409 100644 (file)
@@ -78,7 +78,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
        int i;
 
        fb->dev = dev;
-       fb->format = drm_format_info(mode_cmd->pixel_format);
+       fb->format = drm_get_format_info(dev, mode_cmd);
        fb->width = mode_cmd->width;
        fb->height = mode_cmd->height;
        for (i = 0; i < 4; i++) {
index fcc08da850c854f332dcca7ec65df0b04d0261a2..6942e84b6edde56a1e5a16b1cde2e325a76a6a54 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/types.h>
 #include <uapi/drm/drm_fourcc.h>
 
+struct drm_device;
+struct drm_mode_fb_cmd2;
+
 /**
  * struct drm_format_info - information about a DRM format
  * @format: 4CC format identifier (DRM_FORMAT_*)
@@ -55,6 +58,9 @@ struct drm_format_name_buf {
 
 const struct drm_format_info *__drm_format_info(u32 format);
 const struct drm_format_info *drm_format_info(u32 format);
+const struct drm_format_info *
+drm_get_format_info(struct drm_device *dev,
+                   const struct drm_mode_fb_cmd2 *mode_cmd);
 uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
 int drm_format_num_planes(uint32_t format);
 int drm_format_plane_cpp(uint32_t format, int plane);
index ea169a90b3c4322d010b7dccb260be22eff791a5..579070ff06ef03cca6c4d550030f8f96aacff403 100644 (file)
@@ -34,6 +34,7 @@ struct drm_file;
 struct drm_device;
 struct drm_atomic_state;
 struct drm_mode_fb_cmd2;
+struct drm_format_info;
 
 /**
  * struct drm_mode_config_funcs - basic driver provided mode setting functions
@@ -69,6 +70,19 @@ struct drm_mode_config_funcs {
                                             struct drm_file *file_priv,
                                             const struct drm_mode_fb_cmd2 *mode_cmd);
 
+       /**
+        * @get_format_info:
+        *
+        * Allows a driver to return custom format information for special
+        * fb layouts (eg. ones with auxiliary compression control planes).
+        *
+        * RETURNS:
+        *
+        * The format information specific to the given fb metadata, or
+        * NULL if none is found.
+        */
+       const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd);
+
        /**
         * @output_poll_changed:
         *