All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] drm/omap: updates for addfb2 and plane support
@ 2011-12-20 22:58 Rob Clark
  2011-12-20 22:58 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Rob Clark @ 2011-12-20 22:58 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

The first patch updates omapdrm for API changes introduced when addfb2
support (for multi-planar fb's) was added (in drm-next).  The next patch
adds drm plane (overlay) support, with CRTCs using private plane objects
to avoid code duplication between the CRTC and plane.  (This depends on
the "drm: add support for private planes" patch.)  The final patch adds
support for YUV and multi-planar YUV formats.

This updated patch set rebases on drm-next as of today, and removes an
internal helper function in favor of the new drm_format_num_planes()
helper.  These patches replace the last patchset sent on 15 Dec 2011.

Rob Clark (3):
  drm/omap: drm API update: addfb2
  drm/omap: add drm_plane support
  drm/omap: multiplanar and YUV support

 drivers/staging/omapdrm/Makefile     |    1 +
 drivers/staging/omapdrm/omap_crtc.c  |  191 +++++---------------
 drivers/staging/omapdrm/omap_drv.c   |   53 ++++--
 drivers/staging/omapdrm/omap_drv.h   |   46 ++++-
 drivers/staging/omapdrm/omap_fb.c    |  224 +++++++++++++++++------
 drivers/staging/omapdrm/omap_fbdev.c |   55 ++++--
 drivers/staging/omapdrm/omap_gem.c   |    5 +
 drivers/staging/omapdrm/omap_plane.c |  329 ++++++++++++++++++++++++++++++++++
 drivers/staging/omapdrm/omap_priv.h  |   12 +-
 9 files changed, 665 insertions(+), 251 deletions(-)
 create mode 100644 drivers/staging/omapdrm/omap_plane.c

-- 
1.7.5.4

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-20 22:58 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
@ 2011-12-20 22:58 ` Rob Clark
  2011-12-20 23:30   ` Ville Syrjälä
  2011-12-20 22:58 ` [PATCH 2/3] drm/omap: add drm_plane support Rob Clark
  2011-12-20 22:58 ` [PATCH 3/3] drm/omap: multiplanar and YUV support Rob Clark
  2 siblings, 1 reply; 10+ messages in thread
From: Rob Clark @ 2011-12-20 22:58 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

Update to reflect changes in:
"drm: add an fb creation ioctl that takes a pixel format v5"

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/omap_drv.h   |   30 +++++++++-
 drivers/staging/omapdrm/omap_fb.c    |  103 ++++++++++++++++++++++++++--------
 drivers/staging/omapdrm/omap_fbdev.c |   55 ++++++++++++-------
 3 files changed, 143 insertions(+), 45 deletions(-)

diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 76c4251..4ad2ae5 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
 #include "omap_drm.h"
 #include "omap_priv.h"
 
@@ -80,9 +81,9 @@ void omap_connector_flush(struct drm_connector *connector,
 		int x, int y, int w, int h);
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd);
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo);
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb);
 int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 		void **vaddr, dma_addr_t *paddr, unsigned int *screen_width);
@@ -132,4 +133,29 @@ static inline int align_pitch(int pitch, int width, int bpp)
 	return ALIGN(pitch, 8 * bytespp);
 }
 
+/* should these be made into common util helpers?
+ */
+
+static inline int objects_lookup(struct drm_device *dev,
+		struct drm_file *filp, uint32_t pixel_format,
+		struct drm_gem_object **bos, uint32_t *handles)
+{
+	int i, n = drm_format_num_planes(pixel_format);
+
+	for (i = 0; i < n; i++) {
+		bos[i] = drm_gem_object_lookup(dev, filp, handles[i]);
+		if (!bos[i]) {
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	while (--i > 0) {
+		drm_gem_object_unreference_unlocked(bos[i]);
+	}
+	return -ENOENT;
+}
+
 #endif /* __OMAP_DRV_H__ */
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 0b50c5b..1f9e75f 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -22,11 +22,43 @@
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
-
 /*
  * framebuffer funcs
  */
 
+/* per-format info: */
+struct format {
+	enum omap_color_mode dss_format;
+	uint32_t pixel_format;
+	struct {
+		int stride_bpp;           /* this times width is stride */
+		int sub_y;                /* sub-sample in y dimension */
+	} planes[4];
+	bool yuv;
+};
+
+static const struct format formats[] = {
+	/* 16bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
+	{ OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
+	{ OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
+	{ OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
+	{ OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
+	{ OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */
+	{ OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */
+	/* 24bpp RGB: */
+	{ OMAP_DSS_COLOR_RGB24P,      DRM_FORMAT_RGB888,   {{3, 1}}, false }, /* RGB24-888 */
+	/* 32bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGBX32,      DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */
+	{ OMAP_DSS_COLOR_RGB24U,      DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */
+	{ OMAP_DSS_COLOR_RGBA32,      DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */
+	{ OMAP_DSS_COLOR_ARGB32,      DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */
+	/* YUV: */
+	{ OMAP_DSS_COLOR_NV12,        DRM_FORMAT_NV12,     {{1, 1}, {1, 2}}, true },
+	{ OMAP_DSS_COLOR_YUV2,        DRM_FORMAT_YUYV,     {{2, 1}}, true },
+	{ OMAP_DSS_COLOR_UYVY,        DRM_FORMAT_UYVY,     {{2, 1}}, true },
+};
+
 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
 
 struct omap_framebuffer {
@@ -34,6 +66,7 @@ struct omap_framebuffer {
 	struct drm_gem_object *bo;
 	int size;
 	dma_addr_t paddr;
+	const struct format *format;
 };
 
 static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -91,7 +124,7 @@ int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 	int bpp = fb->bits_per_pixel / 8;
 	unsigned long offset;
 
-	offset = (x * bpp) + (y * fb->pitch);
+	offset = (x * bpp) + (y * fb->pitches[0]);
 
 	if (vaddr) {
 		void *bo_vaddr = omap_gem_vaddr(omap_fb->bo);
@@ -105,7 +138,7 @@ int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 	}
 
 	*paddr = omap_fb->paddr + offset;
-	*screen_width = fb->pitch / bpp;
+	*screen_width = fb->pitches[0] / bpp;
 
 	return omap_fb->size - offset;
 }
@@ -171,39 +204,61 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,
 }
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd)
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	struct drm_gem_object *bo;
+	struct drm_gem_object *bos[4];
 	struct drm_framebuffer *fb;
-	bo = drm_gem_object_lookup(dev, file, mode_cmd->handle);
-	if (!bo) {
-		return ERR_PTR(-ENOENT);
-	}
-	fb = omap_framebuffer_init(dev, mode_cmd, bo);
-	if (!fb) {
-		return ERR_PTR(-ENOMEM);
+	int ret;
+
+	ret = objects_lookup(dev, file, mode_cmd->pixel_format,
+			bos, mode_cmd->handles);
+	if (ret)
+		return ERR_PTR(ret);
+
+	fb = omap_framebuffer_init(dev, mode_cmd, bos);
+	if (IS_ERR(fb)) {
+		int i, n = drm_format_num_planes(mode_cmd->pixel_format);
+		for (i = 0; i < n; i++)
+			drm_gem_object_unreference_unlocked(bos[i]);
+		return fb;
 	}
 	return fb;
 }
 
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo)
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
 	struct omap_framebuffer *omap_fb;
 	struct drm_framebuffer *fb = NULL;
-	int size, ret;
+	const struct format *format = NULL;
+	int i, size, ret;
 
-	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)",
+	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
 			dev, mode_cmd, mode_cmd->width, mode_cmd->height,
-			mode_cmd->bpp);
+			(char *)&mode_cmd->pixel_format);
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].pixel_format == mode_cmd->pixel_format) {
+			format = &formats[i];
+			break;
+		}
+	}
+
+	if (!format) {
+		dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
+				(char *)&mode_cmd->pixel_format);
+		ret = -EINVAL;
+		goto fail;
+	}
 
 	/* in case someone tries to feed us a completely bogus stride: */
