[media] tw686x: Add support for DMA contiguous interlaced frame mode
authorEzequiel Garcia <ezequiel@vanguardiasur.com.ar>
Sat, 4 Jun 2016 23:47:16 +0000 (20:47 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Tue, 28 Jun 2016 10:48:28 +0000 (07:48 -0300)
Now that the driver has the infrastructure to support more
DMA modes, let's add the DMA contiguous interlaced frame mode.

In this mode, the DMA P and B buffers are programmed with
the user-provided buffers. When a P (or B) frame is ready,
a new buffer is dequeued into P (or B).

In addition to interlaced fields, the device can also be
programmed to deliver alternate fields. Only interlaced
mode is supported for now.

Tested-by: Tim Harvey <tharvey@gateworks.com>
Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/pci/tw686x/Kconfig
drivers/media/pci/tw686x/tw686x-core.c
drivers/media/pci/tw686x/tw686x-video.c
drivers/media/pci/tw686x/tw686x.h

index fb8536974052145e60d2502d696cbc4060241132..ef8ca85522f83be89164a2147c4db6dff25035af 100644 (file)
@@ -3,6 +3,7 @@ config VIDEO_TW686X
        depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND
        depends on HAS_DMA
        select VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_DMA_CONTIG
        select SND_PCM
        help
          Support for Intersil/Techwell TW686x-based frame grabber cards.
index 01c06bb59e7804a718cd9741c7599971d3a4e9b9..9a7646c0f9f6e518129dcc76e01aed7a0b9b2402 100644 (file)
@@ -63,6 +63,8 @@ static const char *dma_mode_name(unsigned int mode)
        switch (mode) {
        case TW686X_DMA_MODE_MEMCPY:
                return "memcpy";
+       case TW686X_DMA_MODE_CONTIG:
+               return "contig";
        default:
                return "unknown";
        }
@@ -77,6 +79,8 @@ static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp)
 {
        if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_MEMCPY)))
                dma_mode = TW686X_DMA_MODE_MEMCPY;
+       else if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_CONTIG)))
+               dma_mode = TW686X_DMA_MODE_CONTIG;
        else
                return -EINVAL;
        return 0;
index c0d2a9bd5414eb1105c7ad6100784809d14928c0..b5cb385e4cb15bc57f90436f488b2b7a37ae6221 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-vmalloc.h>
 #include "tw686x.h"
 #include "tw686x-regs.h"
@@ -148,6 +149,53 @@ const struct tw686x_dma_ops memcpy_dma_ops = {
        .field          = V4L2_FIELD_INTERLACED,
 };
 
+static void tw686x_contig_buf_refill(struct tw686x_video_channel *vc,
+                                    unsigned int pb)
+{
+       struct tw686x_v4l2_buf *buf;
+
+       while (!list_empty(&vc->vidq_queued)) {
+               u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch];
+               dma_addr_t phys;
+
+               buf = list_first_entry(&vc->vidq_queued,
+                       struct tw686x_v4l2_buf, list);
+               list_del(&buf->list);
+
+               phys = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+               reg_write(vc->dev, reg, phys);
+
+               buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
+               vc->curr_bufs[pb] = buf;
+               return;
+       }
+       vc->curr_bufs[pb] = NULL;
+}
+
+static void tw686x_contig_cleanup(struct tw686x_dev *dev)
+{
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+}
+
+static int tw686x_contig_setup(struct tw686x_dev *dev)
+{
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&dev->pci_dev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               dev_err(&dev->pci_dev->dev, "unable to init DMA context\n");
+               return PTR_ERR(dev->alloc_ctx);
+       }
+       return 0;
+}
+
+const struct tw686x_dma_ops contig_dma_ops = {
+       .setup          = tw686x_contig_setup,
+       .cleanup        = tw686x_contig_cleanup,
+       .buf_refill     = tw686x_contig_buf_refill,
+       .mem_ops        = &vb2_dma_contig_memops,
+       .hw_dma_mode    = TW686X_FRAME_MODE,
+       .field          = V4L2_FIELD_INTERLACED,
+};
+
 static unsigned int tw686x_fields_map(v4l2_std_id std, unsigned int fps)
 {
        static const unsigned int map[15] = {
@@ -841,6 +889,8 @@ int tw686x_video_init(struct tw686x_dev *dev)
 
        if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY)
                dev->dma_ops = &memcpy_dma_ops;
+       else if (dev->dma_mode == TW686X_DMA_MODE_CONTIG)
+               dev->dma_ops = &contig_dma_ops;
        else
                return -EINVAL;
 
index 977ff6e3c1e2ef105699300aa43daa6d33ee3266..5f4c2131ddac421b5ddd96e637d43819d506801e 100644 (file)
@@ -33,6 +33,7 @@
 #define TW686X_AUDIO_PERIODS_MAX       TW686X_AUDIO_PAGE_MAX
 
 #define TW686X_DMA_MODE_MEMCPY         0
+#define TW686X_DMA_MODE_CONTIG         1
 
 struct tw686x_format {
        char *name;