diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-11-14 14:51:28 -0800 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-11-15 19:53:23 +0000 |
commit | 308e5bcbdb10452e8aba31aa21432fb67ee46d72 (patch) | |
tree | 5e4eebef07685c4047f54d1727fc9bcbace8889d /drivers/gpu/drm/drm_crtc.c | |
parent | 8cf5c9177151537e73ff1816540e4ba24b174391 (diff) |
drm: add an fb creation ioctl that takes a pixel format v5
To properly support the various plane formats supported by different
hardware, the kernel must know the pixel format of a framebuffer object.
So add a new ioctl taking a format argument corresponding to a fourcc
name from the new drm_fourcc.h header file. Implement the fb creation
hooks in terms of the new mode_fb_cmd2 using helpers where the old
bpp/depth values are needed.
v2: create DRM specific fourcc header file for sharing with libdrm etc
v3: fix rebase failure and use DRM fourcc codes in intel_display.c and
update commit message
v4: make fb_cmd2 handle field into an array for multi-object formats
pull in Ville's fix for the memcpy in drm_plane_init
apply Ville's cleanup to zero out fb_cmd2 arg in drm_mode_addfb
v5: add 'flags' field for interlaced support (from Ville)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Reviewed-by: Rob Clark <rob.clark@linaro.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 111 |
1 files changed, 106 insertions, 5 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5e1df76c8f7..e54c0a6a307 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -36,6 +36,7 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_edid.h" +#include "drm_fourcc.h" struct drm_prop_enum_list { int type; @@ -568,7 +569,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, return -ENOMEM; } - memcpy(plane->format_types, formats, format_count); + memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); plane->format_count = format_count; plane->possible_crtcs = possible_crtcs; @@ -1915,6 +1916,42 @@ out: return ret; } +/* Original addfb only supported RGB formats, so figure out which one */ +uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) +{ + uint32_t fmt; + + switch (bpp) { + case 8: + fmt = DRM_FOURCC_RGB332; + break; + case 16: + if (depth == 15) + fmt = DRM_FOURCC_RGB555; + else + fmt = DRM_FOURCC_RGB565; + break; + case 24: + fmt = DRM_FOURCC_RGB24; + break; + case 32: + if (depth == 24) + fmt = DRM_FOURCC_RGB24; + else if (depth == 30) + fmt = DRM_INTEL_RGB30; + else + fmt = DRM_FOURCC_RGB32; + break; + default: + DRM_ERROR("bad bpp, assuming RGB24 pixel format\n"); + fmt = DRM_FOURCC_RGB24; + break; + } + + return fmt; +} +EXPORT_SYMBOL(drm_mode_legacy_fb_format); + /** * drm_mode_addfb - add an FB to the graphics configuration * @inode: inode from the ioctl @@ -1935,7 +1972,74 @@ out: int drm_mode_addfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_fb_cmd *r = data; + struct drm_mode_fb_cmd *or = data; + struct drm_mode_fb_cmd2 r = {}; + struct drm_mode_config *config = &dev->mode_config; + struct drm_framebuffer *fb; + int ret = 0; + + /* Use new struct with format internally */ + r.fb_id = or->fb_id; + r.width = or->width; + r.height = or->height; + r.pitches[0] = or->pitch; + r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth); + r.handles[0] = or->handle; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + if ((config->min_width > r.width) || (r.width > config->max_width)) { + DRM_ERROR("mode new framebuffer width not within limits\n"); + return -EINVAL; + } + if ((config->min_height > r.height) || (r.height > config->max_height)) { + DRM_ERROR("mode new framebuffer height not within limits\n"); + return -EINVAL; + } + + mutex_lock(&dev->mode_config.mutex); + + /* TODO check buffer is sufficiently large */ + /* TODO setup destructor callback */ + + fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); + if (IS_ERR(fb)) { + DRM_ERROR("could not create framebuffer\n"); + ret = PTR_ERR(fb); + goto out; + } + + or->fb_id = fb->base.id; + list_add(&fb->filp_head, &file_priv->fbs); + DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_addfb2 - add an FB to the graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Takes mode config lock. + * + * Add a new FB to the specified CRTC, given a user request with format. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_addfb2(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd2 *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; int ret = 0; @@ -1956,9 +2060,6 @@ int drm_mode_addfb(struct drm_device *dev, mutex_lock(&dev->mode_config.mutex); - /* TODO check buffer is sufficiently large */ - /* TODO setup destructor callback */ - fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (IS_ERR(fb)) { DRM_ERROR("could not create framebuffer\n"); |