-	mode_cmd->pitch = align_pitch(mode_cmd->pitch,
-			mode_cmd->width, mode_cmd->bpp);
+	mode_cmd->pitches[0] = align_pitch(mode_cmd->pitches[0],
+			mode_cmd->width, format->planes[0].stride_bpp);
 
 	omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
 	if (!omap_fb) {
 		dev_err(dev->dev, "could not allocate fb\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
@@ -216,17 +271,19 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
 	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
 
-	size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height);
+	size = PAGE_ALIGN(mode_cmd->pitches[0] * mode_cmd->height);
 
-	if (size > bo->size) {
+	if (size > bos[0]->size) {
 		dev_err(dev->dev, "provided buffer object is too small!\n");
+		ret = -EINVAL;
 		goto fail;
 	}
 
-	omap_fb->bo = bo;
+	omap_fb->bo = bos[0];
 	omap_fb->size = size;
 
-	if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) {
+	ret = omap_gem_get_paddr(bos[0], &omap_fb->paddr, true);
+	if (ret) {
 		dev_err(dev->dev, "could not map (paddr)!\n");
 		goto fail;
 	}
@@ -239,5 +296,5 @@ fail:
 	if (fb) {
 		omap_framebuffer_destroy(fb);
 	}
-	return NULL;
+	return ERR_PTR(ret);
 }
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 093ae2f..ba45306 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -129,10 +129,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 	struct drm_framebuffer *fb = NULL;
 	union omap_gem_size gsize;
 	struct fb_info *fbi = NULL;
-	struct drm_mode_fb_cmd mode_cmd = {0};
+	struct drm_mode_fb_cmd2 mode_cmd = {0};
 	dma_addr_t paddr;
-	void __iomem *vaddr;
-	int size, screen_width;
 	int ret;
 
 	/* only doing ARGB32 since this is what is needed to alpha-blend
@@ -145,36 +143,56 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 			sizes->surface_height, sizes->surface_bpp,
 			sizes->fb_width, sizes->fb_height);
 
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+			sizes->surface_depth);
+
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 
-	mode_cmd.bpp = sizes->surface_bpp;
-	mode_cmd.depth = sizes->surface_depth;
-
-	mode_cmd.pitch = align_pitch(
-			mode_cmd.width * ((mode_cmd.bpp + 7) / 8),
-			mode_cmd.width, mode_cmd.bpp);
+	mode_cmd.pitches[0] = align_pitch(
+			mode_cmd.width * ((sizes->surface_bpp + 7) / 8),
+			mode_cmd.width, sizes->surface_bpp);
 
 	fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled;
 	if (fbdev->ywrap_enabled) {
 		/* need to align pitch to page size if using DMM scrolling */
-		mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE);
+		mode_cmd.pitches[0] = ALIGN(mode_cmd.pitches[0], PAGE_SIZE);
 	}
 
 	/* allocate backing bo */
 	gsize = (union omap_gem_size){
-		.bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height),
+		.bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height),
 	};
 	DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
 	fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
 	if (!fbdev->bo) {
 		dev_err(dev->dev, "failed to allocate buffer object\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
-	fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo);
-	if (!fb) {
+	fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo);
+	if (IS_ERR(fb)) {
 		dev_err(dev->dev, "failed to allocate fb\n");
+		/* note: if fb creation failed, we can't rely on fb destroy
+		 * to unref the bo:
+		 */
+		drm_gem_object_unreference(fbdev->bo);
+		ret = PTR_ERR(fb);
+		goto fail;
+	}
+
+	/* note: this keeps the bo pinned.. which is perhaps not ideal,
+	 * but is needed as long as we use fb_mmap() to mmap to userspace
+	 * (since this happens using fix.smem_start).  Possibly we could
+	 * implement our own mmap using GEM mmap support to avoid this
+	 * (non-tiled buffer doesn't need to be pinned for fbcon to write
+	 * to it).  Then we just need to be sure that we are able to re-
+	 * pin it in case of an opps.
+	 */
+	ret = omap_gem_get_paddr(fbdev->bo, &paddr, true);
+	if (ret) {
+		dev_err(dev->dev, "could not map (paddr)!\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -206,18 +224,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 		goto fail_unlock;
 	}
 
-	drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
-	size = omap_framebuffer_get_buffer(fb, 0, 0,
-			&vaddr, &paddr, &screen_width);
-
 	dev->mode_config.fb_base = paddr;
 
-	fbi->screen_base = vaddr;
-	fbi->screen_size = size;
+	fbi->screen_base = omap_gem_vaddr(fbdev->bo);
+	fbi->screen_size = fbdev->bo->size;
 	fbi->fix.smem_start = paddr;
-	fbi->fix.smem_len = size;
+	fbi->fix.smem_len = fbdev->bo->size;
 
 	/* if we have DMM, then we can use it for scrolling by just
 	 * shuffling pages around in DMM rather than doing sw blit.
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] drm/omap: add drm_plane support
  2011-12-20 22:58 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
  2011-12-20 22:58 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
@ 2011-12-20 22:58 ` Rob Clark
  2011-12-20 22:58 ` [PATCH 3/3] drm/omap: multiplanar and YUV support Rob Clark
  2 siblings, 0 replies; 10+ messages in thread
From: Rob Clark @ 2011-12-20 22:58 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

Because framebuffer layer and overlay scanout video pipes are basically
thing in OMAP display subsystem (the only difference being that the first
video pipe does not support scaling or YUV formats), much of the CRTC
code is pulled into the plane implementation, and a private plane object
is used by the CRTC object.  This avoids code duplication between the
plane and CRTC.

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/Makefile     |    1 +
 drivers/staging/omapdrm/omap_crtc.c  |  189 +++++----------------
 drivers/staging/omapdrm/omap_drv.c   |   53 ++++---
 drivers/staging/omapdrm/omap_drv.h   |    8 +-
 drivers/staging/omapdrm/omap_plane.c |  308 ++++++++++++++++++++++++++++++++++
 drivers/staging/omapdrm/omap_priv.h  |   12 +-
 6 files changed, 403 insertions(+), 168 deletions(-)
 create mode 100644 drivers/staging/omapdrm/omap_plane.c

diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index 592cf69..d9cdc12 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -7,6 +7,7 @@ ccflags-y := -Iinclude/drm -Werror
 omapdrm-y := omap_drv.o \
 	omap_debugfs.o \
 	omap_crtc.o \
+	omap_plane.o \
 	omap_encoder.o \
 	omap_connector.o \
 	omap_fb.o \
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index cffdf5e..a91c788 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -27,196 +27,95 @@
 
 struct omap_crtc {
 	struct drm_crtc base;
-	struct omap_overlay *ovl;
-	struct omap_overlay_info info;
+	struct drm_plane *plane;
+	const char *name;
 	int id;
 
-	/* if there is a pending flip, this will be non-null: */
+	/* if there is a pending flip, these will be non-null: */
 	struct drm_pending_vblank_event *event;
+	struct drm_framebuffer *old_fb;
 };
 
-/* push changes down to dss2 */
-static int commit(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	struct omap_overlay *ovl = omap_crtc->ovl;
-	struct omap_overlay_info *info = &omap_crtc->info;
-	int ret;
-
-	DBG("%s", omap_crtc->ovl->name);
-	DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
-			info->out_height, info->screen_width);
-	DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);
-
-	/* NOTE: do we want to do this at all here, or just wait
-	 * for dpms(ON) since other CRTC's may not have their mode
-	 * set yet, so fb dimensions may still change..
-	 */
-	ret = ovl->set_overlay_info(ovl, info);
-	if (ret) {
-		dev_err(dev->dev, "could not set overlay info\n");
-		return ret;
-	}
-
-	/* our encoder doesn't necessarily get a commit() after this, in
-	 * particular in the dpms() and mode_set_base() cases, so force the
-	 * manager to update:
-	 *
-	 * could this be in the encoder somehow?
-	 */
-	if (ovl->manager) {
-		ret = ovl->manager->apply(ovl->manager);
-		if (ret) {
-			dev_err(dev->dev, "could not apply settings\n");
-			return ret;
-		}
-	}
-
-	if (info->enabled) {
-		omap_framebuffer_flush(crtc->fb, crtc->x, crtc->y,
-				crtc->fb->width, crtc->fb->height);
-	}
-
-	return 0;
-}
-
-/* update parameters that are dependent on the framebuffer dimensions and
- * position within the fb that this crtc scans out from. This is called
- * when framebuffer dimensions or x,y base may have changed, either due
- * to our mode, or a change in another crtc that is scanning out of the
- * same fb.
- */
-static void update_scanout(struct drm_crtc *crtc)
-{
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	dma_addr_t paddr;
-	unsigned int screen_width;
-
-	omap_framebuffer_get_buffer(crtc->fb, crtc->x, crtc->y,
-			NULL, &paddr, &screen_width);
-
-	DBG("%s: %d,%d: %08x (%d)", omap_crtc->ovl->name,
-			crtc->x, crtc->y, (u32)paddr, screen_width);
-
-	omap_crtc->info.paddr = paddr;
-	omap_crtc->info.screen_width = screen_width;
-}
-
 static void omap_crtc_gamma_set(struct drm_crtc *crtc,
 		u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size)
 {
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	DBG("%s", omap_crtc->ovl->name);
+	/* not supported.. at least not yet */
 }
 
 static void omap_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	DBG("%s", omap_crtc->ovl->name);
+	omap_crtc->plane->funcs->destroy(omap_crtc->plane);
 	drm_crtc_cleanup(crtc);
 	kfree(omap_crtc);
 }
 
 static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
+	struct omap_drm_private *priv = crtc->dev->dev_private;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	int i;
 
-	DBG("%s: %d", omap_crtc->ovl->name, mode);
+	WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
 
-	if (mode == DRM_MODE_DPMS_ON) {
-		update_scanout(crtc);
-		omap_crtc->info.enabled = true;
-	} else {
-		omap_crtc->info.enabled = false;
+	for (i = 0; i < priv->num_planes; i++) {
+		struct drm_plane *plane = priv->planes[i];
+		if (plane->crtc == crtc)
+			WARN_ON(omap_plane_dpms(plane, mode));
 	}
-
-	WARN_ON(commit(crtc));
 }
 
 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
-				  struct drm_display_mode *mode,
-				  struct drm_display_mode *adjusted_mode)
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
 {
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	DBG("%s", omap_crtc->ovl->name);
 	return true;
 }
 
 static int omap_crtc_mode_set(struct drm_crtc *crtc,
-			       struct drm_display_mode *mode,
-			       struct drm_display_mode *adjusted_mode,
-			       int x, int y,
-			       struct drm_framebuffer *old_fb)
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode,
+		int x, int y,
+		struct drm_framebuffer *old_fb)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct drm_plane *plane = omap_crtc->plane;
 
-	DBG("%s: %d,%d: %dx%d", omap_crtc->ovl->name, x, y,
-			mode->hdisplay, mode->vdisplay);
-
-	/* just use adjusted mode */
-	mode = adjusted_mode;
-
-	omap_crtc->info.width = mode->hdisplay;
-	omap_crtc->info.height = mode->vdisplay;
-	omap_crtc->info.out_width = mode->hdisplay;
-	omap_crtc->info.out_height = mode->vdisplay;
-	omap_crtc->info.color_mode = OMAP_DSS_COLOR_RGB24U;
-	omap_crtc->info.rotation_type = OMAP_DSS_ROT_DMA;
-	omap_crtc->info.rotation = OMAP_DSS_ROT_0;
-	omap_crtc->info.global_alpha = 0xff;
-	omap_crtc->info.mirror = 0;
-	omap_crtc->info.mirror = 0;
-	omap_crtc->info.pos_x = 0;
-	omap_crtc->info.pos_y = 0;
-#if 0 /* re-enable when these are available in DSS2 driver */
-	omap_crtc->info.zorder = 3;        /* GUI in the front, video behind */
-	omap_crtc->info.min_x_decim = 1;
-	omap_crtc->info.max_x_decim = 1;
-	omap_crtc->info.min_y_decim = 1;
-	omap_crtc->info.max_y_decim = 1;
-#endif
-
-	update_scanout(crtc);
-
-	return 0;
+	return plane->funcs->update_plane(plane, crtc, crtc->fb,
+			0, 0, mode->hdisplay, mode->vdisplay,
+			x << 16, y << 16,
+			mode->hdisplay << 16, mode->vdisplay << 16);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	struct omap_overlay *ovl = omap_crtc->ovl;
-
-	DBG("%s", omap_crtc->ovl->name);
-
-	ovl->get_overlay_info(ovl, &omap_crtc->info);
-
+	DBG("%s", omap_crtc->name);
 	omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 static void omap_crtc_commit(struct drm_crtc *crtc)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	DBG("%s", omap_crtc->ovl->name);
