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>
63 struct mgb4_regs *video = &voutdev->mgbdev->video; in get_timings()
64 const struct mgb4_vout_regs *regs = &voutdev->config->regs; in get_timings()
66 u32 hsync = mgb4_read_reg(video, regs->hsync); in get_timings()
67 u32 vsync = mgb4_read_reg(video, regs->vsync); in get_timings()
68 u32 resolution = mgb4_read_reg(video, regs->resolution); in get_timings()
71 timings->type = V4L2_DV_BT_656_1120; in get_timings()
72 timings->bt.width = resolution >> 16; in get_timings()
73 timings->bt.height = resolution & 0xFFFF; in get_timings()
75 timings->bt.polarities |= V4L2_DV_HSYNC_POS_POL; in get_timings()
77 timings->bt.polarities |= V4L2_DV_VSYNC_POS_POL; in get_timings()
78 timings->bt.pixelclock = voutdev->freq * 1000; in get_timings()
79 timings->bt.hsync = (hsync & 0x00FF0000) >> 16; in get_timings()
80 timings->bt.vsync = (vsync & 0x00FF0000) >> 16; in get_timings()
81 timings->bt.hbackporch = (hsync & 0x0000FF00) >> 8; in get_timings()
82 timings->bt.hfrontporch = hsync & 0x000000FF; in get_timings()
83 timings->bt.vbackporch = (vsync & 0x0000FF00) >> 8; in get_timings()
84 timings->bt.vfrontporch = vsync & 0x000000FF; in get_timings()
93 spin_lock_irqsave(&voutdev->qlock, flags); in return_all_buffers()
94 list_for_each_entry_safe(buf, node, &voutdev->buf_list, list) { in return_all_buffers()
95 vb2_buffer_done(&buf->vb.vb2_buf, state); in return_all_buffers()
96 list_del(&buf->list); in return_all_buffers()
98 spin_unlock_irqrestore(&voutdev->qlock, flags); in return_all_buffers()
106 struct mgb4_regs *video = &voutdev->mgbdev->video; in queue_setup()
107 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in queue_setup()
109 unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height in queue_setup()
117 if (test_bit(0, &voutdev->mgbdev->io_reconfig)) in queue_setup()
118 return -EBUSY; in queue_setup()
121 return sizes[0] < size ? -EINVAL : 0; in queue_setup()
133 INIT_LIST_HEAD(&buf->list); in buffer_init()
140 struct mgb4_vout_dev *voutdev = vb2_get_drv_priv(vb->vb2_queue); in buffer_prepare()
141 struct device *dev = &voutdev->mgbdev->pdev->dev; in buffer_prepare()
142 struct mgb4_regs *video = &voutdev->mgbdev->video; in buffer_prepare()
143 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in buffer_prepare()
145 unsigned int size = (voutdev->width + voutdev->padding) * voutdev->height in buffer_prepare()
151 return -EINVAL; in buffer_prepare()
161 struct mgb4_vout_dev *vindev = vb2_get_drv_priv(vb->vb2_queue); in buffer_queue()
166 spin_lock_irqsave(&vindev->qlock, flags); in buffer_queue()
167 list_add_tail(&buf->list, &vindev->buf_list); in buffer_queue()
168 spin_unlock_irqrestore(&vindev->qlock, flags); in buffer_queue()
174 struct mgb4_dev *mgbdev = voutdev->mgbdev; in stop_streaming()
175 int irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); in stop_streaming()
177 xdma_disable_user_irq(mgbdev->xdev, irq); in stop_streaming()
178 cancel_work_sync(&voutdev->dma_work); in stop_streaming()
180 mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x2, 0x0); in stop_streaming()
181 mgb4_write_reg(&mgbdev->video, voutdev->config->regs.padding, 0); in stop_streaming()
189 struct mgb4_dev *mgbdev = voutdev->mgbdev; in start_streaming()
190 struct device *dev = &mgbdev->pdev->dev; in start_streaming()
192 struct mgb4_regs *video = &mgbdev->video; in start_streaming()
193 const struct mgb4_vout_config *config = voutdev->config; in start_streaming()
194 int irq = xdma_get_user_irq(mgbdev->xdev, config->irq); in start_streaming()
198 mgb4_write_reg(video, config->regs.padding, voutdev->padding); 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()
238 strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); in vidioc_querycap()
239 strscpy(cap->card, "MGB4 PCIe Card", sizeof(cap->card)); in vidioc_querycap()
248 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_enum_fmt()
250 if (f->index == 0) { in vidioc_enum_fmt()
251 f->pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_enum_fmt()
253 } else if (f->index == 1 && has_yuv(video)) { in vidioc_enum_fmt()
254 f->pixelformat = V4L2_PIX_FMT_YUYV; in vidioc_enum_fmt()
257 return -EINVAL; in vidioc_enum_fmt()
264 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_g_fmt()
265 u32 config = mgb4_read_reg(video, voutdev->config->regs.config); in vidioc_g_fmt()
267 f->fmt.pix.width = voutdev->width; in vidioc_g_fmt()
268 f->fmt.pix.height = voutdev->height; in vidioc_g_fmt()
269 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_g_fmt()
272 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; in vidioc_g_fmt()
274 f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; in vidioc_g_fmt()
277 f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; in vidioc_g_fmt()
279 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; in vidioc_g_fmt()
281 f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 2; in vidioc_g_fmt()
283 f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_g_fmt()
284 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; in vidioc_g_fmt()
285 f->fmt.pix.bytesperline = (f->fmt.pix.width + voutdev->padding) * 4; in vidioc_g_fmt()
288 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; in vidioc_g_fmt()
296 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_try_fmt()
299 f->fmt.pix.width = voutdev->width; in vidioc_try_fmt()
300 f->fmt.pix.height = voutdev->height; in vidioc_try_fmt()
301 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_try_fmt()
303 if (has_yuv(video) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { in vidioc_try_fmt()
305 if (!(f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709 || in vidioc_try_fmt()
306 f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M)) in vidioc_try_fmt()
307 f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; in vidioc_try_fmt()
310 f->fmt.pix.pixelformat = V4L2_PIX_FMT_ABGR32; in vidioc_try_fmt()
311 f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; in vidioc_try_fmt()
314 if (f->fmt.pix.bytesperline > f->fmt.pix.width * pixelsize && in vidioc_try_fmt()
315 f->fmt.pix.bytesperline < f->fmt.pix.width * pixelsize * 2) in vidioc_try_fmt()
316 f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline, in vidioc_try_fmt()
319 f->fmt.pix.bytesperline = f->fmt.pix.width * pixelsize; in vidioc_try_fmt()
320 f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; in vidioc_try_fmt()
328 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_s_fmt()
332 if (vb2_is_busy(&voutdev->queue)) in vidioc_s_fmt()
333 return -EBUSY; in vidioc_s_fmt()
339 config = mgb4_read_reg(video, voutdev->config->regs.config); in vidioc_s_fmt()
340 if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { in vidioc_s_fmt()
344 if (f->fmt.pix.colorspace == V4L2_COLORSPACE_REC709) { in vidioc_s_fmt()
347 } else if (f->fmt.pix.colorspace == V4L2_COLORSPACE_SMPTE170M) { in vidioc_s_fmt()
358 mgb4_write_reg(video, voutdev->config->regs.config, config); in vidioc_s_fmt()
360 voutdev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width in vidioc_s_fmt()
374 return i ? -EINVAL : 0; in vidioc_s_output()
380 if (out->index != 0) in vidioc_enum_output()
381 return -EINVAL; in vidioc_enum_output()
383 out->type = V4L2_OUTPUT_TYPE_ANALOG; in vidioc_enum_output()
384 out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; in vidioc_enum_output()
385 strscpy(out->name, "MGB4", sizeof(out->name)); in vidioc_enum_output()
394 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_enum_frameintervals()
397 if (ival->index != 0) in vidioc_enum_frameintervals()
398 return -EINVAL; in vidioc_enum_frameintervals()
399 if (!(ival->pixel_format == V4L2_PIX_FMT_ABGR32 || in vidioc_enum_frameintervals()
400 ((has_yuv(video) && ival->pixel_format == V4L2_PIX_FMT_YUYV)))) in vidioc_enum_frameintervals()
401 return -EINVAL; in vidioc_enum_frameintervals()
402 if (ival->width != voutdev->width || ival->height != voutdev->height) in vidioc_enum_frameintervals()
403 return -EINVAL; in vidioc_enum_frameintervals()
407 ival->type = V4L2_FRMIVAL_TYPE_STEPWISE; in vidioc_enum_frameintervals()
408 ival->stepwise.max.denominator = MGB4_HW_FREQ; in vidioc_enum_frameintervals()
409 ival->stepwise.max.numerator = 0xFFFFFFFF; in vidioc_enum_frameintervals()
410 ival->stepwise.min.denominator = timings.bt.pixelclock; in vidioc_enum_frameintervals()
411 ival->stepwise.min.numerator = pixel_size(&timings); in vidioc_enum_frameintervals()
412 ival->stepwise.step.denominator = MGB4_HW_FREQ; in vidioc_enum_frameintervals()
413 ival->stepwise.step.numerator = 1; in vidioc_enum_frameintervals()
422 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_g_parm()
423 struct v4l2_fract *tpf = &parm->parm.output.timeperframe; in vidioc_g_parm()
425 u32 timer; in vidioc_g_parm() local
427 parm->parm.output.writebuffers = 2; in vidioc_g_parm()
430 timer = mgb4_read_reg(video, voutdev->config->regs.timer); in vidioc_g_parm()
431 if (timer < 0xFFFF) { in vidioc_g_parm()
433 tpf->numerator = pixel_size(&timings); in vidioc_g_parm()
434 tpf->denominator = timings.bt.pixelclock; in vidioc_g_parm()
436 tpf->numerator = timer; in vidioc_g_parm()
437 tpf->denominator = MGB4_HW_FREQ; in vidioc_g_parm()
440 parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; in vidioc_g_parm()
450 struct mgb4_regs *video = &voutdev->mgbdev->video; in vidioc_s_parm()
451 struct v4l2_fract *tpf = &parm->parm.output.timeperframe; in vidioc_s_parm()
453 u32 timer, period; in vidioc_s_parm() local
456 timer = tpf->denominator ? in vidioc_s_parm()
457 MGB4_PERIOD(tpf->numerator, tpf->denominator) : 0; in vidioc_s_parm()
458 if (timer) { in vidioc_s_parm()
462 if (timer < period) in vidioc_s_parm()
463 timer = 0; in vidioc_s_parm()
466 mgb4_write_reg(video, voutdev->config->regs.timer, timer); in vidioc_s_parm()
536 struct mgb4_regs *video = &voutdev->mgbdev->video; in fh_open()
537 struct device *dev = &voutdev->mgbdev->pdev->dev; in fh_open()
542 config = mgb4_read_reg(video, voutdev->config->regs.config); in fh_open()
543 if ((config & 0xc) >> 2 != voutdev->config->id + MGB4_VIN_DEVICES) { in fh_open()
544 dev_dbg(dev, "can not open - device in loopback mode"); in fh_open()
545 return -EBUSY; in fh_open()
548 mutex_lock(&voutdev->lock); in fh_open()
557 resolution = mgb4_read_reg(video, voutdev->config->regs.resolution); in fh_open()
558 voutdev->width = resolution >> 16; in fh_open()
559 voutdev->height = resolution & 0xFFFF; in fh_open()
562 mutex_unlock(&voutdev->lock); in fh_open()
580 struct device *dev = &voutdev->mgbdev->pdev->dev; in dma_transfer()
581 struct mgb4_regs *video = &voutdev->mgbdev->video; in dma_transfer()
587 spin_lock_irqsave(&voutdev->qlock, flags); in dma_transfer()
588 if (!list_empty(&voutdev->buf_list)) { in dma_transfer()
589 buf = list_first_entry(&voutdev->buf_list, in dma_transfer()
591 list_del_init(voutdev->buf_list.next); in dma_transfer()
593 spin_unlock_irqrestore(&voutdev->qlock, flags); in dma_transfer()
598 addr = mgb4_read_reg(video, voutdev->config->regs.address); in dma_transfer()
601 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in dma_transfer()
605 rv = mgb4_dma_transfer(voutdev->mgbdev, voutdev->config->dma_channel, in dma_transfer()
607 vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0)); in dma_transfer()
610 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); in dma_transfer()
612 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); in dma_transfer()
619 struct mgb4_regs *video = &voutdev->mgbdev->video; in handler()
621 schedule_work(&voutdev->dma_work); in handler()
623 mgb4_write_reg(video, 0xB4, 1U << voutdev->config->irq); in handler()
632 struct mgb4_i2c_client *ser = &voutdev->ser; in ser_init()
633 struct device *dev = &voutdev->mgbdev->pdev->dev; in ser_init()
635 if (MGB4_IS_GMSL(voutdev->mgbdev)) in ser_init()
638 rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8); in ser_init()
659 struct mgb4_regs *video = &voutdev->mgbdev->video; in fpga_init()
660 const struct mgb4_vout_regs *regs = &voutdev->config->regs; in fpga_init()
662 mgb4_write_reg(video, regs->config, 0x00000011); in fpga_init()
663 mgb4_write_reg(video, regs->resolution, (1280 << 16) | 640); in fpga_init()
664 mgb4_write_reg(video, regs->hsync, 0x00283232); in fpga_init()
665 mgb4_write_reg(video, regs->vsync, 0x40141F1E); in fpga_init()
666 mgb4_write_reg(video, regs->frame_limit, MGB4_HW_FREQ / 60); in fpga_init()
667 mgb4_write_reg(video, regs->padding, 0x00000000); in fpga_init()
669 voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> 1) << 1; in fpga_init()
671 mgb4_write_reg(video, regs->config, in fpga_init()
672 (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); in fpga_init()
678 struct mgb4_regs *video = &voutdev->mgbdev->video; in create_debugfs()
681 if (IS_ERR_OR_NULL(voutdev->mgbdev->debugfs)) in create_debugfs()
683 entry = debugfs_create_dir(voutdev->vdev.name, voutdev->mgbdev->debugfs); in create_debugfs()
687 voutdev->regs[0].name = "CONFIG"; in create_debugfs()
688 voutdev->regs[0].offset = voutdev->config->regs.config; in create_debugfs()
689 voutdev->regs[1].name = "STATUS"; in create_debugfs()
690 voutdev->regs[1].offset = voutdev->config->regs.status; in create_debugfs()
691 voutdev->regs[2].name = "RESOLUTION"; in create_debugfs()
692 voutdev->regs[2].offset = voutdev->config->regs.resolution; in create_debugfs()
693 voutdev->regs[3].name = "VIDEO_PARAMS_1"; in create_debugfs()
694 voutdev->regs[3].offset = voutdev->config->regs.hsync; in create_debugfs()
695 voutdev->regs[4].name = "VIDEO_PARAMS_2"; in create_debugfs()
696 voutdev->regs[4].offset = voutdev->config->regs.vsync; in create_debugfs()
697 voutdev->regs[5].name = "FRAME_LIMIT"; in create_debugfs()
698 voutdev->regs[5].offset = voutdev->config->regs.frame_limit; in create_debugfs()
699 voutdev->regs[6].name = "PADDING_PIXELS"; in create_debugfs()
700 voutdev->regs[6].offset = voutdev->config->regs.padding; in create_debugfs()
702 voutdev->regs[7].name = "TIMER"; in create_debugfs()
703 voutdev->regs[7].offset = voutdev->config->regs.timer; in create_debugfs()
704 voutdev->regset.nregs = 8; in create_debugfs()
706 voutdev->regset.nregs = 7; in create_debugfs()
709 voutdev->regset.base = video->membase; in create_debugfs()
710 voutdev->regset.regs = voutdev->regs; in create_debugfs()
712 debugfs_create_regset32("registers", 0444, entry, &voutdev->regset); in create_debugfs()
721 struct pci_dev *pdev = mgbdev->pdev; in mgb4_vout_create()
722 struct device *dev = &pdev->dev; in mgb4_vout_create()
728 voutdev->mgbdev = mgbdev; in mgb4_vout_create()
729 voutdev->config = &vout_cfg[id]; in mgb4_vout_create()
732 INIT_LIST_HEAD(&voutdev->buf_list); in mgb4_vout_create()
733 spin_lock_init(&voutdev->qlock); in mgb4_vout_create()
736 INIT_WORK(&voutdev->dma_work, dma_transfer); in mgb4_vout_create()
739 irq = xdma_get_user_irq(mgbdev->xdev, voutdev->config->irq); in mgb4_vout_create()
740 rv = request_irq(irq, handler, 0, "mgb4-vout", voutdev); in mgb4_vout_create()
755 rv = v4l2_device_register(dev, &voutdev->v4l2dev); in mgb4_vout_create()
761 mutex_init(&voutdev->lock); in mgb4_vout_create()
763 voutdev->queue.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; in mgb4_vout_create()
764 voutdev->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; in mgb4_vout_create()
765 voutdev->queue.buf_struct_size = sizeof(struct mgb4_frame_buffer); in mgb4_vout_create()
766 voutdev->queue.ops = &queue_ops; in mgb4_vout_create()
767 voutdev->queue.mem_ops = &vb2_dma_sg_memops; in mgb4_vout_create()
768 voutdev->queue.gfp_flags = GFP_DMA32; in mgb4_vout_create()
769 voutdev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in mgb4_vout_create()
770 voutdev->queue.min_queued_buffers = 2; in mgb4_vout_create()
771 voutdev->queue.drv_priv = voutdev; in mgb4_vout_create()
772 voutdev->queue.lock = &voutdev->lock; in mgb4_vout_create()
773 voutdev->queue.dev = dev; in mgb4_vout_create()
774 rv = vb2_queue_init(&voutdev->queue); in mgb4_vout_create()
780 snprintf(voutdev->vdev.name, sizeof(voutdev->vdev.name), "mgb4-out%d", in mgb4_vout_create()
782 voutdev->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE in mgb4_vout_create()
784 voutdev->vdev.vfl_dir = VFL_DIR_TX; in mgb4_vout_create()
785 voutdev->vdev.fops = &video_fops; in mgb4_vout_create()
786 voutdev->vdev.ioctl_ops = &video_ioctl_ops; in mgb4_vout_create()
787 voutdev->vdev.release = video_device_release_empty; in mgb4_vout_create()
788 voutdev->vdev.v4l2_dev = &voutdev->v4l2dev; in mgb4_vout_create()
789 voutdev->vdev.lock = &voutdev->lock; in mgb4_vout_create()
790 voutdev->vdev.queue = &voutdev->queue; in mgb4_vout_create()
791 video_set_drvdata(&voutdev->vdev, voutdev); in mgb4_vout_create()
793 rv = video_register_device(&voutdev->vdev, VFL_TYPE_VIDEO, -1); in mgb4_vout_create()
802 rv = device_add_groups(&voutdev->vdev.dev, groups); in mgb4_vout_create()
813 video_unregister_device(&voutdev->vdev); in mgb4_vout_create()
815 v4l2_device_unregister(&voutdev->v4l2dev); in mgb4_vout_create()
827 int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq); in mgb4_vout_free()
831 groups = MGB4_IS_GMSL(voutdev->mgbdev) in mgb4_vout_free()
833 device_remove_groups(&voutdev->vdev.dev, groups); in mgb4_vout_free()
835 mgb4_i2c_free(&voutdev->ser); in mgb4_vout_free()
836 video_unregister_device(&voutdev->vdev); in mgb4_vout_free()
837 v4l2_device_unregister(&voutdev->v4l2dev); in mgb4_vout_free()