]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00275033-1 mx6sl: pxp/v4l: port v4l2 output driver to 3.10
authorRobby Cai <R63905@freescale.com>
Thu, 22 Aug 2013 10:01:59 +0000 (18:01 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 20 Aug 2014 08:06:26 +0000 (10:06 +0200)
port v4l2 output driver to 3.10 kernel

- replace .ioctl with .unlocked_ioctl
- add .vfl_dir flag - VFL_DIR_TX (newly introduced) for video_device
- drop __devinit,  __devexit, __exit and __exit_p
- replace mxc_elcdif_frame_addr_setup() with pxp_show_buf(), where pan_display
  be called due to the adoption of mxsfb.c from community
- change the fb id to be compared due to use new mxsfb.c
- mark the s_crop() and s_fbuf() third parameter const
- move local fbi variable to struct pxps
- use module_platform_driver()

Signed-off-by: Robby Cai <R63905@freescale.com>
drivers/media/platform/mxc/output/Kconfig
drivers/media/platform/mxc/output/Makefile
drivers/media/platform/mxc/output/mxc_pxp_v4l2.c [new file with mode: 0644]
drivers/media/platform/mxc/output/mxc_pxp_v4l2.h [new file with mode: 0644]

index b684060abc1802f43f828ee57fa23572868dfb57..237f8a88b5cb5cf6944a28ff64331baa65308158 100644 (file)
@@ -3,3 +3,14 @@ config VIDEO_MXC_IPU_OUTPUT
        depends on VIDEO_MXC_OUTPUT && MXC_IPU
        ---help---
        This is the video4linux2 driver for IPU post processing video output.
+
+config VIDEO_MXC_PXP_V4L2
+        tristate "MXC PxP V4L2 driver"
+        depends on VIDEO_DEV && VIDEO_V4L2
+        select VIDEOBUF_DMA_CONTIG
+        ---help---
+          This is a video4linux driver for the Freescale PxP
+          (Pixel Pipeline). This module supports output overlay of
+          the MXC framebuffer on a video stream.
+
+          To compile this driver as a module, choose M here.
index 7b524fe8e61614cd28238466e43b868343db2ea9..88f1a9fb735d94a46b4ad17a599600d6c4987f93 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o
+obj-$(CONFIG_VIDEO_MXC_PXP_V4L2)   += mxc_pxp_v4l2.o
diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c
new file mode 100644 (file)
index 0000000..6a57d2c
--- /dev/null
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/mxcfb.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mxc_pxp_v4l2.h"
+
+#define PXP_DRIVER_NAME                        "pxp-v4l2"
+#define PXP_DRIVER_MAJOR               2
+#define PXP_DRIVER_MINOR               0
+
+#define PXP_DEF_BUFS                   2
+#define PXP_MIN_PIX                    8
+
+#define V4L2_OUTPUT_TYPE_INTERNAL      4
+
+static int video_nr = -1;      /* -1 ==> auto assign */
+static struct pxp_data_format pxp_s0_formats[] = {
+       {
+               .name = "24-bit RGB",
+               .bpp = 4,
+               .fourcc = V4L2_PIX_FMT_RGB24,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       }, {
+               .name = "16-bit RGB 5:6:5",
+               .bpp = 2,
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       }, {
+               .name = "16-bit RGB 5:5:5",
+               .bpp = 2,
+               .fourcc = V4L2_PIX_FMT_RGB555,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       }, {
+               .name = "YUV 4:2:0 Planar",
+               .bpp = 2,
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+       }, {
+               .name = "YUV 4:2:2 Planar",
+               .bpp = 2,
+               .fourcc = V4L2_PIX_FMT_YUV422P,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+       },
+};
+
+static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt)
+{
+       u32 pxp_fmt = 0;
+
+       if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24)
+               pxp_fmt = PXP_PIX_FMT_RGB24;
+       else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565)
+               pxp_fmt = PXP_PIX_FMT_RGB565;
+       else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
+               pxp_fmt = PXP_PIX_FMT_RGB555;
+       else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
+               pxp_fmt = PXP_PIX_FMT_RGB555;
+       else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420)
+               pxp_fmt = PXP_PIX_FMT_YUV420P;
+       else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P)
+               pxp_fmt = PXP_PIX_FMT_YUV422P;
+
+       return pxp_fmt;
+}
+struct v4l2_queryctrl pxp_controls[] = {
+       {
+               .id             = V4L2_CID_HFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Horizontal Flip",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+       }, {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Vertical Flip",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+       }, {
+               .id             = V4L2_CID_PRIVATE_BASE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Rotation",
+               .minimum        = 0,
+               .maximum        = 270,
+               .step           = 90,
+               .default_value  = 0,
+               .flags          = 0,
+       }, {
+               .id             = V4L2_CID_PRIVATE_BASE + 1,
+               .name           = "Background Color",
+               .minimum        = 0,
+               .maximum        = 0xFFFFFF,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+       }, {
+               .id             = V4L2_CID_PRIVATE_BASE + 2,
+               .name           = "Set S0 Chromakey",
+               .minimum        = -1,
+               .maximum        = 0xFFFFFF,
+               .step           = 1,
+               .default_value  = -1,
+               .flags          = 0,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+       }, {
+               .id             = V4L2_CID_PRIVATE_BASE + 3,
+               .name           = "YUV Colorspace",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+               .flags          = 0,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+       },
+};
+
+/* callback function */
+static void video_dma_done(void *arg)
+{
+       struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+       struct dma_chan *chan = tx_desc->txd.chan;
+       struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+       struct pxps *pxp = pxp_chan->client;
+       struct videobuf_buffer *vb;
+
+       dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+                       tx_desc->txd.cookie,
+                       pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0);
+
+       spin_lock(&pxp->lock);
+       if (pxp->active) {
+               vb = &pxp->active->vb;
+
+               list_del_init(&vb->queue);
+               vb->state = VIDEOBUF_DONE;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+               wake_up(&vb->done);
+       }
+
+       if (list_empty(&pxp->outq)) {
+               pxp->active = NULL;
+               spin_unlock(&pxp->lock);
+
+               return;
+       }
+
+       pxp->active = list_entry(pxp->outq.next,
+                                    struct pxp_buffer, vb.queue);
+       pxp->active->vb.state = VIDEOBUF_ACTIVE;
+       spin_unlock(&pxp->lock);
+}
+
+static int acquire_dma_channel(struct pxps *pxp)
+{
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct pxp_channel **pchan = &pxp->pxp_channel[0];
+
+       if (*pchan) {
+               struct videobuf_buffer *vb, *_vb;
+               dma_release_channel(&(*pchan)->dma_chan);
+               *pchan = NULL;
+               pxp->active = NULL;
+               list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) {
+                       list_del_init(&vb->queue);
+                       vb->state = VIDEOBUF_ERROR;
+                       wake_up(&vb->done);
+               }
+       }
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       dma_cap_set(DMA_PRIVATE, mask);
+       chan = dma_request_channel(mask, NULL, NULL);
+       if (!chan)
+               return -EBUSY;
+
+       *pchan = to_pxp_channel(chan);
+       (*pchan)->client = pxp;
+
+       return 0;
+}
+
+static int _get_fbinfo(struct fb_info **fbi)
+{
+       int i;
+       for (i = 0; i < num_registered_fb; i++) {
+               char *idstr = registered_fb[i]->fix.id;
+               if (strcmp(idstr, "mxs") == 0) {
+                       *fbi = registered_fb[i];
+                       return 0;
+               }
+       }
+
+       return -ENODEV;
+}
+
+static int pxp_set_fbinfo(struct pxps *pxp)
+{
+       struct v4l2_framebuffer *fb = &pxp->fb;
+       int err;
+
+       err = _get_fbinfo(&pxp->fbi);
+       if (err)
+               return err;
+
+       fb->fmt.width = pxp->fbi->var.xres;
+       fb->fmt.height = pxp->fbi->var.yres;
+       pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres;
+       if (pxp->fbi->var.bits_per_pixel == 16)
+               fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+       else
+               fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24;
+
+       fb->base = (void *)pxp->fbi->fix.smem_start;
+
+       return 0;
+}
+
+static int _get_cur_fb_blank(struct pxps *pxp)
+{
+       struct fb_info *fbi;
+       mm_segment_t old_fs;
+       int err = 0;
+
+       err = _get_fbinfo(&fbi);
+       if (err)
+               return err;
+
+       if (fbi->fbops->fb_ioctl) {
+               old_fs = get_fs();
+               set_fs(KERNEL_DS);
+               err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
+                               (unsigned int)(&pxp->fb_blank));
+               set_fs(old_fs);
+       }
+
+       return err;
+}
+
+static int pxp_show_buf(struct pxps *pxp, bool toshow)
+{
+       struct fb_info *fbi = pxp->fbi;
+       int ret;
+
+       console_lock();
+       fbi->fix.smem_start = toshow ?
+                       pxp->outb_phys : (unsigned long)pxp->fb.base;
+       ret = fb_pan_display(fbi, &fbi->var);
+       console_unlock();
+
+       return ret;
+}
+
+static int set_fb_blank(int blank)
+{
+       struct fb_info *fbi;
+       int err = 0;
+
+       err = _get_fbinfo(&fbi);
+       if (err)
+               return err;
+
+       console_lock();
+       fb_blank(fbi, blank);
+       console_unlock();
+
+       return err;
+}
+
+static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+
+       if (vc->id == V4L2_CID_HFLIP) {
+               pxp->pxp_conf.proc_data.hflip = vc->value;
+       } else if (vc->id == V4L2_CID_VFLIP) {
+               pxp->pxp_conf.proc_data.vflip = vc->value;
+       } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
+               if (vc->value % 90)
+                       return -ERANGE;
+               pxp->pxp_conf.proc_data.rotate = vc->value;
+       } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) {
+               pxp->pxp_conf.proc_data.bgcolor = vc->value;
+       } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) {
+               pxp->pxp_conf.s0_param.color_key = vc->value;
+       } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) {
+               pxp->pxp_conf.proc_data.yuv = vc->value;
+       }
+
+       return 0;
+}
+
+static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+       if (vc->id == V4L2_CID_HFLIP)
+               vc->value = pxp->pxp_conf.proc_data.hflip;
+       else if (vc->id == V4L2_CID_VFLIP)
+               vc->value = pxp->pxp_conf.proc_data.vflip;
+       else if (vc->id == V4L2_CID_PRIVATE_BASE)
+               vc->value = pxp->pxp_conf.proc_data.rotate;
+       else if (vc->id == V4L2_CID_PRIVATE_BASE + 1)
+               vc->value = pxp->pxp_conf.proc_data.bgcolor;
+       else if (vc->id == V4L2_CID_PRIVATE_BASE + 2)
+               vc->value = pxp->pxp_conf.s0_param.color_key;
+       else if (vc->id == V4L2_CID_PRIVATE_BASE + 3)
+               vc->value = pxp->pxp_conf.proc_data.yuv;
+
+       return 0;
+}
+
+static int pxp_enumoutput(struct file *file, void *fh,
+                       struct v4l2_output *o)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       if ((o->index < 0) || (o->index > 1))
+               return -EINVAL;
+
+       memset(o, 0, sizeof(struct v4l2_output));
+       if (o->index == 0) {
+               strcpy(o->name, "PxP Display Output");
+               pxp->output = 0;
+       } else {
+               strcpy(o->name, "PxP Virtual Output");
+               pxp->output = 1;
+       }
+       o->type = V4L2_OUTPUT_TYPE_INTERNAL;
+       o->std = 0;
+       o->reserved[0] = pxp->outb_phys;
+
+       return 0;
+}
+
+static int pxp_g_output(struct file *file, void *fh,
+                       unsigned int *i)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       *i = pxp->output;
+
+       return 0;
+}
+
+static int pxp_s_output(struct file *file, void *fh,
+                       unsigned int i)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct v4l2_pix_format *fmt = &pxp->fb.fmt;
+       int bpp;
+
+       if ((i < 0) || (i > 1))
+               return -EINVAL;
+
+       if (pxp->outb)
+               return 0;
+
+       /* Output buffer is same format as fbdev */
+       if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
+               bpp = 4;
+       else
+               bpp = 2;
+
+       pxp->outb_size = fmt->width * fmt->height * bpp;
+       pxp->outb = kmalloc(fmt->width * fmt->height * bpp,
+                               GFP_KERNEL | GFP_DMA);
+       if (pxp->outb == NULL) {
+               dev_err(&pxp->pdev->dev, "No enough memory!\n");
+               return -ENOMEM;
+       }
+       pxp->outb_phys = virt_to_phys(pxp->outb);
+       dma_map_single(NULL, pxp->outb,
+                       fmt->width * fmt->height * bpp, DMA_TO_DEVICE);
+
+       pxp->pxp_conf.out_param.width = fmt->width;
+       pxp->pxp_conf.out_param.height = fmt->height;
+       if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
+               pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB24;
+       else
+               pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+
+       return 0;
+}
+
+static int pxp_enum_fmt_video_output(struct file *file, void *fh,
+                               struct v4l2_fmtdesc *fmt)
+{
+       enum v4l2_buf_type type = fmt->type;
+       int index = fmt->index;
+
+       if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats)))
+               return -EINVAL;
+
+       memset(fmt, 0, sizeof(struct v4l2_fmtdesc));
+       fmt->index = index;
+       fmt->type = type;
+       fmt->pixelformat = pxp_s0_formats[index].fourcc;
+       strcpy(fmt->description, pxp_s0_formats[index].name);
+
+       return 0;
+}
+
+static int pxp_g_fmt_video_output(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pf = &f->fmt.pix;
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct pxp_data_format *fmt = pxp->s0_fmt;
+
+       pf->width = pxp->pxp_conf.s0_param.width;
+       pf->height = pxp->pxp_conf.s0_param.height;
+       pf->pixelformat = fmt->fourcc;
+       pf->field = V4L2_FIELD_NONE;
+       pf->bytesperline = fmt->bpp * pf->width;
+       pf->sizeimage = pf->bytesperline * pf->height;
+       pf->colorspace = fmt->colorspace;
+       pf->priv = 0;
+
+       return 0;
+}
+
+static struct pxp_data_format *pxp_get_format(struct v4l2_format *f)
+{
+       struct pxp_data_format *fmt;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) {
+               fmt = &pxp_s0_formats[i];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(pxp_s0_formats))
+               return NULL;
+
+       return &pxp_s0_formats[i];
+}
+
+static int pxp_try_fmt_video_output(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       int w = f->fmt.pix.width;
+       int h = f->fmt.pix.height;
+       struct pxp_data_format *fmt = pxp_get_format(f);
+
+       if (!fmt)
+               return -EINVAL;
+
+       w = min(w, 2040);
+       w = max(w, 8);
+       h = min(h, 2040);
+       h = max(h, 8);
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.width = w;
+       f->fmt.pix.height = h;
+       f->fmt.pix.pixelformat = fmt->fourcc;
+
+       return 0;
+}
+
+static int pxp_s_fmt_video_output(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct v4l2_pix_format *pf = &f->fmt.pix;
+       int ret;
+
+       ret = acquire_dma_channel(pxp);
+       if (ret < 0)
+               return ret;
+
+       ret = pxp_try_fmt_video_output(file, fh, f);
+       if (ret == 0) {
+               pxp->s0_fmt = pxp_get_format(f);
+               pxp->pxp_conf.s0_param.pixel_fmt =
+                       v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc);
+               pxp->pxp_conf.s0_param.width = pf->width;
+               pxp->pxp_conf.s0_param.height = pf->height;
+       }
+
+
+       return ret;
+}
+
+static int pxp_g_fmt_output_overlay(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct v4l2_window *wf = &f->fmt.win;
+
+       memset(wf, 0, sizeof(struct v4l2_window));
+       wf->chromakey = pxp->s1_chromakey;
+       wf->global_alpha = pxp->global_alpha;
+       wf->field = V4L2_FIELD_NONE;
+       wf->clips = NULL;
+       wf->clipcount = 0;
+       wf->bitmap = NULL;
+       wf->w.left = pxp->pxp_conf.proc_data.srect.left;
+       wf->w.top = pxp->pxp_conf.proc_data.srect.top;
+       wf->w.width = pxp->pxp_conf.proc_data.srect.width;
+       wf->w.height = pxp->pxp_conf.proc_data.srect.height;
+
+       return 0;
+}
+
+static int pxp_try_fmt_output_overlay(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct v4l2_window *wf = &f->fmt.win;
+       struct v4l2_rect srect;
+       u32 s1_chromakey = wf->chromakey;
+       u8 global_alpha = wf->global_alpha;
+
+       memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect));
+
+       pxp_g_fmt_output_overlay(file, fh, f);
+
+       wf->chromakey = s1_chromakey;
+       wf->global_alpha = global_alpha;
+
+       /* Constrain parameters to the input buffer */
+       wf->w.left = srect.left;
+       wf->w.top = srect.top;
+       wf->w.width = min(srect.width,
+                       ((__s32)pxp->pxp_conf.s0_param.width - wf->w.left));
+       wf->w.height = min(srect.height,
+                       ((__s32)pxp->pxp_conf.s0_param.height - wf->w.top));
+
+       return 0;
+}
+
+static int pxp_s_fmt_output_overlay(struct file *file, void *fh,
+                                       struct v4l2_format *f)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       struct v4l2_window *wf = &f->fmt.win;
+       int ret = pxp_try_fmt_output_overlay(file, fh, f);
+
+       if (ret == 0) {
+               pxp->global_alpha = wf->global_alpha;
+               pxp->s1_chromakey = wf->chromakey;
+               pxp->pxp_conf.proc_data.srect.left = wf->w.left;
+               pxp->pxp_conf.proc_data.srect.top = wf->w.top;
+               pxp->pxp_conf.proc_data.srect.width = wf->w.width;
+               pxp->pxp_conf.proc_data.srect.height = wf->w.height;
+               pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha;
+               pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey;
+               pxp->pxp_conf.ol_param[0].color_key_enable =
+                                       pxp->s1_chromakey_state;
+       }
+
+       return ret;
+}
+
+static int pxp_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *r)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       return videobuf_reqbufs(&pxp->s0_vbq, r);
+}
+
+static int pxp_querybuf(struct file *file, void *priv,
+                       struct v4l2_buffer *b)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       return videobuf_querybuf(&pxp->s0_vbq, b);
+}
+
+static int pxp_qbuf(struct file *file, void *priv,
+                       struct v4l2_buffer *b)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       return videobuf_qbuf(&pxp->s0_vbq, b);
+}
+
+static int pxp_dqbuf(struct file *file, void *priv,
+                       struct v4l2_buffer *b)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int pxp_streamon(struct file *file, void *priv,
+                       enum v4l2_buf_type t)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       int ret = 0;
+
+       if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       _get_cur_fb_blank(pxp);
+       set_fb_blank(FB_BLANK_UNBLANK);
+
+       ret = videobuf_streamon(&pxp->s0_vbq);
+
+       if (!ret && (pxp->output == 0))
+               pxp_show_buf(pxp, true);
+
+       return ret;
+}
+
+static int pxp_streamoff(struct file *file, void *priv,
+                       enum v4l2_buf_type t)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       int ret = 0;
+
+       if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+               return -EINVAL;
+
+       ret = videobuf_streamoff(&pxp->s0_vbq);
+
+       if (!ret)
+               pxp_show_buf(pxp, false);
+
+       if (pxp->fb_blank)
+               set_fb_blank(FB_BLANK_POWERDOWN);
+
+       return ret;
+}
+
+static int pxp_buf_setup(struct videobuf_queue *q,
+                       unsigned int *count, unsigned *size)
+{
+       struct pxps *pxp = q->priv_data;
+
+       *size = pxp->pxp_conf.s0_param.width *
+               pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp;
+
+       if (0 == *count)
+               *count = PXP_DEF_BUFS;
+
+       return 0;
+}
+
+static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf)
+{
+       struct videobuf_buffer *vb = &buf->vb;
+       struct dma_async_tx_descriptor *txd = buf->txd;
+
+       BUG_ON(in_interrupt());
+
+       pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+               vb, vb->baddr, vb->bsize);
+
+       /*
+        * This waits until this buffer is out of danger, i.e., until it is no
+        * longer in STATE_QUEUED or STATE_ACTIVE
+        */
+       videobuf_waiton(q, vb, 0, 0);
+       if (txd)
+               async_tx_ack(txd);
+
+       videobuf_dma_contig_free(q, vb);
+       buf->txd = NULL;
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxp_buf_prepare(struct videobuf_queue *q,
+                       struct videobuf_buffer *vb,
+                       enum v4l2_field field)
+{
+       struct pxps *pxp = q->priv_data;
+       struct pxp_config_data *pxp_conf = &pxp->pxp_conf;
+       struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+       struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+       struct pxp_tx_desc *desc;
+       int ret = 0;
+       int i, length;
+
+       vb->width = pxp->pxp_conf.s0_param.width;
+       vb->height = pxp->pxp_conf.s0_param.height;
+       vb->size = vb->width * vb->height * pxp->s0_fmt->bpp;
+       vb->field = V4L2_FIELD_NONE;
+       if (vb->state != VIDEOBUF_NEEDS_INIT)
+               pxp_buf_free(q, buf);
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               struct pxp_channel *pchan = pxp->pxp_channel[0];
+               struct scatterlist *sg = &buf->sg[0];
+
+               /* This actually (allocates and) maps buffers */
+               ret = videobuf_iolock(q, vb, NULL);
+               if (ret) {
+                       pr_err("fail to call videobuf_iolock, ret = %d\n", ret);
+                       goto fail;
+               }
+
+               /*
+                * sg[0] for input(S0)
+                * Sg[1] for output
+                */
+               sg_init_table(sg, 3);
+
+               buf->txd = pchan->dma_chan.device->device_prep_slave_sg(
+                       &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE,
+                       DMA_PREP_INTERRUPT, NULL);
+               if (!buf->txd) {
+                       ret = -EIO;
+                       goto fail;
+               }
+
+               buf->txd->callback_param        = buf->txd;
+               buf->txd->callback              = video_dma_done;
+
+               desc = to_tx_desc(buf->txd);
+               length = desc->len;
+               for (i = 0; i < length; i++) {
+                       if (i == 0) {/* S0 */
+                               memcpy(&desc->proc_data, proc_data,
+                                       sizeof(struct pxp_proc_data));
+                               pxp_conf->s0_param.paddr =
+                                               videobuf_to_dma_contig(vb);
+                               memcpy(&desc->layer_param.s0_param,
+                                       &pxp_conf->s0_param,
+                                       sizeof(struct pxp_layer_param));
+                       } else if (i == 1) { /* Output */
+                               if (proc_data->rotate % 180) {
+                                       pxp_conf->out_param.width =
+                                               pxp->fb.fmt.height;
+                                       pxp_conf->out_param.height =
+                                               pxp->fb.fmt.width;
+                               } else {
+                                       pxp_conf->out_param.width =
+                                               pxp->fb.fmt.width;
+                                       pxp_conf->out_param.height =
+                                               pxp->fb.fmt.height;
+                               }
+
+                               pxp_conf->out_param.paddr = pxp->outb_phys;
+                               memcpy(&desc->layer_param.out_param,
+                                       &pxp_conf->out_param,
+                                       sizeof(struct pxp_layer_param));
+                       } else if (pxp_conf->ol_param[0].combine_enable) {
+                               /* Overlay */
+                               pxp_conf->ol_param[0].paddr =
+                                               (dma_addr_t)pxp->fb.base;
+                               pxp_conf->ol_param[0].width = pxp->fb.fmt.width;
+                               pxp_conf->ol_param[0].height =
+                                               pxp->fb.fmt.height;
+                               pxp_conf->ol_param[0].pixel_fmt =
+                                               pxp_conf->out_param.pixel_fmt;
+                               memcpy(&desc->layer_param.ol_param,
+                                      &pxp_conf->ol_param[0],
+                                      sizeof(struct pxp_layer_param));
+                       }
+
+                       desc = desc->next;
+               }
+
+               vb->state = VIDEOBUF_PREPARED;
+       }
+
+       return 0;
+
+fail:
+       pxp_buf_free(q, buf);
+       return ret;
+}
+
+
+static void pxp_buf_queue(struct videobuf_queue *q,
+                       struct videobuf_buffer *vb)
+{
+       struct pxps *pxp = q->priv_data;
+       struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+       struct dma_async_tx_descriptor *txd = buf->txd;
+       struct pxp_channel *pchan = pxp->pxp_channel[0];
+       dma_cookie_t cookie;
+
+       BUG_ON(!irqs_disabled());
+
+       list_add_tail(&vb->queue, &pxp->outq);
+
+       if (!pxp->active) {
+               pxp->active = buf;
+               vb->state = VIDEOBUF_ACTIVE;
+       } else {
+               vb->state = VIDEOBUF_QUEUED;
+       }
+
+       spin_unlock_irq(&pxp->lock);
+
+       cookie = txd->tx_submit(txd);
+       dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n",
+                               cookie, sg_dma_address(&buf->sg[0]));
+       mdelay(5);
+       /* trigger ePxP */
+       dma_async_issue_pending(&pchan->dma_chan);
+
+       spin_lock_irq(&pxp->lock);
+
+       if (cookie >= 0)
+               return;
+
+       /* Submit error */
+       pr_err("%s: Submit error\n", __func__);
+       vb->state = VIDEOBUF_PREPARED;
+
+       list_del_init(&vb->queue);
+
+       if (pxp->active == buf)
+               pxp->active = NULL;
+}
+
+static void pxp_buf_release(struct videobuf_queue *q,
+                       struct videobuf_buffer *vb)
+{
+       struct pxps *pxp = q->priv_data;
+       struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pxp->lock, flags);
+       if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+           !list_empty(&vb->queue)) {
+               vb->state = VIDEOBUF_ERROR;
+
+               list_del_init(&vb->queue);
+               if (pxp->active == buf)
+                       pxp->active = NULL;
+       }
+       spin_unlock_irqrestore(&pxp->lock, flags);
+
+       pxp_buf_free(q, buf);
+}
+
+static struct videobuf_queue_ops pxp_vbq_ops = {
+       .buf_setup      = pxp_buf_setup,
+       .buf_prepare    = pxp_buf_prepare,
+       .buf_queue      = pxp_buf_queue,
+       .buf_release    = pxp_buf_release,
+};
+
+static int pxp_querycap(struct file *file, void *fh,
+                       struct v4l2_capability *cap)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       memset(cap, 0, sizeof(*cap));
+       strcpy(cap->driver, "pxp");
+       strcpy(cap->card, "pxp");
+       strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev),
+               sizeof(cap->bus_info));
+
+       cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR;
+
+       cap->capabilities = V4L2_CAP_VIDEO_OUTPUT |
+                               V4L2_CAP_VIDEO_OUTPUT_OVERLAY |
+                               V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int pxp_g_fbuf(struct file *file, void *priv,
+                       struct v4l2_framebuffer *fb)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       memset(fb, 0, sizeof(*fb));
+
+       fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+                        V4L2_FBUF_CAP_CHROMAKEY |
+                        V4L2_FBUF_CAP_LOCAL_ALPHA |
+                        V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+       if (pxp->global_alpha_state)
+               fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+       if (pxp->s1_chromakey_state)
+               fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+       return 0;
+}
+
+static int pxp_s_fbuf(struct file *file, void *priv,
+                       const struct v4l2_framebuffer *fb)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       pxp->overlay_state =
+               (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+       pxp->global_alpha_state =
+               (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+       pxp->s1_chromakey_state =
+               (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+
+       pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state;
+       pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state;
+
+       return 0;
+}
+
+static int pxp_g_crop(struct file *file, void *fh,
+                       struct v4l2_crop *c)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+               return -EINVAL;
+
+       c->c.left = pxp->pxp_conf.proc_data.drect.left;
+       c->c.top = pxp->pxp_conf.proc_data.drect.top;
+       c->c.width = pxp->pxp_conf.proc_data.drect.width;
+       c->c.height = pxp->pxp_conf.proc_data.drect.height;
+
+       return 0;
+}
+
+static int pxp_s_crop(struct file *file, void *fh,
+                       const struct v4l2_crop *c)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       int l = c->c.left;
+       int t = c->c.top;
+       int w = c->c.width;
+       int h = c->c.height;
+       int fbw = pxp->fb.fmt.width;
+       int fbh = pxp->fb.fmt.height;
+
+       if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+               return -EINVAL;
+
+       /* Constrain parameters to FB limits */
+       w = min(w, fbw);
+       w = max(w, PXP_MIN_PIX);
+       h = min(h, fbh);
+       h = max(h, PXP_MIN_PIX);
+       if ((l + w) > fbw)
+               l = 0;
+       if ((t + h) > fbh)
+               t = 0;
+
+       /* Round up values to PxP pixel block */
+       l = roundup(l, PXP_MIN_PIX);
+       t = roundup(t, PXP_MIN_PIX);
+       w = roundup(w, PXP_MIN_PIX);
+       h = roundup(h, PXP_MIN_PIX);
+
+       pxp->pxp_conf.proc_data.drect.left = l;
+       pxp->pxp_conf.proc_data.drect.top = t;
+       pxp->pxp_conf.proc_data.drect.width = w;
+       pxp->pxp_conf.proc_data.drect.height = h;
+
+       return 0;
+}
+
+static int pxp_queryctrl(struct file *file, void *priv,
+                        struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+               if (qc->id && qc->id == pxp_controls[i].id) {
+                       memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int pxp_g_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *vc)
+{
+       int i;
+
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+               if (vc->id == pxp_controls[i].id)
+                       return pxp_get_cstate(pxp, vc);
+
+       return -EINVAL;
+}
+
+static int pxp_s_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *vc)
+{
+       int i;
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+               if (vc->id == pxp_controls[i].id) {
+                       if (vc->value < pxp_controls[i].minimum ||
+                           vc->value > pxp_controls[i].maximum)
+                               return -ERANGE;
+                       return pxp_set_cstate(pxp, vc);
+               }
+
+       return -EINVAL;
+}
+
+void pxp_release(struct video_device *vfd)
+{
+       struct pxps *pxp = video_get_drvdata(vfd);
+
+       spin_lock(&pxp->lock);
+       video_device_release(vfd);
+       spin_unlock(&pxp->lock);
+}
+
+static int pxp_open(struct file *file)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       int ret = 0;
+
+       mutex_lock(&pxp->mutex);
+       pxp->users++;
+
+       if (pxp->users > 1) {
+               pxp->users--;
+               ret = -EBUSY;
+               goto out;
+       }
+out:
+       mutex_unlock(&pxp->mutex);
+       if (ret)
+               return ret;
+
+       videobuf_queue_dma_contig_init(&pxp->s0_vbq,
+                               &pxp_vbq_ops,
+                               &pxp->pdev->dev,
+                               &pxp->lock,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT,
+                               V4L2_FIELD_NONE,
+                               sizeof(struct pxp_buffer),
+                               pxp,
+                               NULL);
+       dev_dbg(&pxp->pdev->dev, "call pxp_open\n");
+
+       return 0;
+}
+
+static int pxp_close(struct file *file)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+       videobuf_stop(&pxp->s0_vbq);
+       videobuf_mmap_free(&pxp->s0_vbq);
+       pxp->active = NULL;
+       kfree(pxp->outb);
+       pxp->outb = NULL;
+
+       mutex_lock(&pxp->mutex);
+       pxp->users--;
+       mutex_unlock(&pxp->mutex);
+
+       return 0;
+}
+
+static int pxp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct pxps *pxp = video_get_drvdata(video_devdata(file));
+       int ret;
+
+       ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma);
+
+       return ret;
+}
+
+static const struct v4l2_file_operations pxp_fops = {
+       .owner          = THIS_MODULE,
+       .open           = pxp_open,
+       .release        = pxp_close,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = pxp_mmap,
+};
+
+static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
+       .vidioc_querycap                = pxp_querycap,
+
+       .vidioc_reqbufs                 = pxp_reqbufs,
+       .vidioc_querybuf                = pxp_querybuf,
+       .vidioc_qbuf                    = pxp_qbuf,
+       .vidioc_dqbuf                   = pxp_dqbuf,
+
+       .vidioc_streamon                = pxp_streamon,
+       .vidioc_streamoff               = pxp_streamoff,
+
+       .vidioc_enum_output             = pxp_enumoutput,
+       .vidioc_g_output                = pxp_g_output,
+       .vidioc_s_output                = pxp_s_output,
+
+       .vidioc_enum_fmt_vid_out        = pxp_enum_fmt_video_output,
+       .vidioc_try_fmt_vid_out         = pxp_try_fmt_video_output,
+       .vidioc_g_fmt_vid_out           = pxp_g_fmt_video_output,
+       .vidioc_s_fmt_vid_out           = pxp_s_fmt_video_output,
+
+       .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay,
+       .vidioc_g_fmt_vid_out_overlay   = pxp_g_fmt_output_overlay,
+       .vidioc_s_fmt_vid_out_overlay   = pxp_s_fmt_output_overlay,
+
+       .vidioc_g_fbuf                  = pxp_g_fbuf,
+       .vidioc_s_fbuf                  = pxp_s_fbuf,
+
+       .vidioc_g_crop                  = pxp_g_crop,
+       .vidioc_s_crop                  = pxp_s_crop,
+
+       .vidioc_queryctrl               = pxp_queryctrl,
+       .vidioc_g_ctrl                  = pxp_g_ctrl,
+       .vidioc_s_ctrl                  = pxp_s_ctrl,
+};
+
+static const struct video_device pxp_template = {
+       .name                           = "PxP",
+       .vfl_type                       = V4L2_CAP_VIDEO_OUTPUT |
+                                               V4L2_CAP_VIDEO_OVERLAY |
+                                               V4L2_CAP_STREAMING,
+       .vfl_dir                        = VFL_DIR_TX,
+       .fops                           = &pxp_fops,
+       .release                        = pxp_release,
+       .minor                          = -1,
+       .ioctl_ops                      = &pxp_ioctl_ops,
+};
+
+static const struct of_device_id imx_pxpv4l2_dt_ids[] = {
+       { .compatible = "fsl,imx6sl-pxp-v4l2", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids);
+
+static int pxp_probe(struct platform_device *pdev)
+{
+       struct pxps *pxp;
+       int err = 0;
+
+       pxp = kzalloc(sizeof(*pxp), GFP_KERNEL);
+       if (!pxp) {
+               dev_err(&pdev->dev, "failed to allocate control object\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       dev_set_drvdata(&pdev->dev, pxp);
+
+       INIT_LIST_HEAD(&pxp->outq);
+       spin_lock_init(&pxp->lock);
+       mutex_init(&pxp->mutex);
+
+       pxp->pdev = pdev;
+
+       pxp->vdev = video_device_alloc();
+       if (!pxp->vdev) {
+               dev_err(&pdev->dev, "video_device_alloc() failed\n");
+               err = -ENOMEM;
+               goto freeirq;
+       }
+
+       memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template));
+       video_set_drvdata(pxp->vdev, pxp);
+
+       err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register video device\n");
+               goto freevdev;
+       }
+
+       err = pxp_set_fbinfo(pxp);
+       if (err) {
+               dev_err(&pdev->dev, "failed to call pxp_set_fbinfo\n");
+               goto freevdev;
+       }
+
+       dev_info(&pdev->dev, "initialized\n");
+
+exit:
+       return err;
+
+freevdev:
+       video_device_release(pxp->vdev);
+
+freeirq:
+       kfree(pxp);
+
+       return err;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+       struct pxps *pxp = platform_get_drvdata(pdev);
+
+       video_unregister_device(pxp->vdev);
+       video_device_release(pxp->vdev);
+
+       kfree(pxp);
+
+       return 0;
+}
+
+static struct platform_driver pxp_driver = {
+       .driver         = {
+               .name   = PXP_DRIVER_NAME,
+               .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids),
+       },
+       .probe          = pxp_probe,
+       .remove         = pxp_remove,
+};
+
+module_platform_driver(pxp_driver);
+
+module_param(video_nr, int, 0444);
+MODULE_DESCRIPTION("MXC PxP V4L2 driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h
new file mode 100644 (file)
index 0000000..f1d3da7
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#ifndef        _MXC_PXP_V4L2_H
+#define        _MXC_PXP_V4L2_H
+
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+
+struct pxp_buffer {
+       /* Must be first! */
+       struct videobuf_buffer vb;
+
+       /* One descriptor per scatterlist (per frame) */
+       struct dma_async_tx_descriptor          *txd;
+
+       struct scatterlist                      sg[3];
+};
+
+struct pxps {
+       struct platform_device *pdev;
+
+       spinlock_t lock;
+       struct mutex mutex;
+       int users;
+
+       struct video_device *vdev;
+
+       struct videobuf_queue s0_vbq;
+       struct pxp_buffer *active;
+       struct list_head outq;
+       struct pxp_channel      *pxp_channel[1];        /* We need 1 channel */
+       struct pxp_config_data pxp_conf;
+
+       int output;
+       u32 *outb;
+       dma_addr_t outb_phys;
+       u32 outb_size;
+
+       /* Current S0 configuration */
+       struct pxp_data_format *s0_fmt;
+
+       struct fb_info *fbi;
+       struct v4l2_framebuffer fb;
+
+       /* Output overlay support */
+       int overlay_state;
+       int global_alpha_state;
+       u8  global_alpha;
+       int s1_chromakey_state;
+       u32 s1_chromakey;
+
+       int fb_blank;
+};
+
+struct pxp_data_format {
+       char *name;
+       unsigned int bpp;
+       u32 fourcc;
+       enum v4l2_colorspace colorspace;
+};
+
+#endif