|
@@ -672,30 +672,20 @@ static int tw686x_try_fmt_vid_cap(struct file *file, void *priv,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
- struct v4l2_format *f)
|
|
|
|
|
|
+static int tw686x_set_format(struct tw686x_video_channel *vc,
|
|
|
|
+ unsigned int pixelformat, unsigned int width,
|
|
|
|
+ unsigned int height, bool realloc)
|
|
{
|
|
{
|
|
- struct tw686x_video_channel *vc = video_drvdata(file);
|
|
|
|
struct tw686x_dev *dev = vc->dev;
|
|
struct tw686x_dev *dev = vc->dev;
|
|
- u32 val, width, line_width, height;
|
|
|
|
- unsigned long bitsperframe;
|
|
|
|
|
|
+ u32 val, dma_width, dma_height, dma_line_width;
|
|
int err, pb;
|
|
int err, pb;
|
|
|
|
|
|
- if (vb2_is_busy(&vc->vidq))
|
|
|
|
- return -EBUSY;
|
|
|
|
-
|
|
|
|
- bitsperframe = vc->width * vc->height * vc->format->depth;
|
|
|
|
- err = tw686x_try_fmt_vid_cap(file, priv, f);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
-
|
|
|
|
- vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
|
|
|
|
- vc->width = f->fmt.pix.width;
|
|
|
|
- vc->height = f->fmt.pix.height;
|
|
|
|
|
|
+ vc->format = format_by_fourcc(pixelformat);
|
|
|
|
+ vc->width = width;
|
|
|
|
+ vc->height = height;
|
|
|
|
|
|
/* We need new DMA buffers if the framesize has changed */
|
|
/* We need new DMA buffers if the framesize has changed */
|
|
- if (dev->dma_ops->alloc &&
|
|
|
|
- bitsperframe != vc->width * vc->height * vc->format->depth) {
|
|
|
|
|
|
+ if (dev->dma_ops->alloc && realloc) {
|
|
for (pb = 0; pb < 2; pb++)
|
|
for (pb = 0; pb < 2; pb++)
|
|
dev->dma_ops->free(vc, pb);
|
|
dev->dma_ops->free(vc, pb);
|
|
|
|
|
|
@@ -739,14 +729,36 @@ static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
|
|
reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
|
reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
|
|
|
|
|
/* Program the DMA frame size */
|
|
/* Program the DMA frame size */
|
|
- width = (vc->width * 2) & 0x7ff;
|
|
|
|
- height = vc->height / 2;
|
|
|
|
- line_width = (vc->width * 2) & 0x7ff;
|
|
|
|
- val = (height << 22) | (line_width << 11) | width;
|
|
|
|
|
|
+ dma_width = (vc->width * 2) & 0x7ff;
|
|
|
|
+ dma_height = vc->height / 2;
|
|
|
|
+ dma_line_width = (vc->width * 2) & 0x7ff;
|
|
|
|
+ val = (dma_height << 22) | (dma_line_width << 11) | dma_width;
|
|
reg_write(vc->dev, VDMA_WHP[vc->ch], val);
|
|
reg_write(vc->dev, VDMA_WHP[vc->ch], val);
|
|
return 0;
|
|
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);
|
|
|
|
+ unsigned long area;
|
|
|
|
+ bool realloc;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (vb2_is_busy(&vc->vidq))
|
|
|
|
+ return -EBUSY;
|
|
|
|
+
|
|
|
|
+ area = vc->width * vc->height;
|
|
|
|
+ err = tw686x_try_fmt_vid_cap(file, priv, f);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ realloc = area != (f->fmt.pix.width * f->fmt.pix.height);
|
|
|
|
+ return tw686x_set_format(vc, f->fmt.pix.pixelformat,
|
|
|
|
+ f->fmt.pix.width, f->fmt.pix.height,
|
|
|
|
+ realloc);
|
|
|
|
+}
|
|
|
|
+
|
|
static int tw686x_querycap(struct file *file, void *priv,
|
|
static int tw686x_querycap(struct file *file, void *priv,
|
|
struct v4l2_capability *cap)
|
|
struct v4l2_capability *cap)
|
|
{
|
|
{
|
|
@@ -763,17 +775,9 @@ static int tw686x_querycap(struct file *file, void *priv,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
|
|
|
|
+static int tw686x_set_standard(struct tw686x_video_channel *vc, v4l2_std_id id)
|
|
{
|
|
{
|
|
- struct tw686x_video_channel *vc = video_drvdata(file);
|
|
|
|
- struct v4l2_format f;
|
|
|
|
- u32 val, ret;
|
|
|
|
-
|
|
|
|
- if (vc->video_standard == id)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- if (vb2_is_busy(&vc->vidq))
|
|
|
|
- return -EBUSY;
|
|
|
|
|
|
+ u32 val;
|
|
|
|
|
|
if (id & V4L2_STD_NTSC)
|
|
if (id & V4L2_STD_NTSC)
|
|
val = 0;
|
|
val = 0;
|
|
@@ -802,14 +806,31 @@ static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch));
|
|
val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch));
|
|
reg_write(vc->dev, VIDEO_CONTROL1, val);
|
|
reg_write(vc->dev, VIDEO_CONTROL1, val);
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
|
|
|
|
+{
|
|
|
|
+ struct tw686x_video_channel *vc = video_drvdata(file);
|
|
|
|
+ struct v4l2_format f;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (vc->video_standard == id)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (vb2_is_busy(&vc->vidq))
|
|
|
|
+ return -EBUSY;
|
|
|
|
+
|
|
|
|
+ ret = tw686x_set_standard(vc, id);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
/*
|
|
/*
|
|
* Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change,
|
|
* Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change,
|
|
* calling g_fmt and s_fmt will sanitize the height
|
|
* calling g_fmt and s_fmt will sanitize the height
|
|
* according to the standard.
|
|
* according to the standard.
|
|
*/
|
|
*/
|
|
- ret = tw686x_g_fmt_vid_cap(file, priv, &f);
|
|
|
|
- if (!ret)
|
|
|
|
- tw686x_s_fmt_vid_cap(file, priv, &f);
|
|
|
|
|
|
+ tw686x_g_fmt_vid_cap(file, priv, &f);
|
|
|
|
+ tw686x_s_fmt_vid_cap(file, priv, &f);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Frame decimation depends on the chosen standard,
|
|
* Frame decimation depends on the chosen standard,
|
|
@@ -928,10 +949,21 @@ static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void tw686x_set_input(struct tw686x_video_channel *vc, unsigned int i)
|
|
|
|
+{
|
|
|
|
+ u32 val;
|
|
|
|
+
|
|
|
|
+ vc->input = i;
|
|
|
|
+
|
|
|
|
+ val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
|
|
|
|
+ val &= ~(0x3 << 30);
|
|
|
|
+ val |= i << 30;
|
|
|
|
+ reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
|
|
|
+}
|
|
|
|
+
|
|
static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
|
|
static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
|
|
{
|
|
{
|
|
struct tw686x_video_channel *vc = video_drvdata(file);
|
|
struct tw686x_video_channel *vc = video_drvdata(file);
|
|
- u32 val;
|
|
|
|
|
|
|
|
if (i >= TW686X_INPUTS_PER_CH)
|
|
if (i >= TW686X_INPUTS_PER_CH)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -943,12 +975,7 @@ static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
|
|
if (vb2_is_busy(&vc->vidq))
|
|
if (vb2_is_busy(&vc->vidq))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
- vc->input = i;
|
|
|
|
-
|
|
|
|
- val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
|
|
|
|
- val &= ~(0x3 << 30);
|
|
|
|
- val |= i << 30;
|
|
|
|
- reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
|
|
|
|
|
+ tw686x_set_input(vc, i);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1104,7 +1131,7 @@ void tw686x_video_free(struct tw686x_dev *dev)
|
|
|
|
|
|
int tw686x_video_init(struct tw686x_dev *dev)
|
|
int tw686x_video_init(struct tw686x_dev *dev)
|
|
{
|
|
{
|
|
- unsigned int ch, val, pb;
|
|
|
|
|
|
+ unsigned int ch, val;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY)
|
|
if (dev->dma_mode == TW686X_DMA_MODE_MEMCPY)
|
|
@@ -1138,27 +1165,23 @@ int tw686x_video_init(struct tw686x_dev *dev)
|
|
vc->ch = ch;
|
|
vc->ch = ch;
|
|
|
|
|
|
/* default settings */
|
|
/* default settings */
|
|
- vc->format = &formats[0];
|
|
|
|
- vc->video_standard = V4L2_STD_NTSC;
|
|
|
|
- vc->width = TW686X_VIDEO_WIDTH;
|
|
|
|
- vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard);
|
|
|
|
- vc->input = 0;
|
|
|
|
|
|
+ err = tw686x_set_standard(vc, V4L2_STD_NTSC);
|
|
|
|
+ if (err)
|
|
|
|
+ goto error;
|
|
|
|
|
|
- reg_write(vc->dev, SDT[ch], 0);
|
|
|
|
- tw686x_set_framerate(vc, 30);
|
|
|
|
|
|
+ err = tw686x_set_format(vc, formats[0].fourcc,
|
|
|
|
+ TW686X_VIDEO_WIDTH,
|
|
|
|
+ TW686X_VIDEO_HEIGHT(vc->video_standard),
|
|
|
|
+ true);
|
|
|
|
+ if (err)
|
|
|
|
+ goto error;
|
|
|
|
|
|
|
|
+ tw686x_set_input(vc, 0);
|
|
|
|
+ tw686x_set_framerate(vc, 30);
|
|
reg_write(dev, VDELAY_LO[ch], 0x14);
|
|
reg_write(dev, VDELAY_LO[ch], 0x14);
|
|
reg_write(dev, HACTIVE_LO[ch], 0xd0);
|
|
reg_write(dev, HACTIVE_LO[ch], 0xd0);
|
|
reg_write(dev, VIDEO_SIZE[ch], 0);
|
|
reg_write(dev, VIDEO_SIZE[ch], 0);
|
|
|
|
|
|
- if (dev->dma_ops->alloc) {
|
|
|
|
- for (pb = 0; pb < 2; pb++) {
|
|
|
|
- err = dev->dma_ops->alloc(vc, pb);
|
|
|
|
- if (err)
|
|
|
|
- goto error;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
|
|
vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
|
|
vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vc->vidq.drv_priv = vc;
|
|
vc->vidq.drv_priv = vc;
|