diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 7292f23954df3a456b3a9b15c9500cfcbd827681..53827778b414dcb12e12d62af3220c02f76331f4 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -31,8 +31,6 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/pulse8-cec/Kconfig" -source "drivers/staging/media/tw686x-kh/Kconfig" - source "drivers/staging/media/s5p-cec/Kconfig" # Keep LIRC at the end, as it has sub-menus diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 87ce8ad1e22aa04a127fd59857f911e80b6e011e..6316e8c7a497dbc8dd048c568b1940c2e8c06e32 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -6,4 +6,3 @@ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec/ -obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh/ diff --git a/drivers/staging/media/tw686x-kh/Kconfig b/drivers/staging/media/tw686x-kh/Kconfig deleted file mode 100644 index 6264d30edf5a18bdfaa8d58bb885909160a8f1e2..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config VIDEO_TW686X_KH - tristate "Intersil/Techwell TW686x Video For Linux" - depends on VIDEO_DEV && PCI && VIDEO_V4L2 - depends on !(VIDEO_TW686X=y || VIDEO_TW686X=m) || COMPILE_TEST - 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-kh. diff --git a/drivers/staging/media/tw686x-kh/Makefile b/drivers/staging/media/tw686x-kh/Makefile deleted file mode 100644 index 2a36a38cf30ebddfc670440b6ca059d3fc082d19..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -tw686x-kh-objs := tw686x-kh-core.o tw686x-kh-video.o - -obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh.o diff --git a/drivers/staging/media/tw686x-kh/TODO b/drivers/staging/media/tw686x-kh/TODO deleted file mode 100644 index 480a495b11fb9f3081ef3cb0506736b25515dd53..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/TODO +++ /dev/null @@ -1,6 +0,0 @@ -TODO: - -- implement V4L2_FIELD_INTERLACED* mode(s). -- add audio support - -Please Cc: patches to Krzysztof Halasa . diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-core.c b/drivers/staging/media/tw686x-kh/tw686x-kh-core.c deleted file mode 100644 index 03b3b62c59c445882f6d56938283013a3763be30..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/tw686x-kh-core.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include "tw686x-kh.h" -#include "tw686x-kh-regs.h" - -static irqreturn_t tw686x_irq(int irq, void *dev_id) -{ - struct tw686x_dev *dev = (struct tw686x_dev *)dev_id; - u32 int_status = reg_read(dev, INT_STATUS); /* cleared on read */ - unsigned long flags; - unsigned int handled = 0; - - if (int_status) { - spin_lock_irqsave(&dev->irq_lock, flags); - dev->dma_requests |= int_status; - spin_unlock_irqrestore(&dev->irq_lock, flags); - - if (int_status & 0xFF0000FF) - handled = tw686x_kh_video_irq(dev); - } - - return IRQ_RETVAL(handled); -} - -static int tw686x_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct tw686x_dev *dev; - int err; - - 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; - - sprintf(dev->name, "TW%04X", pci_dev->device); - dev->type = pci_id->driver_data; - - pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name, - pci_name(pci_dev), pci_dev->irq, - (unsigned long)pci_resource_start(pci_dev, 0)); - - dev->pci_dev = pci_dev; - if (pcim_enable_device(pci_dev)) - return -EIO; - - pci_set_master(pci_dev); - - 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; - } - - err = pci_request_regions(pci_dev, dev->name); - if (err < 0) { - pr_err("%s: Unable to get MMIO region\n", dev->name); - return err; - } - - dev->mmio = pci_ioremap_bar(pci_dev, 0); - if (!dev->mmio) { - pr_err("%s: Unable to remap MMIO region\n", dev->name); - return -EIO; - } - - reg_write(dev, SYS_SOFT_RST, 0x0F); /* Reset all subsystems */ - mdelay(1); - - reg_write(dev, SRST[0], 0x3F); - if (max_channels(dev) > 4) - reg_write(dev, SRST[1], 0x3F); - reg_write(dev, DMA_CMD, 0); - reg_write(dev, DMA_CHANNEL_ENABLE, 0); - reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x3EFF0FF0); - reg_write(dev, DMA_TIMER_INTERVAL, 0x38000); - reg_write(dev, DMA_CONFIG, 0xFFFFFF04); - - spin_lock_init(&dev->irq_lock); - - 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); - return err; - } - - err = tw686x_kh_video_init(dev); - if (err) - return err; - - pci_set_drvdata(pci_dev, dev); - return 0; -} - -static void tw686x_remove(struct pci_dev *pci_dev) -{ - struct tw686x_dev *dev = pci_get_drvdata(pci_dev); - - tw686x_kh_video_free(dev); -} - -/* driver_data is number of A/V channels */ -static const struct pci_device_id tw686x_pci_tbl[] = { - {PCI_DEVICE(0x1797, 0x6864), .driver_data = 4}, - /* not tested */ - {PCI_DEVICE(0x1797, 0x6865), .driver_data = 4 | TYPE_SECOND_GEN}, - /* TW6868 supports 8 A/V channels with an external TW2865 chip - - not supported by the driver */ - {PCI_DEVICE(0x1797, 0x6868), .driver_data = 4}, /* not tested */ - {PCI_DEVICE(0x1797, 0x6869), .driver_data = 8 | TYPE_SECOND_GEN}, - {} -}; - -static struct pci_driver tw686x_pci_driver = { - .name = "tw686x-kh", - .id_table = tw686x_pci_tbl, - .probe = tw686x_probe, - .remove = tw686x_remove, -}; - -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_pci_driver(tw686x_pci_driver); diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h b/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h deleted file mode 100644 index 53e1889babd0c6b6adf8c46cfd21d8fbe007b903..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/tw686x-kh-regs.h +++ /dev/null @@ -1,103 +0,0 @@ -/* DMA controller registers */ -#define REG8_1(a0) ((const u16[8]) {a0, a0 + 1, a0 + 2, a0 + 3, \ - a0 + 4, a0 + 5, a0 + 6, a0 + 7}) -#define REG8_2(a0) ((const u16[8]) {a0, a0 + 2, a0 + 4, a0 + 6, \ - a0 + 8, a0 + 0xA, a0 + 0xC, a0 + 0xE}) -#define REG8_8(a0) ((const u16[8]) {a0, a0 + 8, a0 + 0x10, a0 + 0x18, \ - a0 + 0x20, a0 + 0x28, a0 + 0x30, a0 + 0x38}) -#define INT_STATUS 0x00 -#define PB_STATUS 0x01 -#define DMA_CMD 0x02 -#define VIDEO_FIFO_STATUS 0x03 -#define VIDEO_CHANNEL_ID 0x04 -#define VIDEO_PARSER_STATUS 0x05 -#define SYS_SOFT_RST 0x06 -#define DMA_PAGE_TABLE0_ADDR ((const u16[8]) {0x08, 0xD0, 0xD2, 0xD4, \ - 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 VDMA_CHANNEL_CONFIG REG8_1(0x10) -#define ADMA_P_ADDR REG8_2(0x18) -#define ADMA_B_ADDR REG8_2(0x19) -#define DMA10_P_ADDR 0x28 /* ??? */ -#define DMA10_B_ADDR 0x29 -#define VIDEO_CONTROL1 0x2A -#define VIDEO_CONTROL2 0x2B -#define AUDIO_CONTROL1 0x2C -#define AUDIO_CONTROL2 0x2D -#define PHASE_REF 0x2E -#define GPIO_REG 0x2F -#define INTL_HBAR_CTRL REG8_1(0x30) -#define AUDIO_CONTROL3 0x38 -#define VIDEO_FIELD_CTRL REG8_1(0x39) -#define HSCALER_CTRL REG8_1(0x42) -#define VIDEO_SIZE REG8_1(0x4A) -#define VIDEO_SIZE_F2 REG8_1(0x52) -#define MD_CONF REG8_1(0x60) -#define MD_INIT REG8_1(0x68) -#define MD_MAP0 REG8_1(0x70) -#define VDMA_P_ADDR REG8_8(0x80) /* not used in DMA SG mode */ -#define VDMA_WHP REG8_8(0x81) -#define VDMA_B_ADDR REG8_8(0x82) -#define VDMA_F2_P_ADDR REG8_8(0x84) -#define VDMA_F2_WHP REG8_8(0x85) -#define VDMA_F2_B_ADDR REG8_8(0x86) -#define EP_REG_ADDR 0xFE -#define EP_REG_DATA 0xFF - -/* Video decoder registers */ -#define VDREG8(a0) ((const u16[8]) { \ - a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \ - a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130}) -#define VIDSTAT VDREG8(0x100) -#define BRIGHT VDREG8(0x101) -#define CONTRAST VDREG8(0x102) -#define SHARPNESS VDREG8(0x103) -#define SAT_U VDREG8(0x104) -#define SAT_V VDREG8(0x105) -#define HUE VDREG8(0x106) -#define CROP_HI VDREG8(0x107) -#define VDELAY_LO VDREG8(0x108) -#define VACTIVE_LO VDREG8(0x109) -#define HDELAY_LO VDREG8(0x10A) -#define HACTIVE_LO VDREG8(0x10B) -#define MVSN VDREG8(0x10C) -#define STATUS2 VDREG8(0x10C) -#define SDT VDREG8(0x10E) -#define SDT_EN VDREG8(0x10F) - -#define VSCALE_LO VDREG8(0x144) -#define SCALE_HI VDREG8(0x145) -#define HSCALE_LO VDREG8(0x146) -#define F2CROP_HI VDREG8(0x147) -#define F2VDELAY_LO VDREG8(0x148) -#define F2VACTIVE_LO VDREG8(0x149) -#define F2HDELAY_LO VDREG8(0x14A) -#define F2HACTIVE_LO VDREG8(0x14B) -#define F2VSCALE_LO VDREG8(0x14C) -#define F2SCALE_HI VDREG8(0x14D) -#define F2HSCALE_LO VDREG8(0x14E) -#define F2CNT VDREG8(0x14F) - -#define VDREG2(a0) ((const u16[2]) {a0, a0 + 0x100}) -#define SRST VDREG2(0x180) -#define ACNTL VDREG2(0x181) -#define ACNTL2 VDREG2(0x182) -#define CNTRL1 VDREG2(0x183) -#define CKHY VDREG2(0x184) -#define SHCOR VDREG2(0x185) -#define CORING VDREG2(0x186) -#define CLMPG VDREG2(0x187) -#define IAGC VDREG2(0x188) -#define VCTRL1 VDREG2(0x18F) -#define MISC1 VDREG2(0x194) -#define LOOP VDREG2(0x195) -#define MISC2 VDREG2(0x196) - -#define CLMD VDREG2(0x197) -#define AIGAIN ((const u16[8]) {0x1D0, 0x1D1, 0x1D2, 0x1D3, \ - 0x2D0, 0x2D1, 0x2D2, 0x2D3}) diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c b/drivers/staging/media/tw686x-kh/tw686x-kh-video.c deleted file mode 100644 index 9bf32aec2fc6e2a8a85c326c1c1e0bdad8690833..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/tw686x-kh-video.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include "tw686x-kh.h" -#include "tw686x-kh-regs.h" - -#define MAX_SG_ENTRY_SIZE (/* 8192 - 128 */ 4096) -#define MAX_SG_DESC_COUNT 256 /* PAL 704x576 needs up to 198 4-KB pages */ - -static const struct tw686x_format formats[] = { - { - .name = "4:2:2 packed, UYVY", /* aka Y422 */ - .fourcc = V4L2_PIX_FMT_UYVY, - .mode = 0, - .depth = 16, - }, { -#if 0 - .name = "4:2:0 packed, YUV", - .mode = 1, /* non-standard */ - .depth = 12, - }, { - .name = "4:1:1 packed, YUV", - .mode = 2, /* non-standard */ - .depth = 12, - }, { -#endif - .name = "4:1:1 packed, YUV", - .fourcc = V4L2_PIX_FMT_Y41P, - .mode = 3, - .depth = 12, - }, { - .name = "15 bpp RGB", - .fourcc = V4L2_PIX_FMT_RGB555, - .mode = 4, - .depth = 16, - }, { - .name = "16 bpp RGB", - .fourcc = V4L2_PIX_FMT_RGB565, - .mode = 5, - .depth = 16, - }, { - .name = "4:2:2 packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .mode = 6, - .depth = 16, - } - /* mode 7 is "reserved" */ -}; - -static const v4l2_std_id video_standards[7] = { - V4L2_STD_NTSC, - V4L2_STD_PAL, - V4L2_STD_SECAM, - V4L2_STD_NTSC_443, - V4L2_STD_PAL_M, - V4L2_STD_PAL_N, - V4L2_STD_PAL_60, -}; - -static const struct tw686x_format *format_by_fourcc(unsigned int fourcc) -{ - unsigned int cnt; - - for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++) - if (formats[cnt].fourcc == fourcc) - return &formats[cnt]; - return NULL; -} - -static void tw686x_get_format(struct tw686x_video_channel *vc, - struct v4l2_format *f) -{ - const struct tw686x_format *format; - unsigned int 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, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); - unsigned int size = vc->width * vc->height * vc->format->depth / 8; - - if (*nbuffers < 2) - *nbuffers = 2; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - sizes[0] = size; - *nplanes = 1; /* packed formats only */ - return 0; -} - -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(vbuf, struct tw686x_vb2_buf, vb); - - spin_lock(&vc->qlock); - list_add_tail(&buf->list, &vc->vidq_queued); - spin_unlock(&vc->qlock); -} - -static void setup_descs(struct tw686x_video_channel *vc, unsigned int n) -{ -loop: - while (!list_empty(&vc->vidq_queued)) { - struct vdma_desc *descs = vc->sg_descs[n]; - struct tw686x_vb2_buf *buf; - struct sg_table *vbuf; - struct scatterlist *sg; - unsigned int buf_len, count = 0; - int i; - - buf = list_first_entry(&vc->vidq_queued, struct tw686x_vb2_buf, - list); - list_del(&buf->list); - - buf_len = vc->width * vc->height * vc->format->depth / 8; - 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, VB2_BUF_STATE_ERROR); - goto loop; /* try another */ - } - - 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 int len = sg_dma_len(sg); - - while (len && buf_len) { - unsigned int entry_len = min_t(unsigned int, len, - MAX_SG_ENTRY_SIZE); - 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_buf, - VB2_BUF_STATE_ERROR); - goto loop; - } - descs[count].phys = cpu_to_le32(phys); - descs[count++].flags_length = - cpu_to_le32(0x40000000 /* available */ | - entry_len); - phys += entry_len; - len -= entry_len; - buf_len -= entry_len; - } - if (!buf_len) - break; - } - - /* clear the remaining entries */ - while (count < MAX_SG_DESC_COUNT) { - descs[count].phys = 0; - descs[count++].flags_length = 0; /* unavailable */ - } - - buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - vc->curr_bufs[n] = buf; - return; - } - vc->curr_bufs[n] = NULL; -} - -/* On TW6864 and TW6868, all channels share the pair of video DMA SG tables, - with 10-bit start_idx and end_idx determining start and end of frame buffer - for particular channel. - TW6868 with all its 8 channels would be problematic (only 127 SG entries per - channel) but we support only 4 channels on this chip anyway (the first - 4 channels are driven with internal video decoder, the other 4 would require - an external TW286x part). - - On TW6865 and TW6869, each channel has its own DMA SG table, with indexes - starting with 0. Both chips have complete sets of internal video decoders - (respectively 4 or 8-channel). - - All chips have separate SG tables for two video frames. */ - -static void setup_dma_cfg(struct tw686x_video_channel *vc) -{ - unsigned int field_width = 704; - unsigned int field_height = (vc->video_standard & V4L2_STD_625_50) ? - 288 : 240; - unsigned int start_idx = is_second_gen(vc->dev) ? 0 : - vc->ch * MAX_SG_DESC_COUNT; - unsigned int end_idx = start_idx + MAX_SG_DESC_COUNT - 1; - u32 dma_cfg = (0 << 30) /* input selection */ | - (1 << 29) /* field2 dropped (if any) */ | - ((vc->height < 300) << 28) /* field dropping */ | - (1 << 27) /* master */ | - (0 << 25) /* master channel (for slave only) */ | - (0 << 24) /* (no) vertical (line) decimation */ | - ((vc->width < 400) << 23) /* horizontal decimation */ | - (vc->format->mode << 20) /* output video format */ | - (end_idx << 10) /* DMA end index */ | - start_idx /* DMA start index */; - u32 reg; - - reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], dma_cfg); - reg_write(vc->dev, VIDEO_SIZE[vc->ch], (1 << 31) | (field_height << 16) - | field_width); - reg = reg_read(vc->dev, VIDEO_CONTROL1); - if (vc->video_standard & V4L2_STD_625_50) - reg |= 1 << (vc->ch + 13); - else - reg &= ~(1 << (vc->ch + 13)); - reg_write(vc->dev, VIDEO_CONTROL1, reg); -} - -static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); - struct tw686x_dev *dev = vc->dev; - u32 dma_ch_mask; - unsigned int n; - - setup_dma_cfg(vc); - - /* queue video buffers if available */ - spin_lock(&vc->qlock); - for (n = 0; n < 2; n++) - setup_descs(vc, n); - 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); - return 0; -} - -static void tw686x_stop_streaming(struct vb2_queue *vq) -{ - struct tw686x_video_channel *vc = vb2_get_drv_priv(vq); - struct tw686x_dev *dev = vc->dev; - u32 dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE); - u32 dma_cmd = reg_read(dev, DMA_CMD); - unsigned int n; - - dma_ch_mask &= ~(1 << vc->ch); - reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask); - - dev->video_active &= ~(1 << vc->ch); - - dma_cmd &= ~(1 << vc->ch); - reg_write(dev, DMA_CMD, dma_cmd); - - if (!dev->video_active) { - reg_write(dev, DMA_CMD, 0); - reg_write(dev, DMA_CHANNEL_ENABLE, 0); - } - - spin_lock(&vc->qlock); - while (!list_empty(&vc->vidq_queued)) { - struct tw686x_vb2_buf *buf; - - buf = list_entry(vc->vidq_queued.next, struct tw686x_vb2_buf, - list); - list_del(&buf->list); - 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_buf, - VB2_BUF_STATE_ERROR); - - spin_unlock(&vc->qlock); -} - -static struct vb2_ops tw686x_video_qops = { - .queue_setup = tw686x_queue_setup, - .buf_queue = tw686x_buf_queue, - .start_streaming = tw686x_start_streaming, - .stop_streaming = tw686x_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct tw686x_video_channel *vc; - struct tw686x_dev *dev; - unsigned int ch; - - vc = container_of(ctrl->handler, struct tw686x_video_channel, - ctrl_handler); - dev = vc->dev; - ch = vc->ch; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - reg_write(dev, BRIGHT[ch], ctrl->val & 0xFF); - return 0; - - case V4L2_CID_CONTRAST: - reg_write(dev, CONTRAST[ch], ctrl->val); - return 0; - - case V4L2_CID_SATURATION: - reg_write(dev, SAT_U[ch], ctrl->val); - reg_write(dev, SAT_V[ch], ctrl->val); - return 0; - - case V4L2_CID_HUE: - reg_write(dev, HUE[ch], ctrl->val & 0xFF); - return 0; - } - - return -EINVAL; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = tw686x_s_ctrl, -}; - -static int tw686x_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - - f->fmt.pix.width = vc->width; - f->fmt.pix.height = vc->height; - f->fmt.pix.field = vc->field; - f->fmt.pix.pixelformat = vc->format->fourcc; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.bytesperline = f->fmt.pix.width * vc->format->depth / 8; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; -} - -static int tw686x_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - tw686x_get_format(video_drvdata(file), f); - return 0; -} - -static int tw686x_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - - 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; - vc->height = f->fmt.pix.height; - return 0; -} - -static int tw686x_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - struct tw686x_dev *dev = vc->dev; - - strcpy(cap->driver, "tw686x-kh"); - strcpy(cap->card, dev->name); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci_dev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - unsigned int cnt; - u32 sdt = 0; /* default */ - - 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]; - return 0; -} - -static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - - *id = vc->video_standard; - return 0; -} - -static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index >= ARRAY_SIZE(formats)) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - return 0; -} - -static int tw686x_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct tw686x_video_channel *vc = video_drvdata(file); - - if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(&sp->parm.capture, 0, sizeof(sp->parm.capture)); - sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - v4l2_video_std_frame_period(vc->video_standard, - &sp->parm.capture.timeperframe); - - 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 int *v) -{ - *v = 0; - return 0; -} - -static int tw686x_s_input(struct file *file, void *priv, unsigned int v) -{ - if (v) - return -EINVAL; - return 0; -} - -static const struct v4l2_file_operations tw686x_video_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .unlocked_ioctl = video_ioctl2, - .release = vb2_fop_release, - .poll = vb2_fop_poll, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = { - .vidioc_querycap = tw686x_querycap, - .vidioc_enum_fmt_vid_cap = tw686x_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = tw686x_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = tw686x_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = tw686x_try_fmt_vid_cap, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .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, -}; - -static int video_thread(void *arg) -{ - struct tw686x_dev *dev = arg; - DECLARE_WAITQUEUE(wait, current); - - set_freezable(); - add_wait_queue(&dev->video_thread_wait, &wait); - - while (1) { - long timeout = schedule_timeout_interruptible(HZ); - unsigned int ch; - - if (timeout == -ERESTARTSYS || kthread_should_stop()) - break; - - for (ch = 0; ch < max_channels(dev); ch++) { - struct tw686x_video_channel *vc; - unsigned long flags; - u32 request, n, stat = VB2_BUF_STATE_DONE; - - vc = &dev->video_channels[ch]; - if (!(dev->video_active & (1 << ch))) - continue; - - spin_lock_irq(&dev->irq_lock); - request = dev->dma_requests & (0x01000001 << ch); - if (request) - dev->dma_requests &= ~request; - spin_unlock_irq(&dev->irq_lock); - - if (!request) - continue; - - request >>= ch; - - /* handle channel events */ - if ((request & 0x01000000) | - (reg_read(dev, VIDEO_FIFO_STATUS) & (0x01010001 << ch)) | - (reg_read(dev, VIDEO_PARSER_STATUS) & (0x00000101 << ch))) { - /* DMA Errors - reset channel */ - u32 reg; - - spin_lock_irqsave(&dev->irq_lock, flags); - reg = reg_read(dev, DMA_CMD); - /* Reset DMA channel */ - reg_write(dev, DMA_CMD, reg & ~(1 << ch)); - reg_write(dev, DMA_CMD, reg); - spin_unlock_irqrestore(&dev->irq_lock, flags); - 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; - vb->vb2_buf.timestamp = ktime_get_ns(); - 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(); - } - - remove_wait_queue(&dev->video_thread_wait, &wait); - return 0; -} - -int tw686x_kh_video_irq(struct tw686x_dev *dev) -{ - unsigned long flags, handled = 0; - u32 requests; - - spin_lock_irqsave(&dev->irq_lock, flags); - requests = dev->dma_requests; - spin_unlock_irqrestore(&dev->irq_lock, flags); - - if (requests & dev->video_active) { - wake_up_interruptible_all(&dev->video_thread_wait); - handled = 1; - } - return handled; -} - -void tw686x_kh_video_free(struct tw686x_dev *dev) -{ - unsigned int ch, n; - - if (dev->video_thread) - kthread_stop(dev->video_thread); - - for (ch = 0; ch < max_channels(dev); ch++) { - struct tw686x_video_channel *vc = &dev->video_channels[ch]; - - v4l2_ctrl_handler_free(&vc->ctrl_handler); - if (vc->device) - video_unregister_device(vc->device); - for (n = 0; n < 2; n++) { - struct dma_desc *descs = &vc->sg_tables[n]; - - if (descs->virt) - pci_free_consistent(dev->pci_dev, descs->size, - descs->virt, descs->phys); - } - } - - v4l2_device_unregister(&dev->v4l2_dev); -} - -#define SG_TABLE_SIZE (MAX_SG_DESC_COUNT * sizeof(struct vdma_desc)) - -int tw686x_kh_video_init(struct tw686x_dev *dev) -{ - unsigned int ch, n; - int err; - - init_waitqueue_head(&dev->video_thread_wait); - - err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev); - if (err) - return err; - - reg_write(dev, VIDEO_CONTROL1, 0); /* NTSC, disable scaler */ - reg_write(dev, PHASE_REF, 0x00001518); /* Scatter-gather DMA mode */ - - /* setup required SG table sizes */ - for (n = 0; n < 2; n++) - if (is_second_gen(dev)) { - /* TW 6865, TW6869 - each channel needs a pair of - descriptor tables */ - for (ch = 0; ch < max_channels(dev); ch++) - dev->video_channels[ch].sg_tables[n].size = - SG_TABLE_SIZE; - - } else - /* TW 6864, TW6868 - we need to allocate a pair of - descriptor tables, common for all channels. - Each table will be bigger than 4 KB. */ - dev->video_channels[0].sg_tables[n].size = - max_channels(dev) * SG_TABLE_SIZE; - - /* allocate SG tables and initialize video channels */ - for (ch = 0; ch < max_channels(dev); ch++) { - struct tw686x_video_channel *vc = &dev->video_channels[ch]; - struct video_device *vdev; - - mutex_init(&vc->vb_mutex); - spin_lock_init(&vc->qlock); - INIT_LIST_HEAD(&vc->vidq_queued); - - vc->dev = dev; - vc->ch = ch; - - /* default settings: NTSC */ - vc->format = &formats[0]; - 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 = 480; - - for (n = 0; n < 2; n++) { - void *cpu; - - if (vc->sg_tables[n].size) { - unsigned int reg = n ? DMA_PAGE_TABLE1_ADDR[ch] : - DMA_PAGE_TABLE0_ADDR[ch]; - - cpu = pci_alloc_consistent(dev->pci_dev, - vc->sg_tables[n].size, - &vc->sg_tables[n].phys); - if (!cpu) { - pr_err("Error allocating video DMA scatter-gather tables\n"); - err = -ENOMEM; - goto error; - } - vc->sg_tables[n].virt = cpu; - reg_write(dev, reg, vc->sg_tables[n].phys); - } else - cpu = dev->video_channels[0].sg_tables[n].virt + - ch * SG_TABLE_SIZE; - - vc->sg_descs[n] = cpu; - } - - reg_write(dev, VCTRL1[0], 0x24); - reg_write(dev, LOOP[0], 0xA5); - if (max_channels(dev) > 4) { - reg_write(dev, VCTRL1[1], 0x24); - reg_write(dev, LOOP[1], 0xA5); - } - reg_write(dev, VIDEO_FIELD_CTRL[ch], 0); - reg_write(dev, VDELAY_LO[ch], 0x14); - - vdev = video_device_alloc(); - if (!vdev) { - pr_warn("Unable to allocate video device\n"); - err = -ENOMEM; - goto error; - } - - vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - vc->vidq.drv_priv = vc; - vc->vidq.buf_struct_size = sizeof(struct tw686x_vb2_buf); - vc->vidq.ops = &tw686x_video_qops; - vc->vidq.mem_ops = &vb2_dma_sg_memops; - vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - vc->vidq.min_buffers_needed = 2; - vc->vidq.lock = &vc->vb_mutex; - vc->vidq.dev = &dev->pci_dev->dev; - vc->vidq.gfp_flags = GFP_DMA32; - - err = vb2_queue_init(&vc->vidq); - if (err) - goto error; - - strcpy(vdev->name, "TW686x-video"); - snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name); - vdev->fops = &tw686x_video_fops; - vdev->ioctl_ops = &tw686x_video_ioctl_ops; - vdev->release = video_device_release; - vdev->v4l2_dev = &dev->v4l2_dev; - vdev->queue = &vc->vidq; - vdev->tvnorms = V4L2_STD_ALL; - vdev->minor = -1; - vdev->lock = &vc->vb_mutex; - - dev->video_channels[ch].device = vdev; - video_set_drvdata(vdev, vc); - err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); - if (err < 0) - goto error; - - v4l2_ctrl_handler_init(&vc->ctrl_handler, - 4 /* number of controls */); - vdev->ctrl_handler = &vc->ctrl_handler; - v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, - V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); - v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 64); - v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops, V4L2_CID_HUE, - -124, 127, 1, 0); - err = vc->ctrl_handler.error; - if (err) - goto error; - - v4l2_ctrl_handler_setup(&vc->ctrl_handler); - } - - dev->video_thread = kthread_run(video_thread, dev, "tw686x_video"); - if (IS_ERR(dev->video_thread)) { - err = PTR_ERR(dev->video_thread); - goto error; - } - - return 0; - -error: - tw686x_kh_video_free(dev); - return err; -} diff --git a/drivers/staging/media/tw686x-kh/tw686x-kh.h b/drivers/staging/media/tw686x-kh/tw686x-kh.h deleted file mode 100644 index 6284a90d6fe3f0389ca868e4549ce99d6bbcdd9e..0000000000000000000000000000000000000000 --- a/drivers/staging/media/tw686x-kh/tw686x-kh.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TYPE_MAX_CHANNELS 0x0F -#define TYPE_SECOND_GEN 0x10 - -struct tw686x_format { - char *name; - unsigned int fourcc; - unsigned int depth; - unsigned int mode; -}; - -struct dma_desc { - dma_addr_t phys; - void *virt; - unsigned int size; -}; - -struct vdma_desc { - __le32 flags_length; /* 3 MSBits for flags, 13 LSBits for length */ - __le32 phys; -}; - -struct tw686x_vb2_buf { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct tw686x_video_channel { - struct tw686x_dev *dev; - - struct vb2_queue vidq; - struct list_head vidq_queued; - struct video_device *device; - struct dma_desc sg_tables[2]; - struct tw686x_vb2_buf *curr_bufs[2]; - struct vdma_desc *sg_descs[2]; - - struct v4l2_ctrl_handler ctrl_handler; - const struct tw686x_format *format; - struct mutex vb_mutex; - spinlock_t qlock; - v4l2_std_id video_standard; - unsigned int width, height; - enum v4l2_field field; /* supported TOP, BOTTOM, SEQ_TB and SEQ_BT */ - unsigned int seq; /* video field or frame counter */ - unsigned int ch; -}; - -/* global device status */ -struct tw686x_dev { - spinlock_t irq_lock; - - struct v4l2_device v4l2_dev; - struct snd_card *card; /* sound card */ - - unsigned int video_active; /* active video channel mask */ - - char name[32]; - unsigned int type; - struct pci_dev *pci_dev; - __u32 __iomem *mmio; - - struct task_struct *video_thread; - wait_queue_head_t video_thread_wait; - u32 dma_requests; - - struct tw686x_video_channel video_channels[0]; -}; - -static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg) -{ - return readl(dev->mmio + reg); -} - -static inline void reg_write(struct tw686x_dev *dev, unsigned int reg, - uint32_t value) -{ - writel(value, dev->mmio + reg); -} - -static inline unsigned int max_channels(struct tw686x_dev *dev) -{ - return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */ -} - -static inline unsigned int is_second_gen(struct tw686x_dev *dev) -{ - /* each channel has its own DMA SG table */ - return dev->type & TYPE_SECOND_GEN; -} - -int tw686x_kh_video_irq(struct tw686x_dev *dev); -int tw686x_kh_video_init(struct tw686x_dev *dev); -void tw686x_kh_video_free(struct tw686x_dev *dev);