Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 308e5bcb authored by Jesse Barnes's avatar Jesse Barnes Committed by Dave Airlie
Browse files

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: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Acked-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
Reviewed-by: default avatarRob Clark <rob.clark@linaro.org>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 8cf5c917
Loading
Loading
Loading
Loading
+106 −5
Original line number Diff line number Diff line
@@ -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 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
	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 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
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");
+47 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@

#include "drmP.h"
#include "drm_crtc.h"
#include "drm_fourcc.h"
#include "drm_crtc_helper.h"
#include "drm_fb_helper.h"

@@ -810,14 +811,56 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
}
EXPORT_SYMBOL(drm_helper_connector_dpms);

/*
 * Just need to support RGB formats here for compat with code that doesn't
 * use pixel formats directly yet.
 */
void drm_helper_get_fb_bpp_depth(uint32_t format, unsigned int *depth,
				 int *bpp)
{
	switch (format) {
	case DRM_FOURCC_RGB332:
		*depth = 8;
		*bpp = 8;
		break;
	case DRM_FOURCC_RGB555:
		*depth = 15;
		*bpp = 16;
		break;
	case DRM_FOURCC_RGB565:
		*depth = 16;
		*bpp = 16;
		break;
	case DRM_FOURCC_RGB24:
		*depth = 24;
		*bpp = 32;
		break;
	case DRM_INTEL_RGB30:
		*depth = 30;
		*bpp = 32;
		break;
	case DRM_FOURCC_RGB32:
		*depth = 32;
		*bpp = 32;
		break;
	default:
		DRM_DEBUG_KMS("unsupported pixel format\n");
		*depth = 0;
		*bpp = 0;
		break;
	}
}
EXPORT_SYMBOL(drm_helper_get_fb_bpp_depth);

int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
				   struct drm_mode_fb_cmd *mode_cmd)
				   struct drm_mode_fb_cmd2 *mode_cmd)
{
	fb->width = mode_cmd->width;
	fb->height = mode_cmd->height;
	fb->pitch = mode_cmd->pitch;
	fb->bits_per_pixel = mode_cmd->bpp;
	fb->depth = mode_cmd->depth;
	fb->pitch = mode_cmd->pitches[0];
	drm_helper_get_fb_bpp_depth(mode_cmd->pixel_format, &fb->depth,
				    &fb->bits_per_pixel);
	fb->pixel_format = mode_cmd->pixel_format;

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+21 −18
Original line number Diff line number Diff line
@@ -6279,7 +6279,7 @@ static struct drm_display_mode load_detect_mode = {

static struct drm_framebuffer *
intel_framebuffer_create(struct drm_device *dev,
			 struct drm_mode_fb_cmd *mode_cmd,
			 struct drm_mode_fb_cmd2 *mode_cmd,
			 struct drm_i915_gem_object *obj)
{
	struct intel_framebuffer *intel_fb;
@@ -6321,7 +6321,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
				  int depth, int bpp)
{
	struct drm_i915_gem_object *obj;
	struct drm_mode_fb_cmd mode_cmd;
	struct drm_mode_fb_cmd2 mode_cmd;

	obj = i915_gem_alloc_object(dev,
				    intel_framebuffer_size_for_mode(mode, bpp));
@@ -6330,9 +6330,9 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,

	mode_cmd.width = mode->hdisplay;
	mode_cmd.height = mode->vdisplay;
	mode_cmd.depth = depth;
	mode_cmd.bpp = bpp;
	mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp);
	mode_cmd.pitches[0] = intel_framebuffer_pitch_for_width(mode_cmd.width,
								bpp);
	mode_cmd.pixel_format = 0;

	return intel_framebuffer_create(dev, &mode_cmd, obj);
}
@@ -7573,7 +7573,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {

int intel_framebuffer_init(struct drm_device *dev,
			   struct intel_framebuffer *intel_fb,
			   struct drm_mode_fb_cmd *mode_cmd,
			   struct drm_mode_fb_cmd2 *mode_cmd,
			   struct drm_i915_gem_object *obj)
{
	int ret;
@@ -7581,21 +7581,23 @@ int intel_framebuffer_init(struct drm_device *dev,
	if (obj->tiling_mode == I915_TILING_Y)
		return -EINVAL;

	if (mode_cmd->pitch & 63)
	if (mode_cmd->pitches[0] & 63)
		return -EINVAL;

	switch (mode_cmd->bpp) {
	case 8:
	case 16:
		/* Only pre-ILK can handle 5:5:5 */
		if (mode_cmd->depth == 15 && !HAS_PCH_SPLIT(dev))
			return -EINVAL;
	switch (mode_cmd->pixel_format) {
	case DRM_FOURCC_RGB332:
	case DRM_FOURCC_RGB565:
	case DRM_FOURCC_RGB24:
	case DRM_INTEL_RGB30:
		/* RGB formats are common across chipsets */
		break;

	case 24:
	case 32:
	case DRM_FOURCC_YUYV:
	case DRM_FOURCC_UYVY:
	case DRM_FOURCC_YVYU:
	case DRM_FOURCC_VYUY:
		break;
	default:
		DRM_ERROR("unsupported pixel format\n");
		return -EINVAL;
	}

@@ -7613,11 +7615,12 @@ int intel_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev,
			      struct drm_file *filp,
			      struct drm_mode_fb_cmd *mode_cmd)
			      struct drm_mode_fb_cmd2 *mode_cmd)
{
	struct drm_i915_gem_object *obj;

	obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle));
	obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
						mode_cmd->handles[0]));
	if (&obj->base == NULL)
		return ERR_PTR(-ENOENT);

+1 −1
Original line number Diff line number Diff line
@@ -359,7 +359,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,

extern int intel_framebuffer_init(struct drm_device *dev,
				  struct intel_framebuffer *ifb,
				  struct drm_mode_fb_cmd *mode_cmd,
				  struct drm_mode_fb_cmd2 *mode_cmd,
				  struct drm_i915_gem_object *obj);
extern int intel_fbdev_init(struct drm_device *dev);
extern void intel_fbdev_fini(struct drm_device *dev);
Loading