+	DBG("%s", omap_crtc->name);
 	omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 }
 
 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-		    struct drm_framebuffer *old_fb)
+		struct drm_framebuffer *old_fb)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct drm_plane *plane = omap_crtc->plane;
+	struct drm_display_mode *mode = &crtc->mode;
 
-	DBG("%s %d,%d: fb=%p", omap_crtc->ovl->name, x, y, old_fb);
-
-	update_scanout(crtc);
-
-	return commit(crtc);
+	return plane->funcs->update_plane(plane, crtc, crtc->fb,
+			0, 0, mode->hdisplay, mode->vdisplay,
+			x << 16, y << 16,
+			mode->hdisplay << 16, mode->vdisplay << 16);
 }
 
 static void omap_crtc_load_lut(struct drm_crtc *crtc)
 {
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	DBG("%s", omap_crtc->ovl->name);
 }
 
 static void page_flip_cb(void *arg)
@@ -225,15 +124,16 @@ static void page_flip_cb(void *arg)
 	struct drm_device *dev = crtc->dev;
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_pending_vblank_event *event = omap_crtc->event;
+	struct drm_framebuffer *old_fb = omap_crtc->old_fb;
 	struct timeval now;
 	unsigned long flags;
 
 	WARN_ON(!event);
 
 	omap_crtc->event = NULL;
+	omap_crtc->old_fb = NULL;
 
-	update_scanout(crtc);
-	WARN_ON(commit(crtc));
+	omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
 
 	/* wakeup userspace */
 	/* TODO: this should happen *after* flip in vsync IRQ handler */
@@ -264,8 +164,9 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 		return -EINVAL;
 	}
 
-	crtc->fb = fb;
+	omap_crtc->old_fb = crtc->fb;
 	omap_crtc->event = event;
+	crtc->fb = fb;
 
 	omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ,
 			page_flip_cb, crtc);
@@ -290,12 +191,6 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
 	.load_lut = omap_crtc_load_lut,
 };
 
-struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc)
-{
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	return omap_crtc->ovl;
-}
-
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 		struct omap_overlay *ovl, int id)
@@ -310,9 +205,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 		goto fail;
 	}
 
-	omap_crtc->ovl = ovl;
-	omap_crtc->id = id;
 	crtc = &omap_crtc->base;
+
+	omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true);
+	omap_crtc->plane->crtc = crtc;
+	omap_crtc->name = ovl->name;
+	omap_crtc->id = id;
+
 	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 4db40f7..2de99ff 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -204,12 +204,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
 	struct omap_overlay_manager *mgr = NULL;
 	struct drm_crtc *crtc;
 
-	if (ovl->manager) {
-		DBG("disconnecting %s from %s", ovl->name,
-					ovl->manager->name);
-		ovl->unset_manager(ovl);
-	}
-
 	/* find next best connector, ones with detected connection first
 	 */
 	while (*j < priv->num_connectors && !mgr) {
@@ -245,11 +239,6 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
 		(*j)++;
 	}
 
-	if (mgr) {
-		DBG("connecting %s to %s", ovl->name, mgr->name);
-		ovl->set_manager(ovl, mgr);
-	}
-
 	crtc = omap_crtc_init(dev, ovl, priv->num_crtcs);
 
 	if (!crtc) {
@@ -265,6 +254,26 @@ static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
 	return 0;
 }
 
+static int create_plane(struct drm_device *dev, struct omap_overlay *ovl,
+		unsigned int possible_crtcs)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	struct drm_plane *plane =
+			omap_plane_init(dev, ovl, possible_crtcs, false);
+
+	if (!plane) {
+		dev_err(dev->dev, "could not create plane: %s\n",
+				ovl->name);
+		return -ENOMEM;
+	}
+
+	BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
+
+	priv->planes[priv->num_planes++] = plane;
+
+	return 0;
+}
+
 static int match_dev_name(struct omap_dss_device *dssdev, void *data)
 {
 	return !strcmp(dssdev->name, data);
@@ -332,6 +341,12 @@ static int omap_modeset_init(struct drm_device *dev)
 				omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
 			create_crtc(dev, ovl, &j, connected_connectors);
 		}
+
+		for (i = 0; i < kms_pdata->pln_cnt; i++) {
+			struct omap_overlay *ovl =
+				omap_dss_get_overlay(kms_pdata->pln_ids[i]);
+			create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
+		}
 	} else {
 		/* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try
 		 * to make educated guesses about everything else
@@ -353,6 +368,12 @@ static int omap_modeset_init(struct drm_device *dev)
 			create_crtc(dev, omap_dss_get_overlay(i),
 					&j, connected_connectors);
 		}
+
+		/* use any remaining overlays as drm planes */
+		for (; i < omap_dss_get_num_overlays(); i++) {
+			struct omap_overlay *ovl = omap_dss_get_overlay(i);
+			create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
+		}
 	}
 
 	/* for now keep the mapping of CRTCs and encoders static.. */
@@ -361,15 +382,7 @@ static int omap_modeset_init(struct drm_device *dev)
 		struct omap_overlay_manager *mgr =
 				omap_encoder_get_manager(encoder);
 
