2 * Copyright (C) 2010-2013 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 static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt)
91 if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24)
92 pxp_fmt = PXP_PIX_FMT_RGB24;
93 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565)
94 pxp_fmt = PXP_PIX_FMT_RGB565;
95 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
96 pxp_fmt = PXP_PIX_FMT_RGB555;
97 else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
98 pxp_fmt = PXP_PIX_FMT_RGB555;
99 else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420)
100 pxp_fmt = PXP_PIX_FMT_YUV420P;
101 else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P)
102 pxp_fmt = PXP_PIX_FMT_YUV422P;
106 struct v4l2_queryctrl pxp_controls[] = {
108 .id = V4L2_CID_HFLIP,
109 .type = V4L2_CTRL_TYPE_BOOLEAN,
110 .name = "Horizontal Flip",
117 .id = V4L2_CID_VFLIP,
118 .type = V4L2_CTRL_TYPE_BOOLEAN,
119 .name = "Vertical Flip",
126 .id = V4L2_CID_PRIVATE_BASE,
127 .type = V4L2_CTRL_TYPE_INTEGER,
135 .id = V4L2_CID_PRIVATE_BASE + 1,
136 .name = "Background Color",
142 .type = V4L2_CTRL_TYPE_INTEGER,
144 .id = V4L2_CID_PRIVATE_BASE + 2,
145 .name = "Set S0 Chromakey",
151 .type = V4L2_CTRL_TYPE_INTEGER,
153 .id = V4L2_CID_PRIVATE_BASE + 3,
154 .name = "YUV Colorspace",
160 .type = V4L2_CTRL_TYPE_BOOLEAN,
164 /* callback function */
165 static void video_dma_done(void *arg)
167 struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
168 struct dma_chan *chan = tx_desc->txd.chan;
169 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
170 struct pxps *pxp = pxp_chan->client;
171 struct videobuf_buffer *vb;
173 dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
175 pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0);
177 spin_lock(&pxp->lock);
179 vb = &pxp->active->vb;
181 list_del_init(&vb->queue);
182 vb->state = VIDEOBUF_DONE;
183 do_gettimeofday(&vb->ts);
188 if (list_empty(&pxp->outq)) {
190 spin_unlock(&pxp->lock);
195 pxp->active = list_entry(pxp->outq.next,
196 struct pxp_buffer, vb.queue);
197 pxp->active->vb.state = VIDEOBUF_ACTIVE;
198 spin_unlock(&pxp->lock);
201 static int acquire_dma_channel(struct pxps *pxp)
204 struct dma_chan *chan;
205 struct pxp_channel **pchan = &pxp->pxp_channel[0];
208 struct videobuf_buffer *vb, *_vb;
209 dma_release_channel(&(*pchan)->dma_chan);
212 list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) {
213 list_del_init(&vb->queue);
214 vb->state = VIDEOBUF_ERROR;
220 dma_cap_set(DMA_SLAVE, mask);
221 dma_cap_set(DMA_PRIVATE, mask);
222 chan = dma_request_channel(mask, NULL, NULL);
226 *pchan = to_pxp_channel(chan);
227 (*pchan)->client = pxp;
232 static int _get_fbinfo(struct fb_info **fbi)
235 for (i = 0; i < num_registered_fb; i++) {
236 char *idstr = registered_fb[i]->fix.id;
237 if (strcmp(idstr, "mxs") == 0) {
238 *fbi = registered_fb[i];
246 static int pxp_set_fbinfo(struct pxps *pxp)
248 struct v4l2_framebuffer *fb = &pxp->fb;
251 err = _get_fbinfo(&pxp->fbi);
255 fb->fmt.width = pxp->fbi->var.xres;
256 fb->fmt.height = pxp->fbi->var.yres;
257 pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres;
258 if (pxp->fbi->var.bits_per_pixel == 16)
259 fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
261 fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24;
263 fb->base = (void *)pxp->fbi->fix.smem_start;
268 static int _get_cur_fb_blank(struct pxps *pxp)
274 err = _get_fbinfo(&fbi);
278 if (fbi->fbops->fb_ioctl) {
281 err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
282 (unsigned int)(&pxp->fb_blank));
289 static int pxp_show_buf(struct pxps *pxp, bool toshow)
291 struct fb_info *fbi = pxp->fbi;
295 fbi->fix.smem_start = toshow ?
296 pxp->outb_phys : (unsigned long)pxp->fb.base;
297 ret = fb_pan_display(fbi, &fbi->var);
303 static int set_fb_blank(int blank)
308 err = _get_fbinfo(&fbi);
313 fb_blank(fbi, blank);
319 static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc)
322 if (vc->id == V4L2_CID_HFLIP) {
323 pxp->pxp_conf.proc_data.hflip = vc->value;
324 } else if (vc->id == V4L2_CID_VFLIP) {
325 pxp->pxp_conf.proc_data.vflip = vc->value;
326 } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
329 pxp->pxp_conf.proc_data.rotate = vc->value;
330 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) {
331 pxp->pxp_conf.proc_data.bgcolor = vc->value;
332 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) {
333 pxp->pxp_conf.s0_param.color_key = vc->value;
334 } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) {
335 pxp->pxp_conf.proc_data.yuv = vc->value;
341 static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc)
343 if (vc->id == V4L2_CID_HFLIP)
344 vc->value = pxp->pxp_conf.proc_data.hflip;
345 else if (vc->id == V4L2_CID_VFLIP)
346 vc->value = pxp->pxp_conf.proc_data.vflip;
347 else if (vc->id == V4L2_CID_PRIVATE_BASE)
348 vc->value = pxp->pxp_conf.proc_data.rotate;
349 else if (vc->id == V4L2_CID_PRIVATE_BASE + 1)
350 vc->value = pxp->pxp_conf.proc_data.bgcolor;
351 else if (vc->id == V4L2_CID_PRIVATE_BASE + 2)
352 vc->value = pxp->pxp_conf.s0_param.color_key;
353 else if (vc->id == V4L2_CID_PRIVATE_BASE + 3)
354 vc->value = pxp->pxp_conf.proc_data.yuv;
359 static int pxp_enumoutput(struct file *file, void *fh,
360 struct v4l2_output *o)
362 struct pxps *pxp = video_get_drvdata(video_devdata(file));
364 if ((o->index < 0) || (o->index > 1))
367 memset(o, 0, sizeof(struct v4l2_output));
369 strcpy(o->name, "PxP Display Output");
372 strcpy(o->name, "PxP Virtual Output");
375 o->type = V4L2_OUTPUT_TYPE_INTERNAL;
377 o->reserved[0] = pxp->outb_phys;
382 static int pxp_g_output(struct file *file, void *fh,
385 struct pxps *pxp = video_get_drvdata(video_devdata(file));
392 static int pxp_s_output(struct file *file, void *fh,
395 struct pxps *pxp = video_get_drvdata(video_devdata(file));
396 struct v4l2_pix_format *fmt = &pxp->fb.fmt;
399 if ((i < 0) || (i > 1))
405 /* Output buffer is same format as fbdev */
406 if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
411 pxp->outb_size = fmt->width * fmt->height * bpp;
412 pxp->outb = kmalloc(fmt->width * fmt->height * bpp,
413 GFP_KERNEL | GFP_DMA);
414 if (pxp->outb == NULL) {
415 dev_err(&pxp->pdev->dev, "No enough memory!\n");
418 pxp->outb_phys = virt_to_phys(pxp->outb);
419 dma_map_single(NULL, pxp->outb,
420 fmt->width * fmt->height * bpp, DMA_TO_DEVICE);
422 pxp->pxp_conf.out_param.width = fmt->width;
423 pxp->pxp_conf.out_param.height = fmt->height;
424 if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
425 pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB24;
427 pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
432 static int pxp_enum_fmt_video_output(struct file *file, void *fh,
433 struct v4l2_fmtdesc *fmt)
435 enum v4l2_buf_type type = fmt->type;
436 int index = fmt->index;
438 if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats)))
441 memset(fmt, 0, sizeof(struct v4l2_fmtdesc));
444 fmt->pixelformat = pxp_s0_formats[index].fourcc;
445 strcpy(fmt->description, pxp_s0_formats[index].name);
450 static int pxp_g_fmt_video_output(struct file *file, void *fh,
451 struct v4l2_format *f)
453 struct v4l2_pix_format *pf = &f->fmt.pix;
454 struct pxps *pxp = video_get_drvdata(video_devdata(file));
455 struct pxp_data_format *fmt = pxp->s0_fmt;
457 pf->width = pxp->pxp_conf.s0_param.width;
458 pf->height = pxp->pxp_conf.s0_param.height;
459 pf->pixelformat = fmt->fourcc;
460 pf->field = V4L2_FIELD_NONE;
461 pf->bytesperline = fmt->bpp * pf->width;
462 pf->sizeimage = pf->bytesperline * pf->height;
463 pf->colorspace = fmt->colorspace;
469 static struct pxp_data_format *pxp_get_format(struct v4l2_format *f)
471 struct pxp_data_format *fmt;
474 for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) {
475 fmt = &pxp_s0_formats[i];
476 if (fmt->fourcc == f->fmt.pix.pixelformat)
480 if (i == ARRAY_SIZE(pxp_s0_formats))
483 return &pxp_s0_formats[i];
486 static int pxp_try_fmt_video_output(struct file *file, void *fh,
487 struct v4l2_format *f)
489 int w = f->fmt.pix.width;
490 int h = f->fmt.pix.height;
491 struct pxp_data_format *fmt = pxp_get_format(f);
500 f->fmt.pix.field = V4L2_FIELD_NONE;
501 f->fmt.pix.width = w;
502 f->fmt.pix.height = h;
503 f->fmt.pix.pixelformat = fmt->fourcc;
508 static int pxp_s_fmt_video_output(struct file *file, void *fh,
509 struct v4l2_format *f)
511 struct pxps *pxp = video_get_drvdata(video_devdata(file));
512 struct v4l2_pix_format *pf = &f->fmt.pix;
515 ret = acquire_dma_channel(pxp);
519 ret = pxp_try_fmt_video_output(file, fh, f);
521 pxp->s0_fmt = pxp_get_format(f);
522 pxp->pxp_conf.s0_param.pixel_fmt =
523 v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc);
524 pxp->pxp_conf.s0_param.width = pf->width;
525 pxp->pxp_conf.s0_param.height = pf->height;
532 static int pxp_g_fmt_output_overlay(struct file *file, void *fh,
533 struct v4l2_format *f)
535 struct pxps *pxp = video_get_drvdata(video_devdata(file));
536 struct v4l2_window *wf = &f->fmt.win;
538 memset(wf, 0, sizeof(struct v4l2_window));
539 wf->chromakey = pxp->s1_chromakey;
540 wf->global_alpha = pxp->global_alpha;
541 wf->field = V4L2_FIELD_NONE;
545 wf->w.left = pxp->pxp_conf.proc_data.srect.left;
546 wf->w.top = pxp->pxp_conf.proc_data.srect.top;
547 wf->w.width = pxp->pxp_conf.proc_data.srect.width;
548 wf->w.height = pxp->pxp_conf.proc_data.srect.height;
553 static int pxp_try_fmt_output_overlay(struct file *file, void *fh,
554 struct v4l2_format *f)
556 struct pxps *pxp = video_get_drvdata(video_devdata(file));
557 struct v4l2_window *wf = &f->fmt.win;
558 struct v4l2_rect srect;
559 u32 s1_chromakey = wf->chromakey;
560 u8 global_alpha = wf->global_alpha;
562 memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect));
564 pxp_g_fmt_output_overlay(file, fh, f);
566 wf->chromakey = s1_chromakey;
567 wf->global_alpha = global_alpha;
569 /* Constrain parameters to the input buffer */
570 wf->w.left = srect.left;
571 wf->w.top = srect.top;
572 wf->w.width = min(srect.width,
573 ((__s32)pxp->pxp_conf.s0_param.width - wf->w.left));
574 wf->w.height = min(srect.height,
575 ((__s32)pxp->pxp_conf.s0_param.height - wf->w.top));
580 static int pxp_s_fmt_output_overlay(struct file *file, void *fh,
581 struct v4l2_format *f)
583 struct pxps *pxp = video_get_drvdata(video_devdata(file));
584 struct v4l2_window *wf = &f->fmt.win;
585 int ret = pxp_try_fmt_output_overlay(file, fh, f);
588 pxp->global_alpha = wf->global_alpha;
589 pxp->s1_chromakey = wf->chromakey;
590 pxp->pxp_conf.proc_data.srect.left = wf->w.left;
591 pxp->pxp_conf.proc_data.srect.top = wf->w.top;
592 pxp->pxp_conf.proc_data.srect.width = wf->w.width;
593 pxp->pxp_conf.proc_data.srect.height = wf->w.height;
594 pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha;
595 pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey;
596 pxp->pxp_conf.ol_param[0].color_key_enable =
597 pxp->s1_chromakey_state;
603 static int pxp_reqbufs(struct file *file, void *priv,
604 struct v4l2_requestbuffers *r)
606 struct pxps *pxp = video_get_drvdata(video_devdata(file));
608 return videobuf_reqbufs(&pxp->s0_vbq, r);
611 static int pxp_querybuf(struct file *file, void *priv,
612 struct v4l2_buffer *b)
614 struct pxps *pxp = video_get_drvdata(video_devdata(file));
616 return videobuf_querybuf(&pxp->s0_vbq, b);
619 static int pxp_qbuf(struct file *file, void *priv,
620 struct v4l2_buffer *b)
622 struct pxps *pxp = video_get_drvdata(video_devdata(file));
624 return videobuf_qbuf(&pxp->s0_vbq, b);
627 static int pxp_dqbuf(struct file *file, void *priv,
628 struct v4l2_buffer *b)
630 struct pxps *pxp = video_get_drvdata(video_devdata(file));
632 return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK);
635 static int pxp_streamon(struct file *file, void *priv,
636 enum v4l2_buf_type t)
638 struct pxps *pxp = video_get_drvdata(video_devdata(file));
641 if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT)
644 _get_cur_fb_blank(pxp);
645 set_fb_blank(FB_BLANK_UNBLANK);
647 ret = videobuf_streamon(&pxp->s0_vbq);
649 if (!ret && (pxp->output == 0))
650 pxp_show_buf(pxp, true);
655 static int pxp_streamoff(struct file *file, void *priv,
656 enum v4l2_buf_type t)
658 struct pxps *pxp = video_get_drvdata(video_devdata(file));
661 if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
664 ret = videobuf_streamoff(&pxp->s0_vbq);
667 pxp_show_buf(pxp, false);
670 set_fb_blank(FB_BLANK_POWERDOWN);
675 static int pxp_buf_setup(struct videobuf_queue *q,
676 unsigned int *count, unsigned *size)
678 struct pxps *pxp = q->priv_data;
680 *size = pxp->pxp_conf.s0_param.width *
681 pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp;
684 *count = PXP_DEF_BUFS;
689 static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf)
691 struct videobuf_buffer *vb = &buf->vb;
692 struct dma_async_tx_descriptor *txd = buf->txd;
694 BUG_ON(in_interrupt());
696 pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__,
697 vb, vb->baddr, vb->bsize);
700 * This waits until this buffer is out of danger, i.e., until it is no
701 * longer in STATE_QUEUED or STATE_ACTIVE
703 videobuf_waiton(q, vb, 0, 0);
707 videobuf_dma_contig_free(q, vb);
710 vb->state = VIDEOBUF_NEEDS_INIT;
713 static int pxp_buf_prepare(struct videobuf_queue *q,
714 struct videobuf_buffer *vb,
715 enum v4l2_field field)
717 struct pxps *pxp = q->priv_data;
718 struct pxp_config_data *pxp_conf = &pxp->pxp_conf;
719 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
720 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
721 struct pxp_tx_desc *desc;
725 vb->width = pxp->pxp_conf.s0_param.width;
726 vb->height = pxp->pxp_conf.s0_param.height;
727 vb->size = vb->width * vb->height * pxp->s0_fmt->bpp;
728 vb->field = V4L2_FIELD_NONE;
729 if (vb->state != VIDEOBUF_NEEDS_INIT)
730 pxp_buf_free(q, buf);
732 if (vb->state == VIDEOBUF_NEEDS_INIT) {
733 struct pxp_channel *pchan = pxp->pxp_channel[0];
734 struct scatterlist *sg = &buf->sg[0];
736 /* This actually (allocates and) maps buffers */
737 ret = videobuf_iolock(q, vb, NULL);
739 pr_err("fail to call videobuf_iolock, ret = %d\n", ret);
744 * sg[0] for input(S0)
747 sg_init_table(sg, 3);
749 buf->txd = pchan->dma_chan.device->device_prep_slave_sg(
750 &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE,
751 DMA_PREP_INTERRUPT, NULL);
757 buf->txd->callback_param = buf->txd;
758 buf->txd->callback = video_dma_done;
760 desc = to_tx_desc(buf->txd);
762 for (i = 0; i < length; i++) {
763 if (i == 0) {/* S0 */
764 memcpy(&desc->proc_data, proc_data,
765 sizeof(struct pxp_proc_data));
766 pxp_conf->s0_param.paddr =
767 videobuf_to_dma_contig(vb);
768 memcpy(&desc->layer_param.s0_param,
770 sizeof(struct pxp_layer_param));
771 } else if (i == 1) { /* Output */
772 if (proc_data->rotate % 180) {
773 pxp_conf->out_param.width =
775 pxp_conf->out_param.height =
778 pxp_conf->out_param.width =
780 pxp_conf->out_param.height =
784 pxp_conf->out_param.paddr = pxp->outb_phys;
785 memcpy(&desc->layer_param.out_param,
786 &pxp_conf->out_param,
787 sizeof(struct pxp_layer_param));
788 } else if (pxp_conf->ol_param[0].combine_enable) {
790 pxp_conf->ol_param[0].paddr =
791 (dma_addr_t)pxp->fb.base;
792 pxp_conf->ol_param[0].width = pxp->fb.fmt.width;
793 pxp_conf->ol_param[0].height =
795 pxp_conf->ol_param[0].pixel_fmt =
796 pxp_conf->out_param.pixel_fmt;
797 memcpy(&desc->layer_param.ol_param,
798 &pxp_conf->ol_param[0],
799 sizeof(struct pxp_layer_param));
805 vb->state = VIDEOBUF_PREPARED;
811 pxp_buf_free(q, buf);
816 static void pxp_buf_queue(struct videobuf_queue *q,
817 struct videobuf_buffer *vb)
819 struct pxps *pxp = q->priv_data;
820 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
821 struct dma_async_tx_descriptor *txd = buf->txd;
822 struct pxp_channel *pchan = pxp->pxp_channel[0];
825 BUG_ON(!irqs_disabled());
827 list_add_tail(&vb->queue, &pxp->outq);
831 vb->state = VIDEOBUF_ACTIVE;
833 vb->state = VIDEOBUF_QUEUED;
836 spin_unlock_irq(&pxp->lock);
838 cookie = txd->tx_submit(txd);
839 dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n",
840 cookie, sg_dma_address(&buf->sg[0]));
843 dma_async_issue_pending(&pchan->dma_chan);
845 spin_lock_irq(&pxp->lock);
851 pr_err("%s: Submit error\n", __func__);
852 vb->state = VIDEOBUF_PREPARED;
854 list_del_init(&vb->queue);
856 if (pxp->active == buf)
860 static void pxp_buf_release(struct videobuf_queue *q,
861 struct videobuf_buffer *vb)
863 struct pxps *pxp = q->priv_data;
864 struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
867 spin_lock_irqsave(&pxp->lock, flags);
868 if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
869 !list_empty(&vb->queue)) {
870 vb->state = VIDEOBUF_ERROR;
872 list_del_init(&vb->queue);
873 if (pxp->active == buf)
876 spin_unlock_irqrestore(&pxp->lock, flags);
878 pxp_buf_free(q, buf);
881 static struct videobuf_queue_ops pxp_vbq_ops = {
882 .buf_setup = pxp_buf_setup,
883 .buf_prepare = pxp_buf_prepare,
884 .buf_queue = pxp_buf_queue,
885 .buf_release = pxp_buf_release,
888 static int pxp_querycap(struct file *file, void *fh,
889 struct v4l2_capability *cap)
891 struct pxps *pxp = video_get_drvdata(video_devdata(file));
893 memset(cap, 0, sizeof(*cap));
894 strcpy(cap->driver, "pxp");
895 strcpy(cap->card, "pxp");
896 strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev),
897 sizeof(cap->bus_info));
899 cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR;
901 cap->capabilities = V4L2_CAP_VIDEO_OUTPUT |
902 V4L2_CAP_VIDEO_OUTPUT_OVERLAY |
908 static int pxp_g_fbuf(struct file *file, void *priv,
909 struct v4l2_framebuffer *fb)
911 struct pxps *pxp = video_get_drvdata(video_devdata(file));
913 memset(fb, 0, sizeof(*fb));
915 fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
916 V4L2_FBUF_CAP_CHROMAKEY |
917 V4L2_FBUF_CAP_LOCAL_ALPHA |
918 V4L2_FBUF_CAP_GLOBAL_ALPHA;
920 if (pxp->global_alpha_state)
921 fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
922 if (pxp->s1_chromakey_state)
923 fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
928 static int pxp_s_fbuf(struct file *file, void *priv,
929 const struct v4l2_framebuffer *fb)
931 struct pxps *pxp = video_get_drvdata(video_devdata(file));
934 (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
935 pxp->global_alpha_state =
936 (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
937 pxp->s1_chromakey_state =
938 (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
940 pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state;
941 pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state;
946 static int pxp_g_crop(struct file *file, void *fh,
949 struct pxps *pxp = video_get_drvdata(video_devdata(file));
951 if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
954 c->c.left = pxp->pxp_conf.proc_data.drect.left;
955 c->c.top = pxp->pxp_conf.proc_data.drect.top;
956 c->c.width = pxp->pxp_conf.proc_data.drect.width;
957 c->c.height = pxp->pxp_conf.proc_data.drect.height;
962 static int pxp_s_crop(struct file *file, void *fh,
963 const struct v4l2_crop *c)
965 struct pxps *pxp = video_get_drvdata(video_devdata(file));
970 int fbw = pxp->fb.fmt.width;
971 int fbh = pxp->fb.fmt.height;
973 if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
976 /* Constrain parameters to FB limits */
978 w = max(w, PXP_MIN_PIX);
980 h = max(h, PXP_MIN_PIX);
986 /* Round up values to PxP pixel block */
987 l = roundup(l, PXP_MIN_PIX);
988 t = roundup(t, PXP_MIN_PIX);
989 w = roundup(w, PXP_MIN_PIX);
990 h = roundup(h, PXP_MIN_PIX);
992 pxp->pxp_conf.proc_data.drect.left = l;
993 pxp->pxp_conf.proc_data.drect.top = t;
994 pxp->pxp_conf.proc_data.drect.width = w;
995 pxp->pxp_conf.proc_data.drect.height = h;
1000 static int pxp_queryctrl(struct file *file, void *priv,
1001 struct v4l2_queryctrl *qc)
1005 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1006 if (qc->id && qc->id == pxp_controls[i].id) {
1007 memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
1014 static int pxp_g_ctrl(struct file *file, void *priv,
1015 struct v4l2_control *vc)
1019 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1021 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1022 if (vc->id == pxp_controls[i].id)
1023 return pxp_get_cstate(pxp, vc);
1028 static int pxp_s_ctrl(struct file *file, void *priv,
1029 struct v4l2_control *vc)
1032 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1034 for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
1035 if (vc->id == pxp_controls[i].id) {
1036 if (vc->value < pxp_controls[i].minimum ||
1037 vc->value > pxp_controls[i].maximum)
1039 return pxp_set_cstate(pxp, vc);
1045 void pxp_release(struct video_device *vfd)
1047 struct pxps *pxp = video_get_drvdata(vfd);
1049 spin_lock(&pxp->lock);
1050 video_device_release(vfd);
1051 spin_unlock(&pxp->lock);
1054 static int pxp_open(struct file *file)
1056 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1059 mutex_lock(&pxp->mutex);
1062 if (pxp->users > 1) {
1068 mutex_unlock(&pxp->mutex);
1072 ret = pxp_set_fbinfo(pxp);
1074 dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n");
1078 videobuf_queue_dma_contig_init(&pxp->s0_vbq,
1082 V4L2_BUF_TYPE_VIDEO_OUTPUT,
1084 sizeof(struct pxp_buffer),
1087 dev_dbg(&pxp->pdev->dev, "call pxp_open\n");
1092 static int pxp_close(struct file *file)
1094 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1096 videobuf_stop(&pxp->s0_vbq);
1097 videobuf_mmap_free(&pxp->s0_vbq);
1102 mutex_lock(&pxp->mutex);
1104 mutex_unlock(&pxp->mutex);
1109 static int pxp_mmap(struct file *file, struct vm_area_struct *vma)
1111 struct pxps *pxp = video_get_drvdata(video_devdata(file));
1114 ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma);
1119 static const struct v4l2_file_operations pxp_fops = {
1120 .owner = THIS_MODULE,
1122 .release = pxp_close,
1123 .unlocked_ioctl = video_ioctl2,
1127 static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
1128 .vidioc_querycap = pxp_querycap,
1130 .vidioc_reqbufs = pxp_reqbufs,
1131 .vidioc_querybuf = pxp_querybuf,
1132 .vidioc_qbuf = pxp_qbuf,
1133 .vidioc_dqbuf = pxp_dqbuf,
1135 .vidioc_streamon = pxp_streamon,
1136 .vidioc_streamoff = pxp_streamoff,
1138 .vidioc_enum_output = pxp_enumoutput,
1139 .vidioc_g_output = pxp_g_output,
1140 .vidioc_s_output = pxp_s_output,
1142 .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output,
1143 .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output,
1144 .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output,
1145 .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output,
1147 .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay,
1148 .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay,
1149 .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay,
1151 .vidioc_g_fbuf = pxp_g_fbuf,
1152 .vidioc_s_fbuf = pxp_s_fbuf,
1154 .vidioc_g_crop = pxp_g_crop,
1155 .vidioc_s_crop = pxp_s_crop,
1157 .vidioc_queryctrl = pxp_queryctrl,
1158 .vidioc_g_ctrl = pxp_g_ctrl,
1159 .vidioc_s_ctrl = pxp_s_ctrl,
1162 static const struct video_device pxp_template = {
1164 .vfl_type = V4L2_CAP_VIDEO_OUTPUT |
1165 V4L2_CAP_VIDEO_OVERLAY |
1167 .vfl_dir = VFL_DIR_TX,
1169 .release = pxp_release,
1171 .ioctl_ops = &pxp_ioctl_ops,
1174 static const struct of_device_id imx_pxpv4l2_dt_ids[] = {
1175 { .compatible = "fsl,imx6sl-pxp-v4l2", },
1178 MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids);
1180 static int pxp_probe(struct platform_device *pdev)
1185 pxp = kzalloc(sizeof(*pxp), GFP_KERNEL);
1187 dev_err(&pdev->dev, "failed to allocate control object\n");
1192 dev_set_drvdata(&pdev->dev, pxp);
1194 INIT_LIST_HEAD(&pxp->outq);
1195 spin_lock_init(&pxp->lock);
1196 mutex_init(&pxp->mutex);
1200 pxp->vdev = video_device_alloc();
1202 dev_err(&pdev->dev, "video_device_alloc() failed\n");
1207 memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template));
1208 video_set_drvdata(pxp->vdev, pxp);
1210 err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr);
1212 dev_err(&pdev->dev, "failed to register video device\n");
1216 dev_info(&pdev->dev, "initialized\n");
1222 video_device_release(pxp->vdev);
1230 static int pxp_remove(struct platform_device *pdev)
1232 struct pxps *pxp = platform_get_drvdata(pdev);
1234 video_unregister_device(pxp->vdev);
1235 video_device_release(pxp->vdev);
1242 static struct platform_driver pxp_driver = {
1244 .name = PXP_DRIVER_NAME,
1245 .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids),
1248 .remove = pxp_remove,
1251 module_platform_driver(pxp_driver);
1253 module_param(video_nr, int, 0444);
1254 MODULE_DESCRIPTION("MXC PxP V4L2 driver");
1255 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1256 MODULE_LICENSE("GPL");