2 * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Based on STMP378X PxP driver
21 * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
24 #include <linux/dma-mapping.h>
26 #include <linux/init.h>
27 #include <linux/interrupt.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/mutex.h>
32 #include <linux/platform_device.h>
33 #include <linux/vmalloc.h>
34 #include <linux/videodev2.h>
35 #include <linux/dmaengine.h>
36 #include <linux/pxp_dma.h>
37 #include <linux/delay.h>
38 #include <linux/console.h>
39 #include <linux/mxcfb.h>
41 #include <media/videobuf-dma-contig.h>
42 #include <media/v4l2-common.h>
43 #include <media/v4l2-dev.h>
44 #include <media/v4l2-ioctl.h>
46 #include "mxc_pxp_v4l2.h"
48 #define PXP_DRIVER_NAME "pxp-v4l2"
49 #define PXP_DRIVER_MAJOR 2
50 #define PXP_DRIVER_MINOR 0
52 #define PXP_DEF_BUFS 2
55 #define V4L2_OUTPUT_TYPE_INTERNAL 4
57 static int video_nr = -1; /* -1 ==> auto assign */
58 static struct pxp_data_format pxp_s0_formats[] = {
62 .fourcc = V4L2_PIX_FMT_RGB24,
63 .colorspace = V4L2_COLORSPACE_SRGB,
65 .name = "16-bit RGB 5:6:5",
67 .fourcc = V4L2_PIX_FMT_RGB565,
68 .colorspace = V4L2_COLORSPACE_SRGB,
70 .name = "16-bit RGB 5:5:5",
72 .fourcc = V4L2_PIX_FMT_RGB555,
73 .colorspace = V4L2_COLORSPACE_SRGB,
75 .name = "YUV 4:2:0 Planar",
77 .fourcc = V4L2_PIX_FMT_YUV420,
78 .colorspace = V4L2_COLORSPACE_JPEG,
80 .name = "YUV 4:2:2 Planar",
82 .fourcc = V4L2_PIX_FMT_YUV422P,
83 .colorspace = V4L2_COLORSPACE_JPEG,
87 .fourcc = V4L2_PIX_FMT_UYVY,
88 .colorspace = V4L2_COLORSPACE_JPEG,
92 static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt)
96 if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24)
97 pxp_fmt = PXP_PIX_FMT_RGB24;
98 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565)
99 pxp_fmt = PXP_PIX_FMT_RGB565;
100 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
101 pxp_fmt = PXP_PIX_FMT_RGB555;
102 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
103 pxp_fmt = PXP_PIX_FMT_RGB555;
104 else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420)
105 pxp_fmt = PXP_PIX_FMT_YUV420P;
106 else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P)
107 pxp_fmt = PXP_PIX_FMT_YUV422P;
108 else if (v4l2_pix_fmt == V4L2_PIX_FMT_UYVY)
109 pxp_fmt = PXP_PIX_FMT_UYVY;
113 struct v4l2_queryctrl pxp_controls[] = {
115 .id = V4L2_CID_HFLIP,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "Horizontal Flip",
124 .id = V4L2_CID_VFLIP,
125 .type = V4L2_CTRL_TYPE_BOOLEAN,
126 .name = "Vertical Flip",
133 .id = V4L2_CID_PRIVATE_BASE,
134 .type = V4L2_CTRL_TYPE_INTEGER,
142 .id = V4L2_CID_PRIVATE_BASE + 1,
143 .name = "Background Color",
149 .type = V4L2_CTRL_TYPE_INTEGER,
151 .id = V4L2_CID_PRIVATE_BASE + 2,
152 .name = "Set S0 Chromakey",
158 .type = V4L2_CTRL_TYPE_INTEGER,
160 .id = V4L2_CID_PRIVATE_BASE + 3,
161 .name = "YUV Colorspace",
167 .type = V4L2_CTRL_TYPE_BOOLEAN,
171 static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf)
173 dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr);
174 dev_dbg(&pxp->pdev->dev,
175 "free dma size:0x%x, paddr:0x%x\n",
176 buf->size, buf->paddr);
177 memset(buf, 0, sizeof(*buf));
180 static int alloc_dma_buf(struct pxps *pxp, struct dma_mem *buf)
183 buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr,
184 GFP_DMA | GFP_KERNEL);
186 dev_err(&pxp->pdev->dev,
187 "cannot get dma buf size:0x%x\n", buf->size);
190 dev_dbg(&pxp->pdev->dev,
191 "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr);
195 /* callback function */
196 static void video_dma_done(void *arg)
198 struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
199 struct dma_chan *chan = tx_desc->txd.chan;
200 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
201 struct pxps *pxp = pxp_chan->client;
202 struct videobuf_buffer *vb;
204 dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
206 pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0);
208 spin_lock(&pxp->lock);
210 vb = &pxp->active->vb;
212 list_del_init(&vb->queue);
213 vb->state = VIDEOBUF_DONE;
214 do_gettimeofday(&vb->ts);
219 if (list_empty(&pxp->outq)) {
221 spin_unlock(&pxp->lock);
226 pxp->active = list_entry(pxp->outq.next,
227 struct pxp_buffer, vb.queue);
228 pxp->active->vb.state = VIDEOBUF_ACTIVE;
229 spin_unlock(&pxp->lock);
232 static int acquire_dma_channel(struct pxps *pxp)
235 struct dma_chan *chan;
236 struct pxp_channel **pchan = &pxp->pxp_channel[0];
239 struct videobuf_buffer *vb, *_vb;
240 dma_release_channel(&(*pchan)->dma_chan);
243 list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) {
244 list_del_init(&vb->queue);
245 vb->state = VIDEOBUF_ERROR;
251 dma_cap_set(DMA_SLAVE, mask);
252 dma_cap_set(DMA_PRIVATE, mask);
253 chan = dma_request_channel(mask, NULL, NULL);
257 *pchan = to_pxp_channel(chan);
258 (*pchan)->client = pxp;
263 static int _get_fbinfo(struct fb_info **fbi)
266 for (i = 0; i < num_registered_fb; i++) {
267 char *idstr = registered_fb[i]->fix.id;
268 if (strcmp(idstr, "mxs") == 0) {
269 *fbi = registered_fb[i];
277 static int pxp_set_fbinfo(struct pxps *pxp)
279 struct v4l2_framebuffer *fb = &pxp->fb;
282 err = _get_fbinfo(&pxp->fbi);
286 fb->fmt.width = pxp->fbi->var.xres;
287 fb->fmt.height = pxp->fbi->var.yres;
288 pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres;
289 if (pxp->fbi->var.bits_per_pixel == 16)
290 fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
292 fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24;
294 fb->base = (void *)pxp->fbi->fix.smem_start;
299 static int _get_cur_fb_blank(struct pxps *pxp)
305 err = _get_fbinfo(&fbi);
309 if (fbi->fbops->fb_ioctl) {
312 err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
313 (unsigned int)(&pxp->fb_blank));
320 static int pxp_show_buf(struct pxps *pxp, unsigned long paddr)
322 struct fb_info *fbi = pxp->fbi;
326 dev_err(&pxp->pdev->dev, "Invalid paddr\n");
331 fbi->fix.smem_start = paddr;
332 ret = fb_pan_display(fbi, &fbi->var);
338 static int set_fb_blank(int blank)
343 err = _get_fbinfo(&fbi);
348 fb_blank(fbi, blank);
354 static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc)
357 if (vc->id == V4L2_CID_HFLIP) {
358 pxp->pxp_conf.proc_data.hflip = vc->value;
359 } else if (vc->id == V4L2_CID_VFLIP) {
360 pxp->pxp_conf.proc_data.vflip = vc->value;
361 } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
364 pxp->pxp_conf.proc_data.rotate = vc->value;
365 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) {
366 pxp->pxp_conf.proc_data.bgcolor = vc->value;
367 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) {
368 pxp->pxp_conf.s0_param.color_key = vc->value;
369 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) {
370 pxp->pxp_conf.proc_data.yuv = vc->value;
376 static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc)
378 if (vc->id == V4L2_CID_HFLIP)
379 vc->value = pxp->pxp_conf.proc_data.hflip;
380 else if (vc->id == V4L2_CID_VFLIP)
381 vc->value = pxp->pxp_conf.proc_data.vflip;
382 else if (vc->id == V4L2_CID_PRIVATE_BASE)
383 vc->value = pxp->pxp_conf.proc_data.rotate;
384 else if (vc->id == V4L2_CID_PRIVATE_BASE + 1)
385 vc->value = pxp->pxp_conf.proc_data.bgcolor;
386 else if (vc->id == V4L2_CID_PRIVATE_BASE + 2)
387 vc->value = pxp->pxp_conf.s0_param.color_key;
388 else if (vc->id == V4L2_CID_PRIVATE_BASE + 3)
389 vc->value = pxp->pxp_conf.proc_data.yuv;
394 static int pxp_enumoutput(struct file *file, void *fh,
395 struct v4l2_output *o)
397 struct pxps *pxp = video_get_drvdata(video_devdata(file));
399 if ((o->index < 0) || (o->index > 1))
402 memset(o, 0, sizeof(struct v4l2_output));
404 strcpy(o->name, "PxP Display Output");
407 strcpy(o->name, "PxP Virtual Output");
410 o->type = V4L2_OUTPUT_TYPE_INTERNAL;
412 o->reserved[0] = pxp->outbuf.paddr;
417 static int pxp_g_output(struct file *file, void *fh,
420 struct pxps *pxp = video_get_drvdata(video_devdata(file));
427 static int pxp_s_output(struct file *file, void *fh,
430 struct pxps *pxp = video_get_drvdata(video_devdata(file));
431 struct v4l2_pix_format *fmt = &pxp->fb.fmt;
435 if ((i < 0) || (i > 1))
438 /* Output buffer is same format as fbdev */
439 if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
444 size = fmt->width * fmt->height * bpp;
445 if (size > pxp->outbuf.size) {
446 if (pxp->outbuf.vaddr)
447 free_dma_buf(pxp, &pxp->outbuf);
448 pxp->outbuf.size = size;
449 ret = alloc_dma_buf(pxp, &pxp->outbuf);
454 pxp->pxp_conf.out_param.width = fmt->width;
455 pxp->pxp_conf.out_param.height = fmt->height;
456 if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
457 pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB24;
459 pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
464 static int pxp_enum_fmt_video_output(struct file *file, void *fh,
465 struct v4l2_fmtdesc *fmt)
467 enum v4l2_buf_type type = fmt->type;
468 int index = fmt->index;
470 if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats)))
473 memset(fmt, 0, sizeof(struct v4l2_fmtdesc));
476 fmt->pixelformat = pxp_s0_formats[index].fourcc;
477 strcpy(fmt->description, pxp_s0_formats[index].name);
482 static int pxp_g_fmt_video_output(struct file *file, void *fh,
483 struct v4l2_format *f)
485 struct v4l2_pix_format *pf = &f->fmt.pix;
486 struct pxps *pxp = video_get_drvdata(video_devdata(file));
487 struct pxp_data_format *fmt = pxp->s0_fmt;
489 pf->width = pxp->pxp_conf.s0_param.width;
490 pf->height = pxp->pxp_conf.s0_param.height;
491 pf->pixelformat = fmt->fourcc;
492 pf->field = V4L2_FIELD_NONE;
493 pf->bytesperline = fmt->bpp * pf->width;
494 pf->sizeimage = pf->bytesperline * pf->height;
495 pf->colorspace = fmt->colorspace;
501 static struct pxp_data_format *pxp_get_format(struct v4l2_format *f)
503 struct pxp_data_format *fmt;
506 for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) {
507 fmt = &pxp_s0_formats[i];
508 if (fmt->fourcc == f->fmt.pix.pixelformat)
512 if (i == ARRAY_SIZE(pxp_s0_formats))
515 return &pxp_s0_formats[i];
518 static int pxp_try_fmt_video_output(struct file *file, void *fh,
519 struct v4l2_format *f)
521 int w = f->fmt.pix.width;
522 int h = f->fmt.pix.height;
523 struct pxp_data_format *fmt = pxp_get_format(f);
532 f->fmt.pix.field = V4L2_FIELD_NONE;
533 f->fmt.pix.width = w;
534 f->fmt.pix.height = h;
535 f->fmt.pix.pixelformat = fmt->fourcc;
540 static int pxp_s_fmt_video_output(struct file *file, void *fh,
541 struct v4l2_format *f)
543 struct pxps *pxp = video_get_drvdata(video_devdata(file));
544 struct v4l2_pix_format *pf = &f->fmt.pix;
547 ret = acquire_dma_channel(pxp);
551 ret = pxp_try_fmt_video_output(file, fh, f);
553 pxp->s0_fmt = pxp_get_format(f);
554 pxp->pxp_conf.s0_param.pixel_fmt =
555 v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc);
556 pxp->pxp_conf.s0_param.width = pf->width;
557 pxp->pxp_conf.s0_param.height = pf->height;
564 static int pxp_g_fmt_output_overlay(struct file *file, void *fh,
565 struct v4l2_format *f)
567 struct pxps *pxp = video_get_drvdata(video_devdata(file));
568 struct v4l2_window *wf = &f->fmt.win;
570 memset(wf, 0, sizeof(struct v4l2_window));
571 wf->chromakey = pxp->s1_chromakey;
572 wf->global_alpha = pxp->global_alpha;
573 wf->field = V4L2_FIELD_NONE;
577 wf->w.left = pxp->pxp_conf.proc_data.srect.left;
578 wf->w.top = pxp->pxp_conf.proc_data.srect.top;
579 wf->w.width = pxp->pxp_conf.proc_data.srect.width;
580 wf->w.height = pxp->pxp_conf.proc_data.srect.height;
585 static int pxp_try_fmt_output_overlay(struct file *file, void *fh,
586 struct v4l2_format *f)
588 struct pxps *pxp = video_get_drvdata(video_devdata(file));
589 struct v4l2_window *wf = &f->fmt.win;
590 struct v4l2_rect srect;
591 u32 s1_chromakey = wf->chromakey;
592 u8 global_alpha = wf->global_alpha;
594 memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect));
596 pxp_g_fmt_output_overlay(file, fh, f);
598 wf->chromakey = s1_chromakey;
599 wf->global_alpha = global_alpha;
601 /* Constrain parameters to the input buffer */
602 wf->w.left = srect.left;
603 wf->w.top = srect.top;
604 wf->w.width = min(srect.width,
605 ((__u32)pxp->pxp_conf.s0_param.width - wf->w.left));
606 wf->w.height = min(srect.height,
607 ((__u32)pxp->pxp_conf.s0_param.height - wf->w.top));
612 static int pxp_s_fmt_output_overlay(struct file *file, void *fh,
613 struct v4l2_format *f)
615 struct pxps *pxp = video_get_drvdata(video_devdata(file));
616 struct v4l2_window *wf = &f->fmt.win;
617 int ret = pxp_try_fmt_output_overlay(file, fh, f);
620 pxp->global_alpha = wf->global_alpha;
621 pxp->s1_chromakey = wf->chromakey;
622 pxp->pxp_conf.proc_data.srect.left = wf->w.left;
623 pxp->pxp_conf.proc_data.srect.top = wf->w.top;
624 pxp->pxp_conf.proc_data.srect.width = wf->w.width;
625 pxp->pxp_conf.proc_data.srect.height = wf->w.height;
626 pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha;
627 pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey;
628 pxp->pxp_conf.ol_param[0].color_key_enable =
629 pxp->s1_chromakey_state;
635 static int pxp_reqbufs(struct file *file, void *priv,
636 struct v4l2_requestbuffers *r)
638 struct pxps *pxp = video_get_drvdata(video_devdata(file));
640 return videobuf_reqbufs(&pxp->s0_vbq, r);
643 static int pxp_querybuf(struct file *file, void *priv,
644 struct v4l2_buffer *b)
646 struct pxps *pxp = video_get_drvdata(video_devdata(file));
648 return videobuf_querybuf(&pxp->s0_vbq, b);
651 static int pxp_qbuf(struct file *file, void *priv,
652 struct v4l2_buffer *b)
654 struct pxps *pxp = video_get_drvdata(video_devdata(file));
656 return videobuf_qbuf(&pxp->s0_vbq, b);
659 static int pxp_dqbuf(struct file *file, void *priv,
660 struct v4l2_buffer *b)
662 struct pxps *pxp = video_get_drvdata(video_devdata(file));
664 return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK);
667 static int pxp_streamon(struct file *file, void *priv,
668 enum v4l2_buf_type t)
670 struct pxps *pxp = video_get_drvdata(video_devdata(file));
673 if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT)
676 _get_cur_fb_blank(pxp);
677 set_fb_blank(FB_BLANK_UNBLANK);
679 ret = videobuf_streamon(&pxp->s0_vbq);
681 if (!ret && (pxp->output == 0))
682 pxp_show_buf(pxp, pxp->outbuf.paddr);
687 static int pxp_streamoff(struct file *file, void *priv,
688 enum v4l2_buf_type t)
690 struct pxps *pxp = video_get_drvdata(video_devdata(file));
693 if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
696 ret = videobuf_streamoff(&pxp->s0_vbq);
698 pxp_show_buf(pxp, (unsigned long)pxp->fb.base);
701 set_fb_blank(FB_BLANK_POWERDOWN);
706 static int pxp_buf_setup(struct videobuf_queue *q,
707 unsigned int *count, unsigned *size)
709 struct pxps *pxp = q->priv_data;
711 *size = pxp->pxp_conf.s0_param.width *
712 pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp;
715 *count = PXP_DEF_BUFS;
720 static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf)
722 struct videobuf_buffer *vb = &buf->vb;
724 BUG_ON(in_interrupt());
726 pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__,
727 vb, vb->baddr, vb->bsize);
730 * This waits until this buffer is out of danger, i.e., until it is no
731 * longer in STATE_QUEUED or STATE_ACTIVE
733 videobuf_waiton(q, vb, 0, 0);
735 videobuf_dma_contig_free(q, vb);
738 vb->state = VIDEOBUF_NEEDS_INIT;
741 static int pxp_buf_prepare(struct videobuf_queue *q,
742 struct videobuf_buffer *vb,
743 enum v4l2_field field)
745 struct pxps *pxp = q->priv_data;
746 struct pxp_config_data *pxp_conf = &pxp->pxp_conf;
747 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
748 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
749 struct pxp_tx_desc *desc;
753 if (!pxp->outbuf.paddr) {
754 dev_err(&pxp->pdev->dev, "Not allocate memory for "
755 "PxP Out buffer?\n");
759 vb->width = pxp->pxp_conf.s0_param.width;
760 vb->height = pxp->pxp_conf.s0_param.height;
761 vb->size = vb->width * vb->height * pxp->s0_fmt->bpp;
762 vb->field = V4L2_FIELD_NONE;
763 if (vb->state != VIDEOBUF_NEEDS_INIT)
764 pxp_buf_free(q, buf);
766 if (vb->state == VIDEOBUF_NEEDS_INIT) {
767 struct pxp_channel *pchan = pxp->pxp_channel[0];
768 struct scatterlist *sg = &buf->sg[0];
770 /* This actually (allocates and) maps buffers */
771 ret = videobuf_iolock(q, vb, NULL);
773 pr_err("fail to call videobuf_iolock, ret = %d\n", ret);
778 * sg[0] for input(S0)
781 sg_init_table(sg, 3);
783 buf->txd = pchan->dma_chan.device->device_prep_slave_sg(
784 &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE,
785 DMA_PREP_INTERRUPT, NULL);
791 buf->txd->callback_param = buf->txd;
792 buf->txd->callback = video_dma_done;
794 desc = to_tx_desc(buf->txd);
796 for (i = 0; i < length; i++) {
797 if (i == 0) {/* S0 */
798 memcpy(&desc->proc_data, proc_data,
799 sizeof(struct pxp_proc_data));
800 pxp_conf->s0_param.paddr =
801 videobuf_to_dma_contig(vb);
802 memcpy(&desc->layer_param.s0_param,
804 sizeof(struct pxp_layer_param));
805 } else if (i == 1) { /* Output */
806 if (proc_data->rotate % 180) {
807 pxp_conf->out_param.width =
809 pxp_conf->out_param.height =
812 pxp_conf->out_param.width =
814 pxp_conf->out_param.height =
818 pxp_conf->out_param.paddr = pxp->outbuf.paddr;
819 memcpy(&desc->layer_param.out_param,
820 &pxp_conf->out_param,
821 sizeof(struct pxp_layer_param));
822 } else if (pxp_conf->ol_param[0].combine_enable) {
824 pxp_conf->ol_param[0].paddr =
825 (dma_addr_t)pxp->fb.base;
826 pxp_conf->ol_param[0].width = pxp->fb.fmt.width;
827 pxp_conf->ol_param[0].height =
829 pxp_conf->ol_param[0].pixel_fmt =
830 pxp_conf->out_param.pixel_fmt;
831 memcpy(&desc->layer_param.ol_param,
832 &pxp_conf->ol_param[0],
833 sizeof(struct pxp_layer_param));
839 vb->state = VIDEOBUF_PREPARED;
845 pxp_buf_free(q, buf);
850 static void pxp_buf_queue(struct videobuf_queue *q,
851 struct videobuf_buffer *vb)
853 struct pxps *pxp = q->priv_data;
854 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
855 struct dma_async_tx_descriptor *txd = buf->txd;
856 struct pxp_channel *pchan = pxp->pxp_channel[0];
859 BUG_ON(!irqs_disabled());
861 list_add_tail(&vb->queue, &pxp->outq);
865 vb->state = VIDEOBUF_ACTIVE;
867 vb->state = VIDEOBUF_QUEUED;
870 spin_unlock_irq(&pxp->lock);
872 cookie = txd->tx_submit(txd);
873 dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n",
874 cookie, sg_dma_address(&buf->sg[0]));
877 dma_async_issue_pending(&pchan->dma_chan);
879 spin_lock_irq(&pxp->lock);
885 pr_err("%s: Submit error\n", __func__);
886 vb->state = VIDEOBUF_PREPARED;
888 list_del_init(&vb->queue);
890 if (pxp->active == buf)
894 static void pxp_buf_release(struct videobuf_queue *q,
895 struct videobuf_buffer *vb)
897 struct pxps *pxp = q->priv_data;
898 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
901 spin_lock_irqsave(&pxp->lock, flags);
902 if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
903 !list_empty(&vb->queue)) {
904 vb->state = VIDEOBUF_ERROR;
906 list_del_init(&vb->queue);
907 if (pxp->active == buf)
910 spin_unlock_irqrestore(&pxp->lock, flags);
912 pxp_buf_free(q, buf);
915 static struct videobuf_queue_ops pxp_vbq_ops = {
916 .buf_setup = pxp_buf_setup,
917 .buf_prepare = pxp_buf_prepare,
918 .buf_queue = pxp_buf_queue,
919 .buf_release = pxp_buf_release,
922 static int pxp_querycap(struct file *file, void *fh,
923 struct v4l2_capability *cap)
925 struct pxps *pxp = video_get_drvdata(video_devdata(file));
927 memset(cap, 0, sizeof(*cap));
928 strcpy(cap->driver, "pxp");
929 strcpy(cap->card, "pxp");
930 strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev),
931 sizeof(cap->bus_info));
933 cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR;
935 cap->capabilities = V4L2_CAP_VIDEO_OUTPUT |
936 V4L2_CAP_VIDEO_OUTPUT_OVERLAY |
942 static int pxp_g_fbuf(struct file *file, void *priv,
943 struct v4l2_framebuffer *fb)
945 struct pxps *pxp = video_get_drvdata(video_devdata(file));
947 memset(fb, 0, sizeof(*fb));
949 fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
950 V4L2_FBUF_CAP_CHROMAKEY |
951 V4L2_FBUF_CAP_LOCAL_ALPHA |
952 V4L2_FBUF_CAP_GLOBAL_ALPHA;
954 if (pxp->global_alpha_state)
955 fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
956 if (pxp->s1_chromakey_state)
957 fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
962 static int pxp_s_fbuf(struct file *file, void *priv,
963 const struct v4l2_framebuffer *fb)
965 struct pxps *pxp = video_get_drvdata(video_devdata(file));
968 (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
969 pxp->global_alpha_state =
970 (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
971 pxp->s1_chromakey_state =
972 (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
974 pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state;
975 pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state;
980 static int pxp_g_crop(struct file *file, void *fh,
983 struct pxps *pxp = video_get_drvdata(video_devdata(file));
985 if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
988 c->c.left = pxp->pxp_conf.proc_data.drect.left;
989 c->c.top = pxp->pxp_conf.proc_data.drect.top;
990 c->c.width = pxp->pxp_conf.proc_data.drect.width;
991 c->c.height = pxp->pxp_conf.proc_data.drect.height;
996 static int pxp_s_crop(struct file *file, void *fh,
997 const struct v4l2_crop *c)
999 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1003 int h = c->c.height;
1004 int fbw = pxp->fb.fmt.width;
1005 int fbh = pxp->fb.fmt.height;
1007 if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
1010 /* Constrain parameters to FB limits */
1012 w = max(w, PXP_MIN_PIX);
1014 h = max(h, PXP_MIN_PIX);
1020 /* Round up values to PxP pixel block */
1021 l = roundup(l, PXP_MIN_PIX);
1022 t = roundup(t, PXP_MIN_PIX);
1023 w = roundup(w, PXP_MIN_PIX);
1024 h = roundup(h, PXP_MIN_PIX);
1026 pxp->pxp_conf.proc_data.drect.left = l;
1027 pxp->pxp_conf.proc_data.drect.top = t;
1028 pxp->pxp_conf.proc_data.drect.width = w;
1029 pxp->pxp_conf.proc_data.drect.height = h;
1034 static int pxp_queryctrl(struct file *file, void *priv,
1035 struct v4l2_queryctrl *qc)
1039 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1040 if (qc->id && qc->id == pxp_controls[i].id) {
1041 memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
1048 static int pxp_g_ctrl(struct file *file, void *priv,
1049 struct v4l2_control *vc)
1053 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1055 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1056 if (vc->id == pxp_controls[i].id)
1057 return pxp_get_cstate(pxp, vc);
1062 static int pxp_s_ctrl(struct file *file, void *priv,
1063 struct v4l2_control *vc)
1066 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1068 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1069 if (vc->id == pxp_controls[i].id) {
1070 if (vc->value < pxp_controls[i].minimum ||
1071 vc->value > pxp_controls[i].maximum)
1073 return pxp_set_cstate(pxp, vc);
1079 void pxp_release(struct video_device *vfd)
1081 struct pxps *pxp = video_get_drvdata(vfd);
1083 spin_lock(&pxp->lock);
1084 video_device_release(vfd);
1085 spin_unlock(&pxp->lock);
1088 static int pxp_open(struct file *file)
1090 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1093 mutex_lock(&pxp->mutex);
1096 if (pxp->users > 1) {
1102 mutex_unlock(&pxp->mutex);
1106 ret = pxp_set_fbinfo(pxp);
1108 dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n");
1112 videobuf_queue_dma_contig_init(&pxp->s0_vbq,
1116 V4L2_BUF_TYPE_VIDEO_OUTPUT,
1118 sizeof(struct pxp_buffer),
1121 dev_dbg(&pxp->pdev->dev, "call pxp_open\n");
1126 static int pxp_close(struct file *file)
1128 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1130 pxp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_OUTPUT);
1131 videobuf_stop(&pxp->s0_vbq);
1132 videobuf_mmap_free(&pxp->s0_vbq);
1135 mutex_lock(&pxp->mutex);
1137 mutex_unlock(&pxp->mutex);
1142 static int pxp_mmap(struct file *file, struct vm_area_struct *vma)
1144 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1147 ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma);
1152 static const struct v4l2_file_operations pxp_fops = {
1153 .owner = THIS_MODULE,
1155 .release = pxp_close,
1156 .unlocked_ioctl = video_ioctl2,
1160 static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
1161 .vidioc_querycap = pxp_querycap,
1163 .vidioc_reqbufs = pxp_reqbufs,
1164 .vidioc_querybuf = pxp_querybuf,
1165 .vidioc_qbuf = pxp_qbuf,
1166 .vidioc_dqbuf = pxp_dqbuf,
1168 .vidioc_streamon = pxp_streamon,
1169 .vidioc_streamoff = pxp_streamoff,
1171 .vidioc_enum_output = pxp_enumoutput,
1172 .vidioc_g_output = pxp_g_output,
1173 .vidioc_s_output = pxp_s_output,
1175 .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output,
1176 .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output,
1177 .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output,
1178 .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output,
1180 .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay,
1181 .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay,
1182 .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay,
1184 .vidioc_g_fbuf = pxp_g_fbuf,
1185 .vidioc_s_fbuf = pxp_s_fbuf,
1187 .vidioc_g_crop = pxp_g_crop,
1188 .vidioc_s_crop = pxp_s_crop,
1190 .vidioc_queryctrl = pxp_queryctrl,
1191 .vidioc_g_ctrl = pxp_g_ctrl,
1192 .vidioc_s_ctrl = pxp_s_ctrl,
1195 static const struct video_device pxp_template = {
1197 .vfl_type = V4L2_CAP_VIDEO_OUTPUT |
1198 V4L2_CAP_VIDEO_OVERLAY |
1200 .vfl_dir = VFL_DIR_TX,
1202 .release = pxp_release,
1204 .ioctl_ops = &pxp_ioctl_ops,
1207 static const struct of_device_id imx_pxpv4l2_dt_ids[] = {
1208 { .compatible = "fsl,imx6sl-pxp-v4l2", },
1211 MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids);
1213 static int pxp_probe(struct platform_device *pdev)
1218 pxp = kzalloc(sizeof(*pxp), GFP_KERNEL);
1220 dev_err(&pdev->dev, "failed to allocate control object\n");
1225 dev_set_drvdata(&pdev->dev, pxp);
1227 INIT_LIST_HEAD(&pxp->outq);
1228 spin_lock_init(&pxp->lock);
1229 mutex_init(&pxp->mutex);
1233 pxp->vdev = video_device_alloc();
1235 dev_err(&pdev->dev, "video_device_alloc() failed\n");
1240 memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template));
1241 video_set_drvdata(pxp->vdev, pxp);
1243 err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr);
1245 dev_err(&pdev->dev, "failed to register video device\n");
1249 dev_info(&pdev->dev, "initialized\n");
1255 video_device_release(pxp->vdev);
1263 static int pxp_remove(struct platform_device *pdev)
1265 struct pxps *pxp = platform_get_drvdata(pdev);
1267 video_unregister_device(pxp->vdev);
1268 video_device_release(pxp->vdev);
1270 free_dma_buf(pxp, &pxp->outbuf);
1277 static struct platform_driver pxp_driver = {
1279 .name = PXP_DRIVER_NAME,
1280 .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids),
1283 .remove = pxp_remove,
1286 module_platform_driver(pxp_driver);
1288 module_param(video_nr, int, 0444);
1289 MODULE_DESCRIPTION("MXC PxP V4L2 driver");
1290 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1291 MODULE_LICENSE("GPL");