-		encoder->possible_crtcs = 0;
-
-		for (j = 0; j < priv->num_crtcs; j++) {
-			struct omap_overlay *ovl =
-					omap_crtc_get_overlay(priv->crtcs[j]);
-			if (ovl->manager == mgr) {
-				encoder->possible_crtcs |= (1 << j);
-			}
-		}
+		encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
 
 		DBG("%s: possible_crtcs=%08x", mgr->name,
 					encoder->possible_crtcs);
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 4ad2ae5..e2b1b55 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -42,6 +42,8 @@
 struct omap_drm_private {
 	unsigned int num_crtcs;
 	struct drm_crtc *crtcs[8];
+	unsigned int num_planes;
+	struct drm_plane *planes[8];
 	unsigned int num_encoders;
 	struct drm_encoder *encoders[8];
 	unsigned int num_connectors;
@@ -62,7 +64,11 @@ void omap_fbdev_free(struct drm_device *dev);
 
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 		struct omap_overlay *ovl, int id);
-struct omap_overlay *omap_crtc_get_overlay(struct drm_crtc *crtc);
+
+struct drm_plane *omap_plane_init(struct drm_device *dev,
+		struct omap_overlay *ovl, unsigned int possible_crtcs,
+		bool priv);
+int omap_plane_dpms(struct drm_plane *plane, int mode);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
 		struct omap_overlay_manager *mgr);
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
new file mode 100644
index 0000000..a1d948c
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -0,0 +1,308 @@
+/*
+ * drivers/staging/omapdrm/omap_plane.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "omap_drv.h"
+
+/* some hackery because omapdss has an 'enum omap_plane' (which would be
+ * better named omap_plane_id).. and compiler seems unhappy about having
+ * both a 'struct omap_plane' and 'enum omap_plane'
+ */
+#define omap_plane _omap_plane
+
+/*
+ * plane funcs
+ */
+
+#define to_omap_plane(x) container_of(x, struct omap_plane, base)
+
+struct omap_plane {
+	struct drm_plane base;
+	struct omap_overlay *ovl;
+	struct omap_overlay_info info;
+
+	/* Source values, converted to integers because we don't support
+	 * fractional positions:
+	 */
+	unsigned int src_x, src_y;
+};
+
+
+/* push changes down to dss2 */
+static int commit(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_overlay *ovl = omap_plane->ovl;
+	struct omap_overlay_info *info = &omap_plane->info;
+	int ret;
+
+	DBG("%s", ovl->name);
+	DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
+			info->out_height, info->screen_width);
+	DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);
+
+	/* NOTE: do we want to do this at all here, or just wait
+	 * for dpms(ON) since other CRTC's may not have their mode
+	 * set yet, so fb dimensions may still change..
+	 */
+	ret = ovl->set_overlay_info(ovl, info);
+	if (ret) {
+		dev_err(dev->dev, "could not set overlay info\n");
+		return ret;
+	}
+
+	/* our encoder doesn't necessarily get a commit() after this, in
+	 * particular in the dpms() and mode_set_base() cases, so force the
+	 * manager to update:
+	 *
+	 * could this be in the encoder somehow?
+	 */
+	if (ovl->manager) {
+		ret = ovl->manager->apply(ovl->manager);
+		if (ret) {
+			dev_err(dev->dev, "could not apply settings\n");
+			return ret;
+		}
+	}
+
+	if (info->enabled) {
+		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+				info->out_width, info->out_height);
+	}
+
+	return 0;
+}
+
+/* when CRTC that we are attached to has potentially changed, this checks
+ * if we are attached to proper manager, and if necessary updates.
+ */
+static void update_manager(struct drm_plane *plane)
+{
+	struct omap_drm_private *priv = plane->dev->dev_private;
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_overlay *ovl = omap_plane->ovl;
+	struct omap_overlay_manager *mgr = NULL;
+	int i;
+
+	if (plane->crtc) {
+		for (i = 0; i < priv->num_encoders; i++) {
+			struct drm_encoder *encoder = priv->encoders[i];
+			if (encoder->crtc == plane->crtc) {
+				mgr = omap_encoder_get_manager(encoder);
+				break;
+			}
+		}
+	}
+
+	if (ovl->manager != mgr) {
+		bool enabled = omap_plane->info.enabled;
+
+		/* don't switch things around with enabled overlays: */
+		if (enabled)
+			omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+
+		if (ovl->manager) {
+			DBG("disconnecting %s from %s", ovl->name,
+					ovl->manager->name);
+			ovl->unset_manager(ovl);
+		}
+
+		if (mgr) {
+			DBG("connecting %s to %s", ovl->name, mgr->name);
+			ovl->set_manager(ovl, mgr);
+		}
+
+		if (enabled && mgr)
+			omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
+	}
+}
+
+/* update parameters that are dependent on the framebuffer dimensions and
+ * position within the fb that this plane scans out from. This is called
+ * when framebuffer or x,y base may have changed.
+ */
+static void update_scanout(struct drm_plane *plane)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	unsigned int screen_width; /* really means "pitch" */
+	dma_addr_t paddr;
+
+	omap_framebuffer_get_buffer(plane->fb,
+			omap_plane->src_x, omap_plane->src_y,
+			NULL, &paddr, &screen_width);
+
+	DBG("%s: %d,%d: %08x (%d)", omap_plane->ovl->name,
+			omap_plane->src_x, omap_plane->src_y,
+			(u32)paddr, screen_width);
+
+	omap_plane->info.paddr = paddr;
+	omap_plane->info.screen_width = screen_width;
+}
+
+static int omap_plane_update(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+
+	/* src values are in Q16 fixed point, convert to integer: */
+	src_x = src_x >> 16;
+	src_y = src_y >> 16;
+	src_w = src_w >> 16;
+	src_h = src_h >> 16;
+
+	omap_plane->info.enabled = true;
+	omap_plane->info.pos_x = crtc_x;
+	omap_plane->info.pos_y = crtc_y;
+	omap_plane->info.out_width = crtc_w;
+	omap_plane->info.out_height = crtc_h;
+	omap_plane->info.width = src_w;
+	omap_plane->info.height = src_h;
+	omap_plane->src_x = src_x;
+	omap_plane->src_y = src_y;
+
+	/* note: this is done after this fxn returns.. but if we need
+	 * to do a commit/update_scanout, etc before this returns we
+	 * need the current value.
+	 */
+	plane->fb = fb;
+	plane->crtc = crtc;
+
+	update_scanout(plane);
+	update_manager(plane);
+	commit(plane);
+
+	return 0;
+}
+
+static int omap_plane_disable(struct drm_plane *plane)
+{
+	return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+}
+
+static void omap_plane_destroy(struct drm_plane *plane)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	DBG("%s", omap_plane->ovl->name);
+	omap_plane_disable(plane);
+	drm_plane_cleanup(plane);
+	kfree(omap_plane);
+}
+
+int omap_plane_dpms(struct drm_plane *plane, int mode)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+
+	DBG("%s: %d", omap_plane->ovl->name, mode);
+
+	if (mode == DRM_MODE_DPMS_ON) {
+		update_scanout(plane);
+		omap_plane->info.enabled = true;
+	} else {
+		omap_plane->info.enabled = false;
+	}
+
+	return commit(plane);
+}
+
+static const struct drm_plane_funcs omap_plane_funcs = {
+		.update_plane = omap_plane_update,
+		.disable_plane = omap_plane_disable,
+		.destroy = omap_plane_destroy,
+};
+
+static const uint32_t formats[] = {
+		DRM_FORMAT_RGB565,
+		DRM_FORMAT_RGBX4444,
+		DRM_FORMAT_XRGB4444,
+		DRM_FORMAT_RGBA4444,
+		DRM_FORMAT_ABGR4444,
+		DRM_FORMAT_XRGB1555,
+		DRM_FORMAT_ARGB1555,
+		DRM_FORMAT_RGB888,
+		DRM_FORMAT_RGBX8888,
+		DRM_FORMAT_XRGB8888,
+		DRM_FORMAT_RGBA8888,
+		DRM_FORMAT_ARGB8888,
+		DRM_FORMAT_NV12,
+		DRM_FORMAT_YUYV,
+		DRM_FORMAT_UYVY,
+};
+
+/* initialize plane */
+struct drm_plane *omap_plane_init(struct drm_device *dev,
+		struct omap_overlay *ovl, unsigned int possible_crtcs,
+		bool priv)
+{
+	struct drm_plane *plane = NULL;
+	struct omap_plane *omap_plane;
+
+	DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name,
+			possible_crtcs, priv);
+
+	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
+	if (!omap_plane) {
+		dev_err(dev->dev, "could not allocate plane\n");
+		goto fail;
+	}
+
+	omap_plane->ovl = ovl;
+	plane = &omap_plane->base;
+
+	drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
+			formats, ARRAY_SIZE(formats), priv);
+
+	/* get our starting configuration, set defaults for parameters
+	 * we don't currently use, etc:
+	 */
+	ovl->get_overlay_info(ovl, &omap_plane->info);
+	omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA;
+	omap_plane->info.rotation = OMAP_DSS_ROT_0;
+	omap_plane->info.global_alpha = 0xff;
+	omap_plane->info.mirror = 0;
+	omap_plane->info.mirror = 0;
+
+	/* Set defaults depending on whether we are a CRTC or overlay
+	 * layer.
+	 * TODO add ioctl to give userspace an API to change this.. this
+	 * will come in a subsequent patch.
+	 */
+	if (priv)
+		omap_plane->info.zorder = 0;
+	else
+		omap_plane->info.zorder = 1;
+
+	/* TODO color mode should come from fb.. this will come in a
+	 * subsequent patch
+	 */
+	omap_plane->info.color_mode = OMAP_DSS_COLOR_RGB24U;
+
+	update_manager(plane);
+
+	return plane;
+
+fail:
+	if (plane) {
+		omap_plane_destroy(plane);
+	}
+	return NULL;
+}
diff --git a/drivers/staging/omapdrm/omap_priv.h b/drivers/staging/omapdrm/omap_priv.h
index c324709..ef64414 100644
--- a/drivers/staging/omapdrm/omap_priv.h
+++ b/drivers/staging/omapdrm/omap_priv.h
@@ -27,14 +27,22 @@
  * pipes/overlays/CRTCs are used.. if this is not provided, then instead the
  * first CONFIG_DRM_OMAP_NUM_CRTCS are used, and they are each connected to
  * one manager, with priority given to managers that are connected to
- * detected devices.  This should be a good default behavior for most cases,
- * but yet there still might be times when you wish to do something different.
+ * detected devices.  Remaining overlays are used as video planes.  This
+ * should be a good default behavior for most cases, but yet there still
+ * might be times when you wish to do something different.
  */
 struct omap_kms_platform_data {
+	/* overlays to use as CRTCs: */
 	int ovl_cnt;
 	const int *ovl_ids;
+
+	/* overlays to use as video planes: */
+	int pln_cnt;
+	const int *pln_ids;
+
 	int mgr_cnt;
 	const int *mgr_ids;
+
 	int dev_cnt;
 	const char **dev_names;
 };
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] drm/omap: multiplanar and YUV support
  2011-12-20 22:58 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
  2011-12-20 22:58 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
  2011-12-20 22:58 ` [PATCH 2/3] drm/omap: add drm_plane support Rob Clark
@ 2011-12-20 22:58 ` Rob Clark
  2 siblings, 0 replies; 10+ messages in thread
From: Rob Clark @ 2011-12-20 22:58 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

Add support in framebuffer objects for other color formats and multi-
planar YUV (NV12).  Since this requires changing the API between the
plane and fb for getting scanout information (paddr, etc), take
advantage of the opportunity and put in place a way to allow fb's to
be unpinned when they are not being scanned out.  Now, before start
of scanout the plane calls omap_framebuffer_pin() which takes care
to pin all the backing bo's, then omap_framebuffer_update_scanout()
however many times to update the scanout address(es), etc, and then
when finished omap_framebuffer_unpin().

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/omap_crtc.c  |    2 +-
 drivers/staging/omapdrm/omap_drv.h   |    8 +-
 drivers/staging/omapdrm/omap_fb.c    |  149 +++++++++++++++++++++++-----------
 drivers/staging/omapdrm/omap_gem.c   |    5 +
 drivers/staging/omapdrm/omap_plane.c |   53 +++++++++----
 5 files changed, 149 insertions(+), 68 deletions(-)

diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index a91c788..3cee04e 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -168,7 +168,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	omap_crtc->event = event;
 	crtc->fb = fb;
 
-	omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ,
+	omap_gem_op_async(omap_framebuffer_bo(fb, 0), OMAP_GEM_READ,
 			page_flip_cb, crtc);
 
 	return 0;
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index e2b1b55..48f6fce 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -90,9 +90,11 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
 		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
-struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb);
-int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
-		void **vaddr, dma_addr_t *paddr, unsigned int *screen_width);
+struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
+int omap_framebuffer_pin(struct drm_framebuffer *fb);
+void omap_framebuffer_unpin(struct drm_framebuffer *fb);
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
+		struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
 		struct drm_framebuffer *fb, struct drm_connector *from);
 void omap_framebuffer_flush(struct drm_framebuffer *fb,
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 1f9e75f..7ea491c 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -59,14 +59,20 @@ static const struct format formats[] = {
 	{ OMAP_DSS_COLOR_UYVY,        DRM_FORMAT_UYVY,     {{2, 1}}, true },
 };
 
+/* per-plane info for the fb: */
+struct plane {
+	struct drm_gem_object *bo;
+	uint32_t pitch;
+	uint32_t offset;
+	dma_addr_t paddr;
+};
+
 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
 
 struct omap_framebuffer {
 	struct drm_framebuffer base;
-	struct drm_gem_object *bo;
-	int size;
-	dma_addr_t paddr;
 	const struct format *format;
+	struct plane planes[4];
 };
 
 static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -74,22 +80,23 @@ static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
 		unsigned int *handle)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-    return drm_gem_handle_create(file_priv, omap_fb->bo, handle);
