TW686x driver
Subsystems (2)
cover TW686x driver
Hi,
I'm posting a driver for TW686[4589]-based PCIe cards. The first patch has been posted and reviewed by Ezequiel back in July 2015, the subsequent patches are changes made in response to the review and/or are required by the more recent kernel versions.
This driver lacks CMA-based frame mode DMA operation, I'll add it a bit later. Also:
- I haven't converted the kthread to a workqueue - the driver is modeled after other code and it can be done later, if needed
- I have skipped suggested PCI ID changes and the 704 vs 720 pixels/line question - this may need further consideration.
Please merge.
The following changes since Linux 4.4 are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/chris/linux.git techwell-4.4
for you to fetch changes up to 8e495778acd4602c472cefa460a1afb41c4b8f25:
[MEDIA] TW686x: return VB2_BUF_STATE_ERROR frames on timeout/errors (2016-01-27 14:47:41 +0100)
----------------------------------------------------------------
Krzysztof Hałasa (12):
[MEDIA] Add support for TW686[4589]-based frame grabbers [MEDIA] TW686x: Trivial changes suggested by Ezequiel Garcia [MEDIA] TW686x: Switch to devm_*()
[MEDIA] TW686x: Fix s_std() / g_std() / g_parm() pointer to self [MEDIA] TW686x: Fix handling of TV standard values [MEDIA] TW686x: Fix try_fmt() color space
[MEDIA] TW686x: Add enum_input() / g_input() / s_input() [MEDIA] TW686x: do not use pci_dma_supported()
[MEDIA] TW686x: switch to vb2_v4l2_buffer
[MEDIA] TW686x: handle non-NULL format in queue_setup() [MEDIA] TW686x: Track frame sequence numbers
[MEDIA] TW686x: return VB2_BUF_STATE_ERROR frames on timeout/errors
drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/tw686x/Kconfig | 16 ++ drivers/media/pci/tw686x/Makefile | 3 + drivers/media/pci/tw686x/tw686x-core.c | 140 +++++++++++++ drivers/media/pci/tw686x/tw686x-regs.h | 103 +++++++++ drivers/media/pci/tw686x/tw686x-video.c | 815 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/media/pci/tw686x/tw686x.h | 118 +++++++++++ 8 files changed, 1197 insertions(+) create mode 100644 drivers/media/pci/tw686x/Kconfig create mode 100644 drivers/media/pci/tw686x/Makefile create mode 100644 drivers/media/pci/tw686x/tw686x-core.c create mode 100644 drivers/media/pci/tw686x/tw686x-regs.h create mode 100644 drivers/media/pci/tw686x/tw686x-video.c create mode 100644 drivers/media/pci/tw686x/tw686x.h
Thanks.
Signature · 4 lines
Krzysztof Halasa Industrial Research Institute for Automation and Measurements PIAP Al. Jerozolimskie 202, 02-486 Warsaw, Poland
PATCH 1/12 Add support for TW686[4589]-based frame grabbers
drivers/media/pci/Kconfig +1 -0
@@ -14,6 +14,7 @@ source "drivers/media/pci/meye/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/sta2x11/Kconfig" source "drivers/media/pci/tw68/Kconfig" +source "drivers/media/pci/tw686x/Kconfig" source "drivers/media/pci/zoran/Kconfig" endif
drivers/media/pci/Makefile +1 -0
@@ -25,6 +25,7 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_TW68) += tw68/ +obj-$(CONFIG_VIDEO_TW686X) += tw686x/ obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/
drivers/media/pci/tw686x/Kconfig new file +16 -0
@@ -0,0 +1,16 @@ +config VIDEO_TW686X + tristate "Intersil/Techwell TW686x Video For Linux" + depends on VIDEO_DEV && PCI && VIDEO_V4L2 + select VIDEOBUF2_DMA_SG + help + Support for Intersil/Techwell TW686x-based frame grabber cards. + + Currently supported chips: + - TW6864 (4 video channels), + - TW6865 (4 video channels, not tested, second generation chip), + - TW6868 (8 video channels but only 4 first channels using + built-in video decoder are supported, not tested), + - TW6869 (8 video channels, second generation chip). + + To compile this driver as a module, choose M here: the module + will be named tw686x.
drivers/media/pci/tw686x/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +tw686x-objs := tw686x-core.o tw686x-video.o + +obj-$(CONFIG_VIDEO_TW686X) += tw686x.o
drivers/media/pci/tw686x/tw686x-core.c new file +176 -0
176 lines not on this page · raw message
drivers/media/pci/tw686x/tw686x-regs.h new file +103 -0
103 lines not on this page · raw message
drivers/media/pci/tw686x/tw686x-video.c new file +776 -0
776 lines not on this page · raw message
drivers/media/pci/tw686x/tw686x.h new file +117 -0
117 lines not on this page · raw message
PATCH 2/12 TW686x: Trivial changes suggested by Ezequiel Garcia
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-core.c +13 -26
@@ -1,13 +1,13 @@/* -Copyright (C) 2015 Industrial Research Institute for Automation -and Measurements PIAP - -Written by Krzysztof Hałasa. - -This program is free software; you can redistribute it and/or modify it -under the terms of version 2 of the GNU General Public License -as published by the Free Software Foundation. -*/ +* Copyright (C) 2015 Industrial Research Institute for Automation +* and Measurements PIAP +* +* Written by Krzysztof Hałasa. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License +* as published by the Free Software Foundation. +*/ #include <linux/init.h> #include <linux/interrupt.h>
@@ -68,15 +68,13 @@ static int tw686x_probe(struct pci_dev *pci_dev, goto disable; } -if (!request_mem_region (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 ), dev->name)) { + err =pci_request_regions (pci_dev, dev->name); +if (err <0 ) {pr_err ("%s: Unable to get MMIO region\n" , dev->name); - err = -EBUSY ; goto disable; } - dev->mmio =ioremap_nocache (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 )); + dev->mmio =pci_ioremap_bar (pci_dev,0 );if (!dev->mmio) {pr_err ("%s: Unable to remap MMIO region\n" , dev->name); err = -EIO ;
@@ -158,19 +156,8 @@ static struct pci_driver tw686x_pci_driver = { .remove = tw686x_remove, }; -static int tw686x_init (void ) -{ -return pci_register_driver (&tw686x_pci_driver); -} - -static void tw686x_exit (void ) -{ -pci_unregister_driver (&tw686x_pci_driver); -} -MODULE_DESCRIPTION ("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]" );MODULE_AUTHOR ("Krzysztof Halasa" );MODULE_LICENSE ("GPL v2" );MODULE_DEVICE_TABLE (pci, tw686x_pci_tbl); -module_init (tw686x_init); -module_exit (tw686x_exit); +module_pci_driver (tw686x_pci_driver);
drivers/media/pci/tw686x/tw686x-regs.h +4 -4
@@ -16,10 +16,10 @@ 0xD6, 0xD8, 0xDA, 0xDC})#define DMA_PAGE_TABLE1_ADDR ((const u16[8]){0x09, 0xD1, 0xD3, 0xD5, \ 0xD7, 0xD9, 0xDB, 0xDD}) -#define DMA_CHANNEL_ENABLE 0x0a -#define DMA_CONFIG 0x0b -#define DMA_TIMER_INTERVAL 0x0c -#define DMA_CHANNEL_TIMEOUT 0x0d +#define DMA_CHANNEL_ENABLE 0x0A +#define DMA_CONFIG 0x0B +#define DMA_TIMER_INTERVAL 0x0C +#define DMA_CHANNEL_TIMEOUT 0x0D#define VDMA_CHANNEL_CONFIG REG8_1(0x10)#define ADMA_P_ADDR REG8_2(0x18)#define ADMA_B_ADDR REG8_2(0x19)
drivers/media/pci/tw686x/tw686x-video.c +9 -9
@@ -1,13 +1,13 @@/* -Copyright (C) 2015 Industrial Research Institute for Automation -and Measurements PIAP - -Written by Krzysztof Hałasa. - -This program is free software; you can redistribute it and/or modify it -under the terms of version 2 of the GNU General Public License -as published by the Free Software Foundation. -*/ +* Copyright (C) 2015 Industrial Research Institute for Automation +* and Measurements PIAP +* +* Written by Krzysztof Hałasa. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License +* as published by the Free Software Foundation. +*/ #include <linux/init.h> #include <linux/list.h>
drivers/media/pci/tw686x/tw686x.h +9 -9
@@ -1,13 +1,13 @@/* -Copyright (C) 2015 Industrial Research Institute for Automation -and Measurements PIAP - -Written by Krzysztof Hałasa. - -This program is free software; you can redistribute it and/or modify it -under the terms of version 2 of the GNU General Public License -as published by the Free Software Foundation. -*/ +* Copyright (C) 2015 Industrial Research Institute for Automation +* and Measurements PIAP +* +* Written by Krzysztof Hałasa. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License +* as published by the Free Software Foundation. +*/ #include <linux/delay.h> #include <linux/freezer.h>
Re: [PATCH 3/12] TW686x: Switch to devm_*()
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-core.c +12 -35
@@ -42,8 +42,9 @@ static int tw686x_probe(struct pci_dev *pci_dev,struct tw686x_dev *dev;int err; - dev =kzalloc (sizeof (*dev) + (pci_id->driver_data &TYPE_MAX_CHANNELS ) * -sizeof (dev->video_channels[0 ]),GFP_KERNEL ); + dev =devm_kzalloc (&pci_dev->dev, +sizeof (*dev) + (pci_id->driver_data &TYPE_MAX_CHANNELS ) * +sizeof (dev->video_channels[0 ]),GFP_KERNEL );if (!dev)return -ENOMEM ;
@@ -55,30 +56,26 @@ static int tw686x_probe(struct pci_dev *pci_dev, (unsigned long)pci_resource_start(pci_dev, 0)); dev->pci_dev = pci_dev; -if (pci_enable_device (pci_dev)) { - err = -EIO ; - goto free_dev; - } +if (pcim_enable_device (pci_dev)) +return -EIO ;pci_set_master (pci_dev);if (!pci_dma_supported (pci_dev,DMA_BIT_MASK (32 ))) {pr_err ("%s: 32-bit PCI DMA not supported\n" , dev->name); - err = -EIO ; - goto disable; +return -EIO ; } err =pci_request_regions (pci_dev, dev->name);if (err <0 ) {pr_err ("%s: Unable to get MMIO region\n" , dev->name); - goto disable; +return err; } dev->mmio =pci_ioremap_bar (pci_dev,0 );if (!dev->mmio) {pr_err ("%s: Unable to remap MMIO region\n" , dev->name); - err = -EIO ; - goto free_region; +return -EIO ; }reg_write (dev,SYS_SOFT_RST ,0x0F );/* Reset all subsystems */
@@ -95,32 +92,19 @@ static int tw686x_probe(struct pci_dev *pci_dev,spin_lock_init (&dev->irq_lock); - err =request_irq (pci_dev->irq, tw686x_irq,IRQF_SHARED , dev->name, - dev); + err =devm_request_irq (&pci_dev->dev, pci_dev->irq, tw686x_irq, +IRQF_SHARED , dev->name, dev);if (err <0 ) {pr_err ("%s: Unable to get IRQ\n" , dev->name); - goto iounmap; +return err; } err =tw686x_video_init (dev);if (err) - goto free_irq; +return err;pci_set_drvdata (pci_dev, dev);return 0 ; - -free_irq: -free_irq (pci_dev->irq, dev); -iounmap: -iounmap (dev->mmio); -free_region: -release_mem_region (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 )); -disable: -pci_disable_device (pci_dev); -free_dev: -kfree (dev); -return err; }static void tw686x_remove (struct pci_dev *pci_dev)
@@ -128,13 +112,6 @@ static void tw686x_remove(struct pci_dev *pci_dev)struct tw686x_dev *dev =pci_get_drvdata (pci_dev);tw686x_video_free (dev); - -free_irq (pci_dev->irq, dev); -iounmap (dev->mmio); -release_mem_region (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 )); -pci_disable_device (pci_dev); -kfree (dev); }/* driver_data is number of A/V channels */
Re: [PATCH 4/12] TW686x: Fix s_std() / g_std() / g_parm() pointer to self
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +3 -3
@@ -416,7 +416,7 @@ static int tw686x_querycap(struct file *file, void *priv,static int tw686x_s_std (struct file *file,void *priv,v4l2_std_id id) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file);unsigned std, count =0 ;u32 sdt, std_mask =0 ;
@@ -437,7 +437,7 @@ static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)static int tw686x_g_std (struct file *file,void *priv,v4l2_std_id *id) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file); *id = vc->video_standard;return 0 ;
@@ -457,7 +457,7 @@ static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,static int tw686x_g_parm (struct file *file,void *priv,struct v4l2_streamparm *sp) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file);if (sp->type !=V4L2_BUF_TYPE_VIDEO_CAPTURE )return -EINVAL ;
PATCH 3/12 TW686x: Switch to devm_*()
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-core.c +12 -35
@@ -42,8 +42,9 @@ static int tw686x_probe(struct pci_dev *pci_dev,struct tw686x_dev *dev;int err; - dev =kzalloc (sizeof (*dev) + (pci_id->driver_data &TYPE_MAX_CHANNELS ) * -sizeof (dev->video_channels[0 ]),GFP_KERNEL ); + dev =devm_kzalloc (&pci_dev->dev, +sizeof (*dev) + (pci_id->driver_data &TYPE_MAX_CHANNELS ) * +sizeof (dev->video_channels[0 ]),GFP_KERNEL );if (!dev)return -ENOMEM ;
@@ -55,30 +56,26 @@ static int tw686x_probe(struct pci_dev *pci_dev, (unsigned long)pci_resource_start(pci_dev, 0)); dev->pci_dev = pci_dev; -if (pci_enable_device (pci_dev)) { - err = -EIO ; - goto free_dev; - } +if (pcim_enable_device (pci_dev)) +return -EIO ;pci_set_master (pci_dev);if (!pci_dma_supported (pci_dev,DMA_BIT_MASK (32 ))) {pr_err ("%s: 32-bit PCI DMA not supported\n" , dev->name); - err = -EIO ; - goto disable; +return -EIO ; } err =pci_request_regions (pci_dev, dev->name);if (err <0 ) {pr_err ("%s: Unable to get MMIO region\n" , dev->name); - goto disable; +return err; } dev->mmio =pci_ioremap_bar (pci_dev,0 );if (!dev->mmio) {pr_err ("%s: Unable to remap MMIO region\n" , dev->name); - err = -EIO ; - goto free_region; +return -EIO ; }reg_write (dev,SYS_SOFT_RST ,0x0F );/* Reset all subsystems */
@@ -95,32 +92,19 @@ static int tw686x_probe(struct pci_dev *pci_dev,spin_lock_init (&dev->irq_lock); - err =request_irq (pci_dev->irq, tw686x_irq,IRQF_SHARED , dev->name, - dev); + err =devm_request_irq (&pci_dev->dev, pci_dev->irq, tw686x_irq, +IRQF_SHARED , dev->name, dev);if (err <0 ) {pr_err ("%s: Unable to get IRQ\n" , dev->name); - goto iounmap; +return err; } err =tw686x_video_init (dev);if (err) - goto free_irq; +return err;pci_set_drvdata (pci_dev, dev);return 0 ; - -free_irq: -free_irq (pci_dev->irq, dev); -iounmap: -iounmap (dev->mmio); -free_region: -release_mem_region (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 )); -disable: -pci_disable_device (pci_dev); -free_dev: -kfree (dev); -return err; }static void tw686x_remove (struct pci_dev *pci_dev)
@@ -128,13 +112,6 @@ static void tw686x_remove(struct pci_dev *pci_dev)struct tw686x_dev *dev =pci_get_drvdata (pci_dev);tw686x_video_free (dev); - -free_irq (pci_dev->irq, dev); -iounmap (dev->mmio); -release_mem_region (pci_resource_start (pci_dev,0 ), -pci_resource_len (pci_dev,0 )); -pci_disable_device (pci_dev); -kfree (dev); }/* driver_data is number of A/V channels */
PATCH 4/12 TW686x: Fix s_std() / g_std() / g_parm() pointer to self
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +3 -3
@@ -416,7 +416,7 @@ static int tw686x_querycap(struct file *file, void *priv,static int tw686x_s_std (struct file *file,void *priv,v4l2_std_id id) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file);unsigned std, count =0 ;u32 sdt, std_mask =0 ;
@@ -437,7 +437,7 @@ static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)static int tw686x_g_std (struct file *file,void *priv,v4l2_std_id *id) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file); *id = vc->video_standard;return 0 ;
@@ -457,7 +457,7 @@ static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,static int tw686x_g_parm (struct file *file,void *priv,struct v4l2_streamparm *sp) { -struct tw686x_video_channel *vc = priv; +struct tw686x_video_channel *vc =video_drvdata (file);if (sp->type !=V4L2_BUF_TYPE_VIDEO_CAPTURE )return -EINVAL ;
PATCH 5/12 TW686x: Fix handling of TV standard values
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +13 -17
@@ -417,18 +417,14 @@ static int tw686x_querycap(struct file *file, void *priv,static int tw686x_s_std (struct file *file,void *priv,v4l2_std_id id) {struct tw686x_video_channel *vc =video_drvdata (file); -unsigned std, count =0 ; -u32 sdt, std_mask =0 ; - -for (std =0 ; std >ARRAY_SIZE (video_standards); std++) -if (id & video_standards[std]) { - sdt = std; - std_mask |=1 << std; - count++; - } +unsigned cnt; +u32 sdt =0 ;/* default */ -if (count !=1 ) -return -EINVAL ;/* must request exactly one standard */ +for (cnt =0 ; cnt <ARRAY_SIZE (video_standards); cnt++) +if (id & video_standards[cnt]) { + sdt = cnt; +break ; + }reg_write (vc->dev,SDT [vc->ch], sdt); vc->video_standard = video_standards[sdt];
@@ -658,12 +654,13 @@ int tw686x_video_init(struct tw686x_dev *dev) vc->dev = dev; vc->ch = ch; -/* default settings */ +/* default settings: NTSC */ vc->format = &formats[0 ]; - vc->video_standard =V4L2_STD_PAL ; - vc->field =V4L2_FIELD_SEQ_TB ; + vc->video_standard =V4L2_STD_NTSC ; +reg_write (vc->dev,SDT [vc->ch],0 ); + vc->field =V4L2_FIELD_SEQ_BT ; vc->width =704 ; - vc->height =576 ; + vc->height =480 ;for (n =0 ; n <2 ; n++) {void *cpu;
@@ -733,8 +730,7 @@ int tw686x_video_init(struct tw686x_dev *dev) vdev->release = video_device_release; vdev->v4l2_dev = &dev->v4l2_dev; vdev->queue = &vc->vidq; - vdev->tvnorms =V4L2_STD_PAL |V4L2_STD_NTSC |V4L2_STD_SECAM | -V4L2_STD_PAL_60 ; + vdev->tvnorms =V4L2_STD_ALL ; vdev->minor =-1 ; vdev->lock = &vc->vb_mutex;
PATCH 6/12 TW686x: Fix try_fmt() color space
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +1 -0
@@ -379,6 +379,7 @@ static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.height = height; f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth /8 ; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace =V4L2_COLORSPACE_SMPTE170M ;return 0 ; }
PATCH 7/12 TW686x: Add enum_input() / g_input() / s_input()
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +31 -0
@@ -466,6 +466,34 @@ static int tw686x_g_parm(struct file *file, void *priv,return 0 ; } +static int tw686x_enum_input (struct file *file,void *priv, +struct v4l2_input *inp) +{ +/* the chip has internal multiplexer, support can be added +if the actual hw uses it */ +if (inp->index) +return -EINVAL ; + +snprintf (inp->name,sizeof (inp->name),"Composite" ); + inp->type =V4L2_INPUT_TYPE_CAMERA ; + inp->std =V4L2_STD_ALL ; + inp->capabilities =V4L2_IN_CAP_STD ; +return 0 ; +} + +static int tw686x_g_input (struct file *file,void *priv,unsigned *v) +{ + *v =0 ; +return 0 ; +} + +static int tw686x_s_input (struct file *file,void *priv,unsigned v) +{ +if (v) +return -EINVAL ; +return 0 ; +} +const struct v4l2_file_operations tw686x_video_fops = { .owner =THIS_MODULE , .open = v4l2_fh_open,
@@ -492,6 +520,9 @@ const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { .vidioc_g_std = tw686x_g_std, .vidioc_s_std = tw686x_s_std, .vidioc_g_parm = tw686x_g_parm, + .vidioc_enum_input = tw686x_enum_input, + .vidioc_g_input = tw686x_g_input, + .vidioc_s_input = tw686x_s_input, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, };
PATCH 8/12 TW686x: do not use pci_dma_supported()
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-core.c +1 -1
@@ -61,7 +61,7 @@ static int tw686x_probe(struct pci_dev *pci_dev,pci_set_master (pci_dev); -if (!pci_dma_supported (pci_dev,DMA_BIT_MASK (32 ))) { +if (pci_set_dma_mask (pci_dev,DMA_BIT_MASK (32 ))) {pr_err ("%s: 32-bit PCI DMA not supported\n" , dev->name);return -EIO ; }
PATCH 9/12 TW686x: switch to vb2_v4l2_buffer
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +15 -15
@@ -84,8 +84,7 @@ static const struct tw686x_format *format_by_fourcc(unsigned fourcc)/* video queue operations */ -static int tw686x_queue_setup (struct vb2_queue *vq, -const struct v4l2_format *v4l_fmt, +static int tw686x_queue_setup (struct vb2_queue *vq,const void *arg,unsigned int *nbuffers,unsigned int *nplanes,unsigned int sizes[],void *alloc_ctxs[]) {
@@ -103,9 +102,10 @@ static int tw686x_queue_setup(struct vb2_queue *vq,static void tw686x_buf_queue (struct vb2_buffer *vb) {struct tw686x_video_channel *vc =vb2_get_drv_priv (vb->vb2_queue); +struct vb2_v4l2_buffer *vbuf =to_vb2_v4l2_buffer (vb);struct tw686x_vb2_buf *buf; - buf = container_of(vb, struct tw686x_vb2_buf, vb); + buf = container_of(vbuf, struct tw686x_vb2_buf, vb);spin_lock (&vc->qlock);list_add_tail (&buf->list, &vc->vidq_queued);
@@ -128,13 +128,13 @@ loop:list_del (&buf->list); buf_len = vc->width * vc->height * vc->format->depth /8 ; -if (vb2_plane_size (&buf->vb,0 ) < buf_len) { +if (vb2_plane_size (&buf->vb.vb2_buf,0 ) < buf_len) {pr_err ("Video buffer size too small\n" ); -vb2_buffer_done (&buf->vb,VB2_BUF_STATE_ERROR ); +vb2_buffer_done (&buf->vb.vb2_buf,VB2_BUF_STATE_ERROR ); goto loop;/* try another */ } - vbuf =vb2_dma_sg_plane_desc (&buf->vb,0 ); + vbuf =vb2_dma_sg_plane_desc (&buf->vb.vb2_buf,0 );for_each_sg (vbuf->sgl, sg, vbuf->nents, i) {dma_addr_t phys =sg_dma_address (sg);unsigned len =sg_dma_len (sg);
@@ -145,7 +145,7 @@ loop: entry_len =min (entry_len, buf_len);if (count ==MAX_SG_DESC_COUNT ) {pr_err ("Video buffer size too fragmented\n" ); -vb2_buffer_done (&buf->vb, +vb2_buffer_done (&buf->vb.vb2_buf,VB2_BUF_STATE_ERROR ); goto loop; }
@@ -167,7 +167,7 @@ loop: descs[count++].flags_length =0 ;/* unavailable */ } - buf->vb.state =VB2_BUF_STATE_ACTIVE ; + buf->vb.vb2_buf.state =VB2_BUF_STATE_ACTIVE ; vc->curr_bufs[n] = buf;return ; }
@@ -265,12 +265,12 @@ static void tw686x_stop_streaming(struct vb2_queue *vq) buf = list_entry(vc->vidq_queued.next, struct tw686x_vb2_buf, list);list_del (&buf->list); -vb2_buffer_done (&buf->vb,VB2_BUF_STATE_ERROR ); +vb2_buffer_done (&buf->vb.vb2_buf,VB2_BUF_STATE_ERROR ); }for (n =0 ; n <2 ; n++)if (vc->curr_bufs[n]) -vb2_buffer_done (&vc->curr_bufs[n]->vb, +vb2_buffer_done (&vc->curr_bufs[n]->vb.vb2_buf,VB2_BUF_STATE_ERROR );spin_unlock (&vc->qlock);
@@ -581,13 +581,13 @@ static int video_thread(void *arg)spin_lock (&vc->qlock); n = !!(reg_read (dev,PB_STATUS ) & (1 << ch));if (vc->curr_bufs[n]) { -struct vb2_buffer *vb; +struct vb2_v4l2_buffer *vb; vb = &vc->curr_bufs[n]->vb; -v4l2_get_timestamp (&vb->v4l2_buf.timestamp); - vb->v4l2_buf.field = vc->field; -vb2_set_plane_payload (vb,0 , vc->width * vc->height * vc->format->depth /8 ); -vb2_buffer_done (vb,VB2_BUF_STATE_DONE ); +v4l2_get_timestamp (&vb->timestamp); + vb->field = vc->field; +vb2_set_plane_payload (&vb->vb2_buf,0 , vc->width * vc->height * vc->format->depth /8 ); +vb2_buffer_done (&vb->vb2_buf,VB2_BUF_STATE_DONE ); }setup_descs (vc, n);spin_unlock (&vc->qlock);
drivers/media/pci/tw686x/tw686x.h +1 -1
@@ -44,7 +44,7 @@ struct vdma_desc { };struct tw686x_vb2_buf { -struct vb2_buffer vb; +struct vb2_v4l2_buffer vb;struct list_head list; };
PATCH 10/12 TW686x: handle non-NULL format in queue_setup()
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +53 -48
@@ -82,6 +82,50 @@ static const struct tw686x_format *format_by_fourcc(unsigned fourcc)return NULL ; } +static void tw686x_get_format (struct tw686x_video_channel *vc, +struct v4l2_format *f) +{ +const struct tw686x_format *format; +unsigned width, height, height_div =1 ; + + format =format_by_fourcc (f->fmt.pix.pixelformat); +if (!format) { + format = &formats[0 ]; + f->fmt.pix.pixelformat = format->fourcc; + } + + width =704 ; +if (f->fmt.pix.width < width *3 /4 /* halfway */ ) + width /=2 ; + + height = (vc->video_standard &V4L2_STD_625_50 ) ?576 :480 ; +if (f->fmt.pix.height < height *3 /4 /* halfway */ ) + height_div =2 ; + +switch (f->fmt.pix.field) { +case V4L2_FIELD_TOP : +case V4L2_FIELD_BOTTOM : + height_div =2 ; +break ; +case V4L2_FIELD_SEQ_BT : +if (height_div >1 ) + f->fmt.pix.field =V4L2_FIELD_BOTTOM ; +break ; +default : +if (height_div >1 ) + f->fmt.pix.field =V4L2_FIELD_TOP ; +else + f->fmt.pix.field =V4L2_FIELD_SEQ_TB ; + } + height /= height_div; + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth /8 ; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace =V4L2_COLORSPACE_SMPTE170M ; +} +/* video queue operations */ static int tw686x_queue_setup(struct vb2_queue *vq, const void *arg,
@@ -90,12 +134,17 @@ static int tw686x_queue_setup(struct vb2_queue *vq, const void *arg, {struct tw686x_video_channel *vc =vb2_get_drv_priv (vq); - sizes[0 ] = vc->width * vc->height * vc->format->depth /8 ; +if (arg) { +struct v4l2_format fmt = *(const struct v4l2_format *)arg; +tw686x_get_format (vc, &fmt); + sizes[0 ] = fmt.fmt.pix.sizeimage; + }else + sizes[0 ] = vc->width * vc->height * vc->format->depth /8 ; + alloc_ctxs[0 ] = vc->alloc_ctx; *nplanes =1 ;/* packed formats only */ if (*nbuffers <2 ) *nbuffers =2 ; -return 0 ; }
@@ -340,47 +389,7 @@ static int tw686x_g_fmt_vid_cap(struct file *file, void *priv,static int tw686x_try_fmt_vid_cap (struct file *file,void *priv,struct v4l2_format *f) { -struct tw686x_video_channel *vc =video_drvdata (file); -const struct tw686x_format *format; -unsigned width, height, height_div =1 ; - - format =format_by_fourcc (f->fmt.pix.pixelformat); -if (!format) { - format = &formats[0 ]; - f->fmt.pix.pixelformat = format->fourcc; - } - - width =704 ; -if (f->fmt.pix.width < width *3 /4 /* halfway */ ) - width /=2 ; - - height = (vc->video_standard &V4L2_STD_625_50 ) ?576 :480 ; -if (f->fmt.pix.height < height *3 /4 /* halfway */ ) - height_div =2 ; - -switch (f->fmt.pix.field) { -case V4L2_FIELD_TOP : -case V4L2_FIELD_BOTTOM : - height_div =2 ; -break ; -case V4L2_FIELD_SEQ_BT : -if (height_div >1 ) - f->fmt.pix.field =V4L2_FIELD_BOTTOM ; -break ; -default : -if (height_div >1 ) - f->fmt.pix.field =V4L2_FIELD_TOP ; -else - f->fmt.pix.field =V4L2_FIELD_SEQ_TB ; - } - height /= height_div; - - f->fmt.pix.width = width; - f->fmt.pix.height = height; - f->fmt.pix.bytesperline = f->fmt.pix.width * format->depth /8 ; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.colorspace =V4L2_COLORSPACE_SMPTE170M ; - +tw686x_get_format (video_drvdata (file), f);return 0 ; }
@@ -388,12 +397,8 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) {struct tw686x_video_channel *vc =video_drvdata (file); -int err; - - err =tw686x_try_fmt_vid_cap (file, priv, f); -if (err) -return err; +tw686x_get_format (vc, f); vc->format =format_by_fourcc (f->fmt.pix.pixelformat); vc->field = f->fmt.pix.field; vc->width = f->fmt.pix.width;
BTW I had to rewrite the tree on git.kernel.org due to missing SOBs in a part of the commits. It's now fixed.
Signature · 4 lines
Krzysztof Halasa Industrial Research Institute for Automation and Measurements PIAP Al. Jerozolimskie 202, 02-486 Warsaw, Poland
PATCH 11/12 TW686x: Track frame sequence numbers
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +5 -0
@@ -280,6 +280,7 @@ static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count)spin_unlock (&vc->qlock); dev->video_active |=1 << vc->ch; + vc->seq =0 ; dma_ch_mask =reg_read (dev,DMA_CHANNEL_ENABLE ) | (1 << vc->ch);reg_write (dev,DMA_CHANNEL_ENABLE , dma_ch_mask);reg_write (dev,DMA_CMD , (1 <<31 ) | dma_ch_mask);
@@ -591,6 +592,10 @@ static int video_thread(void *arg) vb = &vc->curr_bufs[n]->vb;v4l2_get_timestamp (&vb->timestamp); vb->field = vc->field; +if (V4L2_FIELD_HAS_BOTH (vc->field)) + vb->sequence = vc->seq++; +else + vb->sequence = (vc->seq++) /2 ;vb2_set_plane_payload (&vb->vb2_buf,0 , vc->width * vc->height * vc->format->depth /8 );vb2_buffer_done (&vb->vb2_buf,VB2_BUF_STATE_DONE ); }
drivers/media/pci/tw686x/tw686x.h +1 -0
@@ -66,6 +66,7 @@ struct tw686x_video_channel {v4l2_std_id video_standard;unsigned width, height;enum v4l2_field field;/* supported TOP, BOTTOM, SEQ_TB and SEQ_BT */ +unsigned seq;/* video field or frame counter */ unsigned ch; };
PATCH 12/12 TW686x: return VB2_BUF_STATE_ERROR frames on timeout/errors
In reply to Krzysztof Hałasadrivers/media/pci/tw686x/tw686x-video.c +23 -22
@@ -551,7 +551,7 @@ static int video_thread(void *arg)for (ch =0 ; ch <max_channels (dev); ch++) {struct tw686x_video_channel *vc;unsigned long flags; -u32 request, n; +u32 request, n, stat =VB2_BUF_STATE_DONE ; vc = &dev->video_channels[ch];if (!(dev->video_active & (1 << ch)))
@@ -581,28 +581,29 @@ static int video_thread(void *arg)reg_write (dev,DMA_CMD , reg & ~(1 << ch));reg_write (dev,DMA_CMD , reg);spin_unlock_irqrestore (&dev->irq_lock, flags); - }else { -/* handle video stream */ -mutex_lock (&vc->vb_mutex); -spin_lock (&vc->qlock); - n = !!(reg_read (dev,PB_STATUS ) & (1 << ch)); -if (vc->curr_bufs[n]) { -struct vb2_v4l2_buffer *vb; - - vb = &vc->curr_bufs[n]->vb; -v4l2_get_timestamp (&vb->timestamp); - vb->field = vc->field; -if (V4L2_FIELD_HAS_BOTH (vc->field)) - vb->sequence = vc->seq++; -else - vb->sequence = (vc->seq++) /2 ; -vb2_set_plane_payload (&vb->vb2_buf,0 , vc->width * vc->height * vc->format->depth /8 ); -vb2_buffer_done (&vb->vb2_buf,VB2_BUF_STATE_DONE ); - } -setup_descs (vc, n); -spin_unlock (&vc->qlock); -mutex_unlock (&vc->vb_mutex); + stat =VB2_BUF_STATE_ERROR ; + } + +/* handle video stream */ +mutex_lock (&vc->vb_mutex); +spin_lock (&vc->qlock); + n = !!(reg_read (dev,PB_STATUS ) & (1 << ch)); +if (vc->curr_bufs[n]) { +struct vb2_v4l2_buffer *vb; + + vb = &vc->curr_bufs[n]->vb; +v4l2_get_timestamp (&vb->timestamp); + vb->field = vc->field; +if (V4L2_FIELD_HAS_BOTH (vc->field)) + vb->sequence = vc->seq++; +else + vb->sequence = (vc->seq++) /2 ; +vb2_set_plane_payload (&vb->vb2_buf,0 , vc->width * vc->height * vc->format->depth /8 ); +vb2_buffer_done (&vb->vb2_buf, stat); } +setup_descs (vc, n); +spin_unlock (&vc->qlock); +mutex_unlock (&vc->vb_mutex); }try_to_freeze (); }
Quoted 7 lines · Krzysztof Hałasa
Hi,
I'm posting a driver for TW686[4589]-based PCIe cards. The first patch has been posted and reviewed by Ezequiel back in July 2015, the subsequent patches are changes made in response to the review and/or are required by the more recent kernel versions.
Quoted 8 lines
This driver lacks CMA-based frame mode DMA operation, I'll add it a bit later. Also:
- I haven't converted the kthread to a workqueue - the driver is modeled after other code and it can be done later, if needed
- I have skipped suggested PCI ID changes and the 704 vs 720 pixels/line question - this may need further consideration.Please merge.
Please repost as a single patch. Also make sure it is based on the latest media_tree master branch.
Your current patch series breaks bisectability (basically, after patch 1 it won't compile since it's not using vb2_v4l2_buffer yet).
Also, for new drivers we generally don't care about the history, we prefer a single patch. That makes it easier to review as well.
I'll take a good look at the code once I have a v2.
Now, I am not planning to merge that, but I will compare it to what Ezequiel has and use that comparison as a starting point for further discussions.
As I mentioned before, my preference is to merge a driver that supports both frame and field modes (or whatever they are called).
Regards,
Hans
Quoted 43 lines
The following changes since Linux 4.4 are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/chris/linux.gittechwell-4.4for you to fetch changes up to
8e495778acd4602c472cefa460a1afb41c4b8f25:[MEDIA] TW686x: return
VB2_BUF_STATE_ERRORframes on timeout/errors (2016-01-27 14:47:41 +0100)----------------------------------------------------------------
Krzysztof Hałasa (12):
[MEDIA] Add support for TW686[4589]-based frame grabbers [MEDIA] TW686x: Trivial changes suggested by Ezequiel Garcia [MEDIA] TW686x: Switch to devm_*()
[MEDIA] TW686x: Fixs_std()/g_std()/g_parm()pointer to self [MEDIA] TW686x: Fix handling of TV standard values [MEDIA] TW686x: Fixtry_fmt()color space
[MEDIA] TW686x: Addenum_input()/g_input()/s_input()[MEDIA] TW686x: do not usepci_dma_supported()
[MEDIA] TW686x: switch tovb2_v4l2_buffer
[MEDIA] TW686x: handle non-NULL format inqueue_setup()[MEDIA] TW686x: Track frame sequence numbers
[MEDIA] TW686x: returnVB2_BUF_STATE_ERRORframes on timeout/errorsdrivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/tw686x/Kconfig | 16 ++ drivers/media/pci/tw686x/Makefile | 3 + drivers/media/pci/tw686x/tw686x-core.c | 140 +++++++++++++ drivers/media/pci/tw686x/tw686x-regs.h | 103 +++++++++ drivers/media/pci/tw686x/tw686x-video.c | 815 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/media/pci/tw686x/tw686x.h | 118 +++++++++++ 8 files changed, 1197 insertions(+) create mode 100644 drivers/media/pci/tw686x/Kconfig create mode 100644 drivers/media/pci/tw686x/Makefile create mode 100644 drivers/media/pci/tw686x/tw686x-core.c create mode 100644 drivers/media/pci/tw686x/tw686x-regs.h create mode 100644 drivers/media/pci/tw686x/tw686x-video.c create mode 100644 drivers/media/pci/tw686x/tw686x.hThanks.
Quoted 8 lines · Hans Verkuil
Please repost as a single patch. Also make sure it is based on the latest
media_treemaster branch.Your current patch series breaks bisectability (basically, after patch 1 it won't compile since it's not using
vb2_v4l2_bufferyet).Also, for new drivers we generally don't care about the history, we prefer a single patch. That makes it easier to review as well.
No problem. I posted incremental patches to help with (incremental) review.
Signature · 4 lines
Krzysztof Halasa Industrial Research Institute for Automation and Measurements PIAP Al. Jerozolimskie 202, 02-486 Warsaw, Poland
Quoted 2 lines · Hans Verkuil
Now, I am not planning to merge that, but I will compare it to what Ezequiel has and use that comparison as a starting point for further discussions.
I'm not opposed to Ezequiel's changes in general - I only want him to present them as changes, and not as a "rewritten driver". Unless they are considered a rewritten driver, of course.
Quoted 2 lines
As I mentioned before, my preference is to merge a driver that supports both frame and field modes (or whatever they are called).
Well, I don't know about his, but my version presently only support frame mode (V4L2_FIELD_SEQ_*). It specifically doesn't support INTERLACED frame mode (SG DMA hw limitation) and it doesn't support field mode, except for FIELD_TOP and FIELD_BOTTOM (only specific fields) which I use to get a lower resolution image.
I also plan to use an INTERLACED frame mode with a DMA (non-SG to CMA, it turned out it works well on my systems), but I would rather like to have the driver in the tree before submitting further (non-essential) patches.
Field modes are of course possible, though I've never seen any interest for them, so I haven't bothered. Can add, it's a simple thing and it works fine (apart from increased QBUF/DQBUF rate).
There is also a specific YUV420 mode (with a custom encoding) which I'd like to add (unfortunately unavailable in V4L2_FIELD_SEQ_*, but usable in INTERLACED and FIELD_*). This mode requires two separate line lengths - odd lines contain YUV data and are twice as long as even lines which only contain Y.
How do I set up such a mode (fmt.pix.bytesperline)?
This mode is useful on low-performance machines, e.g. feeding data to H.264 encoders.
Signature · 4 lines
Krzysztof Halasa Industrial Research Institute for Automation and Measurements PIAP Al. Jerozolimskie 202, 02-486 Warsaw, Poland