aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Lofthouse <a0741364@ti.com>2010-10-26 15:30:34 -0400
committerErik Gilling <konkers@android.com>2011-03-30 10:11:33 -0700
commit7d0f7cbbb405be92e13590a07d2fa05a3a7a8c36 (patch)
tree75c5e637b66c99f2037d6d116d01f74b45798ef7
parent7329e934e60b25f9402174f8d95e1a97e0ac18d6 (diff)
downloadexperimental-7d0f7cbbb405be92e13590a07d2fa05a3a7a8c36.tar.gz
V4L2-GFX: (NEW) video capture driver for SGX texture streaming
New driver sources under: drivers/media/video/omapgfx/ Ioctls for texture streaming applications in include/linux/omap_v4l2_gfx.h This patch also needs to increase the number SYS_DEVICE_COUNT in the SGX/PVR kernel services. Also introduces a new Kconfig variable CONFIG_VIDEO_OMAP_GFX Fixed up whitespace and checked with sparse and checkpatch. Change-Id: I909e129c28f8c715037e2233420e70cf3c9fde1c Signed-off-by: Tony Lofthouse <a0741364@ti.com> Signed-off-by: Tony Lofthouse <tony.lofthouse@ti.com>
-rw-r--r--drivers/gpu/pvr/omap4/sysinfo.h2
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/omapgfx/Kbuild6
-rw-r--r--drivers/media/video/omapgfx/Kconfig8
-rw-r--r--drivers/media/video/omapgfx/gfx_bc.c494
-rw-r--r--drivers/media/video/omapgfx/gfx_bc.h76
-rw-r--r--drivers/media/video/omapgfx/gfx_init.c297
-rw-r--r--drivers/media/video/omapgfx/gfx_io.c1329
-rw-r--r--drivers/media/video/omapgfx/gfx_tiler.c152
-rw-r--r--drivers/media/video/omapgfx/v4gfx.h171
-rw-r--r--include/linux/omap_v4l2_gfx.h177
12 files changed, 2714 insertions, 1 deletions
diff --git a/drivers/gpu/pvr/omap4/sysinfo.h b/drivers/gpu/pvr/omap4/sysinfo.h
index 07718276b8d..80b86febda6 100644
--- a/drivers/gpu/pvr/omap4/sysinfo.h
+++ b/drivers/gpu/pvr/omap4/sysinfo.h
@@ -35,6 +35,6 @@
#define WAIT_TRY_COUNT (10000)
-#define SYS_DEVICE_COUNT 3
+#define SYS_DEVICE_COUNT 4
#endif
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4498b944dec..f857727f75e 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -562,6 +562,8 @@ source "drivers/media/video/davinci/Kconfig"
source "drivers/media/video/omap/Kconfig"
+source "drivers/media/video/omapgfx/Kconfig"
+
source "drivers/media/video/bt8xx/Kconfig"
config VIDEO_PMS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ace5d8b5722..6712c8c3fa4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -180,6 +180,7 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-y += davinci/
obj-$(CONFIG_ARCH_OMAP) += omap/
+obj-$(CONFIG_VIDEO_OMAP_GFX) += omapgfx/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/omapgfx/Kbuild b/drivers/media/video/omapgfx/Kbuild
new file mode 100644
index 00000000000..3ba7b68f484
--- /dev/null
+++ b/drivers/media/video/omapgfx/Kbuild
@@ -0,0 +1,6 @@
+
+gfx_vout_mod-objs := gfx_init.o gfx_io.o gfx_bc.o gfx_tiler.o
+
+obj-$(CONFIG_VIDEO_OMAP_GFX) += gfx_vout_mod.o
+
+EXTRA_CFLAGS += -Idrivers/gpu/pvr
diff --git a/drivers/media/video/omapgfx/Kconfig b/drivers/media/video/omapgfx/Kconfig
new file mode 100644
index 00000000000..1d16d8a4360
--- /dev/null
+++ b/drivers/media/video/omapgfx/Kconfig
@@ -0,0 +1,8 @@
+config VIDEO_OMAP_GFX
+ tristate "OMAP V4L2-GFX driver"
+ select VIDEOBUF_GEN
+ select OMAP2_DSS
+ depends on VIDEO_DEV && (ARCH_OMAP34XX || ARCH_OMAP4)
+ default m
+ ---help---
+ V4L2 GFX support for OMAP based boards.
diff --git a/drivers/media/video/omapgfx/gfx_bc.c b/drivers/media/video/omapgfx/gfx_bc.c
new file mode 100644
index 00000000000..619d5d3cd0d
--- /dev/null
+++ b/drivers/media/video/omapgfx/gfx_bc.c
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#define LINUX /* Needed by IMG headers */
+#include "pvrmodule.h"
+#include "img_defs.h"
+#include "servicesext.h"
+#include "kernelbuffer.h"
+#include "gfx_bc.h"
+#include "v4gfx.h"
+
+#define DEVICE_COUNT 1
+
+#define BCLOGNM "v4l2-gfx bc: "
+
+#define BCERR(fmt, arg...) printk(KERN_ERR BCLOGNM fmt, ## arg)
+
+#define BCLOG(fmt, arg...) \
+do { \
+ if (debug >= 1) \
+ printk(KERN_INFO BCLOGNM fmt, ## arg); \
+} while (0)
+
+
+struct bc_buffer {
+ u32 size;
+ unsigned long *paddrp; /* physical addr. array */
+ PVRSRV_SYNC_DATA *pvr_sync_data;
+};
+
+struct gfx_bc_devinfo {
+ struct bc_buffer bc_buf[VIDEO_MAX_FRAME];
+ int ref;
+ int num_bufs;
+ int ref_cnt;
+
+ /* PVR data types */
+ IMG_UINT32 pvr_id;
+ BUFFER_INFO pvr_bcinfo;
+ PVRSRV_BC_SRV2BUFFER_KMJTABLE pvr_s2b_jt;
+};
+
+static struct gfx_bc_devinfo *g_devices[DEVICE_COUNT] = { NULL };
+static PVRSRV_BC_BUFFER2SRV_KMJTABLE pvr_b2s_jt; /* Jump table from driver to SGX */
+
+/*
+ * Service to Buffer Device API - this section covers the entry points from
+ * the SGX kernel services to this driver
+ */
+static PVRSRV_ERROR s2b_open_bc_device(IMG_UINT32 ui32DeviceID,
+ IMG_HANDLE *hdevicep)
+{
+ struct gfx_bc_devinfo *devinfo;
+
+ BCLOG("+%s %d\n", __func__, (int)ui32DeviceID);
+
+#ifdef MULTIPLEBUFFERCLASSDEVICESUPPORTED
+ if (ui32DeviceID >= DEVICE_COUNT) {
+ BCERR("Attempting to open device %d, max device id is %d\n",
+ ui32DeviceID, DEVICE_COUNT-1);
+ return -EINVAL;
+
+ }
+ devinfo = g_devices[ui32DeviceID];
+#else
+ devinfo = g_devices[0];
+#endif
+ *hdevicep = (IMG_HANDLE)devinfo;
+ return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR s2b_close_bc_device(IMG_UINT32 ui32DeviceID,
+ IMG_HANDLE hdevice)
+{
+ PVR_UNREFERENCED_PARAMETER(hdevice);
+ return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR s2b_get_bc_buffer(IMG_HANDLE hdevice,
+ IMG_UINT32 bufno,
+ PVRSRV_SYNC_DATA *pvr_sync_data,
+ IMG_HANDLE *hbufferp)
+{
+ struct gfx_bc_devinfo *devinfo;
+ BCLOG("+%s\n", __func__);
+
+ if (!hdevice || !hbufferp)
+ return PVRSRV_ERROR_INVALID_PARAMS;
+
+ devinfo = (struct gfx_bc_devinfo *) hdevice;
+
+ if (bufno < devinfo->pvr_bcinfo.ui32BufferCount) {
+ devinfo->bc_buf[bufno].pvr_sync_data = pvr_sync_data;
+ *hbufferp = (IMG_HANDLE) &devinfo->bc_buf[bufno];
+
+ } else {
+ return PVRSRV_ERROR_INVALID_PARAMS;
+ }
+
+ return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR s2b_get_bc_info(IMG_HANDLE hdevice, BUFFER_INFO *bcinfop)
+{
+ struct gfx_bc_devinfo *devinfo = NULL;
+ int rv = 0;
+
+ if (!hdevice || !bcinfop) {
+ rv = PVRSRV_ERROR_INVALID_PARAMS;
+ } else {
+ devinfo = (struct gfx_bc_devinfo *) hdevice;
+ *bcinfop = devinfo->pvr_bcinfo;
+
+ BCLOG("ui32BufferCount =%d",
+ (int)devinfo->pvr_bcinfo.ui32BufferCount);
+ BCLOG("pixelformat =%d",
+ (int)devinfo->pvr_bcinfo.pixelformat);
+ BCLOG("ui32Width =%d",
+ (int)devinfo->pvr_bcinfo.ui32Width);
+ BCLOG("ui32Height =%d",
+ (int)devinfo->pvr_bcinfo.ui32Height);
+ BCLOG("ui32ByteStride =%d",
+ (int)devinfo->pvr_bcinfo.ui32ByteStride);
+ BCLOG("ui32BufferDeviceID =%d",
+ (int)devinfo->pvr_bcinfo.ui32BufferDeviceID);
+ BCLOG("ui32Flags = %d",
+ (int)devinfo->pvr_bcinfo.ui32Flags);
+
+ }
+ BCLOG("-%s %d (0x%x)\n", __func__, rv, (int)devinfo);
+ return PVRSRV_OK;
+}
+
+static PVRSRV_ERROR s2b_get_buffer_addr(IMG_HANDLE hdevice,
+ IMG_HANDLE hbuffer,
+ IMG_SYS_PHYADDR **sysaddrpp,
+ IMG_UINT32 *sizebytesp,
+ IMG_VOID **cpuvaddrpp,
+ IMG_HANDLE *osmapinfop,
+ IMG_BOOL *iscontiguousp,
+ IMG_UINT32 *pui32TilingStride)
+{
+ struct bc_buffer *bc_buf;
+ PVRSRV_ERROR rv = PVRSRV_OK;
+ BCLOG("+%s\n", __func__);
+
+ if (!hdevice || !hbuffer || !sysaddrpp || !sizebytesp)
+ return PVRSRV_ERROR_INVALID_PARAMS;
+
+ bc_buf = (struct bc_buffer *)hbuffer;
+ *cpuvaddrpp = NULL;
+ *sizebytesp = bc_buf->size;
+
+ if (bc_buf->paddrp) {
+ *iscontiguousp = IMG_FALSE;
+ *sysaddrpp = (IMG_SYS_PHYADDR *)bc_buf->paddrp;
+ *osmapinfop = IMG_NULL;
+ *pui32TilingStride = 0;
+
+ BCLOG("+%s paddrp[0] 0x%x, vaddr = 0x%x, sizebytes = %d",
+ __func__, (int)bc_buf->paddrp[0],
+ (int)*cpuvaddrpp, (int)*sizebytesp);
+
+ } else {
+ rv = PVRSRV_ERROR_NOT_SUPPORTED;
+ }
+ return rv;
+}
+
+/*
+ * Rest of the functions
+ */
+static PVRSRV_PIXEL_FORMAT v4l2_to_pvr_pixfmt(u32 v4l2pixelfmt)
+{
+ PVRSRV_PIXEL_FORMAT pvr_fmt;
+
+ switch (v4l2pixelfmt) {
+ case V4L2_PIX_FMT_RGB565:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_RGB565;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_RGB888;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YUYV;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_NV12;
+ break;
+ default:
+ pvr_fmt = PVRSRV_PIXEL_FORMAT_UNKNOWN;
+ }
+ return pvr_fmt;
+}
+
+static int gfx_bc_release_device_resources(int id)
+{
+ struct gfx_bc_devinfo *devinfo;
+
+ devinfo = g_devices[id];
+ if (devinfo == NULL)
+ return -ENOENT;
+
+ if (!devinfo->num_bufs)
+ return 0;
+
+ devinfo->num_bufs = 0;
+ devinfo->pvr_bcinfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
+ devinfo->pvr_bcinfo.ui32Width = 0;
+ devinfo->pvr_bcinfo.ui32Height = 0;
+ devinfo->pvr_bcinfo.ui32ByteStride = 0;
+ devinfo->pvr_bcinfo.ui32BufferDeviceID = id;
+ devinfo->pvr_bcinfo.ui32Flags = 0;
+ devinfo->pvr_bcinfo.ui32BufferCount = 0;
+
+ return 0;
+}
+
+static int gfx_bc_register(int id)
+{
+ struct gfx_bc_devinfo *devinfo;
+ int rv = 0;
+ BCLOG("+%s\n", __func__);
+
+ devinfo = g_devices[id];
+
+ if (devinfo) {
+ devinfo->ref_cnt++;
+ BCLOG("%s device already registered\n", __func__);
+ rv = 0;
+ goto end;
+ }
+
+ devinfo = (struct gfx_bc_devinfo *)
+ kzalloc(sizeof(*devinfo), GFP_KERNEL);
+ if (!devinfo) {
+ rv = -ENOMEM;
+ goto end;
+ }
+ BCLOG("%s devinfo id=%d addr=0x%x\n", __func__, id, (int)devinfo);
+
+ devinfo->pvr_bcinfo.pixelformat = PVRSRV_PIXEL_FORMAT_UNKNOWN;
+ devinfo->pvr_bcinfo.ui32Width = 0;
+ devinfo->pvr_bcinfo.ui32Height = 0;
+ devinfo->pvr_bcinfo.ui32ByteStride = 0;
+ devinfo->pvr_bcinfo.ui32BufferDeviceID = id;
+ devinfo->pvr_bcinfo.ui32Flags = 0;
+ devinfo->pvr_bcinfo.ui32BufferCount = devinfo->num_bufs;
+
+ devinfo->pvr_s2b_jt.ui32TableSize =
+ sizeof(PVRSRV_BC_SRV2BUFFER_KMJTABLE);
+ devinfo->pvr_s2b_jt.pfnOpenBCDevice = s2b_open_bc_device;
+ devinfo->pvr_s2b_jt.pfnCloseBCDevice = s2b_close_bc_device;
+ devinfo->pvr_s2b_jt.pfnGetBCBuffer = s2b_get_bc_buffer;
+ devinfo->pvr_s2b_jt.pfnGetBCInfo = s2b_get_bc_info;
+ devinfo->pvr_s2b_jt.pfnGetBufferAddr = s2b_get_buffer_addr;
+
+ if (pvr_b2s_jt.pfnPVRSRVRegisterBCDevice(&devinfo->pvr_s2b_jt,
+ &devinfo->pvr_id) != PVRSRV_OK) {
+ BCLOG("RegisterBCDevice failed\n");
+ rv = -EIO;
+ goto end;
+ }
+
+ BCLOG("my device id: %d\n", (int)devinfo->pvr_id);
+
+ devinfo->ref_cnt++;
+ g_devices[id] = devinfo;
+end:
+ BCLOG("-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int gfx_bc_unregister(int id)
+{
+ int rv = 0;
+ struct gfx_bc_devinfo *devinfo;
+
+ devinfo = g_devices[id];
+ if (devinfo == NULL) {
+ rv = -ENODEV;
+ goto end;
+ }
+
+ devinfo->ref_cnt--;
+
+ if (devinfo->ref_cnt) {
+ rv = -EAGAIN;
+ goto end;
+ }
+
+ if (pvr_b2s_jt.pfnPVRSRVRemoveBCDevice(devinfo->pvr_id) != PVRSRV_OK) {
+ rv = -EIO;
+ goto end;
+ }
+
+ kfree(devinfo);
+ g_devices[id] = NULL;
+
+end:
+ return rv;
+}
+
+#define FIELDCOPY(dst, src, field) { (dst)->field = (src)->field; }
+
+#define BC_BUF_PARAMS_COPY(dst, src) { \
+ FIELDCOPY(dst, src, count); \
+ FIELDCOPY(dst, src, width); \
+ FIELDCOPY(dst, src, height); \
+ FIELDCOPY(dst, src, pixel_fmt); \
+ FIELDCOPY(dst, src, stride); \
+ FIELDCOPY(dst, src, size); \
+ }
+
+static void gfx_bc_params2_to_common(struct bc_buf_params2 *p,
+ struct bc_buf_params_common *pc)
+{
+ BC_BUF_PARAMS_COPY(pc, p);
+}
+
+/*
+ * Validate the bc_buf_params and get the PVR pixel format
+ *
+ * We shouldn't need to do any further validation of the V4L2 pixelformat
+ * properties as this should have been taken care of in the appropriate V4L2
+ * ioctl handlers.
+ */
+static int gfx_bc_validateparams(
+ int id,
+ struct bc_buf_params_common *p,
+ struct gfx_bc_devinfo **devinfop,
+ PVRSRV_PIXEL_FORMAT *pvr_pix_fmtp)
+{
+ struct gfx_bc_devinfo *devinfo;
+ int rv = 0;
+
+ devinfo = g_devices[id];
+ if (devinfo == NULL) {
+ BCLOG("%s: no such device %d", __func__, id);
+ rv = -ENODEV;
+ }
+
+ /* validate a series of params */
+ if (p->count <= 0) {
+ BCLOG("%s: invalid count", __func__);
+ rv = -EINVAL;
+ }
+
+ *pvr_pix_fmtp = v4l2_to_pvr_pixfmt(p->pixel_fmt);
+ if (*pvr_pix_fmtp == PVRSRV_PIXEL_FORMAT_UNKNOWN) {
+ BCLOG("%s: invalid pixel format", __func__);
+ rv = -EINVAL;
+ }
+
+ *devinfop = rv != 0 ? NULL : devinfo;
+ return rv;
+}
+
+/*
+ * API for the V4L2 component
+ */
+int bc_init(void)
+{
+ int id, rv;
+ BCLOG("+%s\n", __func__);
+
+ if (!PVRGetBufferClassJTable(&pvr_b2s_jt)) {
+ BCERR("no jump table to SGX APIs\n");
+ rv = -EIO;
+ goto end;
+ }
+
+ for (id = 0; id < DEVICE_COUNT; id++) {
+ rv = gfx_bc_register(id);
+ if (rv != 0) {
+ BCERR("can't register BC service\n");
+ goto end;
+ }
+ }
+
+end:
+ BCLOG("-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+void bc_cleanup(void)
+{
+ int id;
+ for (id = 0; id < DEVICE_COUNT; id++) {
+ if (gfx_bc_release_device_resources(id) != 0)
+ BCERR("can't b/c device resources: %d\n", id);
+ if (gfx_bc_unregister(id) != 0)
+ BCERR("can't un-register BC service\n");
+ }
+}
+
+int bc_setup_complete(int id, struct bc_buf_params2 *p)
+{
+ /* Fn called after successful bc_setup() so id should be valid */
+ struct gfx_bc_devinfo *devinfo = g_devices[id];
+ if (p->count != devinfo->num_bufs) {
+ BCLOG("+%s: Count doesn't match\n", __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+int bc_setup_buffer(int id, struct bc_buf_params2 *p, unsigned long *paddrp)
+{
+ int idx;
+ /* Fn called after successful bc_setup() so id should be valid */
+ struct gfx_bc_devinfo *devinfo = g_devices[id];
+ idx = devinfo->num_bufs;
+ if (unlikely(idx >= VIDEO_MAX_FRAME))
+ return -ENOENT;
+
+ devinfo->num_bufs++;
+ devinfo->pvr_bcinfo.ui32BufferCount = devinfo->num_bufs;
+
+ memset(&devinfo->bc_buf[idx], 0, sizeof(devinfo->bc_buf[idx]));
+ devinfo->bc_buf[idx].paddrp = paddrp;
+ devinfo->bc_buf[idx].size = p->size;
+ devinfo->bc_buf[idx].pvr_sync_data = IMG_NULL;
+ return 0;
+}
+
+int bc_setup(int id, struct bc_buf_params2 *p)
+{
+ struct gfx_bc_devinfo *devinfo;
+ int rv = 0;
+ PVRSRV_PIXEL_FORMAT pvr_pix_fmt;
+ struct bc_buf_params_common pc;
+
+ BCLOG("+%s\n", __func__);
+
+ gfx_bc_params2_to_common(p, &pc);
+ rv = gfx_bc_validateparams(id, &pc, &devinfo, &pvr_pix_fmt);
+ if (rv != 0)
+ goto end;
+
+ p->stride = 4096; /* Tiler stride */
+ p->size = p->height * p->stride;
+ if (p->pixel_fmt == V4L2_PIX_FMT_NV12)
+ p->size += (p->height / 2) * p->stride; /* UV size */
+
+ devinfo->num_bufs = 0; /* See bc_setup_buffer */
+
+ devinfo->pvr_bcinfo.pixelformat = pvr_pix_fmt;
+ devinfo->pvr_bcinfo.ui32Width = p->width;
+ devinfo->pvr_bcinfo.ui32Height = p->height;
+ devinfo->pvr_bcinfo.ui32ByteStride = p->stride;
+ devinfo->pvr_bcinfo.ui32BufferDeviceID = id;
+ /* I'm not 100% sure these flags are right but here goes */
+ devinfo->pvr_bcinfo.ui32Flags =
+ PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE |
+ PVRSRV_BC_FLAGS_YUVCSC_BT601;
+
+ BCLOG("buffers: count=%d, w=%d, h=%d, stride=%d, sz=%d fmt=%d\n",
+ p->count, p->width, p->height, p->stride, p->size, pvr_pix_fmt);
+end:
+ BCLOG("-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+/*
+ * The caller of this API will ensure that the arguments are valid
+ */
+int bc_sync_status(int id, int bufidx)
+{
+ struct gfx_bc_devinfo *devinfo = g_devices[id];
+ int ui32ReadOpsPending, ui32ReadOpsComplete;
+
+ ui32ReadOpsPending =
+ devinfo->bc_buf[bufidx].pvr_sync_data->ui32ReadOpsPending;
+ ui32ReadOpsComplete =
+ devinfo->bc_buf[bufidx].pvr_sync_data->ui32ReadOpsComplete;
+
+ return ui32ReadOpsComplete == ui32ReadOpsPending ? 1 : 0;
+}
+
diff --git a/drivers/media/video/omapgfx/gfx_bc.h b/drivers/media/video/omapgfx/gfx_bc.h
new file mode 100644
index 00000000000..ea2bf226925
--- /dev/null
+++ b/drivers/media/video/omapgfx/gfx_bc.h
@@ -0,0 +1,76 @@
+/**********************************************************************
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ ******************************************************************************/
+
+#ifndef __V4L2_GFX_BC_H__
+#define __V4L2_GFX_BC_H__
+
+#include <media/v4l2-dev.h>
+
+struct bc_buf_params_common {
+ int count; /*number of buffers */
+ int width; /*buffer width in pixel, multiple of 32 */
+ int height; /*buffer height in pixel */
+ u32 pixel_fmt; /* V4L2 buffer pixel format */
+ int stride;
+ int size;
+};
+
+struct bc_buf_params {
+ int count; /*number of buffers (in) */
+ int width; /*buffer width in pixel, multiple of 32 (in) */
+ int height; /*buffer height in pixel (in) */
+ u32 pixel_fmt; /* V4L2 buffer pixel format (in) */
+ int stride; /*(out) */
+ int size; /*(out */
+};
+
+struct bc_buf_params2 {
+ int count; /*number of buffers (in) */
+ int width; /*buffer width in pixel, multiple of 32 (in) */
+ int height; /*buffer height in pixel (in) */
+ u32 pixel_fmt; /* V4L2 buffer pixel format (in) */
+ int stride; /*(in) */
+ int size; /*(out */
+};
+extern int bc_init(void);
+extern void bc_cleanup(void);
+
+/* bc_setup
+ *
+ * This API will validate the buffer parameters in order to setup a
+ * buffer class device. Buffers should be added with subsequent calls to
+ * bc_setup_buffer()
+ */
+extern int bc_setup(int id, struct bc_buf_params2 *p);
+
+/* bc_setup_buffer
+ *
+ * Only called after a successful bc_setup(), add a physical buffer reference
+ * to this device
+ */
+extern int bc_setup_buffer(
+ int id, struct bc_buf_params2 *p, unsigned long *paddr);
+
+/* bc_setup_complete
+ *
+ * Called after all physical buffers have been added to the device
+ */
+extern int bc_setup_complete(int id, struct bc_buf_params2 *p);
+
+/* bc_sync_status
+ *
+ * Return the synchronization status of this devices buffer
+ *
+ * Return values:
+ * 0 SGX still has pending operations on the buffer
+ * 1 SGX done with the buffer
+ */
+extern int bc_sync_status(int id, int bufidx);
+#endif
diff --git a/drivers/media/video/omapgfx/gfx_init.c b/drivers/media/video/omapgfx/gfx_init.c
new file mode 100644
index 00000000000..14ee80f4fa9
--- /dev/null
+++ b/drivers/media/video/omapgfx/gfx_init.c
@@ -0,0 +1,297 @@
+/*
+ * drivers/media/video/omap/v4gfx.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+
+#include <linux/omap_v4l2_gfx.h> /* private ioctls */
+
+#include <media/v4l2-ioctl.h>
+
+#include "v4gfx.h"
+#include "gfx_bc.h"
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP V4L2 GFX driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Device node will be: /dev/video<VOUT_DEVICENODE_SUFFIX>
+ * See also /sys/devices/virtual/video4linux/<node>/name which will be
+ * whatever the value of VOUT_NAME is
+ */
+#define VOUT_DEVICENODE_SUFFIX 100
+
+static struct gbl_v4gfx *gbl_dev;
+
+int debug; /* is used outside this compilation unit too */
+module_param(debug, int, 0644);
+
+/*
+ * If bypass is set then buffer streaming operations will be bypassed. This
+ * enables us to check what the raw performance of stack above the V4L2
+ * driver is
+ */
+static int bypass;
+module_param(bypass, int, 0644);
+
+
+static int bypass_vidioc_qbuf(
+ struct file *file, void *fh, struct v4l2_buffer *buf) { return 0; }
+
+static int bypass_vidioc_dqbuf(
+ struct file *file, void *fh, struct v4l2_buffer *buf) { return 0; }
+
+static int bypass_vidioc_streamon(
+ struct file *file, void *fh, enum v4l2_buf_type i) { return 0; }
+
+static int bypass_vidioc_streamoff(
+ struct file *file, void *fh, enum v4l2_buf_type i) { return 0; }
+
+static long bypass_vidioc_default(
+ struct file *file, void *fh, int cmd, void *arg)
+{
+ struct v4l2_gfx_buf_params *parms = (struct v4l2_gfx_buf_params *)arg;
+ int rv = 0;
+
+ switch (cmd) {
+ case V4L2_GFX_IOC_CONSUMER:
+ break;
+ case V4L2_GFX_IOC_ACQ:
+ /* In bypass mode default the first buffer */
+ parms->bufid = 0;
+ break;
+ case V4L2_GFX_IOC_REL:
+ break;
+ default:
+ rv = -EINVAL;
+ }
+ return rv;
+}
+
+/*
+ * If the module is put in bypass mode the following ioctls
+ * are effectively nops
+ */
+static void v4gfx_enable_bypass(void)
+{
+ v4gfx_ioctl_ops.vidioc_qbuf = bypass_vidioc_qbuf;
+ v4gfx_ioctl_ops.vidioc_dqbuf = bypass_vidioc_dqbuf;
+ v4gfx_ioctl_ops.vidioc_streamon = bypass_vidioc_streamon;
+ v4gfx_ioctl_ops.vidioc_streamoff = bypass_vidioc_streamoff;
+ v4gfx_ioctl_ops.vidioc_default = bypass_vidioc_default;
+}
+
+static void v4gfx_cleanup_device(struct v4gfx_device *vout)
+{
+ struct video_device *vfd;
+
+ if (!vout)
+ return;
+ vfd = vout->vfd;
+
+ if (vfd) {
+ if (vfd->minor == -1) {
+ /*
+ * The device was never registered, so release the
+ * video_device struct directly.
+ */
+ video_device_release(vfd);
+ } else {
+ /*
+ * The unregister function will release the video_device
+ * struct as well as unregistering it.
+ */
+ video_unregister_device(vfd);
+ }
+ }
+
+ v4gfx_tiler_buffer_free(vout, vout->buffer_allocated, 0);
+ kfree(vout);
+}
+
+static int driver_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+ struct gbl_v4gfx *dev = container_of(v4l2_dev, struct
+ gbl_v4gfx, v4l2_dev);
+ int k;
+
+ v4l2_device_unregister(v4l2_dev);
+ for (k = 0; k < pdev->num_resources; k++)
+ v4gfx_cleanup_device(dev->vouts[k]);
+
+ kfree(gbl_dev);
+ return 0;
+}
+
+static int driver_probe(struct platform_device *pdev)
+{
+ printk(KERN_INFO "Probing: " VOUT_NAME);
+ return 0;
+}
+
+static int v4gfx_create_instance(struct v4gfx_device **voutp)
+{
+ int r = 0;
+ struct v4gfx_device *vout = NULL;
+ struct video_device *vfd = NULL;
+
+ vout = kzalloc(sizeof(struct v4gfx_device), GFP_KERNEL);
+ if (vout == NULL) {
+ r = -ENOMEM;
+ goto end;
+ }
+ mutex_init(&vout->lock);
+ spin_lock_init(&vout->vbq_lock);
+ /* TODO set this to an invalid value, need to change unit test though */
+ vout->bpp = RGB565_BPP;
+ vout->gbl_dev = gbl_dev;
+ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ init_timer(&vout->acquire_timer);
+ vout->acquire_timer.function = v4gfx_acquire_timer;
+ vout->acquire_timer.data = (unsigned long)vout;
+
+ init_waitqueue_head(&vout->sync_done);
+ init_waitqueue_head(&vout->consumer_wait);
+
+ vfd = vout->vfd = video_device_alloc();
+ if (!vfd)
+ goto end;
+
+ strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+ vfd->vfl_type = VFL_TYPE_GRABBER;
+ vfd->release = video_device_release;
+ vfd->ioctl_ops = &v4gfx_ioctl_ops;
+ vfd->fops = &v4gfx_fops;
+ vfd->minor = -1;
+ vfd->debug = debug;
+
+ r = video_register_device(vfd, VFL_TYPE_GRABBER,
+ VOUT_DEVICENODE_SUFFIX);
+ if (r < 0)
+ goto end;
+
+ video_set_drvdata(vfd, vout);
+
+ *voutp = vout;
+ printk(KERN_INFO VOUT_NAME ":video device registered\n");
+ return 0;
+end:
+
+ if (vfd)
+ video_device_release(vfd);
+
+ kfree(vout); /* safe with null vout */
+
+ return r;
+}
+
+static void v4gfx_delete_instance(
+ struct v4l2_device *v4l2_dev, struct v4gfx_device *vout)
+{
+ v4l2_info(v4l2_dev, "unregistering /dev/video%d\n", vout->vfd->num);
+ video_unregister_device(vout->vfd);
+ v4gfx_buffer_array_free(vout, vout->buffer_allocated);
+ kfree(vout);
+ return;
+}
+
+static struct platform_driver v4gfx_driver = {
+ .driver = {
+ .name = VOUT_NAME,
+ },
+ .probe = driver_probe,
+ .remove = driver_remove,
+};
+
+static int module_init_v4gfx(void)
+{
+ int rv;
+ bool v4l2_dev_registered = false;
+ bool bc_dev_registered = false;
+
+ if (bypass) {
+ printk(KERN_INFO VOUT_NAME ":Enable bypass mode\n");
+ v4gfx_enable_bypass();
+ }
+
+ rv = platform_driver_register(&v4gfx_driver);
+ if (rv != 0) {
+ printk(KERN_ERR VOUT_NAME ":platform_driver_register failed\n");
+ goto end;
+ }
+
+ gbl_dev = kzalloc(sizeof(struct gbl_v4gfx), GFP_KERNEL);
+ if (gbl_dev == NULL) {
+ rv = -ENOMEM;
+ goto end;
+ }
+
+ snprintf(gbl_dev->v4l2_dev.name, sizeof(gbl_dev->v4l2_dev.name),
+ "%s-%03d", VOUT_NAME, VOUT_DEVICENODE_SUFFIX);
+
+ rv = v4l2_device_register(NULL, &gbl_dev->v4l2_dev);
+ if (rv != 0) {
+ printk(KERN_ERR VOUT_NAME ":v4l2_device_register failed\n");
+ goto end;
+ }
+ v4l2_dev_registered = true;
+
+ rv = v4gfx_create_instance(&gbl_dev->vouts[0]);
+ if (rv != 0)
+ goto end;
+
+ rv = bc_init();
+ if (rv != 0)
+ goto end;
+
+ bc_dev_registered = true;
+
+ printk(KERN_INFO VOUT_NAME ":OMAP V4L2 GFX driver loaded ok\n");
+ return rv;
+end:
+ printk(KERN_INFO VOUT_NAME ":Error %d loading OMAP V4L2 GFX driver\n",
+ rv);
+
+ if (bc_dev_registered)
+ bc_cleanup();
+
+ if (v4l2_dev_registered)
+ v4l2_device_unregister(&gbl_dev->v4l2_dev);
+
+ kfree(gbl_dev); /* gbl_dev can be null */
+
+ return rv;
+}
+
+static void module_exit_v4gfx(void)
+{
+ bc_cleanup();
+
+ v4gfx_delete_instance(&gbl_dev->v4l2_dev, gbl_dev->vouts[0]);
+
+ v4l2_device_unregister(&gbl_dev->v4l2_dev);
+
+ kfree(gbl_dev);
+
+ platform_driver_unregister(&v4gfx_driver);
+}
+
+module_init(module_init_v4gfx);
+module_exit(module_exit_v4gfx);
diff --git a/drivers/media/video/omapgfx/gfx_io.c b/drivers/media/video/omapgfx/gfx_io.c
new file mode 100644
index 00000000000..e753b4e9ae5
--- /dev/null
+++ b/drivers/media/video/omapgfx/gfx_io.c
@@ -0,0 +1,1329 @@
+/*
+ * drivers/media/video/omap/v4gfx.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/omap_v4l2_gfx.h> /* private ioctls */
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+
+#include "v4gfx.h"
+#include "gfx_bc.h"
+
+#define V4GFX_WAIT_DEQUE 1 /* Poll buffer sync status during dq */
+#define V4GFX_WAIT_UNLOCK 2 /* Poll buffer sync status from render loop */
+/*
+ * V4GFX_WAITMETHOD is used to select between how we wait for SGX to release
+ * buffers sent to it.
+ */
+/* #define V4GFX_WAITMETHOD V4GFX_WAIT_DEQUE */
+#define V4GFX_WAITMETHOD V4GFX_WAIT_UNLOCK
+
+#define VID_MAX_WIDTH 2048 /* Largest width */
+#define VID_MAX_HEIGHT 2048 /* Largest height */
+#define VID_MIN_WIDTH 0
+#define VID_MIN_HEIGHT 0
+#define V4GFX_FRAME_UNLOCK_TIMEOUT 16 /* ms */
+
+
+/*
+ * This will enable dumping of the mappings obtain
+ */
+#ifdef V4L2GFX_DUMPMMAP
+#define DUMPMMAP(msg, k, vma, m, pos, p) \
+ printk(KERN_NOTICE \
+ "%s: vm_start+%d = 0x%lx, dma->vmalloc+%d = 0x%lx, w=0x%x\n", \
+ msg, k, vma->vm_start + k, m, (pos + m), p);
+#else
+#define DUMPMMAP(msg, k, vma, m, pos, p)
+#endif
+
+static struct videobuf_queue_ops video_vbq_ops;
+
+static u32 v4gfx_calc_buffer_size(
+ int bpp, u32 width, u32 height, u32 pixelformat);
+static u32 v4gfx_calc_stride(int bpp, u32 width);
+
+/*
+ * List of image formats supported by the SGX buffer-class api
+ */
+static const struct v4l2_fmtdesc gfx_bc_formats[] = {
+ {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * OMAP video pipelines interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ *
+ * GFX ?? TODO
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .description = "RGB32, le",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ },
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "UYVY, packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .description = "NV12 - YUV420 format",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+};
+
+#define NUM_OUTPUT_FORMATS (ARRAY_SIZE(gfx_bc_formats))
+
+int v4gfx_try_format(struct v4l2_pix_format *pix)
+{
+ int ifmt, bpp = 0;
+
+ pix->height =
+ clamp(pix->height, (u32)VID_MIN_HEIGHT, (u32)VID_MAX_HEIGHT);
+ pix->width = clamp(pix->width, (u32)VID_MIN_WIDTH, (u32)VID_MAX_WIDTH);
+
+ for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
+ if (pix->pixelformat == gfx_bc_formats[ifmt].pixelformat)
+ break;
+ }
+
+ if (ifmt >= NUM_OUTPUT_FORMATS)
+ ifmt = 0; /* Default V4L2_PIX_FMT_RGB565 */
+ pix->pixelformat = gfx_bc_formats[ifmt].pixelformat;
+
+ pix->field = V4L2_FIELD_ANY;
+ pix->priv = 0;
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ bpp = YUYV_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB565_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB24_BPP;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ bpp = RGB32_BPP;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ bpp = 1; /* 12bits per pixel, 1 byte for Y */
+ break;
+ }
+
+ pix->bytesperline = v4gfx_calc_stride(bpp, pix->width);
+ pix->sizeimage = v4gfx_calc_buffer_size(bpp, pix->width, pix->height,
+ pix->pixelformat);
+
+ if (V4L2_PIX_FMT_NV12 == pix->pixelformat)
+ pix->sizeimage += pix->sizeimage >> 1;
+
+ return bpp;
+}
+
+void v4gfx_acquire_timer(unsigned long arg)
+{
+ struct v4gfx_device *vout = (struct v4gfx_device *)arg;
+
+ set_bit(1, &vout->acquire_timedout);
+}
+
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_DEQUE
+static struct videobuf_buffer *v4gfx_get_next_syncframe(
+ struct v4gfx_device *vout)
+{
+ struct videobuf_buffer *buf;
+ mutex_lock(&vout->lock);
+ if (list_empty(&vout->sync_queue)) {
+ mutex_unlock(&vout->lock);
+ return NULL;
+ }
+ buf = list_entry(vout->sync_queue.next, struct videobuf_buffer, queue);
+ mutex_unlock(&vout->lock);
+ return buf;
+}
+
+static int v4gfx_wait_on_pending(struct v4gfx_device *vout, int bufidx)
+{
+ int dqable = 0;
+ int iteration = 0;
+
+ do {
+ dqable = bc_sync_status(0, bufidx);
+ if (!dqable) {
+ /* printk("w-on %d [%d]\n", bufidx, iteration); */
+ if (iteration++ < V4GFX_FRAME_UNLOCK_TIMEOUT) {
+ msleep(1); /* milliseconds */
+ } else {
+ /*printk("t-o %d\n", bufidx); */
+ break; /* Timed out */
+ }
+ }
+/*
+ else {
+ printk("dq-o %d\n", bufidx);
+ }
+ */
+ } while (!dqable);
+
+ return dqable;
+}
+
+static void v4gfx_done_syncframe(struct v4gfx_device *vout,
+ struct videobuf_buffer *sync_frame)
+{
+ struct timeval timevalue = {0};
+ unsigned long flags;
+ mutex_lock(&vout->lock);
+ spin_lock_irqsave(&vout->vbq_lock, flags);
+
+ list_del(&sync_frame->queue);
+
+ do_gettimeofday(&timevalue);
+ sync_frame->ts = timevalue;
+ sync_frame->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&sync_frame->done);
+ spin_unlock_irqrestore(&vout->vbq_lock, flags);
+ mutex_unlock(&vout->lock);
+}
+#endif /* V4GFX_WAIT_DEQUE */
+
+
+static u32 v4gfx_calc_stride(int bpp, u32 width)
+{
+ return PAGE_ALIGN(width * bpp);
+}
+
+static u32 v4gfx_calc_buffer_size(
+ int bpp, u32 width, u32 height, u32 pixelformat)
+{
+ int stride;
+ stride = v4gfx_calc_stride(bpp, width);
+
+ /* i is the block-width - either 4K or 8K, depending upon input width*/
+ /* for NV12 format, buffer is height + height / 2*/
+ if (V4L2_PIX_FMT_NV12 == pixelformat)
+ return height * 3/2 * stride;
+ else
+ return height * stride;
+}
+
+void v4gfx_buffer_array_free(struct v4gfx_device *vout, int cnt)
+{
+ /* Fn should be robust and callable with args in a dubious state */
+ int i;
+ if (!vout || !cnt)
+ return;
+ if (vout->buf_phys_addr_array) {
+ for (i = 0; i < cnt; i++)
+ kfree(vout->buf_phys_addr_array[i]);
+ kfree(vout->buf_phys_addr_array);
+ vout->buf_phys_addr_array = NULL;
+ }
+}
+
+/*
+ * Allocate a buffer array for all the requested buffers
+ * If there is an allocation failure the function will clean up after itself
+ */
+static int v4gfx_buffer_array_realloc(struct v4gfx_device *vout,
+ int oldcnt, int newcnt)
+{
+ int i;
+
+ if (vout->buf_phys_addr_array)
+ v4gfx_buffer_array_free(vout, oldcnt);
+
+ vout->buf_phys_addr_array =
+ kzalloc(sizeof(unsigned long *) * newcnt, GFP_KERNEL);
+ if (!vout->buf_phys_addr_array)
+ return -ENOMEM;
+
+ /* 2048 is the max image height, 2 = (2048 * 4) / CPU_PAGE_SIZE */
+ for (i = 0; i < newcnt; i++) {
+ vout->buf_phys_addr_array[i] =
+ kmalloc(sizeof(unsigned long) * 2048 * 2, GFP_KERNEL);
+ if (!vout->buf_phys_addr_array[i]) {
+ v4gfx_buffer_array_free(vout, newcnt);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void v4gfx_buffer_array_fill(
+ struct v4gfx_device *vout,
+ int bufno,
+ unsigned long tiler_paddr_in,
+ unsigned long tiler_paddr_uv_in)
+{
+ int buf_phys_idx = 0;
+ int m = 0, i;
+ int cpu_pgwidth;
+ int tiler_increment;
+
+ v4gfx_tiler_image_incr(vout, &cpu_pgwidth, &tiler_increment);
+
+ for (i = 0; i < vout->pix.height; i++) {
+ unsigned long pg, pgend, tiler_paddr;
+
+ tiler_paddr = tiler_paddr_in+m;
+ pg = tiler_paddr;
+ pgend = pg + cpu_pgwidth;
+ do {
+ GFXLOGA(2, "%d %d: = %lx\n", bufno, buf_phys_idx,
+ (long)pg);
+ vout->buf_phys_addr_array[bufno][buf_phys_idx] = pg;
+ pg += 4096;
+ buf_phys_idx++;
+ } while (pg < pgend);
+
+ m += tiler_increment;
+ }
+
+ if (V4L2_PIX_FMT_NV12 == vout->pix.pixelformat) {
+ m = 0;
+ v4gfx_tiler_image_incr_uv(vout, &tiler_increment);
+
+ /* UV buffer is height / 2 */
+ for (i = 0; i < vout->pix.height / 2; i++) {
+ unsigned long pg;
+
+ pg = tiler_paddr_uv_in+m;
+ vout->buf_phys_addr_array[bufno][buf_phys_idx] = pg;
+ m += tiler_increment;
+ buf_phys_idx++;
+ }
+
+ GFXLOGA(1, "nv12 uv: 0x%lx\n", tiler_paddr_uv_in);
+ m += tiler_increment;
+ }
+}
+
+static int v4gfx_frame_lock(struct v4gfx_device *vout, int *bufid)
+{
+ struct videobuf_buffer *oldbuf = NULL;
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_UNLOCK
+ struct timeval timevalue = {0};
+#else /* V4GFX_WAIT_DEQUE */
+ int oldbufid = -1;
+#endif
+ unsigned long flags;
+ int rv = 0;
+
+ mutex_lock(&vout->lock);
+ spin_lock_irqsave(&vout->vbq_lock, flags);
+ if (!vout->streaming || !vout->cur_frm) {
+ GFXLOG(1, V4L2DEV(vout),
+ "%s: ERROR: device not streaming yet\n", __func__);
+ rv = -EAGAIN;
+ goto unlock;
+ }
+
+ /* vout->cur_frm must be set if streaming */
+
+ if (vout->cur_frm == vout->locked_frm) {
+ /*
+ * If this frame has been locked before we will
+ * attempt to get the next buffer in the dma queue.
+ * If there is a next buffer, mark the locked
+ * buffer as done and then promote the next buffer
+ * to the current buffer whilst locking it in the
+ * process.
+ */
+ if (list_empty(&vout->dma_queue)) {
+ *bufid = vout->cur_frm->i;
+ /*
+ * We can't do anything else here, it will be upto
+ * the consumer application to decide whether it wants
+ * to re-render the texture which depends on what the
+ * app is doing.
+ */
+ goto unlock;
+ }
+
+ /* Deactivate the cur_frm */
+ oldbuf = vout->cur_frm;
+
+ vout->cur_frm = list_entry(vout->dma_queue.next,
+ struct videobuf_buffer, queue);
+
+ list_del(&vout->cur_frm->queue);
+
+ vout->cur_frm->state = VIDEOBUF_ACTIVE;
+
+ GFXLOG(2, V4L2DEV(vout), "Active frame %d\n", vout->cur_frm->i);
+
+ vout->locked_frm = vout->cur_frm;
+
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_UNLOCK
+ /*
+ * Mark the previous current buffer done and release it for
+ * dequeue
+ */
+ do_gettimeofday(&timevalue);
+ oldbuf->ts = timevalue;
+ oldbuf->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&oldbuf->done);
+#else /* V4GFX_WAIT_DEQUE */
+ oldbufid = oldbuf->i;
+ list_add_tail(&oldbuf->queue, &vout->sync_queue);
+ wake_up_interruptible(&vout->sync_done);
+#endif
+
+ } else {
+ /* First time we've tried to lock this frame */
+ vout->locked_frm = vout->cur_frm;
+ /* We be marked for dequeue next time */
+ }
+ *bufid = vout->locked_frm->i;
+unlock:
+ spin_unlock_irqrestore(&vout->vbq_lock, flags);
+ mutex_unlock(&vout->lock);
+
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_DEQUE
+/*
+ if (oldbufid != -1)
+ printk("sync_queue + %d\n", oldbufid);
+ */
+#endif
+ return rv;
+}
+
+static int v4gfx_frame_unlock(struct v4gfx_device *vout, int bufidx)
+{
+ struct videobuf_buffer *vbuf;
+ int rv = 0;
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_UNLOCK
+ int iteration = 0;
+#endif
+
+ mutex_lock(&vout->lock);
+ vbuf = vout->locked_frm;
+ if (!vbuf) {
+ GFXLOG(1, V4L2DEV(vout),
+ "%s: ERROR: trying to unlock a non-existent frame\n",
+ __func__);
+ rv = -EINVAL;
+ } else if (vbuf->i != bufidx) {
+ GFXLOG(1, V4L2DEV(vout),
+ "%s: ERROR: trying to unlock wrong frame %d %d\n",
+ __func__, vbuf->i, bufidx);
+ rv = -EINVAL;
+ }
+ mutex_unlock(&vout->lock);
+
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_UNLOCK
+ if (rv != 0)
+ goto end;
+
+ do {
+ /*
+ * Interrogate the buffer class synch data buffer to see if SGX
+ * is done with this buffer
+ */
+ rv = bc_sync_status(0, bufidx);
+ if (rv == 0) {
+ if (iteration++ < V4GFX_FRAME_UNLOCK_TIMEOUT)
+ msleep(1); /* milliseconds */
+ }
+ } while (rv == 0);
+
+ if (iteration >= V4GFX_FRAME_UNLOCK_TIMEOUT) {
+ printk("%s: INFO: timed out\n", __func__);
+ rv = -ETIMEDOUT;
+ } else
+ rv = 0;
+end:
+#endif /* V4GFX_WAIT_UNLOCK */
+ return rv;
+}
+
+/*
+ * Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int vbq_ops_buf_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct v4gfx_device *vout = q->priv_data;
+ int rv = 0;
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ if (!vout || (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)) {
+ rv = -EINVAL; goto end;
+ }
+
+ *size = vout->buffer_size = v4gfx_calc_buffer_size(
+ vout->bpp,
+ vout->pix.width,
+ vout->pix.height,
+ vout->pix.pixelformat);
+
+ GFXLOG(1, V4L2DEV(vout), "height=%d, size=%d\n",
+ vout->pix.height, *size);
+
+ if (v4gfx_tiler_buffer_setup(vout, count, 0, &vout->pix)) {
+ rv = -ENOMEM; goto end;
+ }
+
+end:
+ GFXLOG(1, V4L2DEV(vout), "Exiting %s\n", __func__);
+ return rv;
+}
+
+/*
+ * This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * user space virtual address into physical address if userptr memory
+ * exchange mechanism is used.
+ */
+static int vbq_ops_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct v4gfx_device *vout = q->priv_data;
+
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ vb->width = vout->pix.width;
+ vb->height = vout->pix.height;
+ vb->size = vb->width * vb->height * vout->bpp;
+ vb->field = field;
+
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ return 0;
+}
+
+/*
+ * Buffer queue function will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed.
+ */
+static void vbq_ops_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct v4gfx_device *vout = q->priv_data;
+
+ list_add_tail(&vb->queue, &vout->dma_queue);
+ vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated
+ */
+static void vbq_ops_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct v4gfx_device *vout = q->priv_data;
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+
+ if (V4L2_MEMORY_MMAP != vout->memory)
+ return;
+}
+
+/*
+ * File operations
+ */
+static void v4gfx_vm_open(struct vm_area_struct *vma)
+{
+ struct v4gfx_device *vout = vma->vm_private_data;
+
+ GFXLOG(1, V4L2DEV(vout),
+ "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+ vout->mmap_count++;
+}
+
+static void v4gfx_vm_close(struct vm_area_struct *vma)
+{
+ struct v4gfx_device *vout = vma->vm_private_data;
+
+ GFXLOG(1, V4L2DEV(vout),
+ "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+
+ vout->mmap_count--;
+}
+
+static struct vm_operations_struct v4gfx_vm_ops = {
+ .open = v4gfx_vm_open,
+ .close = v4gfx_vm_close,
+};
+
+static int vidfop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct v4gfx_device *vout = file->private_data;
+ struct videobuf_queue *q = &vout->vbq;
+ int i;
+ void *pos;
+ int j = 0, k = 0, m = 0, p = 0, m_increment = 0;
+
+ GFXLOG(1, V4L2DEV(vout), "Entering %s\n", __func__);
+
+ /* look for the buffer to map */
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
+ continue;
+ if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+
+ if (VIDEO_MAX_FRAME == i) {
+ GFXLOG(1, V4L2DEV(vout),
+ "offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ return -EINVAL;
+ }
+ q->bufs[i]->baddr = vma->vm_start;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_ops = &v4gfx_vm_ops;
+ vma->vm_private_data = (void *) vout;
+ pos = (void *)vout->buf_phy_addr[i];
+
+ /* get line width */
+ v4gfx_tiler_image_incr(vout, &p, &m_increment);
+
+ for (j = 0; j < vout->pix.height; j++) {
+ /* map each page of the line */
+ DUMPMMAP("Y buffer", k, vma, m, pos, p);
+
+ vma->vm_pgoff = ((unsigned long)pos + m) >> PAGE_SHIFT;
+
+ if (remap_pfn_range(vma, vma->vm_start + k,
+ ((unsigned long)pos + m) >> PAGE_SHIFT,
+ p, vma->vm_page_prot))
+ return -EAGAIN;
+ k += p;
+ m += m_increment;
+ }
+ m = 0;
+
+ /* UV Buffer in case of NV12 format */
+ if (V4L2_PIX_FMT_NV12 == vout->pix.pixelformat) {
+ pos = (void *)vout->buf_phy_uv_addr[i];
+
+ v4gfx_tiler_image_incr_uv(vout, &m_increment);
+
+ /* UV buffer is height / 2 */
+ for (j = 0; j < vout->pix.height / 2; j++) {
+ /* map each page of the line */
+ DUMPMMAP("UV buffer", k, vma, m, pos, p);
+
+ vma->vm_pgoff = ((unsigned long)pos + m) >> PAGE_SHIFT;
+
+ if (remap_pfn_range(vma, vma->vm_start + k,
+ ((unsigned long)pos + m) >> PAGE_SHIFT,
+ p, vma->vm_page_prot))
+ return -EAGAIN;
+ k += p;
+ m += m_increment;
+ }
+ }
+
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ vout->mmap_count++;
+ GFXLOG(1, V4L2DEV(vout), "Exiting %s\n", __func__);
+ return 0;
+}
+
+static int vidfop_release(struct file *file)
+{
+ struct v4gfx_device *vout = file->private_data;
+ struct videobuf_queue *q;
+ unsigned int r = 0;
+
+ GFXLOG(1, V4L2DEV(vout), "Entering %s\n", __func__);
+ GFXLOG(1, V4L2DEV(vout),
+ "current process id/pid is %d\n", current->pid);
+
+ if (!vout)
+ goto end;
+
+ vout->opened = vout->opened ? vout->opened - 1 : 0;
+ if (vout->opened) {
+ r = 0;
+ goto end;
+ }
+
+ clear_bit(1, &vout->producer_ready);
+
+ q = &vout->vbq;
+
+ if (vout->streaming) {
+ del_timer_sync(&vout->acquire_timer);
+ clear_bit(1, &vout->acquire_timedout);
+
+ vout->streaming = false;
+ videobuf_streamoff(q);
+ videobuf_queue_cancel(q);
+ }
+
+ if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory))
+ videobuf_mmap_free(q);
+ vout->mmap_count = 0;
+
+ /* Free buffers */
+ if (vout->buffer_allocated) {
+ v4gfx_tiler_buffer_free(vout, vout->buffer_allocated, 0);
+ vout->buffer_allocated = 0;
+ }
+
+ memset(&vout->crop, 0, sizeof(vout->crop));
+ memset(&vout->pix, 0, sizeof(vout->pix));
+
+ file->private_data = NULL;
+
+end:
+ GFXLOG(1, V4L2DEV(vout), "Exiting %s\n", __func__);
+ return r;
+}
+
+static int vidfop_open(struct file *file)
+{
+ struct v4gfx_device *vout = NULL;
+ struct videobuf_queue *q;
+ int rv = 0;
+
+ vout = video_drvdata(file);
+ if (vout == NULL) {
+ rv = -ENODEV;
+ goto end;
+ }
+
+ GFXLOG(1, V4L2DEV(vout), "Entering %s : %x\n", __func__, (int)vout);
+ GFXLOG(1, V4L2DEV(vout), "current pid is %d\n", current->pid);
+
+ vout->opened += 1;
+ file->private_data = vout;
+
+ if (vout->opened > 1) {
+ GFXLOG(1, V4L2DEV(vout), "Another opening....\n");
+ goto end;
+ }
+
+ clear_bit(1, &vout->producer_ready);
+
+ q = &vout->vbq;
+ video_vbq_ops.buf_setup = vbq_ops_buf_setup;
+ video_vbq_ops.buf_prepare = vbq_ops_buf_prepare;
+ video_vbq_ops.buf_release = vbq_ops_buf_release;
+ video_vbq_ops.buf_queue = vbq_ops_buf_queue;
+
+ videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
+ &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), vout);
+
+end:
+ GFXLOG(1, V4L2DEV(vout), "Exiting %s :%d\n", __func__, rv);
+ return rv;
+}
+
+/* V4L2 ioctls */
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "Entering %s\n", __func__);
+
+ strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+ cap->bus_info[0] = '\0';
+ cap->version = VOUT_VERSION;
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+ return 0;
+}
+
+static int vidioc_log_status(struct file *file, void *fh)
+{
+ /* struct v4gfx_device *vout = fh; */
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "============== START LOG STATUS ================\n");
+ printk(KERN_INFO "=============== END LOG STATUS =================\n");
+ printk(KERN_INFO "\n");
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct v4gfx_device *vout = fh;
+ int index = fmt->index;
+ enum v4l2_buf_type type = fmt->type;
+ int rv = 0;
+
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ fmt->index = index;
+ fmt->type = type;
+ if (index >= NUM_OUTPUT_FORMATS) {
+ rv = -EINVAL;
+ goto end;
+ }
+
+ fmt->flags = gfx_bc_formats[index].flags;
+ strlcpy(fmt->description, gfx_bc_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = gfx_bc_formats[index].pixelformat;
+end:
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ f->fmt.pix = vout->pix;
+
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, 0);
+ return 0;
+
+}
+
+/*
+ * VIDIOC_TRY_FMT ioctl is equivalent to VIDIOC_S_FMT with one
+ * exception: it does not change driver state. It can also be called at any
+ * time, never returning EBUSY.
+ */
+static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ int r;
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ r = v4gfx_try_format(&f->fmt.pix);
+
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, r);
+ return (r >= 0) ? 0 : r;
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct v4gfx_device *vout = fh;
+ int rv = 0;
+ int bpp;
+
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ mutex_lock(&vout->lock);
+ if (vout->streaming) {
+ rv = -EBUSY;
+ goto end;
+ }
+
+ bpp = v4gfx_try_format(&f->fmt.pix);
+ if (bpp <= 0) {
+ rv = bpp;
+ goto end;
+ }
+
+ /* try & set the new output format */
+ vout->bpp = bpp;
+ vout->pix = f->fmt.pix;
+
+end:
+ mutex_unlock(&vout->lock);
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ struct bc_buf_params2 bc_params;
+ struct v4gfx_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ unsigned int i;
+ int rv = 0;
+
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
+ (req->count < 0) ||
+ (req->memory != V4L2_MEMORY_MMAP)
+ ) {
+ rv = -EINVAL; goto end;
+ }
+
+
+ mutex_lock(&vout->lock);
+ /* Cannot be requested when streaming is on */
+ if (vout->streaming) {
+ mutex_unlock(&vout->lock);
+ rv = -EBUSY; goto end;
+ }
+
+ /*
+ * TODO A count value of zero frees all buffers, after aborting or
+ * finishing any DMA in progress, an implicit VIDIOC_STREAMOFF.
+ */
+
+ /* If buffers are already allocated free them */
+ if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
+ if (vout->mmap_count) {
+ mutex_unlock(&vout->lock);
+ rv = -EBUSY; goto end;
+ }
+
+ v4gfx_tiler_buffer_free(vout, vout->buffer_allocated, 0);
+ vout->buffer_allocated = 0;
+
+ videobuf_mmap_free(q);
+ }
+
+ bc_params.count = req->count;
+ bc_params.width = vout->pix.width;
+ bc_params.height = vout->pix.height;
+ bc_params.pixel_fmt = vout->pix.pixelformat;
+/* bc_params.stride = vout->pix.bytesperline; */
+ rv = bc_setup(0, &bc_params);
+ if (rv < 0) {
+ GFXLOG(1, V4L2DEV(vout),
+ "+%s bc_setup() failed %d\n", __func__, rv);
+ goto end;
+ }
+
+ /*
+ * Note that the actual buffer allocation is done in
+ * vbq_ops_buf_setup
+ */
+ rv = videobuf_reqbufs(q, req);
+ if (rv < 0) {
+ mutex_unlock(&vout->lock);
+ goto end;
+ }
+
+ INIT_LIST_HEAD(&vout->dma_queue);
+ INIT_LIST_HEAD(&vout->sync_queue);
+
+ /*
+ * The realloc will free the old array and allocate a new one
+ */
+ rv = v4gfx_buffer_array_realloc(vout, vout->buffer_allocated,
+ req->count);
+ if (rv < 0) {
+ mutex_unlock(&vout->lock);
+ goto end;
+ }
+
+ vout->memory = req->memory;
+ vout->buffer_allocated = req->count;
+
+ for (i = 0; i < req->count; i++) {
+
+ v4gfx_buffer_array_fill(vout, i,
+ vout->buf_phy_addr[i],
+ V4L2_PIX_FMT_NV12 == vout->pix.pixelformat ?
+ vout->buf_phy_uv_addr[i] : 0);
+
+ bc_setup_buffer(0, &bc_params, vout->buf_phys_addr_array[i]);
+ }
+ bc_setup_complete(0, &bc_params);
+
+ mutex_unlock(&vout->lock);
+end:
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct v4gfx_device *vout = fh;
+ int rv;
+
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ rv = videobuf_querybuf(&vout->vbq, b);
+
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct v4gfx_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int rv = 0;
+
+ GFXLOG(1, V4L2DEV(vout), "qbuf buf: %d\n", buf->index);
+
+ if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) ||
+ (buf->index >= vout->buffer_allocated) ||
+ (q->bufs[buf->index]->memory != buf->memory)) {
+ return -EINVAL;
+ }
+ if (V4L2_MEMORY_USERPTR == buf->memory) {
+ if ((buf->length < vout->pix.sizeimage) ||
+ (0 == buf->m.userptr)) {
+ return -EINVAL;
+ }
+ }
+
+ rv = videobuf_qbuf(q, buf);
+
+ mutex_lock(&vout->lock);
+ if (vout->streaming && vout->acquire_timeout_ms) {
+ del_timer(&vout->acquire_timer);
+ mod_timer(&vout->acquire_timer,
+ jiffies + msecs_to_jiffies(vout->acquire_timeout_ms));
+ }
+ mutex_unlock(&vout->lock);
+
+ GFXLOG(2, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct v4gfx_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int rv = 0;
+ int nonblocking = file->f_flags & O_NONBLOCK ? 1 : 0;
+
+ GFXLOG(2, V4L2DEV(vout), "dqbuf buf: %x (%d)\n",
+ (int)buf, nonblocking);
+
+ mutex_lock(&vout->lock);
+ if (!vout->streaming) {
+ mutex_unlock(&vout->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&vout->lock);
+
+#if V4GFX_WAITMETHOD == V4GFX_WAIT_DEQUE
+{
+ struct videobuf_buffer *sync_frame = NULL;
+
+ wait_event_interruptible(vout->sync_done,
+ !list_empty(&vout->sync_queue));
+
+ sync_frame = v4gfx_get_next_syncframe(vout);
+
+ if (sync_frame) {
+ (void)v4gfx_wait_on_pending(vout, sync_frame->i);
+ v4gfx_done_syncframe(vout, sync_frame);
+ } else {
+ /* Can be from an interrupted task */
+ printk(KERN_INFO "No sync frame\n");
+ }
+}
+#endif
+
+ rv = videobuf_dqbuf(q, buf, nonblocking);
+
+ GFXLOG(2, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct v4gfx_device *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int rv = 0;
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+
+ mutex_lock(&vout->lock);
+
+ if (vout->streaming) {
+ rv = -EBUSY;
+ goto end_unlock;
+ }
+
+ vout->cur_frm = NULL;
+ vout->locked_frm = NULL;
+
+ rv = videobuf_streamon(q);
+ if (rv < 0)
+ goto end_unlock;
+
+ if (list_empty(&vout->dma_queue)) {
+ rv = -EIO;
+ goto end_unlock;
+ }
+
+ vout->streaming = true;
+
+ /* Activate the next current buffer */
+ vout->cur_frm =
+ list_entry(vout->dma_queue.next, struct videobuf_buffer, queue);
+ list_del(&vout->cur_frm->queue);
+ vout->cur_frm->state = VIDEOBUF_ACTIVE;
+
+ set_bit(1, &vout->producer_ready);
+ wake_up_interruptible(&vout->consumer_wait);
+
+end_unlock:
+ mutex_unlock(&vout->lock);
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+
+ return rv;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct v4gfx_device *vout = fh;
+ int rv;
+
+ mutex_lock(&vout->lock);
+ if (!vout->streaming) {
+ rv = -EINVAL;
+ goto end;
+ }
+
+ del_timer_sync(&vout->acquire_timer);
+ clear_bit(1, &vout->acquire_timedout);
+
+ clear_bit(1, &vout->producer_ready);
+
+ vout->streaming = false;
+
+ INIT_LIST_HEAD(&vout->dma_queue);
+ INIT_LIST_HEAD(&vout->sync_queue);
+
+ videobuf_streamoff(&vout->vbq);
+ videobuf_queue_cancel(&vout->vbq);
+end:
+ mutex_unlock(&vout->lock);
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct v4gfx_device *vout = fh;
+ struct v4l2_pix_format *pix = &vout->pix;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ /* Width and height are always even */
+ cropcap->bounds.width = pix->width & ~1;
+ cropcap->bounds.height = pix->height & ~1;
+ cropcap->pixelaspect.numerator = 1;
+ cropcap->pixelaspect.denominator = 1;
+ return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct v4gfx_device *vout = fh;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ crop->c = vout->crop;
+ GFXLOG(1, V4L2DEV(vout), "g_crop w:%d,h:%d\n",
+ crop->c.width, crop->c.height);
+ return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "Entering %s\n", __func__);
+ vout->crop = crop->c;
+ return 0;
+}
+
+static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+ int rv = 0;
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "Entering %s (c=0x%x)\n", __func__, cmd);
+
+ switch (cmd) {
+ case V4L2_GFX_IOC_CONSUMER:
+ {
+ struct v4l2_gfx_consumer_params *parms =
+ (struct v4l2_gfx_consumer_params *)arg;
+ if (parms->type != V4L2_GFX_CONSUMER_WAITSTREAM)
+ return -EINVAL;
+
+ clear_bit(1, &vout->acquire_timedout);
+
+ rv = wait_event_interruptible(vout->consumer_wait,
+ test_bit(1, &vout->producer_ready));
+ mutex_lock(&vout->lock);
+ if (rv == -ERESTARTSYS) {
+ /*
+ * This condition is hit when the user process
+ * generates a signal, when we return this value the
+ * process will continue to block on the ioctl
+ */
+ GFXLOG(1, V4L2DEV(vout), "Woke by signal: %d\n",
+ ERESTARTSYS);
+ } else {
+ vout->acquire_timeout_ms = parms->acquire_timeout_ms;
+ }
+ mutex_unlock(&vout->lock);
+ break;
+
+ }
+ case V4L2_GFX_IOC_INFO:
+ {
+ struct v4l2_gfx_info_params *parms =
+ (struct v4l2_gfx_info_params *)arg;
+ parms->opencnt = vout->opened;
+ break;
+ }
+ case V4L2_GFX_IOC_PRODUCER:
+ {
+ struct v4l2_gfx_producer_params *parms =
+ (struct v4l2_gfx_producer_params *)arg;
+ vout->producer_flags = parms->flags;
+ if (!(vout->producer_flags & V4L2_GFX_PRODUCER_MASK_OPEN)) {
+ /*
+ * We decrement the count here because the Android
+ * mediaserver threads won't close the V4L2 device
+ */
+ if (vout->opened)
+ vout->opened--;
+ }
+ break;
+ }
+ case V4L2_GFX_IOC_ACQ:
+ {
+ struct v4l2_gfx_buf_params *parms =
+ (struct v4l2_gfx_buf_params *)arg;
+ int bufid = -1;
+ int timedout;
+ rv = v4gfx_frame_lock(vout, &bufid);
+ if (!rv) {
+ parms->bufid = bufid;
+ parms->crop_top = vout->crop.top;
+ parms->crop_left = vout->crop.left;
+ parms->crop_width = vout->crop.width;
+ parms->crop_height = vout->crop.height;
+ GFXLOG(3, V4L2DEV(vout), "%d:%d:%d:%d:%d\n",
+ parms->bufid ,
+ parms->crop_top ,
+ parms->crop_left ,
+ parms->crop_width ,
+ parms->crop_height);
+ }
+ timedout = test_and_clear_bit(1, &vout->acquire_timedout);
+ if (timedout) {
+ GFXLOG(1, V4L2DEV(vout), "ACQ Timed out\n");
+ rv = -ETIMEDOUT;
+ }
+ mutex_lock(&vout->lock);
+ if (!vout->streaming) {
+ GFXLOG(1, V4L2DEV(vout), "ACQ stream off\n");
+ rv = -ENODEV;
+ }
+ mutex_unlock(&vout->lock);
+ break;
+ }
+ case V4L2_GFX_IOC_REL:
+ {
+ struct v4l2_gfx_buf_params *parms =
+ (struct v4l2_gfx_buf_params *)arg;
+ int bufid = parms->bufid;
+ rv = v4gfx_frame_unlock(vout, bufid);
+ break;
+ }
+ default:
+ rv = -EINVAL;
+ }
+ GFXLOG(1, V4L2DEV(vout), "Leaving %s (%d)\n", __func__, rv);
+ return rv;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+ struct v4gfx_device *vout = fh;
+ GFXLOG(1, V4L2DEV(vout), "%s: %d\n", __func__, a->id);
+ return 0;
+}
+
+struct v4l2_ioctl_ops v4gfx_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_cropcap = vidioc_cropcap,
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_s_crop = vidioc_s_crop,
+ .vidioc_default = vidioc_default,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+};
+
+const struct v4l2_file_operations v4gfx_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+ .mmap = vidfop_mmap,
+ .open = vidfop_open,
+ .release = vidfop_release,
+};
+
diff --git a/drivers/media/video/omapgfx/gfx_tiler.c b/drivers/media/video/omapgfx/gfx_tiler.c
new file mode 100644
index 00000000000..1e77983053e
--- /dev/null
+++ b/drivers/media/video/omapgfx/gfx_tiler.c
@@ -0,0 +1,152 @@
+/*
+ * drivers/media/video/omap/gfx_tiler.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "v4gfx.h"
+#include "gfx_bc.h"
+
+#ifdef CONFIG_TILER_OMAP
+#include <mach/tiler.h>
+#define TILER_ALLOCATE_V4L2
+#endif
+
+void v4gfx_tiler_buffer_free(struct v4gfx_device *vout, unsigned int count,
+ unsigned int startindex)
+{
+ int i;
+
+ if (startindex < 0)
+ startindex = 0;
+ if (startindex + count > VIDEO_MAX_FRAME)
+ count = VIDEO_MAX_FRAME - startindex;
+
+ for (i = startindex; i < startindex + count; i++) {
+ if (vout->buf_phy_addr_alloced[i])
+ tiler_free(vout->buf_phy_addr_alloced[i]);
+ if (vout->buf_phy_uv_addr_alloced[i])
+ tiler_free(vout->buf_phy_uv_addr_alloced[i]);
+ vout->buf_phy_addr[i] = 0;
+ vout->buf_phy_addr_alloced[i] = 0;
+ vout->buf_phy_uv_addr[i] = 0;
+ vout->buf_phy_uv_addr_alloced[i] = 0;
+ }
+}
+
+/* Allocate the buffers for TILER space. Ideally, the buffers will be ONLY
+ in tiler space, with different rotated views available by just a convert.
+ */
+int v4gfx_tiler_buffer_setup(struct v4gfx_device *vout,
+ unsigned int *count, unsigned int startindex,
+ struct v4l2_pix_format *pix)
+{
+ /* startindex is always passed as 0, possibly tidy up? */
+ int i, aligned = 1, bpp;
+ enum tiler_fmt fmt;
+ int rv = 0;
+
+ /* normalize buffers to allocate so we stay within bounds */
+ int start = (startindex < 0) ? 0 : startindex;
+ int n_alloc = (start + *count > VIDEO_MAX_FRAME) ?
+ VIDEO_MAX_FRAME - start : *count;
+
+ GFXLOG(1, V4L2DEV(vout), "+%s\n", __func__);
+ bpp = v4gfx_try_format(pix);
+ if (bpp <= 0) {
+ rv = bpp; /* error condition */
+ goto end;
+ }
+
+ GFXLOG(1, V4L2DEV(vout), "tiler buffer alloc: "
+ "count = %d, start = %d :\n", *count, startindex);
+
+ /* special allocation scheme for NV12 format */
+ if (V4L2_PIX_FMT_NV12 == pix->pixelformat) {
+
+ tiler_alloc_packed_nv12(&n_alloc, ALIGN(pix->width, 128),
+ pix->height,
+ (void **) vout->buf_phy_addr + start,
+ (void **) vout->buf_phy_uv_addr + start,
+ (void **) vout->buf_phy_addr_alloced + start,
+ (void **) vout->buf_phy_uv_addr_alloced + start,
+ aligned);
+
+ } else {
+ /* Only bpp of 1, 2, and 4 is supported by tiler */
+ fmt = (bpp == 1 ? TILFMT_8BIT :
+ bpp == 2 ? TILFMT_16BIT :
+ bpp == 4 ? TILFMT_32BIT : TILFMT_INVALID);
+ if (fmt == TILFMT_INVALID) {
+ rv = -ENOMEM;
+ goto end;
+ }
+
+ tiler_alloc_packed(&n_alloc, fmt, ALIGN(pix->width, 128 / bpp),
+ pix->height,
+ (void **) vout->buf_phy_addr + start,
+ (void **) vout->buf_phy_addr_alloced + start,
+ aligned);
+ }
+
+ GFXLOG(1, V4L2DEV(vout),
+ "allocated %d buffers\n", n_alloc);
+
+ if (n_alloc < *count) {
+ if (n_alloc && (startindex == -1 ||
+ V4L2_MEMORY_MMAP != vout->memory)) {
+ /* TODO: check this condition's logic */
+ v4gfx_tiler_buffer_free(vout, n_alloc, start);
+ *count = 0;
+ rv = -ENOMEM;
+ goto end;
+ }
+ }
+
+ for (i = start; i < start + n_alloc; i++) {
+ GFXLOG(1, V4L2DEV(vout),
+ "y=%08lx (%d) uv=%08lx (%d)\n",
+ vout->buf_phy_addr[i],
+ vout->buf_phy_addr_alloced[i] ? 1 : 0,
+ vout->buf_phy_uv_addr[i],
+ vout->buf_phy_uv_addr_alloced[i] ? 1 : 0);
+ }
+
+ *count = n_alloc;
+end:
+ GFXLOG(1, V4L2DEV(vout), "-%s [%d]\n", __func__, rv);
+ return rv;
+}
+
+void v4gfx_tiler_image_incr(struct v4gfx_device *vout, int *cpu_pgwidth,
+ int *tiler_increment)
+{
+ /* for NV12, Y buffer is 1bpp*/
+ if (V4L2_PIX_FMT_NV12 == vout->pix.pixelformat) {
+ *cpu_pgwidth =
+ (vout->pix.width + TILER_PAGE - 1) & ~(TILER_PAGE - 1);
+ *tiler_increment = 64 * TILER_WIDTH;
+ } else {
+ *cpu_pgwidth = (vout->pix.width * vout->bpp + TILER_PAGE - 1) &
+ ~(TILER_PAGE - 1);
+ if (vout->bpp > 1)
+ *tiler_increment = 2 * 64 * TILER_WIDTH;
+ else
+ *tiler_increment = 64 * TILER_WIDTH;
+ }
+}
+
+void v4gfx_tiler_image_incr_uv(struct v4gfx_device *vout, int *tiler_increment)
+{
+ if (vout->pix.pixelformat == V4L2_PIX_FMT_NV12)
+ *tiler_increment = 2 * 64 * TILER_WIDTH;
+ /* Otherwise do nothing */
+}
diff --git a/drivers/media/video/omapgfx/v4gfx.h b/drivers/media/video/omapgfx/v4gfx.h
new file mode 100644
index 00000000000..b0b72ddf849
--- /dev/null
+++ b/drivers/media/video/omapgfx/v4gfx.h
@@ -0,0 +1,171 @@
+/*
+ * drivers/media/video/omapgfx/v4gfx.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __V4L2_GFX_H__
+#define __V4L2_GFX_H__
+
+#include <linux/version.h>
+#include <media/videobuf-core.h>
+#include <media/v4l2-device.h>
+#include <asm/atomic.h>
+
+#define MAX_VOUT_DEV 3
+
+struct gbl_v4gfx {
+ struct mutex mtx;
+ int state;
+ struct v4l2_device v4l2_dev;
+ struct v4gfx_device *vouts[MAX_VOUT_DEV];
+};
+
+/* per-device data structure */
+struct v4gfx_device {
+
+ struct video_device *vfd;
+
+ struct gbl_v4gfx *gbl_dev;
+
+ int bpp; /* bytes per pixel */
+
+ enum v4l2_buf_type type;
+
+ struct v4l2_pix_format pix;
+
+ struct v4l2_rect crop;
+
+ enum v4l2_memory memory; /* how memory is managed for the device */
+
+ /* we don't allow to change image fmt/size once buffer has
+ * been allocated
+ */
+ int buffer_allocated; /* count of buffers allocated */
+
+ /* allow to reuse previously allocated buffer which is big enough */
+ int buffer_size;
+
+ unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
+
+ unsigned long buf_phy_uv_addr[VIDEO_MAX_FRAME]; /* NV12 support*/
+
+ /* keep which buffers we actually allocated (via tiler) */
+ unsigned long buf_phy_uv_addr_alloced[VIDEO_MAX_FRAME];
+
+ unsigned long buf_phy_addr_alloced[VIDEO_MAX_FRAME];
+
+ /*
+ For each V4L2 buffer requested we will have an array of page addresses
+ to give through the buffer class API
+ */
+ unsigned long **buf_phys_addr_array;
+
+ int mmap_count;
+
+ int opened; /* inc/dec on open/close of the device */
+
+ bool streaming; /* is streaming is in progress? */
+
+ struct mutex lock; /* protect shared data structures in ioctl */
+
+ struct videobuf_buffer *cur_frm;
+
+ struct videobuf_buffer *locked_frm;
+
+ struct videobuf_queue vbq;
+
+ /*
+ * Buffers added by QBUF from the producer application
+ */
+ struct list_head dma_queue;
+
+ /*
+ * Buffers marked as done with by the consumer application but could
+ * still be being used by the GPU. DQBUF will examine this queue
+ * for available buffers.
+ */
+ struct list_head sync_queue;
+
+ wait_queue_head_t sync_done;
+
+ unsigned long producer_ready;
+
+ wait_queue_head_t consumer_wait;
+
+ /*
+ * If acquire_timeout_ms is non-zero the acquire_timer will be reset
+ * when buffers are queued. If the timer expires ETIMEOUT will be
+ * returned via the V4L2_GFX_IOC_ACQ ioctl.
+ */
+ struct timer_list acquire_timer;
+
+ unsigned int acquire_timeout_ms;
+
+ unsigned long acquire_timedout;
+
+ spinlock_t vbq_lock; /* spinlock for videobuf queues */
+
+ unsigned int producer_flags;
+};
+
+extern int debug;
+
+#define GFXLOG(level, dev, fmt, arg...) \
+do { \
+ if (debug >= level) \
+ printk(KERN_INFO "%s: " fmt, (dev)->name , ## arg); \
+} while (0)
+
+#define GFXLOGA(level, fmt, arg...) \
+do { \
+ if (debug >= level) \
+ printk(KERN_INFO "v4l2-gfx: " fmt, ## arg); \
+} while (0)
+
+/*
+ * Convert local handle to v4l2_dev, currently only a global dev is supported
+ */
+#define V4L2DEV(vout) (&vout->gbl_dev->v4l2_dev)
+
+/* tiler */
+void v4gfx_tiler_buffer_free(
+ struct v4gfx_device *vout, unsigned int count,
+ unsigned int startindex);
+
+int v4gfx_tiler_buffer_setup(struct v4gfx_device *vout,
+ unsigned int *count, unsigned int startindex,
+ struct v4l2_pix_format *pix);
+
+void v4gfx_tiler_image_incr(struct v4gfx_device *vout,
+ int *cpu_pgwidth, int *tiler_increment);
+
+void v4gfx_tiler_image_incr_uv(struct v4gfx_device *vout, int *tiler_increment);
+
+/* v4gfx */
+int v4gfx_try_format(struct v4l2_pix_format *pix);
+void v4gfx_buffer_array_free(struct v4gfx_device *vout, int cnt);
+extern struct v4l2_ioctl_ops v4gfx_ioctl_ops;
+extern const struct v4l2_file_operations v4gfx_fops;
+extern void v4gfx_acquire_timer(unsigned long arg);
+
+/* Other stuff */
+#define YUYV_BPP 2
+#define RGB565_BPP 2
+#define RGB24_BPP 3
+#define RGB32_BPP 4
+
+#define VOUT_NAME "v4gfx"
+
+/* configuration macros */
+#define VOUT_MAJOR_VERSION 0
+#define VOUT_MINOR_VERSION 0
+#define VOUT_RELEASE 0
+#define VOUT_VERSION \
+ KERNEL_VERSION(VOUT_MAJOR_VERSION, VOUT_MINOR_VERSION, VOUT_RELEASE)
+
+#endif /* ifndef __V4L2_GFX_H__ */
diff --git a/include/linux/omap_v4l2_gfx.h b/include/linux/omap_v4l2_gfx.h
new file mode 100644
index 00000000000..cb175e58a11
--- /dev/null
+++ b/include/linux/omap_v4l2_gfx.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file specifies the custom ioctl API between a client "consumer"
+ * process and the V4L2-GFX driver. The consumer process should only use
+ * these APIs and will typically/ultimately be a GL application.
+ *
+ * There will also be a "producer" process which queues multimedia
+ * content to the driver, however, this will only use standard V4L2 APIs.
+ */
+
+#ifndef _OMAP_V4L2_GFX_H_
+#define _OMAP_V4L2_GFX_H_
+
+#include <linux/videodev.h>
+
+/*
+ * @see V4L2_GFX_IOC_CONSUMER, struct v4l2_gfx_consumer_params
+ */
+enum v4l2_gfx_consumer_type {
+ /*
+ * Wait for the producer process to activate a video stream
+ */
+ V4L2_GFX_CONSUMER_WAITSTREAM,
+ };
+
+/*
+ * @see V4L2_GFX_IOC_CONSUMER
+ */
+struct v4l2_gfx_consumer_params {
+ /*
+ * @see v4l2_gfx_consumer_type
+ */
+ int type; /* w */
+ /*
+ * If the consumer process is waiting the ioctl will block until the
+ * timeout expires or the expected event occurs, see the type field
+ */
+ unsigned int timeout_ms; /* w */
+ /*
+ * If acquire_timeout_ms > 0 and no streaming activity has been detected
+ * for acquire_timeout_ms milliseconds the V4L2_GFX_IOC_ACQ ioctl will
+ * return with ETIMEOUT
+ */
+ unsigned int acquire_timeout_ms; /* w */
+};
+
+/*
+ * @see V4L2_GFX_IOC_INFO
+ */
+struct v4l2_gfx_info_params {
+
+ /*
+ * Return how many times the device has been opened, this number will
+ * decrement when the device is closed.
+ *
+ * One use for this might be to detect if a consumer or producer is
+ * active and in the process of setting up a stream. However this could
+ * be unreliable if the processes are in the process of closing / crashing.
+ *
+ * Obviously this value will always be at least one i.e. the process
+ * issuing the ioctl opens the device.
+ */
+ unsigned int opencnt; /* r */
+
+};
+
+/*
+ * @see V4L2_GFX_IOC_PRODUCER
+ */
+struct v4l2_gfx_producer_params {
+ /*
+ * If set mark the producer side as open, if not set mark as closed.
+ * For Android we need this because the mediaserver won't close the
+ * driver.
+ */
+ #define V4L2_GFX_PRODUCER_MASK_OPEN 0x1
+ unsigned int flags; /* w */
+};
+
+struct v4l2_gfx_buf_params {
+ /*
+ * Buffer index.
+ *
+ * On acquire, when the ioctl returns the bufid field will be filled in
+ * with the next buffer with data available.
+ *
+ * On release, the consumer process just specifies the buffer to release
+ * which usually is the last acquired buffer index.
+ */
+ int bufid; /* r/w */
+
+ /*
+ * Cropping information
+ * For the acquire ioctl only
+ */
+ int crop_top; /* r */
+ int crop_left; /* r */
+ int crop_width; /* r */
+ int crop_height; /* r */
+};
+
+/*
+ * This ioctl should be issued once by the consumer process before starting
+ * any rendering loop. It allows the process to wait for the producer process
+ * to become ready.
+ *
+ * @see struct v4l2_gfx_consumer_params
+ *
+ * Return value:
+ * Returns 0 if successful, or -1 on error, in which case errno indicates
+ * the error.
+ */
+#define V4L2_GFX_IOC_CONSUMER _IOWR ('v', BASE_VIDIOCPRIVATE+0, \
+ struct v4l2_gfx_consumer_params)
+
+/*
+ * Acquire the buffer to be rendered and its properties.
+ *
+ * @see struct v4l2_gfx_buf_params
+ *
+ * Return value:
+ * Returns 0 if successful, or -1 on error, in which case errno indicates
+ * the error.
+ *
+ * ETIMEDOUT If acquire_timeout_ms is set via V4L2_GFX_IOC_CONSUMER
+ * this error code can be returned.
+ * ENODEV If the producer side of the stream stops this error will
+ * be returned.
+ */
+#define V4L2_GFX_IOC_ACQ _IOR ('v', BASE_VIDIOCPRIVATE+1, \
+ struct v4l2_gfx_buf_params)
+
+/*
+ * Release the buffer that was rendered
+ *
+ * @see struct v4l2_gfx_buf_params
+ *
+ * Return value:
+ * Returns 0 if successful, or -1 on error, in which case errno indicates
+ * the error.
+ *
+ * ETIMEDOUT It took longer than 16ms for the app to render the frame
+ * (This will probably go away to avoid render loop stalls)
+ * EINVAL Attempted to release an invalid buffer index.
+ */
+#define V4L2_GFX_IOC_REL _IOW ('v', BASE_VIDIOCPRIVATE+2, \
+ struct v4l2_gfx_buf_params)
+
+/*
+ * Ioctl used to get information about the device
+ *
+ * @see struct v4l2_gfx_info_params
+ *
+ * Return value:
+ * Returns 0 if successful, or -1 on error, in which case errno indicates
+ * the error.
+ */
+#define V4L2_GFX_IOC_INFO _IOWR ('v', BASE_VIDIOCPRIVATE+3, \
+ struct v4l2_gfx_info_params)
+
+/*
+ * Ioctl used to set producer params
+ *
+ * @see struct v4l2_gfx_producer_params
+ *
+ * Return value:
+ * Returns 0 if successful, or -1 on error, in which case errno indicates
+ * the error.
+ */
+#define V4L2_GFX_IOC_PRODUCER _IOWR ('v', BASE_VIDIOCPRIVATE+4, \
+ struct v4l2_gfx_producer_params)
+#endif // _OMAP_V4L2_GFX_H_