+	return drm_gem_handle_create(file_priv,
+			omap_fb->planes[0].bo, handle);
 }
 
 static void omap_framebuffer_destroy(struct drm_framebuffer *fb)
 {
-	struct drm_device *dev = fb->dev;
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
+	int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
 
 	DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
 
 	drm_framebuffer_cleanup(fb);
 
-	if (omap_fb->bo) {
-		if (omap_fb->paddr && omap_gem_put_paddr(omap_fb->bo))
-			dev_err(dev->dev, "could not unmap!\n");
-		drm_gem_object_unreference_unlocked(omap_fb->bo);
+	for (i = 0; i < n; i++) {
+		struct plane *plane = &omap_fb->planes[i];
+		if (plane->bo)
+			drm_gem_object_unreference_unlocked(plane->bo);
 	}
 
 	kfree(omap_fb);
@@ -116,37 +123,76 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
 	.dirty = omap_framebuffer_dirty,
 };
 
-/* returns the buffer size */
-int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
-		void **vaddr, dma_addr_t *paddr, unsigned int *screen_width)
+/* pins buffer in preparation for scanout */
+int omap_framebuffer_pin(struct drm_framebuffer *fb)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	int bpp = fb->bits_per_pixel / 8;
-	unsigned long offset;
-
-	offset = (x * bpp) + (y * fb->pitches[0]);
-
-	if (vaddr) {
-		void *bo_vaddr = omap_gem_vaddr(omap_fb->bo);
-		/* note: we can only count on having a vaddr for buffers that
-		 * are allocated physically contiguously to begin with (ie.
-		 * dma_alloc_coherent()).  But this should be ok because it
-		 * is only used by legacy fbdev
-		 */
-		BUG_ON(IS_ERR_OR_NULL(bo_vaddr));
-		*vaddr = bo_vaddr + offset;
+	int ret, i, n = drm_format_num_planes(omap_fb->format->pixel_format);
+
+	for (i = 0; i < n; i++) {
+		struct plane *plane = &omap_fb->planes[i];
+		ret = omap_gem_get_paddr(plane->bo, &plane->paddr, true);
+		if (ret)
+			goto fail;
 	}
 
-	*paddr = omap_fb->paddr + offset;
-	*screen_width = fb->pitches[0] / bpp;
+	return 0;
 
-	return omap_fb->size - offset;
+fail:
+	while (--i > 0) {
+		struct plane *plane = &omap_fb->planes[i];
+		omap_gem_put_paddr(plane->bo);
+	}
+	return ret;
 }
 
-struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb)
+/* releases buffer when done with scanout */
+void omap_framebuffer_unpin(struct drm_framebuffer *fb)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
-	return omap_fb->bo;
+	int i, n = drm_format_num_planes(omap_fb->format->pixel_format);
+
+	for (i = 0; i < n; i++) {
+		struct plane *plane = &omap_fb->planes[i];
+		omap_gem_put_paddr(plane->bo);
+	}
+}
+
+/* update ovl info for scanout, handles cases of multi-planar fb's, etc.
+ */
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
+		struct omap_overlay_info *info)
+{
+	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
+	const struct format *format = omap_fb->format;
+	struct plane *plane = &omap_fb->planes[0];
+	unsigned int offset;
+
+	offset = plane->offset +
+			(x * format->planes[0].stride_bpp) +
+			(y * plane->pitch / format->planes[0].sub_y);
+
+	info->color_mode   = format->dss_format;
+	info->paddr        = plane->paddr + offset;
+	info->screen_width = plane->pitch / format->planes[0].stride_bpp;
+
+	if (format->dss_format == OMAP_DSS_COLOR_NV12) {
+		plane = &omap_fb->planes[1];
+		offset = plane->offset +
+				(x * format->planes[1].stride_bpp) +
+				(y * plane->pitch / format->planes[1].sub_y);
+		info->p_uv_addr = plane->paddr + offset;
+	} else {
+		info->p_uv_addr = 0;
+	}
+}
+
+struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p)
+{
+	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
+	if (p >= drm_format_num_planes(omap_fb->format->pixel_format))
+		return NULL;
+	return omap_fb->planes[p].bo;
 }
 
 /* iterate thru all the connectors, returning ones that are attached
@@ -231,7 +277,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 	struct omap_framebuffer *omap_fb;
 	struct drm_framebuffer *fb = NULL;
 	const struct format *format = NULL;
-	int i, size, ret;
+	int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
 
 	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
 			dev, mode_cmd, mode_cmd->width, mode_cmd->height,
@@ -251,10 +297,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 		goto fail;
 	}
 
-	/* in case someone tries to feed us a completely bogus stride: */
-	mode_cmd->pitches[0] = align_pitch(mode_cmd->pitches[0],
-			mode_cmd->width, format->planes[0].stride_bpp);
-
 	omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
 	if (!omap_fb) {
 		dev_err(dev->dev, "could not allocate fb\n");
@@ -271,21 +313,32 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
 	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
 
-	size = PAGE_ALIGN(mode_cmd->pitches[0] * mode_cmd->height);
+	omap_fb->format = format;
 
-	if (size > bos[0]->size) {
-		dev_err(dev->dev, "provided buffer object is too small!\n");
-		ret = -EINVAL;
-		goto fail;
-	}
+	for (i = 0; i < n; i++) {
+		struct plane *plane = &omap_fb->planes[i];
+		int size, pitch = mode_cmd->pitches[i];
 
-	omap_fb->bo = bos[0];
-	omap_fb->size = size;
+		if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) {
+			dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n",
+					pitch, mode_cmd->width * format->planes[i].stride_bpp);
+			ret = -EINVAL;
+			goto fail;
+		}
 
-	ret = omap_gem_get_paddr(bos[0], &omap_fb->paddr, true);
-	if (ret) {
-		dev_err(dev->dev, "could not map (paddr)!\n");
-		goto fail;
+		size = pitch * mode_cmd->height / format->planes[i].sub_y;
+
+		if (size > (bos[i]->size - mode_cmd->offsets[i])) {
+			dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
+					bos[i]->size - mode_cmd->offsets[i], size);
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		plane->bo     = bos[i];
+		plane->offset = mode_cmd->offsets[i];
+		plane->pitch  = mode_cmd->pitches[i];
+		plane->paddr  = pitch;
 	}
 
 	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index e0ebd1d..ae1ad35 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -1034,6 +1034,11 @@ void omap_gem_free_object(struct drm_gem_object *obj)
 		drm_gem_free_mmap_offset(obj);
 	}
 
+	/* this means the object is still pinned.. which really should
+	 * not happen.  I think..
+	 */
+	WARN_ON(omap_obj->paddr_cnt > 0);
+
 	/* don't free externally allocated backing memory */
 	if (!(omap_obj->flags & OMAP_BO_EXT_MEM)) {
 		if (omap_obj->pages) {
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index a1d948c..66eed75 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -40,6 +40,9 @@ struct omap_plane {
 	 * fractional positions:
 	 */
 	unsigned int src_x, src_y;
+
+	/* last fb that we pinned: */
+	struct drm_framebuffer *pinned_fb;
 };
 
 
@@ -55,7 +58,8 @@ static int commit(struct drm_plane *plane)
 	DBG("%s", ovl->name);
 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
 			info->out_height, info->screen_width);
-	DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);
+	DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
+			info->paddr, info->p_uv_addr);
 
 	/* NOTE: do we want to do this at all here, or just wait
 	 * for dpms(ON) since other CRTC's may not have their mode
@@ -133,6 +137,23 @@ static void update_manager(struct drm_plane *plane)
 	}
 }
 
+/* update which fb (if any) is pinned for scanout */
+static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	int ret = 0;
+
+	if (omap_plane->pinned_fb != fb) {
+		if (omap_plane->pinned_fb)
+			omap_framebuffer_unpin(omap_plane->pinned_fb);
+		omap_plane->pinned_fb = fb;
+		if (fb)
+			ret = omap_framebuffer_pin(fb);
+	}
+
+	return ret;
+}
+
 /* update parameters that are dependent on the framebuffer dimensions and
  * position within the fb that this plane scans out from. This is called
  * when framebuffer or x,y base may have changed.
@@ -140,19 +161,23 @@ static void update_manager(struct drm_plane *plane)
 static void update_scanout(struct drm_plane *plane)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
-	unsigned int screen_width; /* really means "pitch" */
-	dma_addr_t paddr;
+	struct omap_overlay_info *info = &omap_plane->info;
+	int ret;
 
-	omap_framebuffer_get_buffer(plane->fb,
-			omap_plane->src_x, omap_plane->src_y,
-			NULL, &paddr, &screen_width);
+	ret = update_pin(plane, plane->fb);
+	if (ret) {
+		dev_err(plane->dev->dev,
+			"could not pin fb: %d\n", ret);
+		omap_plane->info.enabled = false;
+	}
 
-	DBG("%s: %d,%d: %08x (%d)", omap_plane->ovl->name,
-			omap_plane->src_x, omap_plane->src_y,
-			(u32)paddr, screen_width);
+	omap_framebuffer_update_scanout(plane->fb,
+			omap_plane->src_x, omap_plane->src_y, info);
 
-	omap_plane->info.paddr = paddr;
-	omap_plane->info.screen_width = screen_width;
+	DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name,
+			omap_plane->src_x, omap_plane->src_y,
+			(u32)info->paddr, (u32)info->p_uv_addr,
+			info->screen_width);
 }
 
 static int omap_plane_update(struct drm_plane *plane,
@@ -219,6 +244,7 @@ int omap_plane_dpms(struct drm_plane *plane, int mode)
 		omap_plane->info.enabled = true;
 	} else {
 		omap_plane->info.enabled = false;
+		update_pin(plane, NULL);
 	}
 
 	return commit(plane);
@@ -291,11 +317,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	else
 		omap_plane->info.zorder = 1;
 
-	/* TODO color mode should come from fb.. this will come in a
-	 * subsequent patch
-	 */
-	omap_plane->info.color_mode = OMAP_DSS_COLOR_RGB24U;
-
 	update_manager(plane);
 
 	return plane;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-20 22:58 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
