From: Rob Clark rob@ti.com
Now that drm and fbdev (omapdss) next trees have been pulled by Linus, here are the updates to keep omapdrm compiling.
The first four are re-sends of what was sent earlier, and the fifth takes care of some API changes in omapdss contained in the fbdev pull.
Rob Clark (5): drm/omap: drm API update: make fops struct const drm/omap: drm API update: addfb2 drm/omap: add drm_plane support drm/omap: multiplanar and YUV support drm/omap: updates for DSS fifomerge API changes
drivers/staging/omapdrm/Makefile | 1 + drivers/staging/omapdrm/omap_crtc.c | 191 +++++-------------- drivers/staging/omapdrm/omap_drv.c | 77 +++++--- drivers/staging/omapdrm/omap_drv.h | 52 +++++- 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 | 344 ++++++++++++++++++++++++++++++++++ drivers/staging/omapdrm/omap_priv.h | 12 +- 9 files changed, 699 insertions(+), 262 deletions(-) create mode 100644 drivers/staging/omapdrm/omap_plane.c
From: Rob Clark rob@ti.com
Update to reflect changes in: "Make the per-driver file_operations struct const"
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/omap_drv.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 602aa2d..4db40f7 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -708,6 +708,18 @@ static struct vm_operations_struct omap_gem_vm_ops = { .close = drm_gem_vm_close, };
+static const struct file_operations omapdriver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .unlocked_ioctl = drm_ioctl, + .release = drm_release, + .mmap = omap_gem_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + .read = drm_read, + .llseek = noop_llseek, +}; + static struct drm_driver omap_drm_driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM, @@ -738,17 +750,7 @@ static struct drm_driver omap_drm_driver = { .dumb_destroy = omap_gem_dumb_destroy, .ioctls = ioctls, .num_ioctls = DRM_OMAP_NUM_IOCTLS, - .fops = { - .owner = THIS_MODULE, - .open = drm_open, - .unlocked_ioctl = drm_ioctl, - .release = drm_release, - .mmap = omap_gem_mmap, - .poll = drm_poll, - .fasync = drm_fasync, - .read = drm_read, - .llseek = noop_llseek, - }, + .fops = &omapdriver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE,
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.
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; };
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 805a18e..d021a7e 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;
From: Rob Clark rob@ti.com
Signed-off-by: Rob Clark rob@ti.com --- drivers/staging/omapdrm/omap_crtc.c | 2 +- drivers/staging/omapdrm/omap_drv.h | 6 ++++++ drivers/staging/omapdrm/omap_plane.c | 33 ++++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index 3cee04e..17ca163 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -81,7 +81,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_plane *plane = omap_crtc->plane;
- return plane->funcs->update_plane(plane, crtc, crtc->fb, + return omap_plane_mode_set(plane, crtc, crtc->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 48f6fce..61fe022 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -69,6 +69,12 @@ 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); +int omap_plane_mode_set(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 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 index 66eed75..9790912 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c @@ -85,7 +85,7 @@ static int commit(struct drm_plane *plane) } }
- if (info->enabled) { + if (ovl->is_enabled(ovl)) { omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, info->out_width, info->out_height); } @@ -115,7 +115,7 @@ static void update_manager(struct drm_plane *plane) }
if (ovl->manager != mgr) { - bool enabled = omap_plane->info.enabled; + bool enabled = ovl->is_enabled(ovl);
/* don't switch things around with enabled overlays: */ if (enabled) @@ -168,7 +168,8 @@ static void update_scanout(struct drm_plane *plane) if (ret) { dev_err(plane->dev->dev, "could not pin fb: %d\n", ret); - omap_plane->info.enabled = false; + omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); + return; }
omap_framebuffer_update_scanout(plane->fb, @@ -180,7 +181,7 @@ static void update_scanout(struct drm_plane *plane) info->screen_width); }
-static int omap_plane_update(struct drm_plane *plane, +int omap_plane_mode_set(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, @@ -195,7 +196,6 @@ static int omap_plane_update(struct drm_plane *plane, 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; @@ -214,11 +214,22 @@ static int omap_plane_update(struct drm_plane *plane,
update_scanout(plane); update_manager(plane); - commit(plane);
return 0; }
+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) +{ + omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); + return omap_plane_dpms(plane, DRM_MODE_DPMS_ON); +} + static int omap_plane_disable(struct drm_plane *plane) { return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); @@ -236,18 +247,22 @@ static void omap_plane_destroy(struct drm_plane *plane) int omap_plane_dpms(struct drm_plane *plane, int mode) { struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_overlay *ovl = omap_plane->ovl; + int r;
DBG("%s: %d", omap_plane->ovl->name, mode);
if (mode == DRM_MODE_DPMS_ON) { update_scanout(plane); - omap_plane->info.enabled = true; + r = commit(plane); + if (!r) + r = ovl->enable(ovl); } else { - omap_plane->info.enabled = false; + r = ovl->disable(ovl); update_pin(plane, NULL); }
- return commit(plane); + return r; }
static const struct drm_plane_funcs omap_plane_funcs = {
dri-devel@lists.freedesktop.org