aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/omapgfx/gfx_bc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/omapgfx/gfx_bc.c')
-rw-r--r--drivers/media/video/omapgfx/gfx_bc.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/drivers/media/video/omapgfx/gfx_bc.c b/drivers/media/video/omapgfx/gfx_bc.c
new file mode 100644
index 0000000..619d5d3
--- /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;
+}
+