@ 2011-12-20 23:30   ` Ville Syrjälä
  2011-12-20 23:58     ` Rob Clark
  2012-01-02 16:43     ` Rob Clark
  0 siblings, 2 replies; 10+ messages in thread
From: Ville Syrjälä @ 2011-12-20 23:30 UTC (permalink / raw)
  To: Rob Clark; +Cc: Greg KH, patches, dri-devel, Rob Clark

On Tue, Dec 20, 2011 at 04:58:51PM -0600, Rob Clark wrote:
> +static const struct format formats[] = {
> +	/* 16bpp [A]RGB: */
> +	{ OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
> +	{ OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
> +	{ OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
> +	{ OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
> +	{ OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
                                                 ^^^^^^^^

Should be ARGB4444, no?

BTW I took a quick gander at the format specifications in the OMAP4 TRM
and it has a funny bug.

xRGB16-1555 and ARGB16-1555 are listed like this:

31       ...          0
U  R1 G1 B1 U  R0 B0 G0
A1 R1 G1 B1 A0 R0 B0 G0

So every second pixel has B and G swapped around. That would be some
interesting hardware to use :D

It's possible the TRM I had lying around was an old one though and the
issue is fixed in later revisions.

-- 
Ville Syrjälä
Intel OTC

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-20 23:30   ` Ville Syrjälä
@ 2011-12-20 23:58     ` Rob Clark
  2011-12-21  0:34       ` Ville Syrjälä
  2012-01-02 16:43     ` Rob Clark
  1 sibling, 1 reply; 10+ messages in thread
From: Rob Clark @ 2011-12-20 23:58 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Greg KH, dri-devel, patches

On Tue, Dec 20, 2011 at 5:30 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Tue, Dec 20, 2011 at 04:58:51PM -0600, Rob Clark wrote:
>> +static const struct format formats[] = {
>> +     /* 16bpp [A]RGB: */
>> +     { OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
>> +     { OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
>> +     { OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
>> +     { OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
>> +     { OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
>                                                 ^^^^^^^^
>
> Should be ARGB4444, no?

yes, you are right.. I got that backwards

> BTW I took a quick gander at the format specifications in the OMAP4 TRM
> and it has a funny bug.
>
> xRGB16-1555 and ARGB16-1555 are listed like this:
>
> 31       ...          0
> U  R1 G1 B1 U  R0 B0 G0
> A1 R1 G1 B1 A0 R0 B0 G0
>
> So every second pixel has B and G swapped around. That would be some
> interesting hardware to use :D
>
> It's possible the TRM I had lying around was an old one though and the
> issue is fixed in later revisions.

It is still like this in the version of TRM that I have..  I've never
really used those formats, so can't really if that is a documentation
bug or just a weird format.  Maybe I should remove those from the
table too until I have a chance to verify.

BR,
-R

> --
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-20 23:58     ` Rob Clark
@ 2011-12-21  0:34       ` Ville Syrjälä
  0 siblings, 0 replies; 10+ messages in thread
From: Ville Syrjälä @ 2011-12-21  0:34 UTC (permalink / raw)
  To: Rob Clark; +Cc: Greg KH, dri-devel, patches

On Tue, Dec 20, 2011 at 05:58:41PM -0600, Rob Clark wrote:
> On Tue, Dec 20, 2011 at 5:30 PM, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> > On Tue, Dec 20, 2011 at 04:58:51PM -0600, Rob Clark wrote:
> >> +static const struct format formats[] = {
> >> +     /* 16bpp [A]RGB: */
> >> +     { OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
> >> +     { OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
> >> +     { OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
> >> +     { OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
> >> +     { OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
> >                                                 ^^^^^^^^
> >
> > Should be ARGB4444, no?
> 
> yes, you are right.. I got that backwards
> 
> > BTW I took a quick gander at the format specifications in the OMAP4 TRM
> > and it has a funny bug.
> >
> > xRGB16-1555 and ARGB16-1555 are listed like this:
> >
> > 31       ...          0
> > U  R1 G1 B1 U  R0 B0 G0
> > A1 R1 G1 B1 A0 R0 B0 G0
> >
> > So every second pixel has B and G swapped around. That would be some
> > interesting hardware to use :D
> >
> > It's possible the TRM I had lying around was an old one though and the
> > issue is fixed in later revisions.
> 
> It is still like this in the version of TRM that I have..  I've never
> really used those formats, so can't really if that is a documentation
> bug or just a weird format.  Maybe I should remove those from the
> table too until I have a chance to verify.

I was going to say that I tested them on OMAP3 when I was still @nokia,
but now that I checked again OMAP3 doesn't support the 1555 formats. It
was the 4444 formats I tested, and even exposed to users via Xv on the
N9.

-- 
Ville Syrjälä
syrjala@sci.fi
http://www.sci.fi/~syrjala/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-20 23:30   ` Ville Syrjälä
  2011-12-20 23:58     ` Rob Clark
@ 2012-01-02 16:43     ` Rob Clark
  1 sibling, 0 replies; 10+ messages in thread
From: Rob Clark @ 2012-01-02 16:43 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: Greg KH, dri-devel, patches

