Lines Matching +full:timer +full:- +full:width
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2021-2023 Digiteq Automotive
9 * When the device is in loopback mode (a direct, in HW, in->out frame passing
16 #include <media/v4l2-ioctl.h>
17 #include <media/videobuf2-v4l2.h>
18 #include <media/videobuf2-dma-sg.h>
19 #include <media/v4l2-dv-timings.h>
67 struct mgb4_regs *video = &voutdev->mgbdev->video; in get_timings()
68 const struct mgb4_vout_regs *regs = &voutdev->config->regs; in get_timings()
70 u32 hsync = mgb4_read_reg(video, regs->hsync); in get_timings()
71 u32 vsync = mgb4_read_reg(video, regs->vsync); in get_timings()
72 u32 resolution = mgb4_read_reg(video, regs->resolution); in get_timings()
75 timings->type = V4L2_DV_BT_656_1120; in get_timings()
76 timings->bt.width = resolution >> 16; in get_timings()
77 timings->bt.height = resolution & 0xFFFF; in get_timings()
79 timings->bt.polarities |= V4L2_DV_HSYNC_POS_POL; in get_timings()
81 timings->bt.polarities |= V4L2_DV_VSYNC_POS_POL; in get_timings()
82 timings->bt.pixelclock = voutdev->freq * 1000; in get_timings()
83 timings->bt.hsync = (hsync & 0x00FF0000) >> 16; in get_timings()
84 timings->bt.vsync = (vsync & 0x00FF0000) >> 16; in get_timings()
85 timings->bt.hbackporch = (hsync & 0x0000FF00) >> 8; in get_timings()
86 timings->bt.hfrontporch = hsync & 0x000000FF; in get_timings()
87 timings->bt.vbackporch = (vsync & 0x0000FF00) >> 8; in get_timings()
88 timings->bt.vfrontporch = vsync & 0x000000FF; in get_timings()
97 spin_lock_irqsave(&voutdev->qlock, flags); in return_all_buffers()
98 list_for_each_entry_safe(buf, node, &voutdev->buf_list, list) { in return_all_buffers()
99 vb2_buffer_done(&buf->vb.vb2_buf, state); in return_all_buffers()
100 list_del(&buf->list); in return_all_buffers()
102 spin_unlock_irqrestore(&voutdev->qlock, flags); in return_all_buffers()
110 struct mgb4_regs *video = &voutdev->mgbdev->video; in queue_setup()
111 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in queue_setup()
113 unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height in queue_setup()
121 if (test_bit(0, &voutdev->mgbdev->io_reconfig)) in queue_setup()
122 return -EBUSY; in queue_setup()
125 return sizes[0] < size ? -EINVAL : 0; in queue_setup()
137 INIT_LIST_HEAD(&buf->list); in buffer_init()
144 struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vb->vb2_queue); in buffer_prepare()
145 struct device *dev = &voutdev->mgbdev->pdev->dev; in buffer_prepare()
146 struct mgb4_regs *video = &voutdev->mgbdev->video; in buffer_prepare()
147 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in buffer_prepare()
149 unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height in buffer_prepare()
155 return -EINVAL; in buffer_prepare()
165 struct mgb4_vout_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); in buffer_queue()
170 spin_lock_irqsave(&vindev->qlock, flags); in buffer_queue()
171 list_add_tail(&buf->list, &vindev->buf_list); in buffer_queue()
172 spin_unlock_irqrestore(&vindev->qlock, flags); in buffer_queue()
178 struct mgb4_dev *mgbdev = voutdev->mgbdev; in stop_streaming()
179 int irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); in stop_streaming()
181 xdma_disable_user_irq(mgbdev->xdev, irq); in stop_streaming()
182 cancel_work_sync(&voutdev->dma_work); in stop_streaming()
183 mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x2, 0x0); in stop_streaming()
190 struct mgb4_dev *mgbdev = voutdev->mgbdev; in start_streaming()
191 struct device *dev = &mgbdev->pdev->dev; in start_streaming()
193 struct mgb4_regs *video = &mgbdev->video; in start_streaming()
194 const struct mgb4_vout_config *config = voutdev->config; in start_streaming()
195 int irq = xdma_get_user_irq(mgbdev->xdev, config->irq); in start_streaming()
199 mgb4_mask_reg(video, config->regs.config, 0x2, 0x2); in start_streaming()
201 addr = mgb4_read_reg(video, config->regs.address); in start_streaming()
205 return -EBUSY; in start_streaming()
208 buf = list_first_entry(&voutdev->buf_list, struct mgb4_frame_buffer, in start_streaming()
210 list_del_init(voutdev->buf_list.next); in start_streaming()
212 rv = mgb4_dma_transfer(mgbdev, config->dma_channel, true, addr, in start_streaming()
213 vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); in start_streaming()
216 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in start_streaming()
218 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); in start_streaming()
221 xdma_enable_user_irq(mgbdev->xdev, irq); in start_streaming()
240 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); in vidioc_querycap()
241 strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); in vidioc_querycap()
250 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_enum_fmt()
252 if (f->index == 0) { in vidioc_enum_fmt()
253 f->pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_enum_fmt()
255 } else if (f->index == 1 && has_yuv(video)) { in vidioc_enum_fmt()
256 f->pixelformat = V4L2_PIX_FMT_YUYV; in vidioc_enum_fmt()
259 return -EINVAL; in vidioc_enum_fmt()
266 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_g_fmt()
267 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in vidioc_g_fmt()
269 f->fmt.pix.width = voutdev->width; in vidioc_g_fmt()
270 f->fmt.pix.height = voutdev->height; in vidioc_g_fmt()
271 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_g_fmt()
274 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; in vidioc_g_fmt()
276 f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; in vidioc_g_fmt()
279 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; in vidioc_g_fmt()
281 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; in vidioc_g_fmt()
283 f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 2; in vidioc_g_fmt()
285 f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_g_fmt()
286 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; in vidioc_g_fmt()
287 f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4; in vidioc_g_fmt()
290 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; in vidioc_g_fmt()
298 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_try_fmt()
301 f->fmt.pix.width = voutdev->width; in vidioc_try_fmt()
302 f->fmt.pix.height = voutdev->height; in vidioc_try_fmt()
303 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_try_fmt()
305 if (has_yuv(video) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { in vidioc_try_fmt()
307 if (!(f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709 || in vidioc_try_fmt()
308 f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M)) in vidioc_try_fmt()
309 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; in vidioc_try_fmt()
312 f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_try_fmt()
313 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; in vidioc_try_fmt()
316 if (f->fmt.pix.bytesperline > f->fmt.pix.width * pixelsize && in vidioc_try_fmt()
317 f->fmt.pix.bytesperline < f->fmt.pix.width * pixelsize * 2) in vidioc_try_fmt()
318 f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, in vidioc_try_fmt()
321 f->fmt.pix.bytesperline = f->fmt.pix.width * pixelsize; in vidioc_try_fmt()
322 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; in vidioc_try_fmt()
330 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_s_fmt()
334 if (vb2_is_busy(&voutdev->queue)) in vidioc_s_fmt()
335 return -EBUSY; in vidioc_s_fmt()
341 config = mgb4_read_reg(video, voutdev->config->regs.config); in vidioc_s_fmt()
342 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { in vidioc_s_fmt()
346 if (f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709) { in vidioc_s_fmt()
349 } else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M) { in vidioc_s_fmt()
360 mgb4_write_reg(video, voutdev->config->regs.config, config); in vidioc_s_fmt()
362 voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width in vidioc_s_fmt()
364 mgb4_write_reg(video, voutdev->config->regs.padding, voutdev->padding); in vidioc_s_fmt()
377 return i ? -EINVAL : 0; in vidioc_s_output()
383 if (out->index != 0) in vidioc_enum_output()
384 return -EINVAL; in vidioc_enum_output()
386 out->type = V4L2_OUTPUT_TYPE_ANALOG; in vidioc_enum_output()
387 out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; in vidioc_enum_output()
388 strscpy(out->name, "MGB4", sizeof(out->name)); in vidioc_enum_output()
397 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_enum_frameintervals()
400 if (ival->index != 0) in vidioc_enum_frameintervals()
401 return -EINVAL; in vidioc_enum_frameintervals()
402 if (!(ival->pixel_format == V4L2_PIX_FMT_ABGR32 || in vidioc_enum_frameintervals()
403 ((has_yuv(video) && ival->pixel_format == V4L2_PIX_FMT_YUYV)))) in vidioc_enum_frameintervals()
404 return -EINVAL; in vidioc_enum_frameintervals()
405 if (ival->width != voutdev->width || ival->height != voutdev->height) in vidioc_enum_frameintervals()
406 return -EINVAL; in vidioc_enum_frameintervals()
410 ival->type = V4L2_FRMIVAL_TYPE_STEPWISE; in vidioc_enum_frameintervals()
411 ival->stepwise.max.denominator = MGB4_HW_FREQ; in vidioc_enum_frameintervals()
412 ival->stepwise.max.numerator = 0xFFFFFFFF; in vidioc_enum_frameintervals()
413 ival->stepwise.min.denominator = timings.bt.pixelclock; in vidioc_enum_frameintervals()
414 ival->stepwise.min.numerator = pixel_size(&timings); in vidioc_enum_frameintervals()
415 ival->stepwise.step.denominator = MGB4_HW_FREQ; in vidioc_enum_frameintervals()
416 ival->stepwise.step.numerator = 1; in vidioc_enum_frameintervals()
425 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_g_parm()
426 struct v4l2_fract *tpf = &parm->parm.output.timeperframe; in vidioc_g_parm()
428 u32 timer; in vidioc_g_parm() local
430 parm->parm.output.writebuffers = 2; in vidioc_g_parm()
433 timer = mgb4_read_reg(video, voutdev->config->regs.timer); in vidioc_g_parm()
434 if (timer < 0xFFFF) { in vidioc_g_parm()
436 tpf->numerator = pixel_size(&timings); in vidioc_g_parm()
437 tpf->denominator = timings.bt.pixelclock; in vidioc_g_parm()
439 tpf->numerator = timer; in vidioc_g_parm()
440 tpf->denominator = MGB4_HW_FREQ; in vidioc_g_parm()
443 parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; in vidioc_g_parm()
453 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_s_parm()
454 struct v4l2_fract *tpf = &parm->parm.output.timeperframe; in vidioc_s_parm()
456 u32 timer, period; in vidioc_s_parm() local
459 timer = tpf->denominator ? in vidioc_s_parm()
460 MGB4_PERIOD(tpf->numerator, tpf->denominator) : 0; in vidioc_s_parm()
461 if (timer) { in vidioc_s_parm()
465 if (timer < period) in vidioc_s_parm()
466 timer = 0; in vidioc_s_parm()
469 mgb4_write_reg(video, voutdev->config->regs.timer, timer); in vidioc_s_parm()
539 struct mgb4_regs *video = &voutdev->mgbdev->video; in fh_open()
540 struct device *dev = &voutdev->mgbdev->pdev->dev; in fh_open()
545 config = mgb4_read_reg(video, voutdev->config->regs.config); in fh_open()
546 if ((config & 0xc) >> 2 != voutdev->config->id + MGB4_VIN_DEVICES) { in fh_open()
547 dev_dbg(dev, "can not open - device in loopback mode"); in fh_open()
548 return -EBUSY; in fh_open()
551 mutex_lock(&voutdev->lock); in fh_open()
560 resolution = mgb4_read_reg(video, voutdev->config->regs.resolution); in fh_open()
561 voutdev->width = resolution >> 16; in fh_open()
562 voutdev->height = resolution & 0xFFFF; in fh_open()
565 mutex_unlock(&voutdev->lock); in fh_open()
583 struct device *dev = &voutdev->mgbdev->pdev->dev; in dma_transfer()
584 struct mgb4_regs *video = &voutdev->mgbdev->video; in dma_transfer()
590 spin_lock_irqsave(&voutdev->qlock, flags); in dma_transfer()
591 if (!list_empty(&voutdev->buf_list)) { in dma_transfer()
592 buf = list_first_entry(&voutdev->buf_list, in dma_transfer()
594 list_del_init(voutdev->buf_list.next); in dma_transfer()
596 spin_unlock_irqrestore(&voutdev->qlock, flags); in dma_transfer()
601 addr = mgb4_read_reg(video, voutdev->config->regs.address); in dma_transfer()
604 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in dma_transfer()
608 rv = mgb4_dma_transfer(voutdev->mgbdev, voutdev->config->dma_channel, in dma_transfer()
610 vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); in dma_transfer()
613 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in dma_transfer()
615 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); in dma_transfer()
622 struct mgb4_regs *video = &voutdev->mgbdev->video; in handler()
624 schedule_work(&voutdev->dma_work); in handler()
626 mgb4_write_reg(video, 0xB4, 1U << voutdev->config->irq); in handler()
635 struct mgb4_i2c_client *ser = &voutdev->ser; in ser_init()
636 struct device *dev = &voutdev->mgbdev->pdev->dev; in ser_init()
638 if (MGB4_IS_GMSL(voutdev->mgbdev)) in ser_init()
641 rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8); in ser_init()
662 struct mgb4_regs *video = &voutdev->mgbdev->video; in fpga_init()
663 const struct mgb4_vout_regs *regs = &voutdev->config->regs; in fpga_init()
665 mgb4_write_reg(video, regs->config, 0x00000011); in fpga_init()
666 mgb4_write_reg(video, regs->resolution, in fpga_init()
668 mgb4_write_reg(video, regs->hsync, 0x00283232); in fpga_init()
669 mgb4_write_reg(video, regs->vsync, 0x40141F1E); in fpga_init()
670 mgb4_write_reg(video, regs->frame_limit, DEFAULT_PERIOD); in fpga_init()
671 mgb4_write_reg(video, regs->padding, 0x00000000); in fpga_init()
673 voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> 1) << 1; in fpga_init()
675 mgb4_write_reg(video, regs->config, in fpga_init()
676 (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); in fpga_init()
682 struct mgb4_regs *video = &voutdev->mgbdev->video; in debugfs_init()
684 voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name, in debugfs_init()
685 voutdev->mgbdev->debugfs); in debugfs_init()
686 if (!voutdev->debugfs) in debugfs_init()
689 voutdev->regs[0].name = "CONFIG"; in debugfs_init()
690 voutdev->regs[0].offset = voutdev->config->regs.config; in debugfs_init()
691 voutdev->regs[1].name = "STATUS"; in debugfs_init()
692 voutdev->regs[1].offset = voutdev->config->regs.status; in debugfs_init()
693 voutdev->regs[2].name = "RESOLUTION"; in debugfs_init()
694 voutdev->regs[2].offset = voutdev->config->regs.resolution; in debugfs_init()
695 voutdev->regs[3].name = "VIDEO_PARAMS_1"; in debugfs_init()
696 voutdev->regs[3].offset = voutdev->config->regs.hsync; in debugfs_init()
697 voutdev->regs[4].name = "VIDEO_PARAMS_2"; in debugfs_init()
698 voutdev->regs[4].offset = voutdev->config->regs.vsync; in debugfs_init()
699 voutdev->regs[5].name = "FRAME_LIMIT"; in debugfs_init()
700 voutdev->regs[5].offset = voutdev->config->regs.frame_limit; in debugfs_init()
701 voutdev->regs[6].name = "PADDING_PIXELS"; in debugfs_init()
702 voutdev->regs[6].offset = voutdev->config->regs.padding; in debugfs_init()
704 voutdev->regs[7].name = "TIMER"; in debugfs_init()
705 voutdev->regs[7].offset = voutdev->config->regs.timer; in debugfs_init()
706 voutdev->regset.nregs = 8; in debugfs_init()
708 voutdev->regset.nregs = 7; in debugfs_init()
711 voutdev->regset.base = video->membase; in debugfs_init()
712 voutdev->regset.regs = voutdev->regs; in debugfs_init()
714 debugfs_create_regset32("registers", 0444, voutdev->debugfs, in debugfs_init()
715 &voutdev->regset); in debugfs_init()
724 struct pci_dev *pdev = mgbdev->pdev; in mgb4_vout_create()
725 struct device *dev = &pdev->dev; in mgb4_vout_create()
731 voutdev->mgbdev = mgbdev; in mgb4_vout_create()
732 voutdev->config = &vout_cfg[id]; in mgb4_vout_create()
735 INIT_LIST_HEAD(&voutdev->buf_list); in mgb4_vout_create()
736 spin_lock_init(&voutdev->qlock); in mgb4_vout_create()
739 INIT_WORK(&voutdev->dma_work, dma_transfer); in mgb4_vout_create()
742 irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); in mgb4_vout_create()
743 rv = request_irq(irq, handler, 0, "mgb4-vout", voutdev); in mgb4_vout_create()
758 rv = v4l2_device_register(dev, &voutdev->v4l2dev); in mgb4_vout_create()
764 mutex_init(&voutdev->lock); in mgb4_vout_create()
766 voutdev->queue.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; in mgb4_vout_create()
767 voutdev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; in mgb4_vout_create()
768 voutdev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); in mgb4_vout_create()
769 voutdev->queue.ops = &queue_ops; in mgb4_vout_create()
770 voutdev->queue.mem_ops = &vb2_dma_sg_memops; in mgb4_vout_create()
771 voutdev->queue.gfp_flags = GFP_DMA32; in mgb4_vout_create()
772 voutdev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in mgb4_vout_create()
773 voutdev->queue.min_queued_buffers = 2; in mgb4_vout_create()
774 voutdev->queue.drv_priv = voutdev; in mgb4_vout_create()
775 voutdev->queue.lock = &voutdev->lock; in mgb4_vout_create()
776 voutdev->queue.dev = dev; in mgb4_vout_create()
777 rv = vb2_queue_init(&voutdev->queue); in mgb4_vout_create()
783 snprintf(voutdev->vdev.name, sizeof(voutdev->vdev.name), "mgb4-out%d", in mgb4_vout_create()
785 voutdev->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE in mgb4_vout_create()
787 voutdev->vdev.vfl_dir = VFL_DIR_TX; in mgb4_vout_create()
788 voutdev->vdev.fops = &video_fops; in mgb4_vout_create()
789 voutdev->vdev.ioctl_ops = &video_ioctl_ops; in mgb4_vout_create()
790 voutdev->vdev.release = video_device_release_empty; in mgb4_vout_create()
791 voutdev->vdev.v4l2_dev = &voutdev->v4l2dev; in mgb4_vout_create()
792 voutdev->vdev.lock = &voutdev->lock; in mgb4_vout_create()
793 voutdev->vdev.queue = &voutdev->queue; in mgb4_vout_create()
794 video_set_drvdata(&voutdev->vdev, voutdev); in mgb4_vout_create()
796 rv = video_register_device(&voutdev->vdev, VFL_TYPE_VIDEO, -1); in mgb4_vout_create()
805 rv = device_add_groups(&voutdev->vdev.dev, groups); in mgb4_vout_create()
818 video_unregister_device(&voutdev->vdev); in mgb4_vout_create()
820 v4l2_device_unregister(&voutdev->v4l2dev); in mgb4_vout_create()
832 int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq); in mgb4_vout_free()
837 debugfs_remove_recursive(voutdev->debugfs); in mgb4_vout_free()
840 groups = MGB4_IS_GMSL(voutdev->mgbdev) in mgb4_vout_free()
842 device_remove_groups(&voutdev->vdev.dev, groups); in mgb4_vout_free()
844 mgb4_i2c_free(&voutdev->ser); in mgb4_vout_free()
845 video_unregister_device(&voutdev->vdev); in mgb4_vout_free()
846 v4l2_device_unregister(&voutdev->v4l2dev); in mgb4_vout_free()