summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer-Daniel Olsson <per-daniel.olsson@stericsson.com>2012-02-10 18:30:04 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:28 +0200
commitfdd0c051aff401925d7e6a7118931245052d434a (patch)
tree52b8f72036ed822310324ae5e87f6f65702f66b7
parentf61b197ad7132acff379d7a55f4fcfe48885a803 (diff)
misc: compdev: Updated for new kernel composition
The compdev device has been updated for the new B2R2/MCDE composition in the kernel. All B2R2 work will now be done in the kernel. A callback interface has been added for potential listeners. Such listeners could for example be cloning for external devices. ST-Ericsson Linux next: NA ST-Ericsson ID: 404691 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I0c059fd6ef889356b1de77684c30721ce6b3ebbf Signed-off-by: Per-Daniel Olsson <per-daniel.olsson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49974 Reviewed-by: QATOOLS Reviewed-by: Robert FEKETE <robert.fekete@stericsson.com> Reviewed-by: QABUILD
-rw-r--r--arch/arm/mach-ux500/board-mop500-mcde.c2
-rw-r--r--drivers/misc/compdev/Makefile7
-rw-r--r--drivers/misc/compdev/compdev.c1126
-rw-r--r--include/linux/compdev.h88
4 files changed, 1058 insertions, 165 deletions
diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c
index 5400db27b7e..e60842c86e8 100644
--- a/arch/arm/mach-ux500/board-mop500-mcde.c
+++ b/arch/arm/mach-ux500/board-mop500-mcde.c
@@ -393,7 +393,7 @@ static int display_postregistered_callback(struct notifier_block *nb,
#ifdef CONFIG_COMPDEV
mfb = to_mcde_fb(fbi);
/* Create a compdev overlay for this display */
- if (compdev_create(ddev, mfb->ovlys[0]) < 0) {
+ if (compdev_create(ddev, mfb->ovlys[0], true) < 0) {
dev_warn(&ddev->dev,
"Failed to create compdev for display %s\n",
ddev->name);
diff --git a/drivers/misc/compdev/Makefile b/drivers/misc/compdev/Makefile
index 8d5cd14dc36..b8385848712 100644
--- a/drivers/misc/compdev/Makefile
+++ b/drivers/misc/compdev/Makefile
@@ -1 +1,6 @@
-obj-$(CONFIG_DISPDEV) += compdev.o
+obj-$(CONFIG_COMPDEV) += compdev.o
+
+ifdef CONFIG_COMPDEV_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/misc/compdev/compdev.c b/drivers/misc/compdev/compdev.c
index 4810e20d4cd..e0c34879f65 100644
--- a/drivers/misc/compdev/compdev.c
+++ b/drivers/misc/compdev/compdev.c
@@ -22,13 +22,22 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/ioctl.h>
+#include <linux/sched.h>
#include <linux/compdev.h>
#include <linux/hwmem.h>
+#include <linux/mm.h>
#include <video/mcde_dss.h>
+#include <video/b2r2_blt.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+
+#define BUFFER_CACHE_DEPTH 2
+#define NUM_COMPDEV_BUFS 2
static LIST_HEAD(dev_list);
static DEFINE_MUTEX(dev_list_lock);
+static int dev_counter;
struct compdev_buffer {
struct hwmem_alloc *alloc;
@@ -37,19 +46,76 @@ struct compdev_buffer {
u32 paddr; /* if pinned */
};
-struct compdev {
- bool open;
- struct mutex lock;
- struct miscdevice mdev;
- struct list_head list;
+struct compdev_img_internal {
+ struct compdev_img img;
+ u32 ref_count;
+};
+
+struct compdev_blt_work {
+ struct work_struct work;
+ struct compdev_img *src_img;
+ struct compdev_img_internal *dst_img;
+ int blt_handle;
+ bool mcde_rotation;
+ struct device *dev;
+};
+
+struct compdev_post_callback_work {
+ struct work_struct work;
+ struct compdev_img *img;
+ post_buffer_callback pb_cb;
+ void *cb_data;
+ struct device *dev;
+};
+
+struct buffer_cache_context {
+ struct compdev_img_internal
+ *img[BUFFER_CACHE_DEPTH];
+ u8 index;
+ u8 unused_counter;
+ struct device *dev;
+};
+
+struct dss_context {
+ struct device *dev;
struct mcde_display_device *ddev;
struct mcde_overlay *ovly[NUM_COMPDEV_BUFS];
struct compdev_buffer ovly_buffer[NUM_COMPDEV_BUFS];
struct compdev_size phy_size;
enum mcde_display_rotation display_rotation;
enum compdev_rotation current_buffer_rotation;
+ int blt_handle;
+ u8 temp_img_count;
+ struct compdev_img_internal *temp_img[NUM_COMPDEV_BUFS];
+ struct buffer_cache_context cache_ctx;
+};
+
+struct compdev {
+ struct mutex lock;
+ struct miscdevice mdev;
+ struct device *dev;
+ struct list_head list;
+ struct dss_context dss_ctx;
+ u16 ref_count;
+ struct workqueue_struct *worker_thread;
+ int dev_index;
+ post_buffer_callback pb_cb;
+ post_scene_info_callback si_cb;
+ struct compdev_scene_info s_info;
+ u8 sync_count;
+ u8 image_count;
+ struct compdev_img *images[NUM_COMPDEV_BUFS];
+ struct completion fence;
+ void *cb_data;
+ bool mcde_rotation;
};
+static struct compdev *compdevs[MAX_NBR_OF_COMPDEVS];
+
+static int compdev_post_buffers_dss(struct dss_context *dss_ctx,
+ struct compdev_img *img1, struct compdev_img *img2);
+
+
static int compdev_open(struct inode *inode, struct file *file)
{
struct compdev *cd = NULL;
@@ -63,18 +129,8 @@ static int compdev_open(struct inode *inode, struct file *file)
mutex_unlock(&dev_list_lock);
return -ENODEV;
}
-
- if (cd->open) {
- mutex_unlock(&dev_list_lock);
- return -EBUSY;
- }
-
- cd->open = true;
-
mutex_unlock(&dev_list_lock);
-
file->private_data = cd;
-
return 0;
}
@@ -106,18 +162,17 @@ static int compdev_release(struct inode *inode, struct file *file)
return -ENODEV;
for (i = 0; i < NUM_COMPDEV_BUFS; i++) {
- disable_overlay(cd->ovly[i]);
- if (cd->ovly_buffer[i].paddr &&
- cd->ovly_buffer[i].type ==
+ disable_overlay(cd->dss_ctx.ovly[i]);
+ if (cd->dss_ctx.ovly_buffer[i].paddr &&
+ cd->dss_ctx.ovly_buffer[i].type ==
COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET)
- hwmem_unpin(cd->ovly_buffer[i].alloc);
+ hwmem_unpin(cd->dss_ctx.ovly_buffer[i].alloc);
- cd->ovly_buffer[i].alloc = NULL;
- cd->ovly_buffer[i].size = 0;
- cd->ovly_buffer[i].paddr = 0;
+ cd->dss_ctx.ovly_buffer[i].alloc = NULL;
+ cd->dss_ctx.ovly_buffer[i].size = 0;
+ cd->dss_ctx.ovly_buffer[i].paddr = 0;
}
- cd->open = false;
return 0;
}
@@ -142,7 +197,7 @@ static int compdev_setup_ovly(struct compdev_img *img,
struct compdev_buffer *buffer,
struct mcde_overlay *ovly,
int z_order,
- struct compdev *cd)
+ struct dss_context *dss_ctx)
{
int ret = 0;
enum hwmem_mem_type memtype;
@@ -157,7 +212,7 @@ static int compdev_setup_ovly(struct compdev_img *img,
buffer->alloc = hwmem_resolve_by_name(img->buf.hwmem_buf_name);
if (IS_ERR(buffer->alloc)) {
ret = PTR_ERR(buffer->alloc);
- dev_warn(cd->mdev.this_device,
+ dev_warn(dss_ctx->dev,
"HWMEM resolve failed, %d\n", ret);
goto resolve_failed;
}
@@ -168,13 +223,13 @@ static int compdev_setup_ovly(struct compdev_img *img,
if (!(access & HWMEM_ACCESS_READ) ||
memtype != HWMEM_MEM_CONTIGUOUS_SYS) {
ret = -EACCES;
- dev_warn(cd->mdev.this_device,
+ dev_warn(dss_ctx->dev,
"Invalid_mem overlay, %d\n", ret);
goto invalid_mem;
}
ret = hwmem_pin(buffer->alloc, &mem_chunk, &mem_chunk_length);
if (ret) {
- dev_warn(cd->mdev.this_device,
+ dev_warn(dss_ctx->dev,
"Pin failed, %d\n", ret);
goto pin_failed;
}
@@ -183,7 +238,7 @@ static int compdev_setup_ovly(struct compdev_img *img,
ret = hwmem_set_domain(buffer->alloc, HWMEM_ACCESS_READ,
HWMEM_DOMAIN_SYNC, &rgn);
if (ret)
- dev_warn(cd->mdev.this_device,
+ dev_warn(dss_ctx->dev,
"Set domain failed, %d\n", ret);
buffer->paddr = mem_chunk.paddr;
@@ -205,9 +260,10 @@ static int compdev_setup_ovly(struct compdev_img *img,
info.h = img->dst_rect.height;
info.dirty.x = 0;
info.dirty.y = 0;
- info.dirty.w = cd->phy_size.width;
- info.dirty.h = cd->phy_size.height;
+ info.dirty.w = img->dst_rect.width;
+ info.dirty.h = img->dst_rect.height;
info.paddr = buffer->paddr;
+
mcde_dss_apply_overlay(ovly, &info);
return ret;
@@ -221,120 +277,699 @@ resolve_failed:
return ret;
}
-static int compdev_update_rotation(struct compdev *cd, enum compdev_rotation rotation)
+static int compdev_update_rotation(struct dss_context *dss_ctx,
+ enum compdev_rotation rotation)
{
/* Set video mode */
struct mcde_video_mode vmode;
int ret = 0;
memset(&vmode, 0, sizeof(struct mcde_video_mode));
- mcde_dss_get_video_mode(cd->ddev, &vmode);
- if ((cd->display_rotation + rotation) % 180) {
- vmode.xres = cd->phy_size.height;
- vmode.yres = cd->phy_size.width;
+ mcde_dss_get_video_mode(dss_ctx->ddev, &vmode);
+ if ((dss_ctx->display_rotation + rotation) % 180) {
+ vmode.xres = dss_ctx->phy_size.height;
+ vmode.yres = dss_ctx->phy_size.width;
} else {
- vmode.xres = cd->phy_size.width;
- vmode.yres = cd->phy_size.height;
+ vmode.xres = dss_ctx->phy_size.width;
+ vmode.yres = dss_ctx->phy_size.height;
}
- ret = mcde_dss_set_video_mode(cd->ddev, &vmode);
+ /* Set rotation */
+ ret = mcde_dss_set_rotation(dss_ctx->ddev,
+ (dss_ctx->display_rotation + rotation) % 360);
if (ret != 0)
goto exit;
- /* Set rotation */
- ret = mcde_dss_set_rotation(cd->ddev, (cd->display_rotation + rotation) % 360);
+ ret = mcde_dss_set_video_mode(dss_ctx->ddev, &vmode);
if (ret != 0)
goto exit;
+
/* Apply */
- ret = mcde_dss_apply_channel(cd->ddev);
+ ret = mcde_dss_apply_channel(dss_ctx->ddev);
exit:
return ret;
}
-static int release_prev_frame(struct compdev *cd)
+static int release_prev_frame(struct dss_context *dss_ctx)
{
int ret = 0;
int i;
/* Handle unpin of previous buffers */
for (i = 0; i < NUM_COMPDEV_BUFS; i++) {
- if (cd->ovly_buffer[i].type ==
+ if (dss_ctx->ovly_buffer[i].type ==
COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET &&
- cd->ovly_buffer[i].paddr != 0) {
- hwmem_unpin(cd->ovly_buffer[i].alloc);
- hwmem_release(cd->ovly_buffer[i].alloc);
+ dss_ctx->ovly_buffer[i].paddr != 0) {
+ hwmem_unpin(dss_ctx->ovly_buffer[i].alloc);
+ hwmem_release(dss_ctx->ovly_buffer[i].alloc);
}
- cd->ovly_buffer[i].alloc = NULL;
- cd->ovly_buffer[i].size = 0;
- cd->ovly_buffer[i].paddr = 0;
+ dss_ctx->ovly_buffer[i].alloc = NULL;
+ dss_ctx->ovly_buffer[i].size = 0;
+ dss_ctx->ovly_buffer[i].paddr = 0;
}
return ret;
}
-static void check_buffer(struct compdev *cd,
- struct compdev_buffer *overlay_buffer,
- struct compdev_buf *posted_buffer)
+static enum b2r2_blt_fmt compdev_to_blt_format(enum compdev_fmt fmt)
+{
+ switch (fmt) {
+ case COMPDEV_FMT_RGBA8888:
+ return B2R2_BLT_FMT_32_BIT_ABGR8888;
+ case COMPDEV_FMT_RGB888:
+ return B2R2_BLT_FMT_24_BIT_RGB888;
+ case COMPDEV_FMT_RGB565:
+ return B2R2_BLT_FMT_16_BIT_RGB565;
+ case COMPDEV_FMT_YUV422:
+ return B2R2_BLT_FMT_CB_Y_CR_Y;
+ case COMPDEV_FMT_YCBCR42XMBN:
+ return B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE;
+ case COMPDEV_FMT_YUV420_SP:
+ return B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR;
+ case COMPDEV_FMT_YVU420_SP:
+ return B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR;
+ case COMPDEV_FMT_YUV420_P:
+ return B2R2_BLT_FMT_YUV420_PACKED_PLANAR;
+ default:
+ return B2R2_BLT_FMT_UNUSED;
+ }
+}
+
+static enum b2r2_blt_transform to_blt_transform
+ (enum compdev_rotation compdev_rot)
+{
+ switch (compdev_rot) {
+ case COMPDEV_ROT_0:
+ return B2R2_BLT_TRANSFORM_NONE;
+ case COMPDEV_ROT_90_CCW:
+ return B2R2_BLT_TRANSFORM_CCW_ROT_90;
+ case COMPDEV_ROT_180:
+ return B2R2_BLT_TRANSFORM_CCW_ROT_180;
+ case COMPDEV_ROT_270_CCW:
+ return B2R2_BLT_TRANSFORM_CCW_ROT_90;
+ default:
+ return B2R2_BLT_TRANSFORM_NONE;
+ }
+}
+
+static u32 get_stride(u32 width, enum compdev_fmt fmt)
+{
+ u32 stride = 0;
+ switch (fmt) {
+ case COMPDEV_FMT_RGB565:
+ stride = width * 2;
+ break;
+ case COMPDEV_FMT_RGB888:
+ stride = width * 3;
+ break;
+ case COMPDEV_FMT_RGBX8888:
+ stride = width * 4;
+ break;
+ case COMPDEV_FMT_RGBA8888:
+ stride = width * 4;
+ break;
+ case COMPDEV_FMT_YUV422:
+ stride = width * 2;
+ break;
+ case COMPDEV_FMT_YCBCR42XMBN:
+ case COMPDEV_FMT_YUV420_SP:
+ case COMPDEV_FMT_YVU420_SP:
+ case COMPDEV_FMT_YUV420_P:
+ stride = width;
+ break;
+ }
+
+ /* The display controller requires 8 byte aligned strides */
+ if (stride % 8)
+ stride += 8 - (stride % 8);
+
+ return stride;
+}
+
+static int alloc_comp_internal_img(enum compdev_fmt fmt,
+ u16 width, u16 height, struct compdev_img_internal **img_pp)
+{
+ struct hwmem_alloc *alloc;
+ int name;
+ u32 size;
+ u32 stride;
+ struct compdev_img_internal *img;
+
+ stride = get_stride(width, fmt);
+ size = stride * height;
+ size = PAGE_ALIGN(size);
+
+ img = kzalloc(sizeof(struct compdev_img_internal), GFP_KERNEL);
+
+ if (!img)
+ return -ENOMEM;
+
+ alloc = hwmem_alloc(size, HWMEM_ALLOC_HINT_WRITE_COMBINE |
+ HWMEM_ALLOC_HINT_UNCACHED,
+ (HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE |
+ HWMEM_ACCESS_IMPORT),
+ HWMEM_MEM_CONTIGUOUS_SYS);
+
+ if (IS_ERR(alloc)) {
+ kfree(img);
+ img = NULL;
+ return PTR_ERR(alloc);
+ }
+
+ name = hwmem_get_name(alloc);
+ if (name < 0) {
+ kfree(img);
+ img = NULL;
+ hwmem_release(alloc);
+ return name;
+ }
+
+ img->img.height = height;
+ img->img.width = width;
+ img->img.fmt = fmt;
+ img->img.pitch = stride;
+ img->img.buf.hwmem_buf_name = name;
+ img->img.buf.type = COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET;
+ img->img.buf.offset = 0;
+ img->img.buf.len = size;
+
+ img->ref_count = 1;
+
+ *img_pp = img;
+
+ return 0;
+}
+
+static void free_comp_img_buf(struct compdev_img_internal *img,
+ struct device *dev)
{
- if (overlay_buffer->type == COMPDEV_PTR_PHYSICAL &&
- posted_buffer->type == COMPDEV_PTR_PHYSICAL &&
- overlay_buffer->paddr == posted_buffer->offset &&
- overlay_buffer->paddr != 0)
- dev_warn(cd->mdev.this_device, "The same FB pointer!!\n");
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (img != NULL && img->ref_count) {
+ img->ref_count--;
+ if (img->ref_count == 0) {
+ struct hwmem_alloc *alloc;
+ if (img->img.buf.hwmem_buf_name > 0) {
+ alloc = hwmem_resolve_by_name(
+ img->img.buf.hwmem_buf_name);
+ if (IS_ERR(alloc)) {
+ dev_err(dev, "%s: Error getting Alloc "
+ "from HWMEM\n", __func__);
+ return;
+ }
+ /* Double release needed */
+ hwmem_release(alloc);
+ hwmem_release(alloc);
+ }
+ kfree(img);
+ }
+ }
}
-static int compdev_post_buffers(struct compdev *cd,
- struct compdev_post_buffers_req *req)
+struct compdev_img_internal *compdev_buffer_cache_get_image(
+ struct buffer_cache_context *cache_ctx, enum compdev_fmt fmt,
+ u16 width, u16 height)
+{
+ int i;
+ struct compdev_img_internal *img = NULL;
+
+ dev_dbg(cache_ctx->dev, "%s\n", __func__);
+
+ /* First check for a cache hit */
+ if (cache_ctx->unused_counter > 0) {
+ u8 active_index = cache_ctx->index;
+ struct compdev_img_internal *temp =
+ cache_ctx->img[active_index];
+ if (temp != NULL && temp->img.fmt == fmt &&
+ temp->img.width == width &&
+ temp->img.height == height) {
+ img = temp;
+ cache_ctx->unused_counter = 0;
+ }
+ }
+ /* Check if there was a cache hit */
+ if (img == NULL) {
+ /* Create new buffers and release old */
+ for (i = 0; i < BUFFER_CACHE_DEPTH; i++) {
+ if (cache_ctx->img[i]) {
+ free_comp_img_buf(cache_ctx->img[i],
+ cache_ctx->dev);
+ cache_ctx->img[i] = NULL;
+ }
+ cache_ctx->index = 0;
+ if (alloc_comp_internal_img(fmt, width, height,
+ &cache_ctx->img[i]))
+ dev_err(cache_ctx->dev,
+ "%s: Allocation error\n",
+ __func__);
+ }
+ img = cache_ctx->img[0];
+ }
+
+ if (img != NULL) {
+ img->ref_count++;
+ cache_ctx->unused_counter = 0;
+ cache_ctx->index++;
+ if (cache_ctx->index >= BUFFER_CACHE_DEPTH)
+ cache_ctx->index = 0;
+ }
+
+ return img;
+}
+
+static void compdev_buffer_cache_mark_frame
+ (struct buffer_cache_context *cache_ctx)
+{
+ if (cache_ctx->unused_counter < 2)
+ cache_ctx->unused_counter++;
+ if (cache_ctx->unused_counter == 2) {
+ int i;
+ for (i = 0; i < BUFFER_CACHE_DEPTH; i++) {
+ if (cache_ctx->img[i]) {
+ free_comp_img_buf(cache_ctx->img[i],
+ cache_ctx->dev);
+ cache_ctx->img[i] = NULL;
+ }
+ }
+ }
+}
+
+static bool check_hw_format(enum compdev_fmt fmt)
+{
+ if (fmt == COMPDEV_FMT_RGB565 ||
+ fmt == COMPDEV_FMT_RGB888 ||
+ fmt == COMPDEV_FMT_RGBA8888 ||
+ fmt == COMPDEV_FMT_RGBX8888 ||
+ fmt == COMPDEV_FMT_YUV422)
+ return true;
+ else
+ return false;
+}
+
+static enum compdev_fmt find_compatible_fmt(enum compdev_fmt fmt, bool rotation)
+{
+ if (!rotation) {
+ switch (fmt) {
+ case COMPDEV_FMT_RGB565:
+ case COMPDEV_FMT_RGB888:
+ case COMPDEV_FMT_RGBA8888:
+ case COMPDEV_FMT_RGBX8888:
+ return fmt;
+ case COMPDEV_FMT_YUV422:
+ case COMPDEV_FMT_YCBCR42XMBN:
+ case COMPDEV_FMT_YUV420_SP:
+ case COMPDEV_FMT_YVU420_SP:
+ case COMPDEV_FMT_YUV420_P:
+ return COMPDEV_FMT_YUV422;
+ default:
+ return COMPDEV_FMT_RGBA8888;
+ }
+ } else {
+ switch (fmt) {
+ case COMPDEV_FMT_RGB565:
+ case COMPDEV_FMT_RGB888:
+ case COMPDEV_FMT_RGBA8888:
+ case COMPDEV_FMT_RGBX8888:
+ return fmt;
+ case COMPDEV_FMT_YUV422:
+ case COMPDEV_FMT_YCBCR42XMBN:
+ case COMPDEV_FMT_YUV420_SP:
+ case COMPDEV_FMT_YVU420_SP:
+ case COMPDEV_FMT_YUV420_P:
+ return COMPDEV_FMT_RGB888;
+ default:
+ return COMPDEV_FMT_RGBA8888;
+ }
+ }
+}
+
+static void compdev_callback_worker_function(struct work_struct *work)
+{
+ struct compdev_post_callback_work *cb_work =
+ (struct compdev_post_callback_work *)work;
+
+ if (cb_work->pb_cb != NULL)
+ cb_work->pb_cb(cb_work->cb_data, cb_work->img);
+}
+static void compdev_blt_worker_function(struct work_struct *work)
+{
+ struct compdev_blt_work *blt_work = (struct compdev_blt_work *)work;
+ struct compdev_img *src_img;
+ struct compdev_img *dst_img;
+ struct b2r2_blt_req req;
+ int req_id;
+
+ dev_dbg(blt_work->dev, "%s\n", __func__);
+
+ src_img = blt_work->src_img;
+ dst_img = &blt_work->dst_img->img;
+
+ memset(&req, 0, sizeof(req));
+ req.size = sizeof(req);
+
+ if (src_img->buf.type == COMPDEV_PTR_PHYSICAL) {
+ req.src_img.buf.type = B2R2_BLT_PTR_PHYSICAL;
+ req.src_img.buf.fd = src_img->buf.fd;
+ } else {
+ struct hwmem_alloc *alloc;
+
+ req.src_img.buf.type = B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET;
+ req.src_img.buf.hwmem_buf_name = src_img->buf.hwmem_buf_name;
+
+ alloc = hwmem_resolve_by_name(src_img->buf.hwmem_buf_name);
+ if (IS_ERR(alloc)) {
+ dev_warn(blt_work->dev,
+ "HWMEM resolve failed\n");
+ }
+ hwmem_set_access(alloc,
+ HWMEM_ACCESS_READ | HWMEM_ACCESS_IMPORT,
+ task_tgid_nr(current));
+ hwmem_release(alloc);
+ }
+ req.src_img.pitch = src_img->pitch;
+ req.src_img.buf.offset = src_img->buf.offset;
+ req.src_img.buf.len = src_img->buf.len;
+ req.src_img.fmt = compdev_to_blt_format(src_img->fmt);
+ req.src_img.width = src_img->width;
+ req.src_img.height = src_img->height;
+
+ req.src_rect.x = src_img->src_rect.x;
+ req.src_rect.y = src_img->src_rect.y;
+ req.src_rect.width = src_img->src_rect.width;
+ req.src_rect.height = src_img->src_rect.height;
+
+ if (dst_img->buf.type == COMPDEV_PTR_PHYSICAL) {
+ req.dst_img.buf.type = B2R2_BLT_PTR_PHYSICAL;
+ req.dst_img.buf.fd = dst_img->buf.fd;
+ } else {
+ req.dst_img.buf.type = B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET;
+ req.dst_img.buf.hwmem_buf_name = dst_img->buf.hwmem_buf_name;
+ }
+ req.dst_img.pitch = dst_img->pitch;
+ req.dst_img.buf.offset = dst_img->buf.offset;
+ req.dst_img.buf.len = dst_img->buf.len;
+ req.dst_img.fmt = compdev_to_blt_format(dst_img->fmt);
+ req.dst_img.width = dst_img->width;
+ req.dst_img.height = dst_img->height;
+
+ if (blt_work->mcde_rotation)
+ req.transform = B2R2_BLT_TRANSFORM_NONE;
+ else
+ req.transform = to_blt_transform(src_img->rotation);
+ req.dst_rect.x = 0;
+ req.dst_rect.y = 0;
+ req.dst_rect.width = src_img->dst_rect.width;
+ req.dst_rect.height = src_img->dst_rect.height;
+
+ req.global_alpha = 0xff;
+ req.flags = B2R2_BLT_FLAG_DITHER;
+
+ req_id = b2r2_blt_request(blt_work->blt_handle, &req);
+
+ if (b2r2_blt_synch(blt_work->blt_handle, req_id) < 0) {
+ dev_err(blt_work->dev,
+ "%s: Could not perform b2r2_blt_synch",
+ __func__);
+ }
+
+ dst_img->src_rect.x = 0;
+ dst_img->src_rect.x = 0;
+ dst_img->src_rect.width = dst_img->width;
+ dst_img->src_rect.height = dst_img->height;
+
+ dst_img->dst_rect.x = src_img->dst_rect.x;
+ dst_img->dst_rect.y = src_img->dst_rect.y;
+ dst_img->dst_rect.width = src_img->dst_rect.width;
+ dst_img->dst_rect.height = src_img->dst_rect.height;
+
+ dst_img->rotation = src_img->rotation;
+}
+
+static int compdev_post_buffer_locked(struct compdev *cd,
+ struct compdev_img *src_img)
{
int ret = 0;
- int i, j;
+ int i;
+ bool transform_needed = false;
+ struct compdev_img *resulting_img;
+ struct compdev_blt_work blt_work;
+ struct compdev_post_callback_work cb_work;
+ bool callback_work = false;
+ bool bypass_case = false;
+
+ dev_dbg(cd->dev, "%s\n", __func__);
+
+ /* Free potential temp buffers */
+ for (i = 0; i < cd->dss_ctx.temp_img_count; i++)
+ free_comp_img_buf(cd->dss_ctx.temp_img[i], cd->dev);
+ cd->dss_ctx.temp_img_count = 0;
+
+ /* Check for bypass images */
+ if (src_img->flags & COMPDEV_BYPASS_FLAG)
+ bypass_case = true;
+
+ /* Handle callback */
+ if (cd->pb_cb != NULL) {
+ callback_work = true;
+ INIT_WORK((struct work_struct *)&cb_work,
+ compdev_callback_worker_function);
+ cb_work.img = src_img;
+ cb_work.pb_cb = cd->pb_cb;
+ cb_work.cb_data = cd->cb_data;
+ cb_work.dev = cd->dev;
+ queue_work(cd->worker_thread, (struct work_struct *)&cb_work);
+ }
- for (i = 0; i < NUM_COMPDEV_BUFS; i++)
- for (j = 0; j < NUM_COMPDEV_BUFS; j++)
- check_buffer(cd, &cd->ovly_buffer[i],
- &req->img_buffers[j].buf);
+ if (!bypass_case) {
+ /* Determine if transform is needed */
+ /* First check scaling */
+ if ((src_img->rotation == COMPDEV_ROT_0 ||
+ src_img->rotation == COMPDEV_ROT_180) &&
+ (src_img->src_rect.width != src_img->dst_rect.width ||
+ src_img->src_rect.height != src_img->dst_rect.height))
+ transform_needed = true;
+ else if ((src_img->rotation == COMPDEV_ROT_90_CCW ||
+ src_img->rotation == COMPDEV_ROT_270_CCW) &&
+ (src_img->src_rect.width != src_img->dst_rect.height ||
+ src_img->src_rect.height != src_img->dst_rect.width))
+ transform_needed = true;
+
+ if (!transform_needed && check_hw_format(src_img->fmt) == false)
+ transform_needed = true;
+
+ if (transform_needed) {
+ u16 width = 0;
+ u16 height = 0;
+ enum compdev_fmt fmt;
+
+ INIT_WORK((struct work_struct *)&blt_work,
+ compdev_blt_worker_function);
+
+ if (cd->dss_ctx.blt_handle == 0) {
+ dev_dbg(cd->dev, "%s: B2R2 opened\n", __func__);
+ cd->dss_ctx.blt_handle = b2r2_blt_open();
+ if (cd->dss_ctx.blt_handle < 0) {
+ dev_warn(cd->dev,
+ "%s(%d): Failed to "
+ "open b2r2 device\n",
+ __func__, __LINE__);
+ }
+ }
+ blt_work.blt_handle = cd->dss_ctx.blt_handle;
+ blt_work.src_img = src_img;
+ blt_work.mcde_rotation = cd->mcde_rotation;
- /* Unpin the previous frame */
- release_prev_frame(cd);
+ width = src_img->dst_rect.width;
+ height = src_img->dst_rect.height;
+
+ fmt = find_compatible_fmt(src_img->fmt,
+ (!cd->mcde_rotation) &&
+ (src_img->rotation != COMPDEV_ROT_0));
+
+ blt_work.dst_img = compdev_buffer_cache_get_image
+ (&cd->dss_ctx.cache_ctx,
+ fmt, width, height);
+
+ blt_work.dst_img->img.flags = src_img->flags;
+ blt_work.dev = cd->dev;
+
+ queue_work(cd->worker_thread,
+ (struct work_struct *)&blt_work);
+ flush_work_sync((struct work_struct *)&blt_work);
+
+ resulting_img = &blt_work.dst_img->img;
- /* Validate buffer count */
- if (req->buffer_count > NUM_COMPDEV_BUFS || req->buffer_count == 0) {
- dev_warn(cd->mdev.this_device,
- "Illegal buffer count, will be clamped to %d\n",
- NUM_COMPDEV_BUFS);
- req->buffer_count = NUM_COMPDEV_BUFS;
+ cd->dss_ctx.temp_img[cd->dss_ctx.temp_img_count] =
+ blt_work.dst_img;
+ cd->dss_ctx.temp_img_count++;
+
+ } else {
+ resulting_img = src_img;
+ }
+
+ if (!cd->mcde_rotation)
+ resulting_img->rotation = COMPDEV_ROT_0;
+
+ cd->images[cd->image_count] = resulting_img;
+ cd->image_count++;
+
+ /* make sure that a potential callback has returned */
+ if (callback_work)
+ flush_work_sync((struct work_struct *)&cb_work);
+
+ if (cd->sync_count > 1) {
+ cd->sync_count--;
+ mutex_unlock(&cd->lock);
+ /* Wait for fence */
+ wait_for_completion(&cd->fence);
+ mutex_lock(&cd->lock);
+ } else {
+ struct compdev_img *img1 = NULL;
+ struct compdev_img *img2 = NULL;
+
+ if (cd->sync_count)
+ cd->sync_count--;
+
+ img1 = cd->images[0];
+ if (cd->image_count)
+ img2 = cd->images[1];
+
+ /* Do the refresh */
+ compdev_post_buffers_dss(&cd->dss_ctx, img1, img2);
+ compdev_buffer_cache_mark_frame
+ (&cd->dss_ctx.cache_ctx);
+
+ if (cd->s_info.img_count > 1) {
+ /* Releasing fence */
+ complete(&cd->fence);
+ }
+
+ cd->sync_count = 0;
+ cd->image_count = 0;
+ cd->images[0] = NULL;
+ cd->images[1] = NULL;
+ }
+ } else {
+ /* make sure that a potential callback has returned */
+ if (callback_work)
+ flush_work_sync((struct work_struct *)&cb_work);
}
+ return ret;
+}
+
+static int compdev_post_buffers_dss(struct dss_context *dss_ctx,
+ struct compdev_img *img1, struct compdev_img *img2)
+{
+ int ret = 0;
+ int i = 0;
+
+ struct compdev_img *fb_img = NULL;
+ struct compdev_img *ovly_img = NULL;
+
+ /* Unpin the previous frame */
+ release_prev_frame(dss_ctx);
+
/* Set channel rotation */
- if (req->buffer_count > 0 &&
- (cd->current_buffer_rotation != req->rotation)) {
- if (compdev_update_rotation(cd, req->rotation) != 0)
- dev_warn(cd->mdev.this_device,
- "Failed to update MCDE rotation (req->rotation = %d), %d\n",
- req->rotation, ret);
+ if (img1 != NULL &&
+ (dss_ctx->current_buffer_rotation != img1->rotation)) {
+ if (compdev_update_rotation(dss_ctx, img1->rotation) != 0)
+ dev_warn(dss_ctx->dev,
+ "Failed to update MCDE rotation "
+ "(img1->rotation = %d), %d\n",
+ img1->rotation, ret);
else
- cd->current_buffer_rotation = req->rotation;
+ dss_ctx->current_buffer_rotation = img1->rotation;
}
+ if ((img1 != NULL) && (img1->flags & COMPDEV_OVERLAY_FLAG))
+ ovly_img = img1;
+ else if (img1 != NULL)
+ fb_img = img1;
+
+
+ if ((img2 != NULL) && (img2->flags & COMPDEV_OVERLAY_FLAG))
+ ovly_img = img2;
+ else if (img2 != NULL)
+ fb_img = img2;
+
/* Handle buffers */
- for (i = 0; i < req->buffer_count; i++) {
- int overlay_index = req->buffer_count - i - 1;
- ret = compdev_setup_ovly(&req->img_buffers[i],
- &cd->ovly_buffer[i], cd->ovly[overlay_index], i, cd);
+ if (fb_img != NULL) {
+ ret = compdev_setup_ovly(fb_img,
+ &dss_ctx->ovly_buffer[i], dss_ctx->ovly[0], 1, dss_ctx);
if (ret)
- dev_warn(cd->mdev.this_device,
- "Failed to setup overlay[%d], %d\n", i, ret);
+ dev_warn(dss_ctx->dev,
+ "Failed to setup overlay[%d], %d\n", 0, ret);
+ i++;
+ } else {
+ disable_overlay(dss_ctx->ovly[0]);
}
- for (i = NUM_COMPDEV_BUFS; i > req->buffer_count; i--)
- disable_overlay(cd->ovly[i-1]);
+
+ if (ovly_img != NULL) {
+ ret = compdev_setup_ovly(ovly_img,
+ &dss_ctx->ovly_buffer[i], dss_ctx->ovly[1], 0, dss_ctx);
+ if (ret)
+ dev_warn(dss_ctx->dev,
+ "Failed to setup overlay[%d], %d\n", 1, ret);
+ } else {
+ disable_overlay(dss_ctx->ovly[1]);
+ }
/* Do the display update */
- if (req->buffer_count > 0)
- mcde_dss_update_overlay(cd->ovly[0], false);
- else
- dev_warn(cd->mdev.this_device, "No overlays requested\n");
+ mcde_dss_update_overlay(dss_ctx->ovly[0], true);
+
+ return ret;
+}
+
+static int compdev_post_scene_info_locked(struct compdev *cd,
+ struct compdev_scene_info *s_info)
+{
+ int ret = 0;
+
+ dev_dbg(cd->dev, "%s\n", __func__);
+
+ cd->s_info = *s_info;
+ cd->sync_count = cd->s_info.img_count;
+
+ /* always complete the fence in case someone is hanging incorrectly. */
+ complete(&cd->fence);
+ init_completion(&cd->fence);
+
+ /* Handle callback */
+ if (cd->si_cb != NULL) {
+ mutex_unlock(&cd->lock);
+ cd->si_cb(cd->cb_data, s_info);
+ mutex_lock(&cd->lock);
+ }
+ return ret;
+}
+
+
+static int compdev_get_size_locked(struct dss_context *dss_ctx,
+ struct compdev_size *size)
+{
+ int ret = 0;
+ if ((dss_ctx->display_rotation) % 180) {
+ size->height = dss_ctx->phy_size.width;
+ size->width = dss_ctx->phy_size.height;
+ } else {
+ size->height = dss_ctx->phy_size.height;
+ size->width = dss_ctx->phy_size.width;
+ }
+
+ return ret;
+}
+
+static int compdev_get_listener_state_locked(struct compdev *cd,
+ enum compdev_listener_state *state)
+{
+ int ret = 0;
+
+ *state = COMPDEV_LISTENER_OFF;
+ if (cd->pb_cb != NULL)
+ *state = COMPDEV_LISTENER_ON;
return ret;
}
@@ -344,50 +979,59 @@ static long compdev_ioctl(struct file *file,
{
int ret;
struct compdev *cd = (struct compdev *)file->private_data;
- struct compdev_post_buffers_req req;
+ struct compdev_img img;
+ struct compdev_scene_info s_info;
mutex_lock(&cd->lock);
switch (cmd) {
case COMPDEV_GET_SIZE_IOC:
- {
- struct compdev_size tmp;
- if ((cd->display_rotation) % 180) {
- tmp.height = cd->phy_size.width;
- tmp.width = cd->phy_size.height;
- } else {
- tmp.height = cd->phy_size.height;
- tmp.width = cd->phy_size.width;
- }
- ret = copy_to_user((void __user *)arg, &tmp,
- sizeof(tmp));
- if (ret)
- ret = -EFAULT;
+ {
+ struct compdev_size tmp;
+ compdev_get_size_locked(&cd->dss_ctx, &tmp);
+ ret = copy_to_user((void __user *)arg, &tmp,
+ sizeof(tmp));
+ if (ret)
+ ret = -EFAULT;
+ }
+ break;
+ case COMPDEV_GET_LISTENER_STATE_IOC:
+ {
+ enum compdev_listener_state state;
+ compdev_get_listener_state_locked(cd, &state);
+ ret = copy_to_user((void __user *)arg, &state,
+ sizeof(state));
+ if (ret)
+ ret = -EFAULT;
+ }
+ break;
+ case COMPDEV_POST_BUFFER_IOC:
+ memset(&img, 0, sizeof(img));
+ /* Get the user data */
+ if (copy_from_user(&img, (void *)arg, sizeof(img))) {
+ dev_warn(cd->dev,
+ "%s: copy_from_user failed\n",
+ __func__);
+ mutex_unlock(&cd->lock);
+ return -EFAULT;
}
- break;
- case COMPDEV_POST_BUFFERS_IOC:
- /* arg is user pointer to struct compdev_post_buffers_req */
-
- /* Initialize the structure */
- memset(&req, 0, sizeof(req));
-
- /*
- * The user request is a sub structure of the
- * kernel request structure.
- */
+ ret = compdev_post_buffer_locked(cd, &img);
+ break;
+ case COMPDEV_POST_SCENE_INFO_IOC:
+ memset(&s_info, 0, sizeof(s_info));
/* Get the user data */
- if (copy_from_user(&req, (void *)arg, sizeof(req))) {
- dev_warn(cd->mdev.this_device,
+ if (copy_from_user(&s_info, (void *)arg, sizeof(s_info))) {
+ dev_warn(cd->dev,
"%s: copy_from_user failed\n",
__func__);
mutex_unlock(&cd->lock);
return -EFAULT;
}
-
- ret = compdev_post_buffers(cd, &req);
+ ret = compdev_post_scene_info_locked(cd, &s_info);
break;
+
default:
ret = -ENOSYS;
}
@@ -403,19 +1047,29 @@ static const struct file_operations compdev_fops = {
.unlocked_ioctl = compdev_ioctl,
};
-static void init_compdev(struct compdev *cd, struct mcde_display_device *ddev,
- const char *name)
+static void init_compdev(struct compdev *cd, const char *name)
{
mutex_init(&cd->lock);
INIT_LIST_HEAD(&cd->list);
- cd->ddev = ddev;
+ init_completion(&cd->fence);
+
cd->mdev.minor = MISC_DYNAMIC_MINOR;
cd->mdev.name = name;
cd->mdev.fops = &compdev_fops;
+ cd->dev = cd->mdev.this_device;
+}
+
+static void init_dss_context(struct dss_context *dss_ctx,
+ struct mcde_display_device *ddev, struct compdev *cd)
+{
+ dss_ctx->ddev = ddev;
+ dss_ctx->dev = cd->dev;
+ memset(&dss_ctx->cache_ctx, 0, sizeof(struct buffer_cache_context));
+ dss_ctx->cache_ctx.dev = dss_ctx->dev;
}
int compdev_create(struct mcde_display_device *ddev,
- struct mcde_overlay *parent_ovly)
+ struct mcde_overlay *parent_ovly, bool mcde_rotation)
{
int ret = 0;
int i;
@@ -423,39 +1077,59 @@ int compdev_create(struct mcde_display_device *ddev,
struct mcde_video_mode vmode;
struct mcde_overlay_info info;
- static int counter;
char name[10];
+ if (dev_counter == 0) {
+ for (i = 0; i < MAX_NBR_OF_COMPDEVS; i++)
+ compdevs[i] = NULL;
+ }
+
+ if (dev_counter > MAX_NBR_OF_COMPDEVS)
+ return -ENOMEM;
+
cd = kzalloc(sizeof(struct compdev), GFP_KERNEL);
if (!cd)
return -ENOMEM;
+ compdevs[dev_counter] = cd;
+ cd->dev_index = dev_counter;
+
snprintf(name, sizeof(name), "%s%d", COMPDEV_DEFAULT_DEVICE_PREFIX,
- counter++);
- init_compdev(cd, ddev, name);
+ dev_counter++);
+ init_compdev(cd, name);
+
+ init_dss_context(&cd->dss_ctx, ddev, cd);
+
mcde_dss_get_video_mode(ddev, &vmode);
- cd->ovly[0] = parent_ovly;
- if (!cd->ovly[0]) {
+ cd->worker_thread = create_workqueue(name);
+ if (!cd->worker_thread) {
+ ret = -ENOMEM;
+ goto fail_workqueue;
+ }
+
+ cd->dss_ctx.ovly[0] = parent_ovly;
+ if (!cd->dss_ctx.ovly[0]) {
ret = -ENOMEM;
goto fail_create_ovly;
}
for (i = 1; i < NUM_COMPDEV_BUFS; i++) {
- cd->ovly[i] = mcde_dss_create_overlay(ddev, &info);
- if (!cd->ovly[i]) {
+ cd->dss_ctx.ovly[i] = mcde_dss_create_overlay(ddev, &info);
+ if (!cd->dss_ctx.ovly[i]) {
ret = -ENOMEM;
goto fail_create_ovly;
}
- mcde_dss_enable_overlay(cd->ovly[i]);
- disable_overlay(cd->ovly[i]);
+ mcde_dss_enable_overlay(cd->dss_ctx.ovly[i]);
+ disable_overlay(cd->dss_ctx.ovly[i]);
}
- mcde_dss_get_native_resolution(ddev, &cd->phy_size.width,
- &cd->phy_size.height);
+ mcde_dss_get_native_resolution(ddev, &cd->dss_ctx.phy_size.width,
+ &cd->dss_ctx.phy_size.height);
+ cd->dss_ctx.display_rotation = mcde_dss_get_rotation(ddev);
+ cd->dss_ctx.current_buffer_rotation = 0;
- cd->display_rotation = mcde_dss_get_rotation(ddev);
- cd->current_buffer_rotation = 0;
+ cd->mcde_rotation = mcde_rotation;
ret = misc_register(&cd->mdev);
if (ret)
@@ -469,14 +1143,145 @@ int compdev_create(struct mcde_display_device *ddev,
fail_register_misc:
fail_create_ovly:
for (i = 0; i < NUM_COMPDEV_BUFS; i++) {
- if (cd->ovly[i])
- mcde_dss_destroy_overlay(cd->ovly[i]);
+ if (cd->dss_ctx.ovly[i])
+ mcde_dss_destroy_overlay(cd->dss_ctx.ovly[i]);
}
+fail_workqueue:
kfree(cd);
out:
return ret;
}
+
+int compdev_get(int dev_idx, struct compdev **cd_pp)
+{
+ struct compdev *cd;
+ cd = NULL;
+
+ if (dev_idx >= MAX_NBR_OF_COMPDEVS)
+ return -ENOMEM;
+
+ cd = compdevs[dev_idx];
+ if (cd != NULL) {
+ mutex_lock(&cd->lock);
+ cd->ref_count++;
+ mutex_unlock(&cd->lock);
+ *cd_pp = cd;
+ return 0;
+ } else {
+ return -ENOMEM;
+ }
+}
+EXPORT_SYMBOL(compdev_get);
+
+int compdev_put(struct compdev *cd)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cd->lock);
+ cd->ref_count--;
+ if (cd->ref_count < 0)
+ dev_warn(cd->dev,
+ "%s: Incorrect ref count\n", __func__);
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_put);
+
+int compdev_get_size(struct compdev *cd, struct compdev_size *size)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cd->lock);
+
+ ret = compdev_get_size_locked(&cd->dss_ctx, size);
+
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_get_size);
+
+int compdev_get_listener_state(struct compdev *cd,
+ enum compdev_listener_state *listener_state)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cd->lock);
+
+ ret = compdev_get_listener_state_locked(cd, listener_state);
+
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_get_listener_state);
+
+
+int compdev_post_buffer(struct compdev *cd, struct compdev_img *img)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cd->lock);
+
+ ret = compdev_post_buffer_locked(cd, img);
+
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_post_buffer);
+
+int compdev_post_scene_info(struct compdev *cd,
+ struct compdev_scene_info *s_info)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&cd->lock);
+
+ ret = compdev_post_scene_info_locked(cd, s_info);
+
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_post_scene_info);
+
+int compdev_register_listener_callbacks(struct compdev *cd, void *data,
+ post_buffer_callback pb_cb, post_scene_info_callback si_cb)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+ mutex_lock(&cd->lock);
+ cd->cb_data = data;
+ cd->pb_cb = pb_cb;
+ cd->si_cb = si_cb;
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_register_listener_callbacks);
+
+int compdev_deregister_callbacks(struct compdev *cd)
+{
+ int ret = 0;
+ if (cd == NULL)
+ return -ENOMEM;
+ mutex_lock(&cd->lock);
+ cd->cb_data = NULL;
+ cd->pb_cb = NULL;
+ cd->si_cb = NULL;
+ mutex_unlock(&cd->lock);
+ return ret;
+}
+EXPORT_SYMBOL(compdev_deregister_callbacks);
+
void compdev_destroy(struct mcde_display_device *ddev)
{
struct compdev *cd;
@@ -485,15 +1290,35 @@ void compdev_destroy(struct mcde_display_device *ddev)
mutex_lock(&dev_list_lock);
list_for_each_entry_safe(cd, tmp, &dev_list, list) {
- if (cd->ddev == ddev) {
+ if (cd->dss_ctx.ddev == ddev) {
list_del(&cd->list);
misc_deregister(&cd->mdev);
- for (i = 0; i < NUM_COMPDEV_BUFS; i++)
- mcde_dss_destroy_overlay(cd->ovly[i]);
+ for (i = 1; i < NUM_COMPDEV_BUFS; i++)
+ mcde_dss_destroy_overlay(cd->dss_ctx.ovly[i]);
+ b2r2_blt_close(cd->dss_ctx.blt_handle);
+
+ release_prev_frame(&cd->dss_ctx);
+
+ /* Free potential temp buffers */
+ for (i = 0; i < cd->dss_ctx.temp_img_count; i++)
+ free_comp_img_buf(cd->dss_ctx.temp_img[i],
+ cd->dev);
+
+ for (i = 0; i < BUFFER_CACHE_DEPTH; i++) {
+ if (cd->dss_ctx.cache_ctx.img[i]) {
+ free_comp_img_buf
+ (cd->dss_ctx.cache_ctx.img[i],
+ cd->dev);
+ cd->dss_ctx.cache_ctx.img[i] = NULL;
+ }
+ }
+
+ destroy_workqueue(cd->worker_thread);
kfree(cd);
break;
}
}
+ dev_counter--;
mutex_unlock(&dev_list_lock);
}
@@ -508,7 +1333,22 @@ static void compdev_destroy_all(void)
list_del(&cd->list);
misc_deregister(&cd->mdev);
for (i = 0; i < NUM_COMPDEV_BUFS; i++)
- mcde_dss_destroy_overlay(cd->ovly[i]);
+ mcde_dss_destroy_overlay(cd->dss_ctx.ovly[i]);
+
+ release_prev_frame(&cd->dss_ctx);
+ /* Free potential temp buffers */
+ for (i = 0; i < cd->dss_ctx.temp_img_count; i++)
+ free_comp_img_buf(cd->dss_ctx.temp_img[i], cd->dev);
+
+ for (i = 0; i < BUFFER_CACHE_DEPTH; i++) {
+ if (cd->dss_ctx.cache_ctx.img[i]) {
+ free_comp_img_buf
+ (cd->dss_ctx.cache_ctx.img[i],
+ cd->dev);
+ cd->dss_ctx.cache_ctx.img[i] = NULL;
+ }
+ }
+
kfree(cd);
}
mutex_unlock(&dev_list_lock);
diff --git a/include/linux/compdev.h b/include/linux/compdev.h
index 9e707c7b770..83285c61b62 100644
--- a/include/linux/compdev.h
+++ b/include/linux/compdev.h
@@ -30,7 +30,7 @@
#endif
#define COMPDEV_DEFAULT_DEVICE_PREFIX "comp"
-#define NUM_COMPDEV_BUFS 2
+
enum compdev_fmt {
COMPDEV_FMT_RGB565,
@@ -38,34 +38,52 @@ enum compdev_fmt {
COMPDEV_FMT_RGBX8888,
COMPDEV_FMT_RGBA8888,
COMPDEV_FMT_YUV422,
+ COMPDEV_FMT_YCBCR42XMBN,
+ COMPDEV_FMT_YUV420_SP,
+ COMPDEV_FMT_YVU420_SP,
+ COMPDEV_FMT_YUV420_P,
};
struct compdev_size {
- uint16_t width;
- uint16_t height;
+ __u16 width;
+ __u16 height;
};
/* Display rotation */
enum compdev_rotation {
COMPDEV_ROT_0 = 0,
COMPDEV_ROT_90_CCW = 90,
- COMPDEV_ROT_180_CCW = 180,
+ COMPDEV_ROT_180 = 180,
COMPDEV_ROT_270_CCW = 270,
COMPDEV_ROT_90_CW = COMPDEV_ROT_270_CCW,
- COMPDEV_ROT_180_CW = COMPDEV_ROT_180_CCW,
COMPDEV_ROT_270_CW = COMPDEV_ROT_90_CCW,
};
+enum compdev_flag {
+ COMPDEV_NO_FLAG = 0x00,
+ COMPDEV_OVERLAY_FLAG = 0x01,
+ COMPDEV_FRAMEBUFFER_FLAG = 0x02,
+ COMPDEV_BYPASS_FLAG = 0x04,
+ COMPDEV_EXTERNAL_DISP_FLAG = 0x08,
+ COMPDEV_PROTECTED_FLAG = 0x0F,
+};
+
enum compdev_ptr_type {
COMPDEV_PTR_PHYSICAL,
COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET,
};
+enum compdev_listener_state {
+ COMPDEV_LISTENER_OFF,
+ COMPDEV_LISTENER_ON,
+};
+
+
struct compdev_rect {
- __s32 x;
- __s32 y;
- __s32 width;
- __s32 height;
+ __s16 x;
+ __s16 y;
+ __u16 width;
+ __u16 height;
};
struct compdev_buf {
@@ -79,27 +97,57 @@ struct compdev_buf {
struct compdev_img {
enum compdev_fmt fmt;
struct compdev_buf buf;
- __s32 width;
- __s32 height;
- __u32 pitch;
+ __u16 width;
+ __u16 height;
+ __u16 pitch;
+ __u8 z_position;
struct compdev_rect dst_rect;
+ struct compdev_rect src_rect;
+ enum compdev_rotation rotation;
+ __u32 flags;
};
-struct compdev_post_buffers_req {
- enum compdev_rotation rotation;
- struct compdev_img img_buffers[NUM_COMPDEV_BUFS];
- __u8 buffer_count;
+struct compdev_scene_info {
+ enum compdev_rotation ovly_rotation;
+ enum compdev_rotation fb_rotation;
+ __u8 img_count;
};
-#define COMPDEV_GET_SIZE_IOC _IOR('D', 1, struct compdev_size)
-#define COMPDEV_POST_BUFFERS_IOC _IOW('D', 2, struct compdev_post_buffers_req)
-#ifdef __KERNEL__
+#define COMPDEV_GET_SIZE_IOC _IOR('D', 1, struct compdev_size)
+#define COMPDEV_POST_BUFFER_IOC _IOW('D', 2, struct compdev_img)
+#define COMPDEV_POST_SCENE_INFO_IOC _IOW('D', 3, struct compdev_scene_info)
+#define COMPDEV_GET_LISTENER_STATE_IOC _IOR('D', 4, enum compdev_listener_state)
+
+
+#if defined(__KERNEL__) || defined(_KERNEL)
+
+#define MAX_NBR_OF_COMPDEVS 2
+
+struct compdev;
+typedef void (*post_buffer_callback)(void *data, struct compdev_img *img);
+typedef void (*post_scene_info_callback)(void *data,
+ struct compdev_scene_info *s_info);
+
int compdev_create(struct mcde_display_device *ddev,
- struct mcde_overlay *parent_ovly);
+ struct mcde_overlay *parent_ovly,
+ bool mcde_rotation);
void compdev_destroy(struct mcde_display_device *ddev);
+int compdev_get(int dev_idx, struct compdev **dev);
+int compdev_put(struct compdev *dev);
+int compdev_get_size(struct compdev *dev, struct compdev_size *size);
+int compdev_post_buffer(struct compdev *dev, struct compdev_img *img);
+int compdev_post_scene_info(struct compdev *dev,
+ struct compdev_scene_info *s_info);
+int compdev_get_listener_state(struct compdev *dev,
+ enum compdev_listener_state *listener_state);
+
+int compdev_register_listener_callbacks(struct compdev *dev, void *data,
+ post_buffer_callback pb_cb, post_scene_info_callback si_cb);
+int compdev_deregister_callbacks(struct compdev *dev);
+
#endif /* __KERNEL__ */
#endif /* _COMPDEV_H_ */