On Tue, Dec 20, 2011 at 5:30 PM, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
> On Tue, Dec 20, 2011 at 04:58:51PM -0600, Rob Clark wrote:
>> +static const struct format formats[] = {
>> +     /* 16bpp [A]RGB: */
>> +     { OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
>> +     { OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
>> +     { OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
>> +     { OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
>> +     { OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
>                                                 ^^^^^^^^
>
> Should be ARGB4444, no?
>
> BTW I took a quick gander at the format specifications in the OMAP4 TRM
> and it has a funny bug.
>
> xRGB16-1555 and ARGB16-1555 are listed like this:
>
> 31       ...          0
> U  R1 G1 B1 U  R0 B0 G0
> A1 R1 G1 B1 A0 R0 B0 G0
>
> So every second pixel has B and G swapped around. That would be some
> interesting hardware to use :D

fwiw, I finally had a chance to make a small test, and that is indeed
a documentation bug.  The format is actually what would be expected
for A/xRGB16-1555:

U/A1  R1 G1 B1 U/A1  R0 G0 B0

BR,
-R

> It's possible the TRM I had lying around was an old one though and the
> issue is fixed in later revisions.
>
> --
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] drm/omap: drm API update: addfb2
  2012-01-05 21:22 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
@ 2012-01-05 21:22 ` Rob Clark
  0 siblings, 0 replies; 10+ messages in thread
From: Rob Clark @ 2012-01-05 21:22 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

Update to reflect changes in:
"drm: add an fb creation ioctl that takes a pixel format v5"

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/omap_drv.h   |   30 +++++++++-
 drivers/staging/omapdrm/omap_fb.c    |  103 ++++++++++++++++++++++++++--------
 drivers/staging/omapdrm/omap_fbdev.c |   55 ++++++++++++-------
 3 files changed, 143 insertions(+), 45 deletions(-)

diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 76c4251..4ad2ae5 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
 #include "omap_drm.h"
 #include "omap_priv.h"
 
@@ -80,9 +81,9 @@ void omap_connector_flush(struct drm_connector *connector,
 		int x, int y, int w, int h);
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd);
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo);
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb);
 int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 		void **vaddr, dma_addr_t *paddr, unsigned int *screen_width);
@@ -132,4 +133,29 @@ static inline int align_pitch(int pitch, int width, int bpp)
 	return ALIGN(pitch, 8 * bytespp);
 }
 
+/* should these be made into common util helpers?
+ */
+
+static inline int objects_lookup(struct drm_device *dev,
+		struct drm_file *filp, uint32_t pixel_format,
+		struct drm_gem_object **bos, uint32_t *handles)
+{
+	int i, n = drm_format_num_planes(pixel_format);
+
+	for (i = 0; i < n; i++) {
+		bos[i] = drm_gem_object_lookup(dev, filp, handles[i]);
+		if (!bos[i]) {
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	while (--i > 0) {
+		drm_gem_object_unreference_unlocked(bos[i]);
+	}
+	return -ENOENT;
+}
+
 #endif /* __OMAP_DRV_H__ */
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 0b50c5b..805a18e 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -22,11 +22,43 @@
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
-
 /*
  * framebuffer funcs
  */
 
+/* per-format info: */
+struct format {
+	enum omap_color_mode dss_format;
+	uint32_t pixel_format;
+	struct {
+		int stride_bpp;           /* this times width is stride */
+		int sub_y;                /* sub-sample in y dimension */
+	} planes[4];
+	bool yuv;
+};
+
+static const struct format formats[] = {
+	/* 16bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
+	{ OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
+	{ OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
+	{ OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
+	{ OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */
+	{ OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */
+	{ OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */
+	/* 24bpp RGB: */
+	{ OMAP_DSS_COLOR_RGB24P,      DRM_FORMAT_RGB888,   {{3, 1}}, false }, /* RGB24-888 */
+	/* 32bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGBX32,      DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */
+	{ OMAP_DSS_COLOR_RGB24U,      DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */
+	{ OMAP_DSS_COLOR_RGBA32,      DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */
+	{ OMAP_DSS_COLOR_ARGB32,      DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */
+	/* YUV: */
+	{ OMAP_DSS_COLOR_NV12,        DRM_FORMAT_NV12,     {{1, 1}, {1, 2}}, true },
+	{ OMAP_DSS_COLOR_YUV2,        DRM_FORMAT_YUYV,     {{2, 1}}, true },
+	{ OMAP_DSS_COLOR_UYVY,        DRM_FORMAT_UYVY,     {{2, 1}}, true },
+};
+
 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
 
 struct omap_framebuffer {
@@ -34,6 +66,7 @@ struct omap_framebuffer {
 	struct drm_gem_object *bo;
 	int size;
 	dma_addr_t paddr;
+	const struct format *format;
 };
 
 static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -91,7 +124,7 @@ int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 	int bpp = fb->bits_per_pixel / 8;
 	unsigned long offset;
 
-	offset = (x * bpp) + (y * fb->pitch);
+	offset = (x * bpp) + (y * fb->pitches[0]);
 
 	if (vaddr) {
 		void *bo_vaddr = omap_gem_vaddr(omap_fb->bo);
@@ -105,7 +138,7 @@ int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 	}
 
 	*paddr = omap_fb->paddr + offset;
-	*screen_width = fb->pitch / bpp;
+	*screen_width = fb->pitches[0] / bpp;
 
 	return omap_fb->size - offset;
 }
@@ -171,39 +204,61 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,
 }
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd)
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	struct drm_gem_object *bo;
+	struct drm_gem_object *bos[4];
 	struct drm_framebuffer *fb;
-	bo = drm_gem_object_lookup(dev, file, mode_cmd->handle);
-	if (!bo) {
-		return ERR_PTR(-ENOENT);
-	}
-	fb = omap_framebuffer_init(dev, mode_cmd, bo);
-	if (!fb) {
-		return ERR_PTR(-ENOMEM);
+	int ret;
+
+	ret = objects_lookup(dev, file, mode_cmd->pixel_format,
+			bos, mode_cmd->handles);
+	if (ret)
+		return ERR_PTR(ret);
+
+	fb = omap_framebuffer_init(dev, mode_cmd, bos);
+	if (IS_ERR(fb)) {
+		int i, n = drm_format_num_planes(mode_cmd->pixel_format);
+		for (i = 0; i < n; i++)
+			drm_gem_object_unreference_unlocked(bos[i]);
+		return fb;
 	}
 	return fb;
 }
 
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo)
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
 	struct omap_framebuffer *omap_fb;
 	struct drm_framebuffer *fb = NULL;
-	int size, ret;
+	const struct format *format = NULL;
+	int i, size, ret;
 
-	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)",
+	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
 			dev, mode_cmd, mode_cmd->width, mode_cmd->height,
-			mode_cmd->bpp);
+			(char *)&mode_cmd->pixel_format);
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].pixel_format == mode_cmd->pixel_format) {
+			format = &formats[i];
+			break;
+		}
+	}
+
+	if (!format) {
+		dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
+				(char *)&mode_cmd->pixel_format);
+		ret = -EINVAL;
+		goto fail;
+	}
 
 	/* in case someone tries to feed us a completely bogus stride: */
-	mode_cmd->pitch = align_pitch(mode_cmd->pitch,
-			mode_cmd->width, mode_cmd->bpp);
+	mode_cmd->pitches[0] = align_pitch(mode_cmd->pitches[0],
+			mode_cmd->width, format->planes[0].stride_bpp);
 
 	omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
 	if (!omap_fb) {
 		dev_err(dev->dev, "could not allocate fb\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
@@ -216,17 +271,19 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
 	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
 
-	size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height);
+	size = PAGE_ALIGN(mode_cmd->pitches[0] * mode_cmd->height);
 
-	if (size > bo->size) {
+	if (size > bos[0]->size) {
 		dev_err(dev->dev, "provided buffer object is too small!\n");
+		ret = -EINVAL;
 		goto fail;
 	}
 
-	omap_fb->bo = bo;
+	omap_fb->bo = bos[0];
 	omap_fb->size = size;
 
-	if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) {
+	ret = omap_gem_get_paddr(bos[0], &omap_fb->paddr, true);
+	if (ret) {
 		dev_err(dev->dev, "could not map (paddr)!\n");
 		goto fail;
 	}
@@ -239,5 +296,5 @@ fail:
 	if (fb) {
 		omap_framebuffer_destroy(fb);
 	}
-	return NULL;
+	return ERR_PTR(ret);
 }
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 093ae2f..ba45306 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -129,10 +129,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 	struct drm_framebuffer *fb = NULL;
 	union omap_gem_size gsize;
 	struct fb_info *fbi = NULL;
-	struct drm_mode_fb_cmd mode_cmd = {0};
+	struct drm_mode_fb_cmd2 mode_cmd = {0};
 	dma_addr_t paddr;
-	void __iomem *vaddr;
-	int size, screen_width;
 	int ret;
 
 	/* only doing ARGB32 since this is what is needed to alpha-blend
@@ -145,36 +143,56 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 			sizes->surface_height, sizes->surface_bpp,
 			sizes->fb_width, sizes->fb_height);
 
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+			sizes->surface_depth);
+
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 
-	mode_cmd.bpp = sizes->surface_bpp;
-	mode_cmd.depth = sizes->surface_depth;
-
-	mode_cmd.pitch = align_pitch(
-			mode_cmd.width * ((mode_cmd.bpp + 7) / 8),
-			mode_cmd.width, mode_cmd.bpp);
+	mode_cmd.pitches[0] = align_pitch(
+			mode_cmd.width * ((sizes->surface_bpp + 7) / 8),
+			mode_cmd.width, sizes->surface_bpp);
 
 	fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled;
 	if (fbdev->ywrap_enabled) {
 		/* need to align pitch to page size if using DMM scrolling */
-		mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE);
+		mode_cmd.pitches[0] = ALIGN(mode_cmd.pitches[0], PAGE_SIZE);
 	}
 
 	/* allocate backing bo */
 	gsize = (union omap_gem_size){
-		.bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height),
+		.bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height),
 	};
 	DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
 	fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
 	if (!fbdev->bo) {
 		dev_err(dev->dev, "failed to allocate buffer object\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
-	fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo);
-	if (!fb) {
+	fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo);
+	if (IS_ERR(fb)) {
 		dev_err(dev->dev, "failed to allocate fb\n");
+		/* note: if fb creation failed, we can't rely on fb destroy
+		 * to unref the bo:
+		 */
+		drm_gem_object_unreference(fbdev->bo);
+		ret = PTR_ERR(fb);
+		goto fail;
+	}
+
+	/* note: this keeps the bo pinned.. which is perhaps not ideal,
+	 * but is needed as long as we use fb_mmap() to mmap to userspace
+	 * (since this happens using fix.smem_start).  Possibly we could
+	 * implement our own mmap using GEM mmap support to avoid this
+	 * (non-tiled buffer doesn't need to be pinned for fbcon to write
+	 * to it).  Then we just need to be sure that we are able to re-
+	 * pin it in case of an opps.
+	 */
+	ret = omap_gem_get_paddr(fbdev->bo, &paddr, true);
+	if (ret) {
+		dev_err(dev->dev, "could not map (paddr)!\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -206,18 +224,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 		goto fail_unlock;
 	}
 
-	drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
-	size = omap_framebuffer_get_buffer(fb, 0, 0,
-			&vaddr, &paddr, &screen_width);
-
 	dev->mode_config.fb_base = paddr;
 
-	fbi->screen_base = vaddr;
-	fbi->screen_size = size;
+	fbi->screen_base = omap_gem_vaddr(fbdev->bo);
+	fbi->screen_size = fbdev->bo->size;
 	fbi->fix.smem_start = paddr;
-	fbi->fix.smem_len = size;
+	fbi->fix.smem_len = fbdev->bo->size;
 
 	/* if we have DMM, then we can use it for scrolling by just
 	 * shuffling pages around in DMM rather than doing sw blit.
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 1/3] drm/omap: drm API update: addfb2
  2011-12-15  6:16 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
@ 2011-12-15  6:16 ` Rob Clark
  0 siblings, 0 replies; 10+ messages in thread
From: Rob Clark @ 2011-12-15  6:16 UTC (permalink / raw)
  To: dri-devel; +Cc: Greg KH, Rob Clark, patches

From: Rob Clark <rob@ti.com>

Update to reflect changes in:
"drm: add an fb creation ioctl that takes a pixel format v5"

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/omap_drv.h   |   53 +++++++++++++++++-
 drivers/staging/omapdrm/omap_fb.c    |   99 ++++++++++++++++++++++++++-------
 drivers/staging/omapdrm/omap_fbdev.c |   53 ++++++++++++-------
 3 files changed, 163 insertions(+), 42 deletions(-)

diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index 8dd7d74..bc8daa7 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -76,9 +76,9 @@ void omap_connector_flush(struct drm_connector *connector,
 void omap_connector_dpms(struct drm_connector *connector, int mode);
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd);
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo);
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
 struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb);
 int omap_framebuffer_get_buffer(struct drm_framebuffer *fb, int x, int y,
 		void **vaddr, dma_addr_t *paddr, unsigned int *screen_width);
@@ -128,4 +128,53 @@ static inline int align_pitch(int pitch, int width, int bpp)
 	return ALIGN(pitch, 8 * bytespp);
 }
 
+/* should these be made into common util helpers?
+ */
+
+static inline int num_planes(uint32_t pixel_format)
+{
+	switch (pixel_format) {
+	default:
+		return 1;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		return 2;
+	case DRM_FORMAT_YUV410:
+	case DRM_FORMAT_YVU410:
+	case DRM_FORMAT_YUV411:
+	case DRM_FORMAT_YVU411:
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YVU422:
+	case DRM_FORMAT_YUV444:
+	case DRM_FORMAT_YVU444:
+		return 3;
+	}
+}
+
+static inline int objects_lookup(struct drm_device *dev,
+		struct drm_file *filp, uint32_t pixel_format,
+		struct drm_gem_object **bos, uint32_t *handles)
+{
+	int i, n = num_planes(pixel_format);
+
+	for (i = 0; i < n; i++) {
+		bos[i] = drm_gem_object_lookup(dev, filp, handles[i]);
+		if (!bos[i]) {
+			goto fail;
+		}
+	}
+
+	return 0;
+
+fail:
+	while (--i > 0) {
+		drm_gem_object_unreference_unlocked(bos[i]);
+	}
+	return -ENOENT;
+}
+
 #endif /* __OMAP_DRV_H__ */
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 0b50c5b..0d3a15e 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -22,11 +22,43 @@
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
-
 /*
  * framebuffer funcs
  */
 
+/* per-format info: */
+struct format {
+	enum omap_color_mode dss_format;
+	uint32_t pixel_format;
+	struct {
+		int stride_bpp;           /* this times width is stride */
+		int sub_y;                /* sub-sample in y dimension */
+	} planes[4];
+	bool yuv;
+};
+
+static const struct format formats[] = {
+	/* 16bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGB16,       DRM_FORMAT_RGB565,   {{2, 1}}, false }, /* RGB16-565 */
+	{ OMAP_DSS_COLOR_RGB12U,      DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
+	{ OMAP_DSS_COLOR_RGBX16,      DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
+	{ OMAP_DSS_COLOR_RGBA16,      DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
+	{ OMAP_DSS_COLOR_ARGB16,      DRM_FORMAT_ABGR4444, {{2, 1}}, false }, /* ARGB16-4444 */
+	{ OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */
+	{ OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */
+	/* 24bpp RGB: */
+	{ OMAP_DSS_COLOR_RGB24P,      DRM_FORMAT_RGB888,   {{3, 1}}, false }, /* RGB24-888 */
+	/* 32bpp [A]RGB: */
+	{ OMAP_DSS_COLOR_RGBX32,      DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */
+	{ OMAP_DSS_COLOR_RGB24U,      DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */
+	{ OMAP_DSS_COLOR_RGBA32,      DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */
+	{ OMAP_DSS_COLOR_ARGB32,      DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */
+	/* YUV: */
+	{ OMAP_DSS_COLOR_NV12,        DRM_FORMAT_NV12,     {{1, 1}, {1, 2}}, true },
+	{ OMAP_DSS_COLOR_YUV2,        DRM_FORMAT_YUYV,     {{2, 1}}, true },
+	{ OMAP_DSS_COLOR_UYVY,        DRM_FORMAT_UYVY,     {{2, 1}}, true },
+};
+
 #define to_omap_framebuffer(x) container_of(x, struct omap_framebuffer, base)
 
 struct omap_framebuffer {
@@ -34,6 +66,7 @@ struct omap_framebuffer {
 	struct drm_gem_object *bo;
 	int size;
 	dma_addr_t paddr;
+	const struct format *format;
 };
 
 static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -171,39 +204,61 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,
 }
 
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
-		struct drm_file *file, struct drm_mode_fb_cmd *mode_cmd)
+		struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
 {
-	struct drm_gem_object *bo;
+	struct drm_gem_object *bos[4];
 	struct drm_framebuffer *fb;
-	bo = drm_gem_object_lookup(dev, file, mode_cmd->handle);
-	if (!bo) {
-		return ERR_PTR(-ENOENT);
-	}
-	fb = omap_framebuffer_init(dev, mode_cmd, bo);
-	if (!fb) {
-		return ERR_PTR(-ENOMEM);
+	int ret;
+
+	ret = objects_lookup(dev, file, mode_cmd->pixel_format,
+			bos, mode_cmd->handles);
+	if (ret)
+		return ERR_PTR(ret);
+
+	fb = omap_framebuffer_init(dev, mode_cmd, bos);
+	if (IS_ERR(fb)) {
+		int i, n = num_planes(mode_cmd->pixel_format);
+		for (i = 0; i < n; i++)
+			drm_gem_object_unreference_unlocked(bos[i]);
+		return fb;
 	}
 	return fb;
 }
 
 struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
-		struct drm_mode_fb_cmd *mode_cmd, struct drm_gem_object *bo)
+		struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 {
 	struct omap_framebuffer *omap_fb;
 	struct drm_framebuffer *fb = NULL;
-	int size, ret;
+	const struct format *format = NULL;
+	int i, size, ret;
 
-	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%d)",
+	DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
 			dev, mode_cmd, mode_cmd->width, mode_cmd->height,
-			mode_cmd->bpp);
+			(char *)&mode_cmd->pixel_format);
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].pixel_format == mode_cmd->pixel_format) {
+			format = &formats[i];
+			break;
+		}
+	}
+
+	if (!format) {
+		dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
+				(char *)&mode_cmd->pixel_format);
+		ret = -EINVAL;
+		goto fail;
+	}
 
 	/* in case someone tries to feed us a completely bogus stride: */
-	mode_cmd->pitch = align_pitch(mode_cmd->pitch,
-			mode_cmd->width, mode_cmd->bpp);
+	mode_cmd->pitches[0] = align_pitch(mode_cmd->pitches[0],
+			mode_cmd->width, format->planes[0].stride_bpp);
 
 	omap_fb = kzalloc(sizeof(*omap_fb), GFP_KERNEL);
 	if (!omap_fb) {
 		dev_err(dev->dev, "could not allocate fb\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
@@ -216,17 +271,19 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
 	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
 
-	size = PAGE_ALIGN(mode_cmd->pitch * mode_cmd->height);
+	size = PAGE_ALIGN(mode_cmd->pitches[0] * mode_cmd->height);
 
-	if (size > bo->size) {
+	if (size > bos[0]->size) {
 		dev_err(dev->dev, "provided buffer object is too small!\n");
+		ret = -EINVAL;
 		goto fail;
 	}
 
-	omap_fb->bo = bo;
+	omap_fb->bo = bos[0];
 	omap_fb->size = size;
 
-	if (omap_gem_get_paddr(bo, &omap_fb->paddr, true)) {
+	ret = omap_gem_get_paddr(bos[0], &omap_fb->paddr, true);
+	if (ret) {
 		dev_err(dev->dev, "could not map (paddr)!\n");
 		goto fail;
 	}
@@ -239,5 +296,5 @@ fail:
 	if (fb) {
 		omap_framebuffer_destroy(fb);
 	}
-	return NULL;
+	return ERR_PTR(ret);
 }
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 093ae2f..a3cd78c 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -129,10 +129,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 	struct drm_framebuffer *fb = NULL;
 	union omap_gem_size gsize;
 	struct fb_info *fbi = NULL;
-	struct drm_mode_fb_cmd mode_cmd = {0};
+	struct drm_mode_fb_cmd2 mode_cmd = {0};
 	dma_addr_t paddr;
-	void __iomem *vaddr;
-	int size, screen_width;
 	int ret;
 
 	/* only doing ARGB32 since this is what is needed to alpha-blend
@@ -145,36 +143,56 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 			sizes->surface_height, sizes->surface_bpp,
 			sizes->fb_width, sizes->fb_height);
 
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+			sizes->surface_depth);
+
 	mode_cmd.width = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 
-	mode_cmd.bpp = sizes->surface_bpp;
-	mode_cmd.depth = sizes->surface_depth;
-
-	mode_cmd.pitch = align_pitch(
-			mode_cmd.width * ((mode_cmd.bpp + 7) / 8),
-			mode_cmd.width, mode_cmd.bpp);
+	mode_cmd.pitches[0] = align_pitch(
+			mode_cmd.width * ((sizes->surface_bpp + 7) / 8),
+			mode_cmd.width, sizes->surface_bpp);
 
 	fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled;
 	if (fbdev->ywrap_enabled) {
 		/* need to align pitch to page size if using DMM scrolling */
-		mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE);
+		mode_cmd.pitches[0] = ALIGN(mode_cmd.pitches[0], PAGE_SIZE);
 	}
 
 	/* allocate backing bo */
 	gsize = (union omap_gem_size){
-		.bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height),
+		.bytes = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height),
 	};
 	DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index);
 	fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC);
 	if (!fbdev->bo) {
 		dev_err(dev->dev, "failed to allocate buffer object\n");
+		ret = -ENOMEM;
 		goto fail;
 	}
 
-	fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo);
-	if (!fb) {
+	fb = omap_framebuffer_init(dev, &mode_cmd, &fbdev->bo);
+	if (IS_ERR(fb)) {
 		dev_err(dev->dev, "failed to allocate fb\n");
+		/* note: if fb creation failed, we can't rely on fb destroy
+		 * to unref the bo:
+		 */
+		drm_gem_object_unreference(fbdev->bo);
+		ret = PTR_ERR(fb);
+		goto fail;
+	}
+
+	/* note: this keeps the bo pinned.. which is perhaps not ideal,
+	 * but is needed as long as we use fb_mmap() to mmap to userspace
+	 * (since this happens using fix.smem_start).  Possibly we could
+	 * implement our own mmap using GEM mmap support to avoid this
+	 * (non-tiled buffer doesn't need to be pinned for fbcon to write
+	 * to it).  Then we just need to be sure that we are able to re-
+	 * pin it in case of an opps.
+	 */
+	ret = omap_gem_get_paddr(fbdev->bo, &paddr, true);
+	if (ret) {
+		dev_err(dev->dev, "could not map (paddr)!\n");
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -209,15 +227,12 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
 	drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
 	drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
 
-	size = omap_framebuffer_get_buffer(fb, 0, 0,
-			&vaddr, &paddr, &screen_width);
-
 	dev->mode_config.fb_base = paddr;
 
-	fbi->screen_base = vaddr;
-	fbi->screen_size = size;
+	fbi->screen_base = omap_gem_vaddr(fbdev->bo);
+	fbi->screen_size = fbdev->bo->size;
 	fbi->fix.smem_start = paddr;
-	fbi->fix.smem_len = size;
+	fbi->fix.smem_len = fbdev->bo->size;
 
 	/* if we have DMM, then we can use it for scrolling by just
 	 * shuffling pages around in DMM rather than doing sw blit.
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-01-05 21:22 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-20 22:58 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
2011-12-20 22:58 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
2011-12-20 23:30   ` Ville Syrjälä
2011-12-20 23:58     ` Rob Clark
2011-12-21  0:34       ` Ville Syrjälä
2012-01-02 16:43     ` Rob Clark
2011-12-20 22:58 ` [PATCH 2/3] drm/omap: add drm_plane support Rob Clark
2011-12-20 22:58 ` [PATCH 3/3] drm/omap: multiplanar and YUV support Rob Clark
  -- strict thread matches above, loose matches on Subject: below --
2012-01-05 21:22 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
2012-01-05 21:22 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark
2011-12-15  6:16 [PATCH 0/3] drm/omap: updates for addfb2 and plane support Rob Clark
2011-12-15  6:16 ` [PATCH 1/3] drm/omap: drm API update: addfb2 Rob Clark

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.