diff options
Diffstat (limited to 'drivers/media/video/omapgfx/gfx_bc.c')
-rw-r--r-- | drivers/media/video/omapgfx/gfx_bc.c | 494 |
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; +} + |