1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * tw68 functions to handle video data
5 * Much of this code is derived from the cx88 and sa7134 drivers, which
6 * were in turn derived from the bt87x driver. The original work was by
7 * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
8 * Hans Verkuil, Andy Walls and many others. Their work is gratefully
9 * acknowledged. Full credit goes to them - any problems within this code
12 * Copyright (C) 2009 William M. Brack
14 * Refactored and updated to the latest v4l core frameworks:
16 * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
19 #include <linux/module.h>
20 #include <media/v4l2-common.h>
21 #include <media/v4l2-event.h>
22 #include <media/videobuf2-dma-sg.h>
27 /* ------------------------------------------------------------------ */
28 /* data structs for video */
31 * Note that the saa7134 has formats, e.g. YUV420, which are classified
32 * as "planar". These affect overlay mode, and are flagged with a field
33 * ".planar" in the format. Do we need to implement this in this driver?
35 static const struct tw68_format formats
[] = {
37 .fourcc
= V4L2_PIX_FMT_RGB555
,
39 .twformat
= ColorFormatRGB15
,
41 .fourcc
= V4L2_PIX_FMT_RGB555X
,
43 .twformat
= ColorFormatRGB15
| ColorFormatBSWAP
,
45 .fourcc
= V4L2_PIX_FMT_RGB565
,
47 .twformat
= ColorFormatRGB16
,
49 .fourcc
= V4L2_PIX_FMT_RGB565X
,
51 .twformat
= ColorFormatRGB16
| ColorFormatBSWAP
,
53 .fourcc
= V4L2_PIX_FMT_BGR24
,
55 .twformat
= ColorFormatRGB24
,
57 .fourcc
= V4L2_PIX_FMT_RGB24
,
59 .twformat
= ColorFormatRGB24
| ColorFormatBSWAP
,
61 .fourcc
= V4L2_PIX_FMT_BGR32
,
63 .twformat
= ColorFormatRGB32
,
65 .fourcc
= V4L2_PIX_FMT_RGB32
,
67 .twformat
= ColorFormatRGB32
| ColorFormatBSWAP
|
70 .fourcc
= V4L2_PIX_FMT_YUYV
,
72 .twformat
= ColorFormatYUY2
,
74 .fourcc
= V4L2_PIX_FMT_UYVY
,
76 .twformat
= ColorFormatYUY2
| ColorFormatBSWAP
,
79 #define FORMATS ARRAY_SIZE(formats)
89 .video_v_start = 24, \
90 .video_v_stop = 311, \
99 .vbi_v_start_0 = 10, \
100 .vbi_v_stop_0 = 21, \
101 .video_v_start = 22, \
102 .video_v_stop = 262, \
106 * The following table is searched by tw68_s_std, first for a specific
107 * match, then for an entry which contains the desired id. The table
108 * entries should therefore be ordered in ascending order of specificity.
110 static const struct tw68_tvnorm tvnorms
[] = {
112 .name
= "PAL", /* autodetect */
116 .sync_control
= 0x18,
117 .luma_control
= 0x40,
118 .chroma_ctrl1
= 0x81,
120 .chroma_ctrl2
= 0x06,
122 .format
= VideoFormatPALBDGHI
,
128 .sync_control
= 0x59,
129 .luma_control
= 0x40,
130 .chroma_ctrl1
= 0x89,
132 .chroma_ctrl2
= 0x0e,
134 .format
= VideoFormatNTSC
,
137 .id
= V4L2_STD_SECAM
,
140 .sync_control
= 0x18,
141 .luma_control
= 0x1b,
142 .chroma_ctrl1
= 0xd1,
144 .chroma_ctrl2
= 0x00,
146 .format
= VideoFormatSECAM
,
149 .id
= V4L2_STD_PAL_M
,
152 .sync_control
= 0x59,
153 .luma_control
= 0x40,
154 .chroma_ctrl1
= 0xb9,
156 .chroma_ctrl2
= 0x0e,
158 .format
= VideoFormatPALM
,
161 .id
= V4L2_STD_PAL_Nc
,
164 .sync_control
= 0x18,
165 .luma_control
= 0x40,
166 .chroma_ctrl1
= 0xa1,
168 .chroma_ctrl2
= 0x06,
170 .format
= VideoFormatPALNC
,
173 .id
= V4L2_STD_PAL_60
,
182 .vbi_v_start_1
= 273,
184 .sync_control
= 0x18,
185 .luma_control
= 0x40,
186 .chroma_ctrl1
= 0x81,
188 .chroma_ctrl2
= 0x06,
190 .format
= VideoFormatPAL60
,
193 #define TVNORMS ARRAY_SIZE(tvnorms)
195 static const struct tw68_format
*format_by_fourcc(unsigned int fourcc
)
199 for (i
= 0; i
< FORMATS
; i
++)
200 if (formats
[i
].fourcc
== fourcc
)
206 /* ------------------------------------------------------------------ */
208 * Note that the cropping rectangles are described in terms of a single
209 * frame, i.e. line positions are only 1/2 the interlaced equivalent
211 static void set_tvnorm(struct tw68_dev
*dev
, const struct tw68_tvnorm
*norm
)
213 if (norm
!= dev
->tvnorm
) {
215 dev
->height
= (norm
->id
& V4L2_STD_525_60
) ? 480 : 576;
217 tw68_set_tvnorm_hw(dev
);
224 * Scaling and Cropping for video decoding
226 * We are working with 3 values for horizontal and vertical - scale,
229 * HACTIVE represent the actual number of pixels in the "usable" image,
230 * before scaling. HDELAY represents the number of pixels skipped
231 * between the start of the horizontal sync and the start of the image.
232 * HSCALE is calculated using the formula
233 * HSCALE = (HACTIVE / (#pixels desired)) * 256
235 * The vertical registers are similar, except based upon the total number
236 * of lines in the image, and the first line of the image (i.e. ignoring
237 * vertical sync and VBI).
239 * Note that the number of bytes reaching the FIFO (and hence needing
240 * to be processed by the DMAP program) is completely dependent upon
241 * these values, especially HSCALE.
244 * @dev pointer to the device structure, needed for
245 * getting current norm (as well as debug print)
246 * @width actual image width (from user buffer)
247 * @height actual image height
248 * @field indicates Top, Bottom or Interlaced
250 static int tw68_set_scale(struct tw68_dev
*dev
, unsigned int width
,
251 unsigned int height
, enum v4l2_field field
)
253 const struct tw68_tvnorm
*norm
= dev
->tvnorm
;
254 /* set individually for debugging clarity */
255 int hactive
, hdelay
, hscale
;
256 int vactive
, vdelay
, vscale
;
259 if (V4L2_FIELD_HAS_BOTH(field
)) /* if field is interlaced */
260 height
/= 2; /* we must set for 1-frame */
262 pr_debug("%s: width=%d, height=%d, both=%d\n"
263 " tvnorm h_delay=%d, h_start=%d, h_stop=%d, v_delay=%d, v_start=%d, v_stop=%d\n",
264 __func__
, width
, height
, V4L2_FIELD_HAS_BOTH(field
),
265 norm
->h_delay
, norm
->h_start
, norm
->h_stop
,
266 norm
->v_delay
, norm
->video_v_start
,
269 switch (dev
->vdecoder
) {
271 hdelay
= norm
->h_delay0
;
274 hdelay
= norm
->h_delay
;
278 hdelay
+= norm
->h_start
;
279 hactive
= norm
->h_stop
- norm
->h_start
+ 1;
281 hscale
= (hactive
* 256) / (width
);
283 vdelay
= norm
->v_delay
;
284 vactive
= ((norm
->id
& V4L2_STD_525_60
) ? 524 : 624) / 2 - norm
->video_v_start
;
285 vscale
= (vactive
* 256) / height
;
287 pr_debug("%s: %dx%d [%s%s,%s]\n", __func__
,
289 V4L2_FIELD_HAS_TOP(field
) ? "T" : "",
290 V4L2_FIELD_HAS_BOTTOM(field
) ? "B" : "",
291 v4l2_norm_to_name(dev
->tvnorm
->id
));
292 pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n",
294 hactive
, hdelay
, hscale
, vactive
, vdelay
, vscale
);
296 comb
= ((vdelay
& 0x300) >> 2) |
297 ((vactive
& 0x300) >> 4) |
298 ((hdelay
& 0x300) >> 6) |
299 ((hactive
& 0x300) >> 8);
300 pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
301 __func__
, comb
, vdelay
, vactive
, hdelay
, hactive
);
302 tw_writeb(TW68_CROP_HI
, comb
);
303 tw_writeb(TW68_VDELAY_LO
, vdelay
& 0xff);
304 tw_writeb(TW68_VACTIVE_LO
, vactive
& 0xff);
305 tw_writeb(TW68_HDELAY_LO
, hdelay
& 0xff);
306 tw_writeb(TW68_HACTIVE_LO
, hactive
& 0xff);
308 comb
= ((vscale
& 0xf00) >> 4) | ((hscale
& 0xf00) >> 8);
309 pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n",
310 __func__
, comb
, vscale
, hscale
);
311 tw_writeb(TW68_SCALE_HI
, comb
);
312 tw_writeb(TW68_VSCALE_LO
, vscale
);
313 tw_writeb(TW68_HSCALE_LO
, hscale
);
318 /* ------------------------------------------------------------------ */
320 int tw68_video_start_dma(struct tw68_dev
*dev
, struct tw68_buf
*buf
)
322 /* Set cropping and scaling */
323 tw68_set_scale(dev
, dev
->width
, dev
->height
, dev
->field
);
325 * Set start address for RISC program. Note that if the DMAP
326 * processor is currently running, it must be stopped before
327 * a new address can be set.
329 tw_clearl(TW68_DMAC
, TW68_DMAP_EN
);
330 tw_writel(TW68_DMAP_SA
, buf
->dma
);
331 /* Clear any pending interrupts */
332 tw_writel(TW68_INTSTAT
, dev
->board_virqmask
);
333 /* Enable the risc engine and the fifo */
334 tw_andorl(TW68_DMAC
, 0xff, dev
->fmt
->twformat
|
335 ColorFormatGamma
| TW68_DMAP_EN
| TW68_FIFO_EN
);
336 dev
->pci_irqmask
|= dev
->board_virqmask
;
337 tw_setl(TW68_INTMASK
, dev
->pci_irqmask
);
341 /* ------------------------------------------------------------------ */
343 /* calc max # of buffers from size (must not exceed the 4MB virtual
344 * address space per DMA channel) */
345 static int tw68_buffer_count(unsigned int size
, unsigned int count
)
347 unsigned int maxcount
;
349 maxcount
= (4 * 1024 * 1024) / roundup(size
, PAGE_SIZE
);
350 if (count
> maxcount
)
355 /* ------------------------------------------------------------- */
356 /* vb2 queue operations */
358 static int tw68_queue_setup(struct vb2_queue
*q
,
359 unsigned int *num_buffers
, unsigned int *num_planes
,
360 unsigned int sizes
[], struct device
*alloc_devs
[])
362 struct tw68_dev
*dev
= vb2_get_drv_priv(q
);
363 unsigned tot_bufs
= q
->num_buffers
+ *num_buffers
;
364 unsigned size
= (dev
->fmt
->depth
* dev
->width
* dev
->height
) >> 3;
368 tot_bufs
= tw68_buffer_count(size
, tot_bufs
);
369 *num_buffers
= tot_bufs
- q
->num_buffers
;
371 * We allow create_bufs, but only if the sizeimage is >= as the
372 * current sizeimage. The tw68_buffer_count calculation becomes quite
373 * difficult otherwise.
376 return sizes
[0] < size
? -EINVAL
: 0;
384 * The risc program for each buffers works as follows: it starts with a simple
385 * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
386 * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
389 * This is the program of the first buffer to be queued if the active list is
390 * empty and it just keeps DMAing this buffer without generating any interrupts.
392 * If a new buffer is added then the initial JUMP in the program generates an
393 * interrupt as well which signals that the previous buffer has been DMAed
394 * successfully and that it can be returned to userspace.
396 * It also sets the final jump of the previous buffer to the start of the new
397 * buffer, thus chaining the new buffer into the DMA chain. This is a single
398 * atomic u32 write, so there is no race condition.
400 * The end-result of all this that you only get an interrupt when a buffer
401 * is ready, so the control flow is very easy.
403 static void tw68_buf_queue(struct vb2_buffer
*vb
)
405 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
406 struct vb2_queue
*vq
= vb
->vb2_queue
;
407 struct tw68_dev
*dev
= vb2_get_drv_priv(vq
);
408 struct tw68_buf
*buf
= container_of(vbuf
, struct tw68_buf
, vb
);
409 struct tw68_buf
*prev
;
412 spin_lock_irqsave(&dev
->slock
, flags
);
414 /* append a 'JUMP to start of buffer' to the buffer risc program */
415 buf
->jmp
[0] = cpu_to_le32(RISC_JUMP
);
416 buf
->jmp
[1] = cpu_to_le32(buf
->dma
+ 8);
418 if (!list_empty(&dev
->active
)) {
419 prev
= list_entry(dev
->active
.prev
, struct tw68_buf
, list
);
420 buf
->cpu
[0] |= cpu_to_le32(RISC_INT_BIT
);
421 prev
->jmp
[1] = cpu_to_le32(buf
->dma
);
423 list_add_tail(&buf
->list
, &dev
->active
);
424 spin_unlock_irqrestore(&dev
->slock
, flags
);
430 * Set the ancillary information into the buffer structure. This
431 * includes generating the necessary risc program if it hasn't already
432 * been done for the current buffer format.
433 * The structure fh contains the details of the format requested by the
434 * user - type, width, height and #fields. This is compared with the
435 * last format set for the current buffer. If they differ, the risc
436 * code (which controls the filling of the buffer) is (re-)generated.
438 static int tw68_buf_prepare(struct vb2_buffer
*vb
)
440 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
441 struct vb2_queue
*vq
= vb
->vb2_queue
;
442 struct tw68_dev
*dev
= vb2_get_drv_priv(vq
);
443 struct tw68_buf
*buf
= container_of(vbuf
, struct tw68_buf
, vb
);
444 struct sg_table
*dma
= vb2_dma_sg_plane_desc(vb
, 0);
447 size
= (dev
->width
* dev
->height
* dev
->fmt
->depth
) >> 3;
448 if (vb2_plane_size(vb
, 0) < size
)
450 vb2_set_plane_payload(vb
, 0, size
);
452 bpl
= (dev
->width
* dev
->fmt
->depth
) >> 3;
453 switch (dev
->field
) {
455 tw68_risc_buffer(dev
->pci
, buf
, dma
->sgl
,
456 0, UNSET
, bpl
, 0, dev
->height
);
458 case V4L2_FIELD_BOTTOM
:
459 tw68_risc_buffer(dev
->pci
, buf
, dma
->sgl
,
460 UNSET
, 0, bpl
, 0, dev
->height
);
462 case V4L2_FIELD_SEQ_TB
:
463 tw68_risc_buffer(dev
->pci
, buf
, dma
->sgl
,
464 0, bpl
* (dev
->height
>> 1),
465 bpl
, 0, dev
->height
>> 1);
467 case V4L2_FIELD_SEQ_BT
:
468 tw68_risc_buffer(dev
->pci
, buf
, dma
->sgl
,
469 bpl
* (dev
->height
>> 1), 0,
470 bpl
, 0, dev
->height
>> 1);
472 case V4L2_FIELD_INTERLACED
:
474 tw68_risc_buffer(dev
->pci
, buf
, dma
->sgl
,
475 0, bpl
, bpl
, bpl
, dev
->height
>> 1);
481 static void tw68_buf_finish(struct vb2_buffer
*vb
)
483 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
484 struct vb2_queue
*vq
= vb
->vb2_queue
;
485 struct tw68_dev
*dev
= vb2_get_drv_priv(vq
);
486 struct tw68_buf
*buf
= container_of(vbuf
, struct tw68_buf
, vb
);
488 pci_free_consistent(dev
->pci
, buf
->size
, buf
->cpu
, buf
->dma
);
491 static int tw68_start_streaming(struct vb2_queue
*q
, unsigned int count
)
493 struct tw68_dev
*dev
= vb2_get_drv_priv(q
);
494 struct tw68_buf
*buf
=
495 container_of(dev
->active
.next
, struct tw68_buf
, list
);
498 tw68_video_start_dma(dev
, buf
);
502 static void tw68_stop_streaming(struct vb2_queue
*q
)
504 struct tw68_dev
*dev
= vb2_get_drv_priv(q
);
506 /* Stop risc & fifo */
507 tw_clearl(TW68_DMAC
, TW68_DMAP_EN
| TW68_FIFO_EN
);
508 while (!list_empty(&dev
->active
)) {
509 struct tw68_buf
*buf
=
510 container_of(dev
->active
.next
, struct tw68_buf
, list
);
512 list_del(&buf
->list
);
513 vb2_buffer_done(&buf
->vb
.vb2_buf
, VB2_BUF_STATE_ERROR
);
517 static const struct vb2_ops tw68_video_qops
= {
518 .queue_setup
= tw68_queue_setup
,
519 .buf_queue
= tw68_buf_queue
,
520 .buf_prepare
= tw68_buf_prepare
,
521 .buf_finish
= tw68_buf_finish
,
522 .start_streaming
= tw68_start_streaming
,
523 .stop_streaming
= tw68_stop_streaming
,
524 .wait_prepare
= vb2_ops_wait_prepare
,
525 .wait_finish
= vb2_ops_wait_finish
,
528 /* ------------------------------------------------------------------ */
530 static int tw68_s_ctrl(struct v4l2_ctrl
*ctrl
)
532 struct tw68_dev
*dev
=
533 container_of(ctrl
->handler
, struct tw68_dev
, hdl
);
536 case V4L2_CID_BRIGHTNESS
:
537 tw_writeb(TW68_BRIGHT
, ctrl
->val
);
540 tw_writeb(TW68_HUE
, ctrl
->val
);
542 case V4L2_CID_CONTRAST
:
543 tw_writeb(TW68_CONTRAST
, ctrl
->val
);
545 case V4L2_CID_SATURATION
:
546 tw_writeb(TW68_SAT_U
, ctrl
->val
);
547 tw_writeb(TW68_SAT_V
, ctrl
->val
);
549 case V4L2_CID_COLOR_KILLER
:
551 tw_andorb(TW68_MISC2
, 0xe0, 0xe0);
553 tw_andorb(TW68_MISC2
, 0xe0, 0x00);
555 case V4L2_CID_CHROMA_AGC
:
557 tw_andorb(TW68_LOOP
, 0x30, 0x20);
559 tw_andorb(TW68_LOOP
, 0x30, 0x00);
565 /* ------------------------------------------------------------------ */
568 * Note that this routine returns what is stored in the fh structure, and
569 * does not interrogate any of the device registers.
571 static int tw68_g_fmt_vid_cap(struct file
*file
, void *priv
,
572 struct v4l2_format
*f
)
574 struct tw68_dev
*dev
= video_drvdata(file
);
576 f
->fmt
.pix
.width
= dev
->width
;
577 f
->fmt
.pix
.height
= dev
->height
;
578 f
->fmt
.pix
.field
= dev
->field
;
579 f
->fmt
.pix
.pixelformat
= dev
->fmt
->fourcc
;
580 f
->fmt
.pix
.bytesperline
=
581 (f
->fmt
.pix
.width
* (dev
->fmt
->depth
)) >> 3;
582 f
->fmt
.pix
.sizeimage
=
583 f
->fmt
.pix
.height
* f
->fmt
.pix
.bytesperline
;
584 f
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_SMPTE170M
;
588 static int tw68_try_fmt_vid_cap(struct file
*file
, void *priv
,
589 struct v4l2_format
*f
)
591 struct tw68_dev
*dev
= video_drvdata(file
);
592 const struct tw68_format
*fmt
;
593 enum v4l2_field field
;
596 fmt
= format_by_fourcc(f
->fmt
.pix
.pixelformat
);
600 field
= f
->fmt
.pix
.field
;
601 maxh
= (dev
->tvnorm
->id
& V4L2_STD_525_60
) ? 480 : 576;
605 case V4L2_FIELD_BOTTOM
:
607 case V4L2_FIELD_INTERLACED
:
608 case V4L2_FIELD_SEQ_BT
:
609 case V4L2_FIELD_SEQ_TB
:
613 field
= (f
->fmt
.pix
.height
> maxh
/ 2)
614 ? V4L2_FIELD_INTERLACED
619 f
->fmt
.pix
.field
= field
;
620 if (f
->fmt
.pix
.width
< 48)
621 f
->fmt
.pix
.width
= 48;
622 if (f
->fmt
.pix
.height
< 32)
623 f
->fmt
.pix
.height
= 32;
624 if (f
->fmt
.pix
.width
> 720)
625 f
->fmt
.pix
.width
= 720;
626 if (f
->fmt
.pix
.height
> maxh
)
627 f
->fmt
.pix
.height
= maxh
;
628 f
->fmt
.pix
.width
&= ~0x03;
629 f
->fmt
.pix
.bytesperline
=
630 (f
->fmt
.pix
.width
* (fmt
->depth
)) >> 3;
631 f
->fmt
.pix
.sizeimage
=
632 f
->fmt
.pix
.height
* f
->fmt
.pix
.bytesperline
;
633 f
->fmt
.pix
.colorspace
= V4L2_COLORSPACE_SMPTE170M
;
638 * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
639 * and it will be used for all future new buffers. However, there could be
640 * some number of buffers on the "active" chain which will be filled before
641 * the change takes place.
643 static int tw68_s_fmt_vid_cap(struct file
*file
, void *priv
,
644 struct v4l2_format
*f
)
646 struct tw68_dev
*dev
= video_drvdata(file
);
649 err
= tw68_try_fmt_vid_cap(file
, priv
, f
);
653 dev
->fmt
= format_by_fourcc(f
->fmt
.pix
.pixelformat
);
654 dev
->width
= f
->fmt
.pix
.width
;
655 dev
->height
= f
->fmt
.pix
.height
;
656 dev
->field
= f
->fmt
.pix
.field
;
660 static int tw68_enum_input(struct file
*file
, void *priv
,
661 struct v4l2_input
*i
)
663 struct tw68_dev
*dev
= video_drvdata(file
);
667 if (n
>= TW68_INPUT_MAX
)
670 i
->type
= V4L2_INPUT_TYPE_CAMERA
;
671 snprintf(i
->name
, sizeof(i
->name
), "Composite %d", n
);
673 /* If the query is for the current input, get live data */
674 if (n
== dev
->input
) {
675 int v1
= tw_readb(TW68_STATUS1
);
676 int v2
= tw_readb(TW68_MVSN
);
678 if (0 != (v1
& (1 << 7)))
679 i
->status
|= V4L2_IN_ST_NO_SYNC
;
680 if (0 != (v1
& (1 << 6)))
681 i
->status
|= V4L2_IN_ST_NO_H_LOCK
;
682 if (0 != (v1
& (1 << 2)))
683 i
->status
|= V4L2_IN_ST_NO_SIGNAL
;
684 if (0 != (v1
& 1 << 1))
685 i
->status
|= V4L2_IN_ST_NO_COLOR
;
686 if (0 != (v2
& (1 << 2)))
687 i
->status
|= V4L2_IN_ST_MACROVISION
;
689 i
->std
= video_devdata(file
)->tvnorms
;
693 static int tw68_g_input(struct file
*file
, void *priv
, unsigned int *i
)
695 struct tw68_dev
*dev
= video_drvdata(file
);
701 static int tw68_s_input(struct file
*file
, void *priv
, unsigned int i
)
703 struct tw68_dev
*dev
= video_drvdata(file
);
705 if (i
>= TW68_INPUT_MAX
)
708 tw_andorb(TW68_INFORM
, 0x03 << 2, dev
->input
<< 2);
712 static int tw68_querycap(struct file
*file
, void *priv
,
713 struct v4l2_capability
*cap
)
715 struct tw68_dev
*dev
= video_drvdata(file
);
717 strscpy(cap
->driver
, "tw68", sizeof(cap
->driver
));
718 strscpy(cap
->card
, "Techwell Capture Card",
720 sprintf(cap
->bus_info
, "PCI:%s", pci_name(dev
->pci
));
724 static int tw68_s_std(struct file
*file
, void *priv
, v4l2_std_id id
)
726 struct tw68_dev
*dev
= video_drvdata(file
);
729 if (vb2_is_busy(&dev
->vidq
))
732 /* Look for match on complete norm id (may have mult bits) */
733 for (i
= 0; i
< TVNORMS
; i
++) {
734 if (id
== tvnorms
[i
].id
)
738 /* If no exact match, look for norm which contains this one */
740 for (i
= 0; i
< TVNORMS
; i
++)
741 if (id
& tvnorms
[i
].id
)
744 /* If still not matched, give up */
748 set_tvnorm(dev
, &tvnorms
[i
]); /* do the actual setting */
752 static int tw68_g_std(struct file
*file
, void *priv
, v4l2_std_id
*id
)
754 struct tw68_dev
*dev
= video_drvdata(file
);
756 *id
= dev
->tvnorm
->id
;
760 static int tw68_enum_fmt_vid_cap(struct file
*file
, void *priv
,
761 struct v4l2_fmtdesc
*f
)
763 if (f
->index
>= FORMATS
)
766 f
->pixelformat
= formats
[f
->index
].fourcc
;
772 * Used strictly for internal development and debugging, this routine
773 * prints out the current register contents for the tw68xx device.
775 static void tw68_dump_regs(struct tw68_dev
*dev
)
777 unsigned char line
[80];
781 pr_info("Full dump of TW68 registers:\n");
782 /* First we do the PCI regs, 8 4-byte regs per line */
783 for (i
= 0; i
< 0x100; i
+= 32) {
785 cptr
+= sprintf(cptr
, "%03x ", i
);
786 /* j steps through the next 4 words */
787 for (j
= i
; j
< i
+ 16; j
+= 4)
788 cptr
+= sprintf(cptr
, "%08x ", tw_readl(j
));
790 for (; j
< i
+ 32; j
+= 4)
791 cptr
+= sprintf(cptr
, "%08x ", tw_readl(j
));
796 /* Next the control regs, which are single-byte, address mod 4 */
799 cptr
+= sprintf(cptr
, "%03x ", i
);
800 /* Print out 4 groups of 4 bytes */
801 for (j
= 0; j
< 4; j
++) {
802 for (k
= 0; k
< 4; k
++) {
803 cptr
+= sprintf(cptr
, "%02x ",
815 static int vidioc_log_status(struct file
*file
, void *priv
)
817 struct tw68_dev
*dev
= video_drvdata(file
);
820 return v4l2_ctrl_log_status(file
, priv
);
823 #ifdef CONFIG_VIDEO_ADV_DEBUG
824 static int vidioc_g_register(struct file
*file
, void *priv
,
825 struct v4l2_dbg_register
*reg
)
827 struct tw68_dev
*dev
= video_drvdata(file
);
830 reg
->val
= tw_readb(reg
->reg
);
832 reg
->val
= tw_readl(reg
->reg
);
836 static int vidioc_s_register(struct file
*file
, void *priv
,
837 const struct v4l2_dbg_register
*reg
)
839 struct tw68_dev
*dev
= video_drvdata(file
);
842 tw_writeb(reg
->reg
, reg
->val
);
844 tw_writel(reg
->reg
& 0xffff, reg
->val
);
849 static const struct v4l2_ctrl_ops tw68_ctrl_ops
= {
850 .s_ctrl
= tw68_s_ctrl
,
853 static const struct v4l2_file_operations video_fops
= {
854 .owner
= THIS_MODULE
,
855 .open
= v4l2_fh_open
,
856 .release
= vb2_fop_release
,
857 .read
= vb2_fop_read
,
858 .poll
= vb2_fop_poll
,
859 .mmap
= vb2_fop_mmap
,
860 .unlocked_ioctl
= video_ioctl2
,
863 static const struct v4l2_ioctl_ops video_ioctl_ops
= {
864 .vidioc_querycap
= tw68_querycap
,
865 .vidioc_enum_fmt_vid_cap
= tw68_enum_fmt_vid_cap
,
866 .vidioc_reqbufs
= vb2_ioctl_reqbufs
,
867 .vidioc_create_bufs
= vb2_ioctl_create_bufs
,
868 .vidioc_querybuf
= vb2_ioctl_querybuf
,
869 .vidioc_qbuf
= vb2_ioctl_qbuf
,
870 .vidioc_dqbuf
= vb2_ioctl_dqbuf
,
871 .vidioc_s_std
= tw68_s_std
,
872 .vidioc_g_std
= tw68_g_std
,
873 .vidioc_enum_input
= tw68_enum_input
,
874 .vidioc_g_input
= tw68_g_input
,
875 .vidioc_s_input
= tw68_s_input
,
876 .vidioc_streamon
= vb2_ioctl_streamon
,
877 .vidioc_streamoff
= vb2_ioctl_streamoff
,
878 .vidioc_g_fmt_vid_cap
= tw68_g_fmt_vid_cap
,
879 .vidioc_try_fmt_vid_cap
= tw68_try_fmt_vid_cap
,
880 .vidioc_s_fmt_vid_cap
= tw68_s_fmt_vid_cap
,
881 .vidioc_log_status
= vidioc_log_status
,
882 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
883 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
884 #ifdef CONFIG_VIDEO_ADV_DEBUG
885 .vidioc_g_register
= vidioc_g_register
,
886 .vidioc_s_register
= vidioc_s_register
,
890 static const struct video_device tw68_video_template
= {
891 .name
= "tw68_video",
893 .ioctl_ops
= &video_ioctl_ops
,
894 .release
= video_device_release_empty
,
895 .tvnorms
= TW68_NORMS
,
896 .device_caps
= V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_READWRITE
|
900 /* ------------------------------------------------------------------ */
902 void tw68_set_tvnorm_hw(struct tw68_dev
*dev
)
904 tw_andorb(TW68_SDT
, 0x07, dev
->tvnorm
->format
);
907 int tw68_video_init1(struct tw68_dev
*dev
)
909 struct v4l2_ctrl_handler
*hdl
= &dev
->hdl
;
911 v4l2_ctrl_handler_init(hdl
, 6);
912 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
913 V4L2_CID_BRIGHTNESS
, -128, 127, 1, 20);
914 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
915 V4L2_CID_CONTRAST
, 0, 255, 1, 100);
916 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
917 V4L2_CID_SATURATION
, 0, 255, 1, 128);
919 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
920 V4L2_CID_HUE
, -128, 127, 1, 0);
921 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
922 V4L2_CID_COLOR_KILLER
, 0, 1, 1, 0);
923 v4l2_ctrl_new_std(hdl
, &tw68_ctrl_ops
,
924 V4L2_CID_CHROMA_AGC
, 0, 1, 1, 1);
926 v4l2_ctrl_handler_free(hdl
);
929 dev
->v4l2_dev
.ctrl_handler
= hdl
;
930 v4l2_ctrl_handler_setup(hdl
);
934 int tw68_video_init2(struct tw68_dev
*dev
, int video_nr
)
938 set_tvnorm(dev
, &tvnorms
[0]);
940 dev
->fmt
= format_by_fourcc(V4L2_PIX_FMT_BGR24
);
943 dev
->field
= V4L2_FIELD_INTERLACED
;
945 INIT_LIST_HEAD(&dev
->active
);
946 dev
->vidq
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
947 dev
->vidq
.timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
;
948 dev
->vidq
.io_modes
= VB2_MMAP
| VB2_USERPTR
| VB2_READ
| VB2_DMABUF
;
949 dev
->vidq
.ops
= &tw68_video_qops
;
950 dev
->vidq
.mem_ops
= &vb2_dma_sg_memops
;
951 dev
->vidq
.drv_priv
= dev
;
952 dev
->vidq
.gfp_flags
= __GFP_DMA32
| __GFP_KSWAPD_RECLAIM
;
953 dev
->vidq
.buf_struct_size
= sizeof(struct tw68_buf
);
954 dev
->vidq
.lock
= &dev
->lock
;
955 dev
->vidq
.min_buffers_needed
= 2;
956 dev
->vidq
.dev
= &dev
->pci
->dev
;
957 ret
= vb2_queue_init(&dev
->vidq
);
960 dev
->vdev
= tw68_video_template
;
961 dev
->vdev
.v4l2_dev
= &dev
->v4l2_dev
;
962 dev
->vdev
.lock
= &dev
->lock
;
963 dev
->vdev
.queue
= &dev
->vidq
;
964 video_set_drvdata(&dev
->vdev
, dev
);
965 return video_register_device(&dev
->vdev
, VFL_TYPE_VIDEO
, video_nr
);
969 * tw68_irq_video_done
971 void tw68_irq_video_done(struct tw68_dev
*dev
, unsigned long status
)
975 /* reset interrupts handled by this routine */
976 tw_writel(TW68_INTSTAT
, status
);
978 * Check most likely first
980 * DMAPI shows we have reached the end of the risc code
981 * for the current buffer.
983 if (status
& TW68_DMAPI
) {
984 struct tw68_buf
*buf
;
986 spin_lock(&dev
->slock
);
987 buf
= list_entry(dev
->active
.next
, struct tw68_buf
, list
);
988 list_del(&buf
->list
);
989 spin_unlock(&dev
->slock
);
990 buf
->vb
.vb2_buf
.timestamp
= ktime_get_ns();
991 buf
->vb
.field
= dev
->field
;
992 buf
->vb
.sequence
= dev
->seqnr
++;
993 vb2_buffer_done(&buf
->vb
.vb2_buf
, VB2_BUF_STATE_DONE
);
994 status
&= ~(TW68_DMAPI
);
998 if (status
& (TW68_VLOCK
| TW68_HLOCK
))
999 dev_dbg(&dev
->pci
->dev
, "Lost sync\n");
1000 if (status
& TW68_PABORT
)
1001 dev_err(&dev
->pci
->dev
, "PABORT interrupt\n");
1002 if (status
& TW68_DMAPERR
)
1003 dev_err(&dev
->pci
->dev
, "DMAPERR interrupt\n");
1005 * On TW6800, FDMIS is apparently generated if video input is switched
1006 * during operation. Therefore, it is not enabled for that chip.
1008 if (status
& TW68_FDMIS
)
1009 dev_dbg(&dev
->pci
->dev
, "FDMIS interrupt\n");
1010 if (status
& TW68_FFOF
) {
1011 /* probably a logic error */
1012 reg
= tw_readl(TW68_DMAC
) & TW68_FIFO_EN
;
1013 tw_clearl(TW68_DMAC
, TW68_FIFO_EN
);
1014 dev_dbg(&dev
->pci
->dev
, "FFOF interrupt\n");
1015 tw_setl(TW68_DMAC
, reg
);
1017 if (status
& TW68_FFERR
)
1018 dev_dbg(&dev
->pci
->dev
, "FFERR interrupt\n");