xref: /linux/drivers/media/pci/cx18/cx18-streams.c (revision 3e30a927af3ca86f6556faf437da44ca8bcf54a4)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b285192aSMauro Carvalho Chehab /*
3b285192aSMauro Carvalho Chehab  *  cx18 init/start/stop/exit stream functions
4b285192aSMauro Carvalho Chehab  *
5b285192aSMauro Carvalho Chehab  *  Derived from ivtv-streams.c
6b285192aSMauro Carvalho Chehab  *
7b285192aSMauro Carvalho Chehab  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
8b285192aSMauro Carvalho Chehab  *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.net>
9b285192aSMauro Carvalho Chehab  */
10b285192aSMauro Carvalho Chehab 
11b285192aSMauro Carvalho Chehab #include "cx18-driver.h"
12b285192aSMauro Carvalho Chehab #include "cx18-io.h"
13b285192aSMauro Carvalho Chehab #include "cx18-fileops.h"
14b285192aSMauro Carvalho Chehab #include "cx18-mailbox.h"
15b285192aSMauro Carvalho Chehab #include "cx18-i2c.h"
16b285192aSMauro Carvalho Chehab #include "cx18-queue.h"
17b285192aSMauro Carvalho Chehab #include "cx18-ioctl.h"
18b285192aSMauro Carvalho Chehab #include "cx18-streams.h"
19b285192aSMauro Carvalho Chehab #include "cx18-cards.h"
20b285192aSMauro Carvalho Chehab #include "cx18-scb.h"
21b285192aSMauro Carvalho Chehab #include "cx18-dvb.h"
22b285192aSMauro Carvalho Chehab 
23b285192aSMauro Carvalho Chehab #define CX18_DSP0_INTERRUPT_MASK	0xd0004C
24b285192aSMauro Carvalho Chehab 
25e66fb184SBhumika Goyal static const struct v4l2_file_operations cx18_v4l2_enc_fops = {
26b285192aSMauro Carvalho Chehab 	.owner = THIS_MODULE,
27b285192aSMauro Carvalho Chehab 	.read = cx18_v4l2_read,
28b285192aSMauro Carvalho Chehab 	.open = cx18_v4l2_open,
29b285192aSMauro Carvalho Chehab 	.unlocked_ioctl = video_ioctl2,
30b285192aSMauro Carvalho Chehab 	.release = cx18_v4l2_close,
31b285192aSMauro Carvalho Chehab 	.poll = cx18_v4l2_enc_poll,
32b285192aSMauro Carvalho Chehab 	.mmap = cx18_v4l2_mmap,
33b285192aSMauro Carvalho Chehab };
34b285192aSMauro Carvalho Chehab 
35b285192aSMauro Carvalho Chehab /* offset from 0 to register ts v4l2 minors on */
36b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_TS_OFFSET   16
37b285192aSMauro Carvalho Chehab /* offset from 0 to register pcm v4l2 minors on */
38b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_PCM_OFFSET  24
39b285192aSMauro Carvalho Chehab /* offset from 0 to register yuv v4l2 minors on */
40b285192aSMauro Carvalho Chehab #define CX18_V4L2_ENC_YUV_OFFSET  32
41b285192aSMauro Carvalho Chehab 
42b285192aSMauro Carvalho Chehab static struct {
43b285192aSMauro Carvalho Chehab 	const char *name;
44b285192aSMauro Carvalho Chehab 	int vfl_type;
45b285192aSMauro Carvalho Chehab 	int num_offset;
46b285192aSMauro Carvalho Chehab 	int dma;
47dfdf780bSHans Verkuil 	u32 caps;
48b285192aSMauro Carvalho Chehab } cx18_stream_info[] = {
49b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_MPG */
50b285192aSMauro Carvalho Chehab 		"encoder MPEG",
51*3e30a927SHans Verkuil 		VFL_TYPE_VIDEO, 0,
52ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
53dfdf780bSHans Verkuil 		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
54dfdf780bSHans Verkuil 		V4L2_CAP_AUDIO | V4L2_CAP_TUNER
55b285192aSMauro Carvalho Chehab 	},
56b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_TS */
57b285192aSMauro Carvalho Chehab 		"TS",
58*3e30a927SHans Verkuil 		VFL_TYPE_VIDEO, -1,
59ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
60b285192aSMauro Carvalho Chehab 	},
61b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_YUV */
62b285192aSMauro Carvalho Chehab 		"encoder YUV",
63*3e30a927SHans Verkuil 		VFL_TYPE_VIDEO, CX18_V4L2_ENC_YUV_OFFSET,
64ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
65dfdf780bSHans Verkuil 		V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
66dfdf780bSHans Verkuil 		V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER
67b285192aSMauro Carvalho Chehab 	},
68b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_VBI */
69b285192aSMauro Carvalho Chehab 		"encoder VBI",
70b285192aSMauro Carvalho Chehab 		VFL_TYPE_VBI, 0,
71ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
72dfdf780bSHans Verkuil 		V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
73dfdf780bSHans Verkuil 		V4L2_CAP_READWRITE | V4L2_CAP_TUNER
74b285192aSMauro Carvalho Chehab 	},
75b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_PCM */
76b285192aSMauro Carvalho Chehab 		"encoder PCM audio",
77*3e30a927SHans Verkuil 		VFL_TYPE_VIDEO, CX18_V4L2_ENC_PCM_OFFSET,
78ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
792b4fd3edSHans Verkuil 		V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
80b285192aSMauro Carvalho Chehab 	},
81b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_IDX */
82b285192aSMauro Carvalho Chehab 		"encoder IDX",
83*3e30a927SHans Verkuil 		VFL_TYPE_VIDEO, -1,
84ff82b211SHans Verkuil 		PCI_DMA_FROMDEVICE,
85b285192aSMauro Carvalho Chehab 	},
86b285192aSMauro Carvalho Chehab 	{	/* CX18_ENC_STREAM_TYPE_RAD */
87b285192aSMauro Carvalho Chehab 		"encoder radio",
88b285192aSMauro Carvalho Chehab 		VFL_TYPE_RADIO, 0,
89ff82b211SHans Verkuil 		PCI_DMA_NONE,
90dfdf780bSHans Verkuil 		V4L2_CAP_RADIO | V4L2_CAP_TUNER
91b285192aSMauro Carvalho Chehab 	},
92b285192aSMauro Carvalho Chehab };
93b285192aSMauro Carvalho Chehab 
94b285192aSMauro Carvalho Chehab 
955e6e81b2SMauro Carvalho Chehab static void cx18_dma_free(struct videobuf_queue *q,
96b285192aSMauro Carvalho Chehab 	struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
97b285192aSMauro Carvalho Chehab {
98b285192aSMauro Carvalho Chehab 	videobuf_waiton(q, &buf->vb, 0, 0);
99b285192aSMauro Carvalho Chehab 	videobuf_vmalloc_free(&buf->vb);
100b285192aSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
101b285192aSMauro Carvalho Chehab }
102b285192aSMauro Carvalho Chehab 
103b285192aSMauro Carvalho Chehab static int cx18_prepare_buffer(struct videobuf_queue *q,
104b285192aSMauro Carvalho Chehab 	struct cx18_stream *s,
105b285192aSMauro Carvalho Chehab 	struct cx18_videobuf_buffer *buf,
106b285192aSMauro Carvalho Chehab 	u32 pixelformat,
107b285192aSMauro Carvalho Chehab 	unsigned int width, unsigned int height,
108b285192aSMauro Carvalho Chehab 	enum v4l2_field field)
109b285192aSMauro Carvalho Chehab {
110b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
111b285192aSMauro Carvalho Chehab 	int rc = 0;
112b285192aSMauro Carvalho Chehab 
113b285192aSMauro Carvalho Chehab 	/* check settings */
114b285192aSMauro Carvalho Chehab 	buf->bytes_used = 0;
115b285192aSMauro Carvalho Chehab 
116b285192aSMauro Carvalho Chehab 	if ((width  < 48) || (height < 32))
117b285192aSMauro Carvalho Chehab 		return -EINVAL;
118b285192aSMauro Carvalho Chehab 
119b285192aSMauro Carvalho Chehab 	buf->vb.size = (width * height * 2);
120b285192aSMauro Carvalho Chehab 	if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
121b285192aSMauro Carvalho Chehab 		return -EINVAL;
122b285192aSMauro Carvalho Chehab 
123b285192aSMauro Carvalho Chehab 	/* alloc + fill struct (if changed) */
124b285192aSMauro Carvalho Chehab 	if (buf->vb.width != width || buf->vb.height != height ||
125b285192aSMauro Carvalho Chehab 	    buf->vb.field != field || s->pixelformat != pixelformat ||
126b285192aSMauro Carvalho Chehab 	    buf->tvnorm != cx->std) {
127b285192aSMauro Carvalho Chehab 
128b285192aSMauro Carvalho Chehab 		buf->vb.width  = width;
129b285192aSMauro Carvalho Chehab 		buf->vb.height = height;
130b285192aSMauro Carvalho Chehab 		buf->vb.field  = field;
131b285192aSMauro Carvalho Chehab 		buf->tvnorm    = cx->std;
132b285192aSMauro Carvalho Chehab 		s->pixelformat = pixelformat;
133b285192aSMauro Carvalho Chehab 
134b285192aSMauro Carvalho Chehab 		/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
135b285192aSMauro Carvalho Chehab 		   UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
136b285192aSMauro Carvalho Chehab 		if (s->pixelformat == V4L2_PIX_FMT_HM12)
137b285192aSMauro Carvalho Chehab 			s->vb_bytes_per_frame = height * 720 * 3 / 2;
138b285192aSMauro Carvalho Chehab 		else
139b285192aSMauro Carvalho Chehab 			s->vb_bytes_per_frame = height * 720 * 2;
140b285192aSMauro Carvalho Chehab 		cx18_dma_free(q, s, buf);
141b285192aSMauro Carvalho Chehab 	}
142b285192aSMauro Carvalho Chehab 
143b285192aSMauro Carvalho Chehab 	if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
144b285192aSMauro Carvalho Chehab 		return -EINVAL;
145b285192aSMauro Carvalho Chehab 
146b285192aSMauro Carvalho Chehab 	if (buf->vb.field == 0)
147b285192aSMauro Carvalho Chehab 		buf->vb.field = V4L2_FIELD_INTERLACED;
148b285192aSMauro Carvalho Chehab 
149b285192aSMauro Carvalho Chehab 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
150b285192aSMauro Carvalho Chehab 		buf->vb.width  = width;
151b285192aSMauro Carvalho Chehab 		buf->vb.height = height;
152b285192aSMauro Carvalho Chehab 		buf->vb.field  = field;
153b285192aSMauro Carvalho Chehab 		buf->tvnorm    = cx->std;
154b285192aSMauro Carvalho Chehab 		s->pixelformat = pixelformat;
155b285192aSMauro Carvalho Chehab 
156b285192aSMauro Carvalho Chehab 		/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
157b285192aSMauro Carvalho Chehab 		   UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
158b285192aSMauro Carvalho Chehab 		if (s->pixelformat == V4L2_PIX_FMT_HM12)
159b285192aSMauro Carvalho Chehab 			s->vb_bytes_per_frame = height * 720 * 3 / 2;
160b285192aSMauro Carvalho Chehab 		else
161b285192aSMauro Carvalho Chehab 			s->vb_bytes_per_frame = height * 720 * 2;
162b285192aSMauro Carvalho Chehab 		rc = videobuf_iolock(q, &buf->vb, NULL);
163b285192aSMauro Carvalho Chehab 		if (rc != 0)
164b285192aSMauro Carvalho Chehab 			goto fail;
165b285192aSMauro Carvalho Chehab 	}
166b285192aSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_PREPARED;
167b285192aSMauro Carvalho Chehab 	return 0;
168b285192aSMauro Carvalho Chehab 
169b285192aSMauro Carvalho Chehab fail:
170b285192aSMauro Carvalho Chehab 	cx18_dma_free(q, s, buf);
171b285192aSMauro Carvalho Chehab 	return rc;
172b285192aSMauro Carvalho Chehab 
173b285192aSMauro Carvalho Chehab }
174b285192aSMauro Carvalho Chehab 
175b285192aSMauro Carvalho Chehab /* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
176b285192aSMauro Carvalho Chehab    1440 is a single line of 4:2:2 YUV at 720 luma samples wide
177b285192aSMauro Carvalho Chehab */
178b285192aSMauro Carvalho Chehab #define VB_MIN_BUFFERS 32
179b285192aSMauro Carvalho Chehab #define VB_MIN_BUFSIZE 4147200
180b285192aSMauro Carvalho Chehab 
181b285192aSMauro Carvalho Chehab static int buffer_setup(struct videobuf_queue *q,
182b285192aSMauro Carvalho Chehab 	unsigned int *count, unsigned int *size)
183b285192aSMauro Carvalho Chehab {
184b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = q->priv_data;
185b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
186b285192aSMauro Carvalho Chehab 
187b285192aSMauro Carvalho Chehab 	*size = 2 * cx->cxhdl.width * cx->cxhdl.height;
188b285192aSMauro Carvalho Chehab 	if (*count == 0)
189b285192aSMauro Carvalho Chehab 		*count = VB_MIN_BUFFERS;
190b285192aSMauro Carvalho Chehab 
191b285192aSMauro Carvalho Chehab 	while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
192b285192aSMauro Carvalho Chehab 		(*count)--;
193b285192aSMauro Carvalho Chehab 
194b285192aSMauro Carvalho Chehab 	q->field = V4L2_FIELD_INTERLACED;
195b285192aSMauro Carvalho Chehab 	q->last = V4L2_FIELD_INTERLACED;
196b285192aSMauro Carvalho Chehab 
197b285192aSMauro Carvalho Chehab 	return 0;
198b285192aSMauro Carvalho Chehab }
199b285192aSMauro Carvalho Chehab 
200b285192aSMauro Carvalho Chehab static int buffer_prepare(struct videobuf_queue *q,
201b285192aSMauro Carvalho Chehab 	struct videobuf_buffer *vb,
202b285192aSMauro Carvalho Chehab 	enum v4l2_field field)
203b285192aSMauro Carvalho Chehab {
204b285192aSMauro Carvalho Chehab 	struct cx18_videobuf_buffer *buf =
205b285192aSMauro Carvalho Chehab 		container_of(vb, struct cx18_videobuf_buffer, vb);
206b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = q->priv_data;
207b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
208b285192aSMauro Carvalho Chehab 
209b285192aSMauro Carvalho Chehab 	return cx18_prepare_buffer(q, s, buf, s->pixelformat,
210b285192aSMauro Carvalho Chehab 		cx->cxhdl.width, cx->cxhdl.height, field);
211b285192aSMauro Carvalho Chehab }
212b285192aSMauro Carvalho Chehab 
213b285192aSMauro Carvalho Chehab static void buffer_release(struct videobuf_queue *q,
214b285192aSMauro Carvalho Chehab 	struct videobuf_buffer *vb)
215b285192aSMauro Carvalho Chehab {
216b285192aSMauro Carvalho Chehab 	struct cx18_videobuf_buffer *buf =
217b285192aSMauro Carvalho Chehab 		container_of(vb, struct cx18_videobuf_buffer, vb);
218b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = q->priv_data;
219b285192aSMauro Carvalho Chehab 
220b285192aSMauro Carvalho Chehab 	cx18_dma_free(q, s, buf);
221b285192aSMauro Carvalho Chehab }
222b285192aSMauro Carvalho Chehab 
223b285192aSMauro Carvalho Chehab static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
224b285192aSMauro Carvalho Chehab {
225b285192aSMauro Carvalho Chehab 	struct cx18_videobuf_buffer *buf =
226b285192aSMauro Carvalho Chehab 		container_of(vb, struct cx18_videobuf_buffer, vb);
227b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = q->priv_data;
228b285192aSMauro Carvalho Chehab 
229b285192aSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_QUEUED;
230b285192aSMauro Carvalho Chehab 
231b285192aSMauro Carvalho Chehab 	list_add_tail(&buf->vb.queue, &s->vb_capture);
232b285192aSMauro Carvalho Chehab }
233b285192aSMauro Carvalho Chehab 
23466883248SJulia Lawall static const struct videobuf_queue_ops cx18_videobuf_qops = {
235b285192aSMauro Carvalho Chehab 	.buf_setup    = buffer_setup,
236b285192aSMauro Carvalho Chehab 	.buf_prepare  = buffer_prepare,
237b285192aSMauro Carvalho Chehab 	.buf_queue    = buffer_queue,
238b285192aSMauro Carvalho Chehab 	.buf_release  = buffer_release,
239b285192aSMauro Carvalho Chehab };
240b285192aSMauro Carvalho Chehab 
241b285192aSMauro Carvalho Chehab static void cx18_stream_init(struct cx18 *cx, int type)
242b285192aSMauro Carvalho Chehab {
243b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = &cx->streams[type];
244b285192aSMauro Carvalho Chehab 
245b285192aSMauro Carvalho Chehab 	memset(s, 0, sizeof(*s));
246b285192aSMauro Carvalho Chehab 
247b285192aSMauro Carvalho Chehab 	/* initialize cx18_stream fields */
248b285192aSMauro Carvalho Chehab 	s->dvb = NULL;
249b285192aSMauro Carvalho Chehab 	s->cx = cx;
250b285192aSMauro Carvalho Chehab 	s->type = type;
251b285192aSMauro Carvalho Chehab 	s->name = cx18_stream_info[type].name;
252b285192aSMauro Carvalho Chehab 	s->handle = CX18_INVALID_TASK_HANDLE;
253b285192aSMauro Carvalho Chehab 
254b285192aSMauro Carvalho Chehab 	s->dma = cx18_stream_info[type].dma;
255dfdf780bSHans Verkuil 	s->v4l2_dev_caps = cx18_stream_info[type].caps;
256b285192aSMauro Carvalho Chehab 	s->buffers = cx->stream_buffers[type];
257b285192aSMauro Carvalho Chehab 	s->buf_size = cx->stream_buf_size[type];
258b285192aSMauro Carvalho Chehab 	INIT_LIST_HEAD(&s->buf_pool);
259b285192aSMauro Carvalho Chehab 	s->bufs_per_mdl = 1;
260b285192aSMauro Carvalho Chehab 	s->mdl_size = s->buf_size * s->bufs_per_mdl;
261b285192aSMauro Carvalho Chehab 
262b285192aSMauro Carvalho Chehab 	init_waitqueue_head(&s->waitq);
263b285192aSMauro Carvalho Chehab 	s->id = -1;
264b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->q_free.lock);
265b285192aSMauro Carvalho Chehab 	cx18_queue_init(&s->q_free);
266b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->q_busy.lock);
267b285192aSMauro Carvalho Chehab 	cx18_queue_init(&s->q_busy);
268b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->q_full.lock);
269b285192aSMauro Carvalho Chehab 	cx18_queue_init(&s->q_full);
270b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->q_idle.lock);
271b285192aSMauro Carvalho Chehab 	cx18_queue_init(&s->q_idle);
272b285192aSMauro Carvalho Chehab 
273b285192aSMauro Carvalho Chehab 	INIT_WORK(&s->out_work_order, cx18_out_work_handler);
274b285192aSMauro Carvalho Chehab 
275b285192aSMauro Carvalho Chehab 	INIT_LIST_HEAD(&s->vb_capture);
276162e6376SKees Cook 	timer_setup(&s->vb_timeout, cx18_vb_timeout, 0);
277b285192aSMauro Carvalho Chehab 	spin_lock_init(&s->vb_lock);
278b285192aSMauro Carvalho Chehab 	if (type == CX18_ENC_STREAM_TYPE_YUV) {
279b285192aSMauro Carvalho Chehab 		spin_lock_init(&s->vbuf_q_lock);
280b285192aSMauro Carvalho Chehab 
281b285192aSMauro Carvalho Chehab 		s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
282b285192aSMauro Carvalho Chehab 		videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
283b285192aSMauro Carvalho Chehab 			&cx->pci_dev->dev, &s->vbuf_q_lock,
284b285192aSMauro Carvalho Chehab 			V4L2_BUF_TYPE_VIDEO_CAPTURE,
285b285192aSMauro Carvalho Chehab 			V4L2_FIELD_INTERLACED,
286b285192aSMauro Carvalho Chehab 			sizeof(struct cx18_videobuf_buffer),
287b285192aSMauro Carvalho Chehab 			s, &cx->serialize_lock);
288b285192aSMauro Carvalho Chehab 
289b285192aSMauro Carvalho Chehab 		/* Assume the previous pixel default */
290b285192aSMauro Carvalho Chehab 		s->pixelformat = V4L2_PIX_FMT_HM12;
291b285192aSMauro Carvalho Chehab 		s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
2923a29a4f1SHans Verkuil 		s->vb_bytes_per_line = 720;
293b285192aSMauro Carvalho Chehab 	}
294b285192aSMauro Carvalho Chehab }
295b285192aSMauro Carvalho Chehab 
296b285192aSMauro Carvalho Chehab static int cx18_prep_dev(struct cx18 *cx, int type)
297b285192aSMauro Carvalho Chehab {
298b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = &cx->streams[type];
299b285192aSMauro Carvalho Chehab 	u32 cap = cx->v4l2_cap;
300b285192aSMauro Carvalho Chehab 	int num_offset = cx18_stream_info[type].num_offset;
301b285192aSMauro Carvalho Chehab 	int num = cx->instance + cx18_first_minor + num_offset;
302b285192aSMauro Carvalho Chehab 
303b285192aSMauro Carvalho Chehab 	/*
304b285192aSMauro Carvalho Chehab 	 * These five fields are always initialized.
30508569d64SHans Verkuil 	 * For analog capture related streams, if video_dev.v4l2_dev == NULL then the
306b285192aSMauro Carvalho Chehab 	 * stream is not in use.
307b285192aSMauro Carvalho Chehab 	 * For the TS stream, if dvb == NULL then the stream is not in use.
308b285192aSMauro Carvalho Chehab 	 * In those cases no other fields but these four can be used.
309b285192aSMauro Carvalho Chehab 	 */
31008569d64SHans Verkuil 	s->video_dev.v4l2_dev = NULL;
311b285192aSMauro Carvalho Chehab 	s->dvb = NULL;
312b285192aSMauro Carvalho Chehab 	s->cx = cx;
313b285192aSMauro Carvalho Chehab 	s->type = type;
314b285192aSMauro Carvalho Chehab 	s->name = cx18_stream_info[type].name;
315b285192aSMauro Carvalho Chehab 
316b285192aSMauro Carvalho Chehab 	/* Check whether the radio is supported */
317b285192aSMauro Carvalho Chehab 	if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
318b285192aSMauro Carvalho Chehab 		return 0;
319b285192aSMauro Carvalho Chehab 
320b285192aSMauro Carvalho Chehab 	/* Check whether VBI is supported */
321b285192aSMauro Carvalho Chehab 	if (type == CX18_ENC_STREAM_TYPE_VBI &&
322b285192aSMauro Carvalho Chehab 	    !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
323b285192aSMauro Carvalho Chehab 		return 0;
324b285192aSMauro Carvalho Chehab 
325b285192aSMauro Carvalho Chehab 	/* User explicitly selected 0 buffers for these streams, so don't
326b285192aSMauro Carvalho Chehab 	   create them. */
327b285192aSMauro Carvalho Chehab 	if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
328b285192aSMauro Carvalho Chehab 	    cx->stream_buffers[type] == 0) {
329b285192aSMauro Carvalho Chehab 		CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
330b285192aSMauro Carvalho Chehab 		return 0;
331b285192aSMauro Carvalho Chehab 	}
332b285192aSMauro Carvalho Chehab 
333b285192aSMauro Carvalho Chehab 	cx18_stream_init(cx, type);
334b285192aSMauro Carvalho Chehab 
335b285192aSMauro Carvalho Chehab 	/* Allocate the cx18_dvb struct only for the TS on cards with DTV */
336b285192aSMauro Carvalho Chehab 	if (type == CX18_ENC_STREAM_TYPE_TS) {
337b285192aSMauro Carvalho Chehab 		if (cx->card->hw_all & CX18_HW_DVB) {
338b285192aSMauro Carvalho Chehab 			s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL);
339b285192aSMauro Carvalho Chehab 			if (s->dvb == NULL) {
3406beb1388SMauro Carvalho Chehab 				CX18_ERR("Couldn't allocate cx18_dvb structure for %s\n",
3416beb1388SMauro Carvalho Chehab 					 s->name);
342b285192aSMauro Carvalho Chehab 				return -ENOMEM;
343b285192aSMauro Carvalho Chehab 			}
344b285192aSMauro Carvalho Chehab 		} else {
345b285192aSMauro Carvalho Chehab 			/* Don't need buffers for the TS, if there is no DVB */
346b285192aSMauro Carvalho Chehab 			s->buffers = 0;
347b285192aSMauro Carvalho Chehab 		}
348b285192aSMauro Carvalho Chehab 	}
349b285192aSMauro Carvalho Chehab 
350b285192aSMauro Carvalho Chehab 	if (num_offset == -1)
351b285192aSMauro Carvalho Chehab 		return 0;
352b285192aSMauro Carvalho Chehab 
35308569d64SHans Verkuil 	/* initialize the v4l2 video device structure */
35408569d64SHans Verkuil 	snprintf(s->video_dev.name, sizeof(s->video_dev.name), "%s %s",
355b285192aSMauro Carvalho Chehab 		 cx->v4l2_dev.name, s->name);
356b285192aSMauro Carvalho Chehab 
35708569d64SHans Verkuil 	s->video_dev.num = num;
35808569d64SHans Verkuil 	s->video_dev.v4l2_dev = &cx->v4l2_dev;
35908569d64SHans Verkuil 	s->video_dev.fops = &cx18_v4l2_enc_fops;
36008569d64SHans Verkuil 	s->video_dev.release = video_device_release_empty;
3613a29a4f1SHans Verkuil 	if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER)
3623a29a4f1SHans Verkuil 		s->video_dev.tvnorms = cx->tuner_std;
3633a29a4f1SHans Verkuil 	else
36408569d64SHans Verkuil 		s->video_dev.tvnorms = V4L2_STD_ALL;
36508569d64SHans Verkuil 	s->video_dev.lock = &cx->serialize_lock;
36608569d64SHans Verkuil 	cx18_set_funcs(&s->video_dev);
367b285192aSMauro Carvalho Chehab 	return 0;
368b285192aSMauro Carvalho Chehab }
369b285192aSMauro Carvalho Chehab 
370b285192aSMauro Carvalho Chehab /* Initialize v4l2 variables and register v4l2 devices */
371b285192aSMauro Carvalho Chehab int cx18_streams_setup(struct cx18 *cx)
372b285192aSMauro Carvalho Chehab {
373b285192aSMauro Carvalho Chehab 	int type, ret;
374b285192aSMauro Carvalho Chehab 
375b285192aSMauro Carvalho Chehab 	/* Setup V4L2 Devices */
376b285192aSMauro Carvalho Chehab 	for (type = 0; type < CX18_MAX_STREAMS; type++) {
377b285192aSMauro Carvalho Chehab 		/* Prepare device */
378b285192aSMauro Carvalho Chehab 		ret = cx18_prep_dev(cx, type);
379b285192aSMauro Carvalho Chehab 		if (ret < 0)
380b285192aSMauro Carvalho Chehab 			break;
381b285192aSMauro Carvalho Chehab 
382b285192aSMauro Carvalho Chehab 		/* Allocate Stream */
383b285192aSMauro Carvalho Chehab 		ret = cx18_stream_alloc(&cx->streams[type]);
384b285192aSMauro Carvalho Chehab 		if (ret < 0)
385b285192aSMauro Carvalho Chehab 			break;
386b285192aSMauro Carvalho Chehab 	}
387b285192aSMauro Carvalho Chehab 	if (type == CX18_MAX_STREAMS)
388b285192aSMauro Carvalho Chehab 		return 0;
389b285192aSMauro Carvalho Chehab 
390b285192aSMauro Carvalho Chehab 	/* One or more streams could not be initialized. Clean 'em all up. */
391b285192aSMauro Carvalho Chehab 	cx18_streams_cleanup(cx, 0);
392b285192aSMauro Carvalho Chehab 	return ret;
393b285192aSMauro Carvalho Chehab }
394b285192aSMauro Carvalho Chehab 
395b285192aSMauro Carvalho Chehab static int cx18_reg_dev(struct cx18 *cx, int type)
396b285192aSMauro Carvalho Chehab {
397b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = &cx->streams[type];
398b285192aSMauro Carvalho Chehab 	int vfl_type = cx18_stream_info[type].vfl_type;
399b285192aSMauro Carvalho Chehab 	const char *name;
400b285192aSMauro Carvalho Chehab 	int num, ret;
401b285192aSMauro Carvalho Chehab 
402b285192aSMauro Carvalho Chehab 	if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) {
403b285192aSMauro Carvalho Chehab 		ret = cx18_dvb_register(s);
404b285192aSMauro Carvalho Chehab 		if (ret < 0) {
405b285192aSMauro Carvalho Chehab 			CX18_ERR("DVB failed to register\n");
406b285192aSMauro Carvalho Chehab 			return ret;
407b285192aSMauro Carvalho Chehab 		}
408b285192aSMauro Carvalho Chehab 	}
409b285192aSMauro Carvalho Chehab 
41008569d64SHans Verkuil 	if (s->video_dev.v4l2_dev == NULL)
411b285192aSMauro Carvalho Chehab 		return 0;
412b285192aSMauro Carvalho Chehab 
41308569d64SHans Verkuil 	num = s->video_dev.num;
41421615365SHans Verkuil 	s->video_dev.device_caps = s->v4l2_dev_caps;	/* device capabilities */
415b285192aSMauro Carvalho Chehab 	/* card number + user defined offset + device offset */
416b285192aSMauro Carvalho Chehab 	if (type != CX18_ENC_STREAM_TYPE_MPG) {
417b285192aSMauro Carvalho Chehab 		struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
418b285192aSMauro Carvalho Chehab 
41908569d64SHans Verkuil 		if (s_mpg->video_dev.v4l2_dev)
42008569d64SHans Verkuil 			num = s_mpg->video_dev.num
421b285192aSMauro Carvalho Chehab 			    + cx18_stream_info[type].num_offset;
422b285192aSMauro Carvalho Chehab 	}
42308569d64SHans Verkuil 	video_set_drvdata(&s->video_dev, s);
424b285192aSMauro Carvalho Chehab 
425b285192aSMauro Carvalho Chehab 	/* Register device. First try the desired minor, then any free one. */
42608569d64SHans Verkuil 	ret = video_register_device_no_warn(&s->video_dev, vfl_type, num);
427b285192aSMauro Carvalho Chehab 	if (ret < 0) {
428b285192aSMauro Carvalho Chehab 		CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
429b285192aSMauro Carvalho Chehab 			s->name, num);
43008569d64SHans Verkuil 		s->video_dev.v4l2_dev = NULL;
431b285192aSMauro Carvalho Chehab 		return ret;
432b285192aSMauro Carvalho Chehab 	}
433b285192aSMauro Carvalho Chehab 
43408569d64SHans Verkuil 	name = video_device_node_name(&s->video_dev);
435b285192aSMauro Carvalho Chehab 
436b285192aSMauro Carvalho Chehab 	switch (vfl_type) {
437*3e30a927SHans Verkuil 	case VFL_TYPE_VIDEO:
438b285192aSMauro Carvalho Chehab 		CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n",
439b285192aSMauro Carvalho Chehab 			  name, s->name, cx->stream_buffers[type],
440b285192aSMauro Carvalho Chehab 			  cx->stream_buf_size[type] / 1024,
441b285192aSMauro Carvalho Chehab 			  (cx->stream_buf_size[type] * 100 / 1024) % 100);
442b285192aSMauro Carvalho Chehab 		break;
443b285192aSMauro Carvalho Chehab 
444b285192aSMauro Carvalho Chehab 	case VFL_TYPE_RADIO:
445b285192aSMauro Carvalho Chehab 		CX18_INFO("Registered device %s for %s\n", name, s->name);
446b285192aSMauro Carvalho Chehab 		break;
447b285192aSMauro Carvalho Chehab 
448b285192aSMauro Carvalho Chehab 	case VFL_TYPE_VBI:
449b285192aSMauro Carvalho Chehab 		if (cx->stream_buffers[type])
4506beb1388SMauro Carvalho Chehab 			CX18_INFO("Registered device %s for %s (%d x %d bytes)\n",
451b285192aSMauro Carvalho Chehab 				  name, s->name, cx->stream_buffers[type],
452b285192aSMauro Carvalho Chehab 				  cx->stream_buf_size[type]);
453b285192aSMauro Carvalho Chehab 		else
454b285192aSMauro Carvalho Chehab 			CX18_INFO("Registered device %s for %s\n",
455b285192aSMauro Carvalho Chehab 				name, s->name);
456b285192aSMauro Carvalho Chehab 		break;
457b285192aSMauro Carvalho Chehab 	}
458b285192aSMauro Carvalho Chehab 
459b285192aSMauro Carvalho Chehab 	return 0;
460b285192aSMauro Carvalho Chehab }
461b285192aSMauro Carvalho Chehab 
462b285192aSMauro Carvalho Chehab /* Register v4l2 devices */
463b285192aSMauro Carvalho Chehab int cx18_streams_register(struct cx18 *cx)
464b285192aSMauro Carvalho Chehab {
465b285192aSMauro Carvalho Chehab 	int type;
466b285192aSMauro Carvalho Chehab 	int err;
467b285192aSMauro Carvalho Chehab 	int ret = 0;
468b285192aSMauro Carvalho Chehab 
469b285192aSMauro Carvalho Chehab 	/* Register V4L2 devices */
470b285192aSMauro Carvalho Chehab 	for (type = 0; type < CX18_MAX_STREAMS; type++) {
471b285192aSMauro Carvalho Chehab 		err = cx18_reg_dev(cx, type);
472b285192aSMauro Carvalho Chehab 		if (err && ret == 0)
473b285192aSMauro Carvalho Chehab 			ret = err;
474b285192aSMauro Carvalho Chehab 	}
475b285192aSMauro Carvalho Chehab 
476b285192aSMauro Carvalho Chehab 	if (ret == 0)
477b285192aSMauro Carvalho Chehab 		return 0;
478b285192aSMauro Carvalho Chehab 
479b285192aSMauro Carvalho Chehab 	/* One or more streams could not be initialized. Clean 'em all up. */
480b285192aSMauro Carvalho Chehab 	cx18_streams_cleanup(cx, 1);
481b285192aSMauro Carvalho Chehab 	return ret;
482b285192aSMauro Carvalho Chehab }
483b285192aSMauro Carvalho Chehab 
484b285192aSMauro Carvalho Chehab /* Unregister v4l2 devices */
485b285192aSMauro Carvalho Chehab void cx18_streams_cleanup(struct cx18 *cx, int unregister)
486b285192aSMauro Carvalho Chehab {
487b285192aSMauro Carvalho Chehab 	struct video_device *vdev;
488b285192aSMauro Carvalho Chehab 	int type;
489b285192aSMauro Carvalho Chehab 
490b285192aSMauro Carvalho Chehab 	/* Teardown all streams */
491b285192aSMauro Carvalho Chehab 	for (type = 0; type < CX18_MAX_STREAMS; type++) {
492b285192aSMauro Carvalho Chehab 
493b285192aSMauro Carvalho Chehab 		/* The TS has a cx18_dvb structure, not a video_device */
494b285192aSMauro Carvalho Chehab 		if (type == CX18_ENC_STREAM_TYPE_TS) {
495b285192aSMauro Carvalho Chehab 			if (cx->streams[type].dvb != NULL) {
496b285192aSMauro Carvalho Chehab 				if (unregister)
497b285192aSMauro Carvalho Chehab 					cx18_dvb_unregister(&cx->streams[type]);
498b285192aSMauro Carvalho Chehab 				kfree(cx->streams[type].dvb);
499b285192aSMauro Carvalho Chehab 				cx->streams[type].dvb = NULL;
500b285192aSMauro Carvalho Chehab 				cx18_stream_free(&cx->streams[type]);
501b285192aSMauro Carvalho Chehab 			}
502b285192aSMauro Carvalho Chehab 			continue;
503b285192aSMauro Carvalho Chehab 		}
504b285192aSMauro Carvalho Chehab 
505b285192aSMauro Carvalho Chehab 		/* No struct video_device, but can have buffers allocated */
506b285192aSMauro Carvalho Chehab 		if (type == CX18_ENC_STREAM_TYPE_IDX) {
507b285192aSMauro Carvalho Chehab 			/* If the module params didn't inhibit IDX ... */
508b285192aSMauro Carvalho Chehab 			if (cx->stream_buffers[type] != 0) {
509b285192aSMauro Carvalho Chehab 				cx->stream_buffers[type] = 0;
510b285192aSMauro Carvalho Chehab 				/*
511b285192aSMauro Carvalho Chehab 				 * Before calling cx18_stream_free(),
512b285192aSMauro Carvalho Chehab 				 * check if the IDX stream was actually set up.
513b285192aSMauro Carvalho Chehab 				 * Needed, since the cx18_probe() error path
514b285192aSMauro Carvalho Chehab 				 * exits through here as well as normal clean up
515b285192aSMauro Carvalho Chehab 				 */
516b285192aSMauro Carvalho Chehab 				if (cx->streams[type].buffers != 0)
517b285192aSMauro Carvalho Chehab 					cx18_stream_free(&cx->streams[type]);
518b285192aSMauro Carvalho Chehab 			}
519b285192aSMauro Carvalho Chehab 			continue;
520b285192aSMauro Carvalho Chehab 		}
521b285192aSMauro Carvalho Chehab 
522b285192aSMauro Carvalho Chehab 		/* If struct video_device exists, can have buffers allocated */
52308569d64SHans Verkuil 		vdev = &cx->streams[type].video_dev;
524b285192aSMauro Carvalho Chehab 
52508569d64SHans Verkuil 		if (vdev->v4l2_dev == NULL)
526b285192aSMauro Carvalho Chehab 			continue;
527b285192aSMauro Carvalho Chehab 
528b285192aSMauro Carvalho Chehab 		if (type == CX18_ENC_STREAM_TYPE_YUV)
529b285192aSMauro Carvalho Chehab 			videobuf_mmap_free(&cx->streams[type].vbuf_q);
530b285192aSMauro Carvalho Chehab 
531b285192aSMauro Carvalho Chehab 		cx18_stream_free(&cx->streams[type]);
532b285192aSMauro Carvalho Chehab 
533b285192aSMauro Carvalho Chehab 		video_unregister_device(vdev);
534b285192aSMauro Carvalho Chehab 	}
535b285192aSMauro Carvalho Chehab }
536b285192aSMauro Carvalho Chehab 
537b285192aSMauro Carvalho Chehab static void cx18_vbi_setup(struct cx18_stream *s)
538b285192aSMauro Carvalho Chehab {
539b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
540b285192aSMauro Carvalho Chehab 	int raw = cx18_raw_vbi(cx);
541b285192aSMauro Carvalho Chehab 	u32 data[CX2341X_MBOX_MAX_DATA];
542b285192aSMauro Carvalho Chehab 	int lines;
543b285192aSMauro Carvalho Chehab 
544b285192aSMauro Carvalho Chehab 	if (cx->is_60hz) {
545b285192aSMauro Carvalho Chehab 		cx->vbi.count = 12;
546b285192aSMauro Carvalho Chehab 		cx->vbi.start[0] = 10;
547b285192aSMauro Carvalho Chehab 		cx->vbi.start[1] = 273;
548b285192aSMauro Carvalho Chehab 	} else {        /* PAL/SECAM */
549b285192aSMauro Carvalho Chehab 		cx->vbi.count = 18;
550b285192aSMauro Carvalho Chehab 		cx->vbi.start[0] = 6;
551b285192aSMauro Carvalho Chehab 		cx->vbi.start[1] = 318;
552b285192aSMauro Carvalho Chehab 	}
553b285192aSMauro Carvalho Chehab 
554b285192aSMauro Carvalho Chehab 	/* setup VBI registers */
555b285192aSMauro Carvalho Chehab 	if (raw)
556b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi);
557b285192aSMauro Carvalho Chehab 	else
558b285192aSMauro Carvalho Chehab 		v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced);
559b285192aSMauro Carvalho Chehab 
560b285192aSMauro Carvalho Chehab 	/*
561b285192aSMauro Carvalho Chehab 	 * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw
562b285192aSMauro Carvalho Chehab 	 * VBI when the first analog capture channel starts, as once it starts
563b285192aSMauro Carvalho Chehab 	 * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup
564b285192aSMauro Carvalho Chehab 	 * (i.e. for the VBI capture channels).  We also send it for each
565b285192aSMauro Carvalho Chehab 	 * analog capture channel anyway just to make sure we get the proper
566b285192aSMauro Carvalho Chehab 	 * behavior
567b285192aSMauro Carvalho Chehab 	 */
568b285192aSMauro Carvalho Chehab 	if (raw) {
569b285192aSMauro Carvalho Chehab 		lines = cx->vbi.count * 2;
570b285192aSMauro Carvalho Chehab 	} else {
571b285192aSMauro Carvalho Chehab 		/*
572b285192aSMauro Carvalho Chehab 		 * For 525/60 systems, according to the VIP 2 & BT.656 std:
573b285192aSMauro Carvalho Chehab 		 * The EAV RP code's Field bit toggles on line 4, a few lines
574b285192aSMauro Carvalho Chehab 		 * after the Vertcal Blank bit has already toggled.
575b285192aSMauro Carvalho Chehab 		 * Tell the encoder to capture 21-4+1=18 lines per field,
576b285192aSMauro Carvalho Chehab 		 * since we want lines 10 through 21.
577b285192aSMauro Carvalho Chehab 		 *
578b285192aSMauro Carvalho Chehab 		 * For 625/50 systems, according to the VIP 2 & BT.656 std:
579b285192aSMauro Carvalho Chehab 		 * The EAV RP code's Field bit toggles on line 1, a few lines
580b285192aSMauro Carvalho Chehab 		 * after the Vertcal Blank bit has already toggled.
581b285192aSMauro Carvalho Chehab 		 * (We've actually set the digitizer so that the Field bit
582b285192aSMauro Carvalho Chehab 		 * toggles on line 2.) Tell the encoder to capture 23-2+1=22
583b285192aSMauro Carvalho Chehab 		 * lines per field, since we want lines 6 through 23.
584b285192aSMauro Carvalho Chehab 		 */
585b285192aSMauro Carvalho Chehab 		lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
586b285192aSMauro Carvalho Chehab 	}
587b285192aSMauro Carvalho Chehab 
588b285192aSMauro Carvalho Chehab 	data[0] = s->handle;
589b285192aSMauro Carvalho Chehab 	/* Lines per field */
590b285192aSMauro Carvalho Chehab 	data[1] = (lines / 2) | ((lines / 2) << 16);
591b285192aSMauro Carvalho Chehab 	/* bytes per line */
592318de791SMauro Carvalho Chehab 	data[2] = (raw ? VBI_ACTIVE_SAMPLES
593318de791SMauro Carvalho Chehab 		       : (cx->is_60hz ? VBI_HBLANK_SAMPLES_60HZ
594318de791SMauro Carvalho Chehab 				      : VBI_HBLANK_SAMPLES_50HZ));
595b285192aSMauro Carvalho Chehab 	/* Every X number of frames a VBI interrupt arrives
596b285192aSMauro Carvalho Chehab 	   (frames as in 25 or 30 fps) */
597b285192aSMauro Carvalho Chehab 	data[3] = 1;
598b285192aSMauro Carvalho Chehab 	/*
599b285192aSMauro Carvalho Chehab 	 * Set the SAV/EAV RP codes to look for as start/stop points
600b285192aSMauro Carvalho Chehab 	 * when in VIP-1.1 mode
601b285192aSMauro Carvalho Chehab 	 */
602b285192aSMauro Carvalho Chehab 	if (raw) {
603b285192aSMauro Carvalho Chehab 		/*
604b285192aSMauro Carvalho Chehab 		 * Start codes for beginning of "active" line in vertical blank
605b285192aSMauro Carvalho Chehab 		 * 0x20 (               VerticalBlank                )
606b285192aSMauro Carvalho Chehab 		 * 0x60 (     EvenField VerticalBlank                )
607b285192aSMauro Carvalho Chehab 		 */
608b285192aSMauro Carvalho Chehab 		data[4] = 0x20602060;
609b285192aSMauro Carvalho Chehab 		/*
610b285192aSMauro Carvalho Chehab 		 * End codes for end of "active" raw lines and regular lines
611b285192aSMauro Carvalho Chehab 		 * 0x30 (               VerticalBlank HorizontalBlank)
612b285192aSMauro Carvalho Chehab 		 * 0x70 (     EvenField VerticalBlank HorizontalBlank)
613b285192aSMauro Carvalho Chehab 		 * 0x90 (Task                         HorizontalBlank)
614b285192aSMauro Carvalho Chehab 		 * 0xd0 (Task EvenField               HorizontalBlank)
615b285192aSMauro Carvalho Chehab 		 */
616b285192aSMauro Carvalho Chehab 		data[5] = 0x307090d0;
617b285192aSMauro Carvalho Chehab 	} else {
618b285192aSMauro Carvalho Chehab 		/*
619b285192aSMauro Carvalho Chehab 		 * End codes for active video, we want data in the hblank region
620b285192aSMauro Carvalho Chehab 		 * 0xb0 (Task         0 VerticalBlank HorizontalBlank)
621b285192aSMauro Carvalho Chehab 		 * 0xf0 (Task EvenField VerticalBlank HorizontalBlank)
622b285192aSMauro Carvalho Chehab 		 *
623b285192aSMauro Carvalho Chehab 		 * Since the V bit is only allowed to toggle in the EAV RP code,
624b285192aSMauro Carvalho Chehab 		 * just before the first active region line, these two
625b285192aSMauro Carvalho Chehab 		 * are problematic:
626b285192aSMauro Carvalho Chehab 		 * 0x90 (Task                         HorizontalBlank)
627b285192aSMauro Carvalho Chehab 		 * 0xd0 (Task EvenField               HorizontalBlank)
628b285192aSMauro Carvalho Chehab 		 *
629b285192aSMauro Carvalho Chehab 		 * We have set the digitzer such that we don't have to worry
630b285192aSMauro Carvalho Chehab 		 * about these problem codes.
631b285192aSMauro Carvalho Chehab 		 */
632b285192aSMauro Carvalho Chehab 		data[4] = 0xB0F0B0F0;
633b285192aSMauro Carvalho Chehab 		/*
634b285192aSMauro Carvalho Chehab 		 * Start codes for beginning of active line in vertical blank
635b285192aSMauro Carvalho Chehab 		 * 0xa0 (Task           VerticalBlank                )
636b285192aSMauro Carvalho Chehab 		 * 0xe0 (Task EvenField VerticalBlank                )
637b285192aSMauro Carvalho Chehab 		 */
638b285192aSMauro Carvalho Chehab 		data[5] = 0xA0E0A0E0;
639b285192aSMauro Carvalho Chehab 	}
640b285192aSMauro Carvalho Chehab 
641b285192aSMauro Carvalho Chehab 	CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
642b285192aSMauro Carvalho Chehab 			data[0], data[1], data[2], data[3], data[4], data[5]);
643b285192aSMauro Carvalho Chehab 
644b285192aSMauro Carvalho Chehab 	cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
645b285192aSMauro Carvalho Chehab }
646b285192aSMauro Carvalho Chehab 
647b285192aSMauro Carvalho Chehab void cx18_stream_rotate_idx_mdls(struct cx18 *cx)
648b285192aSMauro Carvalho Chehab {
649b285192aSMauro Carvalho Chehab 	struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
650b285192aSMauro Carvalho Chehab 	struct cx18_mdl *mdl;
651b285192aSMauro Carvalho Chehab 
652b285192aSMauro Carvalho Chehab 	if (!cx18_stream_enabled(s))
653b285192aSMauro Carvalho Chehab 		return;
654b285192aSMauro Carvalho Chehab 
655b285192aSMauro Carvalho Chehab 	/* Return if the firmware is not running low on MDLs */
656b285192aSMauro Carvalho Chehab 	if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >=
657b285192aSMauro Carvalho Chehab 					    CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN)
658b285192aSMauro Carvalho Chehab 		return;
659b285192aSMauro Carvalho Chehab 
660b285192aSMauro Carvalho Chehab 	/* Return if there are no MDLs to rotate back to the firmware */
661b285192aSMauro Carvalho Chehab 	if (atomic_read(&s->q_full.depth) < 2)
662b285192aSMauro Carvalho Chehab 		return;
663b285192aSMauro Carvalho Chehab 
664b285192aSMauro Carvalho Chehab 	/*
665b285192aSMauro Carvalho Chehab 	 * Take the oldest IDX MDL still holding data, and discard its index
666b285192aSMauro Carvalho Chehab 	 * entries by scheduling the MDL to go back to the firmware
667b285192aSMauro Carvalho Chehab 	 */
668b285192aSMauro Carvalho Chehab 	mdl = cx18_dequeue(s, &s->q_full);
669b285192aSMauro Carvalho Chehab 	if (mdl != NULL)
670b285192aSMauro Carvalho Chehab 		cx18_enqueue(s, mdl, &s->q_free);
671b285192aSMauro Carvalho Chehab }
672b285192aSMauro Carvalho Chehab 
673b285192aSMauro Carvalho Chehab static
674b285192aSMauro Carvalho Chehab struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s,
675b285192aSMauro Carvalho Chehab 					   struct cx18_mdl *mdl)
676b285192aSMauro Carvalho Chehab {
677b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
678b285192aSMauro Carvalho Chehab 	struct cx18_queue *q;
679b285192aSMauro Carvalho Chehab 
680b285192aSMauro Carvalho Chehab 	/* Don't give it to the firmware, if we're not running a capture */
681b285192aSMauro Carvalho Chehab 	if (s->handle == CX18_INVALID_TASK_HANDLE ||
682b285192aSMauro Carvalho Chehab 	    test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
683b285192aSMauro Carvalho Chehab 	    !test_bit(CX18_F_S_STREAMING, &s->s_flags))
684b285192aSMauro Carvalho Chehab 		return cx18_enqueue(s, mdl, &s->q_free);
685b285192aSMauro Carvalho Chehab 
686b285192aSMauro Carvalho Chehab 	q = cx18_enqueue(s, mdl, &s->q_busy);
687b285192aSMauro Carvalho Chehab 	if (q != &s->q_busy)
688b285192aSMauro Carvalho Chehab 		return q; /* The firmware has the max MDLs it can handle */
689b285192aSMauro Carvalho Chehab 
690b285192aSMauro Carvalho Chehab 	cx18_mdl_sync_for_device(s, mdl);
691b285192aSMauro Carvalho Chehab 	cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
692b285192aSMauro Carvalho Chehab 		  (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem,
693b285192aSMauro Carvalho Chehab 		  s->bufs_per_mdl, mdl->id, s->mdl_size);
694b285192aSMauro Carvalho Chehab 	return q;
695b285192aSMauro Carvalho Chehab }
696b285192aSMauro Carvalho Chehab 
697b285192aSMauro Carvalho Chehab static
698b285192aSMauro Carvalho Chehab void _cx18_stream_load_fw_queue(struct cx18_stream *s)
699b285192aSMauro Carvalho Chehab {
700b285192aSMauro Carvalho Chehab 	struct cx18_queue *q;
701b285192aSMauro Carvalho Chehab 	struct cx18_mdl *mdl;
702b285192aSMauro Carvalho Chehab 
703b285192aSMauro Carvalho Chehab 	if (atomic_read(&s->q_free.depth) == 0 ||
704b285192aSMauro Carvalho Chehab 	    atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
705b285192aSMauro Carvalho Chehab 		return;
706b285192aSMauro Carvalho Chehab 
707b285192aSMauro Carvalho Chehab 	/* Move from q_free to q_busy notifying the firmware, until the limit */
708b285192aSMauro Carvalho Chehab 	do {
709b285192aSMauro Carvalho Chehab 		mdl = cx18_dequeue(s, &s->q_free);
710b285192aSMauro Carvalho Chehab 		if (mdl == NULL)
711b285192aSMauro Carvalho Chehab 			break;
712b285192aSMauro Carvalho Chehab 		q = _cx18_stream_put_mdl_fw(s, mdl);
713b285192aSMauro Carvalho Chehab 	} while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM
714b285192aSMauro Carvalho Chehab 		 && q == &s->q_busy);
715b285192aSMauro Carvalho Chehab }
716b285192aSMauro Carvalho Chehab 
717b285192aSMauro Carvalho Chehab void cx18_out_work_handler(struct work_struct *work)
718b285192aSMauro Carvalho Chehab {
719b285192aSMauro Carvalho Chehab 	struct cx18_stream *s =
720b285192aSMauro Carvalho Chehab 			 container_of(work, struct cx18_stream, out_work_order);
721b285192aSMauro Carvalho Chehab 
722b285192aSMauro Carvalho Chehab 	_cx18_stream_load_fw_queue(s);
723b285192aSMauro Carvalho Chehab }
724b285192aSMauro Carvalho Chehab 
725b285192aSMauro Carvalho Chehab static void cx18_stream_configure_mdls(struct cx18_stream *s)
726b285192aSMauro Carvalho Chehab {
727b285192aSMauro Carvalho Chehab 	cx18_unload_queues(s);
728b285192aSMauro Carvalho Chehab 
729b285192aSMauro Carvalho Chehab 	switch (s->type) {
730b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_YUV:
731b285192aSMauro Carvalho Chehab 		/*
732b285192aSMauro Carvalho Chehab 		 * Height should be a multiple of 32 lines.
733b285192aSMauro Carvalho Chehab 		 * Set the MDL size to the exact size needed for one frame.
734b285192aSMauro Carvalho Chehab 		 * Use enough buffers per MDL to cover the MDL size
735b285192aSMauro Carvalho Chehab 		 */
736b285192aSMauro Carvalho Chehab 		if (s->pixelformat == V4L2_PIX_FMT_HM12)
737b285192aSMauro Carvalho Chehab 			s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
738b285192aSMauro Carvalho Chehab 		else
739b285192aSMauro Carvalho Chehab 			s->mdl_size = 720 * s->cx->cxhdl.height * 2;
740b285192aSMauro Carvalho Chehab 		s->bufs_per_mdl = s->mdl_size / s->buf_size;
741b285192aSMauro Carvalho Chehab 		if (s->mdl_size % s->buf_size)
742b285192aSMauro Carvalho Chehab 			s->bufs_per_mdl++;
743b285192aSMauro Carvalho Chehab 		break;
744b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_VBI:
745b285192aSMauro Carvalho Chehab 		s->bufs_per_mdl = 1;
746b285192aSMauro Carvalho Chehab 		if  (cx18_raw_vbi(s->cx)) {
747b285192aSMauro Carvalho Chehab 			s->mdl_size = (s->cx->is_60hz ? 12 : 18)
748318de791SMauro Carvalho Chehab 						       * 2 * VBI_ACTIVE_SAMPLES;
749b285192aSMauro Carvalho Chehab 		} else {
750b285192aSMauro Carvalho Chehab 			/*
751b285192aSMauro Carvalho Chehab 			 * See comment in cx18_vbi_setup() below about the
752b285192aSMauro Carvalho Chehab 			 * extra lines we capture in sliced VBI mode due to
753b285192aSMauro Carvalho Chehab 			 * the lines on which EAV RP codes toggle.
754b285192aSMauro Carvalho Chehab 			*/
755b285192aSMauro Carvalho Chehab 			s->mdl_size = s->cx->is_60hz
756318de791SMauro Carvalho Chehab 				   ? (21 - 4 + 1) * 2 * VBI_HBLANK_SAMPLES_60HZ
757318de791SMauro Carvalho Chehab 				   : (23 - 2 + 1) * 2 * VBI_HBLANK_SAMPLES_50HZ;
758b285192aSMauro Carvalho Chehab 		}
759b285192aSMauro Carvalho Chehab 		break;
760b285192aSMauro Carvalho Chehab 	default:
761b285192aSMauro Carvalho Chehab 		s->bufs_per_mdl = 1;
762b285192aSMauro Carvalho Chehab 		s->mdl_size = s->buf_size * s->bufs_per_mdl;
763b285192aSMauro Carvalho Chehab 		break;
764b285192aSMauro Carvalho Chehab 	}
765b285192aSMauro Carvalho Chehab 
766b285192aSMauro Carvalho Chehab 	cx18_load_queues(s);
767b285192aSMauro Carvalho Chehab }
768b285192aSMauro Carvalho Chehab 
769b285192aSMauro Carvalho Chehab int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
770b285192aSMauro Carvalho Chehab {
771b285192aSMauro Carvalho Chehab 	u32 data[MAX_MB_ARGUMENTS];
772b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
773b285192aSMauro Carvalho Chehab 	int captype = 0;
774b285192aSMauro Carvalho Chehab 	struct cx18_stream *s_idx;
775b285192aSMauro Carvalho Chehab 
776b285192aSMauro Carvalho Chehab 	if (!cx18_stream_enabled(s))
777b285192aSMauro Carvalho Chehab 		return -EINVAL;
778b285192aSMauro Carvalho Chehab 
779b285192aSMauro Carvalho Chehab 	CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
780b285192aSMauro Carvalho Chehab 
781b285192aSMauro Carvalho Chehab 	switch (s->type) {
782b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_MPG:
783b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_MPEG;
784b285192aSMauro Carvalho Chehab 		cx->mpg_data_received = cx->vbi_data_inserted = 0;
785b285192aSMauro Carvalho Chehab 		cx->dualwatch_jiffies = jiffies;
786b285192aSMauro Carvalho Chehab 		cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
787b285192aSMauro Carvalho Chehab 		cx->search_pack_header = 0;
788b285192aSMauro Carvalho Chehab 		break;
789b285192aSMauro Carvalho Chehab 
790b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_IDX:
791b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_INDEX;
792b285192aSMauro Carvalho Chehab 		break;
793b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_TS:
794b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_TS;
795b285192aSMauro Carvalho Chehab 		break;
796b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_YUV:
797b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_YUV;
798b285192aSMauro Carvalho Chehab 		break;
799b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_PCM:
800b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_PCM;
801b285192aSMauro Carvalho Chehab 		break;
802b285192aSMauro Carvalho Chehab 	case CX18_ENC_STREAM_TYPE_VBI:
803b285192aSMauro Carvalho Chehab #ifdef CX18_ENCODER_PARSES_SLICED
804b285192aSMauro Carvalho Chehab 		captype = cx18_raw_vbi(cx) ?
805b285192aSMauro Carvalho Chehab 		     CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
806b285192aSMauro Carvalho Chehab #else
807b285192aSMauro Carvalho Chehab 		/*
808b285192aSMauro Carvalho Chehab 		 * Currently we set things up so that Sliced VBI from the
809b285192aSMauro Carvalho Chehab 		 * digitizer is handled as Raw VBI by the encoder
810b285192aSMauro Carvalho Chehab 		 */
811b285192aSMauro Carvalho Chehab 		captype = CAPTURE_CHANNEL_TYPE_VBI;
812b285192aSMauro Carvalho Chehab #endif
813b285192aSMauro Carvalho Chehab 		cx->vbi.frame = 0;
814b285192aSMauro Carvalho Chehab 		cx->vbi.inserted_frame = 0;
815b285192aSMauro Carvalho Chehab 		memset(cx->vbi.sliced_mpeg_size,
816b285192aSMauro Carvalho Chehab 			0, sizeof(cx->vbi.sliced_mpeg_size));
817b285192aSMauro Carvalho Chehab 		break;
818b285192aSMauro Carvalho Chehab 	default:
819b285192aSMauro Carvalho Chehab 		return -EINVAL;
820b285192aSMauro Carvalho Chehab 	}
821b285192aSMauro Carvalho Chehab 
822b285192aSMauro Carvalho Chehab 	/* Clear Streamoff flags in case left from last capture */
823b285192aSMauro Carvalho Chehab 	clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
824b285192aSMauro Carvalho Chehab 
825b285192aSMauro Carvalho Chehab 	cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
826b285192aSMauro Carvalho Chehab 	s->handle = data[0];
827b285192aSMauro Carvalho Chehab 	cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
828b285192aSMauro Carvalho Chehab 
829b285192aSMauro Carvalho Chehab 	/*
830b285192aSMauro Carvalho Chehab 	 * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and
831b285192aSMauro Carvalho Chehab 	 * set up all the parameters, as it is not obvious which parameters the
832b285192aSMauro Carvalho Chehab 	 * firmware shares across capture channel types and which it does not.
833b285192aSMauro Carvalho Chehab 	 *
834b285192aSMauro Carvalho Chehab 	 * Some of the cx18_vapi() calls below apply to only certain capture
835b285192aSMauro Carvalho Chehab 	 * channel types.  We're hoping there's no harm in calling most of them
836b285192aSMauro Carvalho Chehab 	 * anyway, as long as the values are all consistent.  Setting some
837b285192aSMauro Carvalho Chehab 	 * shared parameters will have no effect once an analog capture channel
838b285192aSMauro Carvalho Chehab 	 * has started streaming.
839b285192aSMauro Carvalho Chehab 	 */
840b285192aSMauro Carvalho Chehab 	if (captype != CAPTURE_CHANNEL_TYPE_TS) {
841b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
842b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
843b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
844b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
845b285192aSMauro Carvalho Chehab 
846b285192aSMauro Carvalho Chehab 		/*
847b285192aSMauro Carvalho Chehab 		 * Audio related reset according to
8482ebe0bb3SMauro Carvalho Chehab 		 * Documentation/media/v4l-drivers/cx2341x.rst
849b285192aSMauro Carvalho Chehab 		 */
850b285192aSMauro Carvalho Chehab 		if (atomic_read(&cx->ana_capturing) == 0)
851b285192aSMauro Carvalho Chehab 			cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
852b285192aSMauro Carvalho Chehab 				  s->handle, 12);
853b285192aSMauro Carvalho Chehab 
854b285192aSMauro Carvalho Chehab 		/*
855b285192aSMauro Carvalho Chehab 		 * Number of lines for Field 1 & Field 2 according to
8562ebe0bb3SMauro Carvalho Chehab 		 * Documentation/media/v4l-drivers/cx2341x.rst
857b285192aSMauro Carvalho Chehab 		 * Field 1 is 312 for 625 line systems in BT.656
858b285192aSMauro Carvalho Chehab 		 * Field 2 is 313 for 625 line systems in BT.656
859b285192aSMauro Carvalho Chehab 		 */
860b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
861b285192aSMauro Carvalho Chehab 			  s->handle, 312, 313);
862b285192aSMauro Carvalho Chehab 
863b285192aSMauro Carvalho Chehab 		if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
864b285192aSMauro Carvalho Chehab 			cx18_vbi_setup(s);
865b285192aSMauro Carvalho Chehab 
866b285192aSMauro Carvalho Chehab 		/*
867b285192aSMauro Carvalho Chehab 		 * Select to receive I, P, and B frame index entries, if the
868b285192aSMauro Carvalho Chehab 		 * index stream is enabled.  Otherwise disable index entry
869b285192aSMauro Carvalho Chehab 		 * generation.
870b285192aSMauro Carvalho Chehab 		 */
871b285192aSMauro Carvalho Chehab 		s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
872b285192aSMauro Carvalho Chehab 		cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2,
873b285192aSMauro Carvalho Chehab 				 s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
874b285192aSMauro Carvalho Chehab 
875b285192aSMauro Carvalho Chehab 		/* Call out to the common CX2341x API setup for user controls */
876b285192aSMauro Carvalho Chehab 		cx->cxhdl.priv = s;
877b285192aSMauro Carvalho Chehab 		cx2341x_handler_setup(&cx->cxhdl);
878b285192aSMauro Carvalho Chehab 
879b285192aSMauro Carvalho Chehab 		/*
880b285192aSMauro Carvalho Chehab 		 * When starting a capture and we're set for radio,
881b285192aSMauro Carvalho Chehab 		 * ensure the video is muted, despite the user control.
882b285192aSMauro Carvalho Chehab 		 */
883b285192aSMauro Carvalho Chehab 		if (!cx->cxhdl.video_mute &&
884b285192aSMauro Carvalho Chehab 		    test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
885b285192aSMauro Carvalho Chehab 			cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
886b285192aSMauro Carvalho Chehab 			  (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
887b285192aSMauro Carvalho Chehab 
888b285192aSMauro Carvalho Chehab 		/* Enable the Video Format Converter for UYVY 4:2:2 support,
889b285192aSMauro Carvalho Chehab 		 * rather than the default HM12 Macroblovk 4:2:0 support.
890b285192aSMauro Carvalho Chehab 		 */
891b285192aSMauro Carvalho Chehab 		if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
892b285192aSMauro Carvalho Chehab 			if (s->pixelformat == V4L2_PIX_FMT_UYVY)
893b285192aSMauro Carvalho Chehab 				cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
894b285192aSMauro Carvalho Chehab 					s->handle, 1);
895b285192aSMauro Carvalho Chehab 			else
896b285192aSMauro Carvalho Chehab 				/* If in doubt, default to HM12 */
897b285192aSMauro Carvalho Chehab 				cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
898b285192aSMauro Carvalho Chehab 					s->handle, 0);
899b285192aSMauro Carvalho Chehab 		}
900b285192aSMauro Carvalho Chehab 	}
901b285192aSMauro Carvalho Chehab 
902b285192aSMauro Carvalho Chehab 	if (atomic_read(&cx->tot_capturing) == 0) {
903b285192aSMauro Carvalho Chehab 		cx2341x_handler_set_busy(&cx->cxhdl, 1);
904b285192aSMauro Carvalho Chehab 		clear_bit(CX18_F_I_EOS, &cx->i_flags);
905b285192aSMauro Carvalho Chehab 		cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
906b285192aSMauro Carvalho Chehab 	}
907b285192aSMauro Carvalho Chehab 
908b285192aSMauro Carvalho Chehab 	cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
909b285192aSMauro Carvalho Chehab 		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
910b285192aSMauro Carvalho Chehab 		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
911b285192aSMauro Carvalho Chehab 
912b285192aSMauro Carvalho Chehab 	/* Init all the cpu_mdls for this stream */
913b285192aSMauro Carvalho Chehab 	cx18_stream_configure_mdls(s);
914b285192aSMauro Carvalho Chehab 	_cx18_stream_load_fw_queue(s);
915b285192aSMauro Carvalho Chehab 
916b285192aSMauro Carvalho Chehab 	/* begin_capture */
917b285192aSMauro Carvalho Chehab 	if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
918b285192aSMauro Carvalho Chehab 		CX18_DEBUG_WARN("Error starting capture!\n");
919b285192aSMauro Carvalho Chehab 		/* Ensure we're really not capturing before releasing MDLs */
920b285192aSMauro Carvalho Chehab 		set_bit(CX18_F_S_STOPPING, &s->s_flags);
921b285192aSMauro Carvalho Chehab 		if (s->type == CX18_ENC_STREAM_TYPE_MPG)
922b285192aSMauro Carvalho Chehab 			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
923b285192aSMauro Carvalho Chehab 		else
924b285192aSMauro Carvalho Chehab 			cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
925b285192aSMauro Carvalho Chehab 		clear_bit(CX18_F_S_STREAMING, &s->s_flags);
926b285192aSMauro Carvalho Chehab 		/* FIXME - CX18_F_S_STREAMOFF as well? */
927b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
928b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
929b285192aSMauro Carvalho Chehab 		s->handle = CX18_INVALID_TASK_HANDLE;
930b285192aSMauro Carvalho Chehab 		clear_bit(CX18_F_S_STOPPING, &s->s_flags);
931b285192aSMauro Carvalho Chehab 		if (atomic_read(&cx->tot_capturing) == 0) {
932b285192aSMauro Carvalho Chehab 			set_bit(CX18_F_I_EOS, &cx->i_flags);
933b285192aSMauro Carvalho Chehab 			cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
934b285192aSMauro Carvalho Chehab 		}
935b285192aSMauro Carvalho Chehab 		return -EINVAL;
936b285192aSMauro Carvalho Chehab 	}
937b285192aSMauro Carvalho Chehab 
938b285192aSMauro Carvalho Chehab 	/* you're live! sit back and await interrupts :) */
939b285192aSMauro Carvalho Chehab 	if (captype != CAPTURE_CHANNEL_TYPE_TS)
940b285192aSMauro Carvalho Chehab 		atomic_inc(&cx->ana_capturing);
941b285192aSMauro Carvalho Chehab 	atomic_inc(&cx->tot_capturing);
942b285192aSMauro Carvalho Chehab 	return 0;
943b285192aSMauro Carvalho Chehab }
944b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx18_start_v4l2_encode_stream);
945b285192aSMauro Carvalho Chehab 
946b285192aSMauro Carvalho Chehab void cx18_stop_all_captures(struct cx18 *cx)
947b285192aSMauro Carvalho Chehab {
948b285192aSMauro Carvalho Chehab 	int i;
949b285192aSMauro Carvalho Chehab 
950b285192aSMauro Carvalho Chehab 	for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
951b285192aSMauro Carvalho Chehab 		struct cx18_stream *s = &cx->streams[i];
952b285192aSMauro Carvalho Chehab 
953b285192aSMauro Carvalho Chehab 		if (!cx18_stream_enabled(s))
954b285192aSMauro Carvalho Chehab 			continue;
955b285192aSMauro Carvalho Chehab 		if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
956b285192aSMauro Carvalho Chehab 			cx18_stop_v4l2_encode_stream(s, 0);
957b285192aSMauro Carvalho Chehab 	}
958b285192aSMauro Carvalho Chehab }
959b285192aSMauro Carvalho Chehab 
960b285192aSMauro Carvalho Chehab int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
961b285192aSMauro Carvalho Chehab {
962b285192aSMauro Carvalho Chehab 	struct cx18 *cx = s->cx;
963b285192aSMauro Carvalho Chehab 
964b285192aSMauro Carvalho Chehab 	if (!cx18_stream_enabled(s))
965b285192aSMauro Carvalho Chehab 		return -EINVAL;
966b285192aSMauro Carvalho Chehab 
967b285192aSMauro Carvalho Chehab 	/* This function assumes that you are allowed to stop the capture
968b285192aSMauro Carvalho Chehab 	   and that we are actually capturing */
969b285192aSMauro Carvalho Chehab 
970b285192aSMauro Carvalho Chehab 	CX18_DEBUG_INFO("Stop Capture\n");
971b285192aSMauro Carvalho Chehab 
972b285192aSMauro Carvalho Chehab 	if (atomic_read(&cx->tot_capturing) == 0)
973b285192aSMauro Carvalho Chehab 		return 0;
974b285192aSMauro Carvalho Chehab 
975b285192aSMauro Carvalho Chehab 	set_bit(CX18_F_S_STOPPING, &s->s_flags);
976b285192aSMauro Carvalho Chehab 	if (s->type == CX18_ENC_STREAM_TYPE_MPG)
977b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
978b285192aSMauro Carvalho Chehab 	else
979b285192aSMauro Carvalho Chehab 		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
980b285192aSMauro Carvalho Chehab 
981b285192aSMauro Carvalho Chehab 	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
982b285192aSMauro Carvalho Chehab 		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
983b285192aSMauro Carvalho Chehab 	}
984b285192aSMauro Carvalho Chehab 
985b285192aSMauro Carvalho Chehab 	if (s->type != CX18_ENC_STREAM_TYPE_TS)
986b285192aSMauro Carvalho Chehab 		atomic_dec(&cx->ana_capturing);
987b285192aSMauro Carvalho Chehab 	atomic_dec(&cx->tot_capturing);
988b285192aSMauro Carvalho Chehab 
989b285192aSMauro Carvalho Chehab 	/* Clear capture and no-read bits */
990b285192aSMauro Carvalho Chehab 	clear_bit(CX18_F_S_STREAMING, &s->s_flags);
991b285192aSMauro Carvalho Chehab 
992b285192aSMauro Carvalho Chehab 	/* Tell the CX23418 it can't use our buffers anymore */
993b285192aSMauro Carvalho Chehab 	cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
994b285192aSMauro Carvalho Chehab 
995b285192aSMauro Carvalho Chehab 	cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
996b285192aSMauro Carvalho Chehab 	s->handle = CX18_INVALID_TASK_HANDLE;
997b285192aSMauro Carvalho Chehab 	clear_bit(CX18_F_S_STOPPING, &s->s_flags);
998b285192aSMauro Carvalho Chehab 
999b285192aSMauro Carvalho Chehab 	if (atomic_read(&cx->tot_capturing) > 0)
1000b285192aSMauro Carvalho Chehab 		return 0;
1001b285192aSMauro Carvalho Chehab 
1002b285192aSMauro Carvalho Chehab 	cx2341x_handler_set_busy(&cx->cxhdl, 0);
1003b285192aSMauro Carvalho Chehab 	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
1004b285192aSMauro Carvalho Chehab 	wake_up(&s->waitq);
1005b285192aSMauro Carvalho Chehab 
1006b285192aSMauro Carvalho Chehab 	return 0;
1007b285192aSMauro Carvalho Chehab }
1008b285192aSMauro Carvalho Chehab EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream);
1009b285192aSMauro Carvalho Chehab 
1010b285192aSMauro Carvalho Chehab u32 cx18_find_handle(struct cx18 *cx)
1011b285192aSMauro Carvalho Chehab {
1012b285192aSMauro Carvalho Chehab 	int i;
1013b285192aSMauro Carvalho Chehab 
1014b285192aSMauro Carvalho Chehab 	/* find first available handle to be used for global settings */
1015b285192aSMauro Carvalho Chehab 	for (i = 0; i < CX18_MAX_STREAMS; i++) {
1016b285192aSMauro Carvalho Chehab 		struct cx18_stream *s = &cx->streams[i];
1017b285192aSMauro Carvalho Chehab 
101808569d64SHans Verkuil 		if (s->video_dev.v4l2_dev && (s->handle != CX18_INVALID_TASK_HANDLE))
1019b285192aSMauro Carvalho Chehab 			return s->handle;
1020b285192aSMauro Carvalho Chehab 	}
1021b285192aSMauro Carvalho Chehab 	return CX18_INVALID_TASK_HANDLE;
1022b285192aSMauro Carvalho Chehab }
1023b285192aSMauro Carvalho Chehab 
1024b285192aSMauro Carvalho Chehab struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
1025b285192aSMauro Carvalho Chehab {
1026b285192aSMauro Carvalho Chehab 	int i;
1027b285192aSMauro Carvalho Chehab 	struct cx18_stream *s;
1028b285192aSMauro Carvalho Chehab 
1029b285192aSMauro Carvalho Chehab 	if (handle == CX18_INVALID_TASK_HANDLE)
1030b285192aSMauro Carvalho Chehab 		return NULL;
1031b285192aSMauro Carvalho Chehab 
1032b285192aSMauro Carvalho Chehab 	for (i = 0; i < CX18_MAX_STREAMS; i++) {
1033b285192aSMauro Carvalho Chehab 		s = &cx->streams[i];
1034b285192aSMauro Carvalho Chehab 		if (s->handle != handle)
1035b285192aSMauro Carvalho Chehab 			continue;
1036b285192aSMauro Carvalho Chehab 		if (cx18_stream_enabled(s))
1037b285192aSMauro Carvalho Chehab 			return s;
1038b285192aSMauro Carvalho Chehab 	}
1039b285192aSMauro Carvalho Chehab 	return NULL;
1040b285192aSMauro Carvalho Chehab }
1041