xref: /linux/drivers/media/common/saa7146/saa7146_vbi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
139d08ab9SHans Verkuil // SPDX-License-Identifier: GPL-2.0
239d08ab9SHans Verkuil #include <media/drv-intf/saa7146_vv.h>
339d08ab9SHans Verkuil 
439d08ab9SHans Verkuil static int vbi_pixel_to_capture = 720 * 2;
539d08ab9SHans Verkuil 
vbi_workaround(struct saa7146_dev * dev)639d08ab9SHans Verkuil static int vbi_workaround(struct saa7146_dev *dev)
739d08ab9SHans Verkuil {
839d08ab9SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
939d08ab9SHans Verkuil 
1039d08ab9SHans Verkuil 	u32          *cpu;
1139d08ab9SHans Verkuil 	dma_addr_t   dma_addr;
1239d08ab9SHans Verkuil 
1339d08ab9SHans Verkuil 	int count = 0;
1439d08ab9SHans Verkuil 	int i;
1539d08ab9SHans Verkuil 
1639d08ab9SHans Verkuil 	DECLARE_WAITQUEUE(wait, current);
1739d08ab9SHans Verkuil 
1839d08ab9SHans Verkuil 	DEB_VBI("dev:%p\n", dev);
1939d08ab9SHans Verkuil 
2039d08ab9SHans Verkuil 	/* once again, a bug in the saa7146: the brs acquisition
2139d08ab9SHans Verkuil 	   is buggy and especially the BXO-counter does not work
2239d08ab9SHans Verkuil 	   as specified. there is this workaround, but please
2339d08ab9SHans Verkuil 	   don't let me explain it. ;-) */
2439d08ab9SHans Verkuil 
2539d08ab9SHans Verkuil 	cpu = dma_alloc_coherent(&dev->pci->dev, 4096, &dma_addr, GFP_KERNEL);
2639d08ab9SHans Verkuil 	if (NULL == cpu)
2739d08ab9SHans Verkuil 		return -ENOMEM;
2839d08ab9SHans Verkuil 
2939d08ab9SHans Verkuil 	/* setup some basic programming, just for the workaround */
3039d08ab9SHans Verkuil 	saa7146_write(dev, BASE_EVEN3,	dma_addr);
3139d08ab9SHans Verkuil 	saa7146_write(dev, BASE_ODD3,	dma_addr+vbi_pixel_to_capture);
3239d08ab9SHans Verkuil 	saa7146_write(dev, PROT_ADDR3,	dma_addr+4096);
3339d08ab9SHans Verkuil 	saa7146_write(dev, PITCH3,	vbi_pixel_to_capture);
3439d08ab9SHans Verkuil 	saa7146_write(dev, BASE_PAGE3,	0x0);
3539d08ab9SHans Verkuil 	saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));
3639d08ab9SHans Verkuil 	saa7146_write(dev, MC2, MASK_04|MASK_20);
3739d08ab9SHans Verkuil 
3839d08ab9SHans Verkuil 	/* load brs-control register */
3939d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
4039d08ab9SHans Verkuil 	/* BXO = 1h, BRS to outbound */
4139d08ab9SHans Verkuil 	WRITE_RPS1(0xc000008c);
4239d08ab9SHans Verkuil 	/* wait for vbi_a or vbi_b*/
4339d08ab9SHans Verkuil 	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
4439d08ab9SHans Verkuil 		DEB_D("...using port b\n");
4539d08ab9SHans Verkuil 		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);
4639d08ab9SHans Verkuil 		WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);
4739d08ab9SHans Verkuil /*
4839d08ab9SHans Verkuil 		WRITE_RPS1(CMD_PAUSE | MASK_09);
4939d08ab9SHans Verkuil */
5039d08ab9SHans Verkuil 	} else {
5139d08ab9SHans Verkuil 		DEB_D("...using port a\n");
5239d08ab9SHans Verkuil 		WRITE_RPS1(CMD_PAUSE | MASK_10);
5339d08ab9SHans Verkuil 	}
5439d08ab9SHans Verkuil 	/* upload brs */
5539d08ab9SHans Verkuil 	WRITE_RPS1(CMD_UPLOAD | MASK_08);
5639d08ab9SHans Verkuil 	/* load brs-control register */
5739d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
5839d08ab9SHans Verkuil 	/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */
5939d08ab9SHans Verkuil 	WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);
6039d08ab9SHans Verkuil 	/* wait for brs_done */
6139d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | MASK_08);
6239d08ab9SHans Verkuil 	/* upload brs */
6339d08ab9SHans Verkuil 	WRITE_RPS1(CMD_UPLOAD | MASK_08);
6439d08ab9SHans Verkuil 	/* load video-dma3 NumLines3 and NumBytes3 */
6539d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));
6639d08ab9SHans Verkuil 	/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */
6739d08ab9SHans Verkuil 	WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));
6839d08ab9SHans Verkuil 	/* load brs-control register */
6939d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));
7039d08ab9SHans Verkuil 	/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */
7139d08ab9SHans Verkuil 	WRITE_RPS1((540 << 7) | (5 << 19));  // 5 == vbi_start
7239d08ab9SHans Verkuil 	/* wait for brs_done */
7339d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | MASK_08);
7439d08ab9SHans Verkuil 	/* upload brs and video-dma3*/
7539d08ab9SHans Verkuil 	WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);
7639d08ab9SHans Verkuil 	/* load mc2 register: enable dma3 */
7739d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));
7839d08ab9SHans Verkuil 	WRITE_RPS1(MASK_20 | MASK_04);
7939d08ab9SHans Verkuil 	/* generate interrupt */
8039d08ab9SHans Verkuil 	WRITE_RPS1(CMD_INTERRUPT);
8139d08ab9SHans Verkuil 	/* stop rps1 */
8239d08ab9SHans Verkuil 	WRITE_RPS1(CMD_STOP);
8339d08ab9SHans Verkuil 
8439d08ab9SHans Verkuil 	/* we have to do the workaround twice to be sure that
8539d08ab9SHans Verkuil 	   everything is ok */
8639d08ab9SHans Verkuil 	for(i = 0; i < 2; i++) {
8739d08ab9SHans Verkuil 
8839d08ab9SHans Verkuil 		/* indicate to the irq handler that we do the workaround */
8939d08ab9SHans Verkuil 		saa7146_write(dev, MC2, MASK_31|MASK_15);
9039d08ab9SHans Verkuil 
9139d08ab9SHans Verkuil 		saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));
9239d08ab9SHans Verkuil 		saa7146_write(dev, MC2, MASK_04|MASK_20);
9339d08ab9SHans Verkuil 
9439d08ab9SHans Verkuil 		/* enable rps1 irqs */
9539d08ab9SHans Verkuil 		SAA7146_IER_ENABLE(dev,MASK_28);
9639d08ab9SHans Verkuil 
9739d08ab9SHans Verkuil 		/* prepare to wait to be woken up by the irq-handler */
9839d08ab9SHans Verkuil 		add_wait_queue(&vv->vbi_wq, &wait);
9939d08ab9SHans Verkuil 		set_current_state(TASK_INTERRUPTIBLE);
10039d08ab9SHans Verkuil 
10139d08ab9SHans Verkuil 		/* start rps1 to enable workaround */
10239d08ab9SHans Verkuil 		saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
10339d08ab9SHans Verkuil 		saa7146_write(dev, MC1, (MASK_13 | MASK_29));
10439d08ab9SHans Verkuil 
10539d08ab9SHans Verkuil 		schedule();
10639d08ab9SHans Verkuil 
10739d08ab9SHans Verkuil 		DEB_VBI("brs bug workaround %d/1\n", i);
10839d08ab9SHans Verkuil 
10939d08ab9SHans Verkuil 		remove_wait_queue(&vv->vbi_wq, &wait);
11039d08ab9SHans Verkuil 		__set_current_state(TASK_RUNNING);
11139d08ab9SHans Verkuil 
11239d08ab9SHans Verkuil 		/* disable rps1 irqs */
11339d08ab9SHans Verkuil 		SAA7146_IER_DISABLE(dev,MASK_28);
11439d08ab9SHans Verkuil 
11539d08ab9SHans Verkuil 		/* stop video-dma3 */
11639d08ab9SHans Verkuil 		saa7146_write(dev, MC1, MASK_20);
11739d08ab9SHans Verkuil 
11839d08ab9SHans Verkuil 		if(signal_pending(current)) {
11939d08ab9SHans Verkuil 
12039d08ab9SHans Verkuil 			DEB_VBI("aborted (rps:0x%08x)\n",
12139d08ab9SHans Verkuil 				saa7146_read(dev, RPS_ADDR1));
12239d08ab9SHans Verkuil 
12339d08ab9SHans Verkuil 			/* stop rps1 for sure */
12439d08ab9SHans Verkuil 			saa7146_write(dev, MC1, MASK_29);
12539d08ab9SHans Verkuil 
12639d08ab9SHans Verkuil 			dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr);
12739d08ab9SHans Verkuil 			return -EINTR;
12839d08ab9SHans Verkuil 		}
12939d08ab9SHans Verkuil 	}
13039d08ab9SHans Verkuil 
13139d08ab9SHans Verkuil 	dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr);
13239d08ab9SHans Verkuil 	return 0;
13339d08ab9SHans Verkuil }
13439d08ab9SHans Verkuil 
saa7146_set_vbi_capture(struct saa7146_dev * dev,struct saa7146_buf * buf,struct saa7146_buf * next)13539d08ab9SHans Verkuil static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
13639d08ab9SHans Verkuil {
13739d08ab9SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
13839d08ab9SHans Verkuil 
13939d08ab9SHans Verkuil 	struct saa7146_video_dma vdma3;
14039d08ab9SHans Verkuil 
14139d08ab9SHans Verkuil 	int count = 0;
14239d08ab9SHans Verkuil 	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;
14339d08ab9SHans Verkuil 	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;
14439d08ab9SHans Verkuil 
14539d08ab9SHans Verkuil /*
14639d08ab9SHans Verkuil 	vdma3.base_even	= 0xc8000000+2560*70;
14739d08ab9SHans Verkuil 	vdma3.base_odd	= 0xc8000000;
14839d08ab9SHans Verkuil 	vdma3.prot_addr	= 0xc8000000+2560*164;
14939d08ab9SHans Verkuil 	vdma3.pitch	= 2560;
15039d08ab9SHans Verkuil 	vdma3.base_page	= 0;
15139d08ab9SHans Verkuil 	vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!
15239d08ab9SHans Verkuil */
15339d08ab9SHans Verkuil 	vdma3.base_even	= buf->pt[2].offset;
15439d08ab9SHans Verkuil 	vdma3.base_odd	= buf->pt[2].offset + 16 * vbi_pixel_to_capture;
15539d08ab9SHans Verkuil 	vdma3.prot_addr	= buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;
15639d08ab9SHans Verkuil 	vdma3.pitch	= vbi_pixel_to_capture;
15739d08ab9SHans Verkuil 	vdma3.base_page	= buf->pt[2].dma | ME1;
15839d08ab9SHans Verkuil 	vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;
15939d08ab9SHans Verkuil 
16039d08ab9SHans Verkuil 	saa7146_write_out_dma(dev, 3, &vdma3);
16139d08ab9SHans Verkuil 
16239d08ab9SHans Verkuil 	/* write beginning of rps-program */
16339d08ab9SHans Verkuil 	count = 0;
16439d08ab9SHans Verkuil 
16539d08ab9SHans Verkuil 	/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */
16639d08ab9SHans Verkuil 
16739d08ab9SHans Verkuil 	/* we don't wait here for the first field anymore. this is different from the video
16839d08ab9SHans Verkuil 	   capture and might cause that the first buffer is only half filled (with only
16939d08ab9SHans Verkuil 	   one field). but since this is some sort of streaming data, this is not that negative.
17039d08ab9SHans Verkuil 	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
17139d08ab9SHans Verkuil 
17239d08ab9SHans Verkuil /*
17339d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
17439d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);
17539d08ab9SHans Verkuil */
17639d08ab9SHans Verkuil 	/* set bit 1 */
17739d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));
17839d08ab9SHans Verkuil 	WRITE_RPS1(MASK_28 | MASK_12);
17939d08ab9SHans Verkuil 
18039d08ab9SHans Verkuil 	/* turn on video-dma3 */
18139d08ab9SHans Verkuil 	WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));
18239d08ab9SHans Verkuil 	WRITE_RPS1(MASK_04 | MASK_20);			/* => mask */
18339d08ab9SHans Verkuil 	WRITE_RPS1(MASK_04 | MASK_20);			/* => values */
18439d08ab9SHans Verkuil 
18539d08ab9SHans Verkuil 	/* wait for o_fid_a/b / e_fid_a/b toggle */
18639d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | o_wait);
18739d08ab9SHans Verkuil 	WRITE_RPS1(CMD_PAUSE | e_wait);
18839d08ab9SHans Verkuil 
18939d08ab9SHans Verkuil 	/* generate interrupt */
19039d08ab9SHans Verkuil 	WRITE_RPS1(CMD_INTERRUPT);
19139d08ab9SHans Verkuil 
19239d08ab9SHans Verkuil 	/* stop */
19339d08ab9SHans Verkuil 	WRITE_RPS1(CMD_STOP);
19439d08ab9SHans Verkuil 
19539d08ab9SHans Verkuil 	/* enable rps1 irqs */
19639d08ab9SHans Verkuil 	SAA7146_IER_ENABLE(dev, MASK_28);
19739d08ab9SHans Verkuil 
19839d08ab9SHans Verkuil 	/* write the address of the rps-program */
19939d08ab9SHans Verkuil 	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
20039d08ab9SHans Verkuil 
20139d08ab9SHans Verkuil 	/* turn on rps */
20239d08ab9SHans Verkuil 	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
20339d08ab9SHans Verkuil }
20439d08ab9SHans Verkuil 
buffer_activate(struct saa7146_dev * dev,struct saa7146_buf * buf,struct saa7146_buf * next)20539d08ab9SHans Verkuil static int buffer_activate(struct saa7146_dev *dev,
20639d08ab9SHans Verkuil 			   struct saa7146_buf *buf,
20739d08ab9SHans Verkuil 			   struct saa7146_buf *next)
20839d08ab9SHans Verkuil {
20939d08ab9SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
21039d08ab9SHans Verkuil 
21139d08ab9SHans Verkuil 	DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
21239d08ab9SHans Verkuil 	saa7146_set_vbi_capture(dev,buf,next);
21339d08ab9SHans Verkuil 
21439d08ab9SHans Verkuil 	mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
21539d08ab9SHans Verkuil 	return 0;
21639d08ab9SHans Verkuil }
21739d08ab9SHans Verkuil 
21839d08ab9SHans Verkuil /* ------------------------------------------------------------------ */
21939d08ab9SHans Verkuil 
queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])220*0b6e30bdSHans Verkuil static int queue_setup(struct vb2_queue *q,
221*0b6e30bdSHans Verkuil 		       unsigned int *num_buffers, unsigned int *num_planes,
222*0b6e30bdSHans Verkuil 		       unsigned int sizes[], struct device *alloc_devs[])
22339d08ab9SHans Verkuil {
224*0b6e30bdSHans Verkuil 	unsigned int size = 16 * 2 * vbi_pixel_to_capture;
225*0b6e30bdSHans Verkuil 
226*0b6e30bdSHans Verkuil 	if (*num_planes)
227*0b6e30bdSHans Verkuil 		return sizes[0] < size ? -EINVAL : 0;
228*0b6e30bdSHans Verkuil 	*num_planes = 1;
229*0b6e30bdSHans Verkuil 	sizes[0] = size;
230*0b6e30bdSHans Verkuil 
231*0b6e30bdSHans Verkuil 	return 0;
232*0b6e30bdSHans Verkuil }
233*0b6e30bdSHans Verkuil 
buf_queue(struct vb2_buffer * vb)234*0b6e30bdSHans Verkuil static void buf_queue(struct vb2_buffer *vb)
235*0b6e30bdSHans Verkuil {
236*0b6e30bdSHans Verkuil 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
237*0b6e30bdSHans Verkuil 	struct vb2_queue *vq = vb->vb2_queue;
238*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(vq);
239*0b6e30bdSHans Verkuil 	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
240*0b6e30bdSHans Verkuil 	unsigned long flags;
241*0b6e30bdSHans Verkuil 
242*0b6e30bdSHans Verkuil 	spin_lock_irqsave(&dev->slock, flags);
243*0b6e30bdSHans Verkuil 
244*0b6e30bdSHans Verkuil 	saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf);
245*0b6e30bdSHans Verkuil 	spin_unlock_irqrestore(&dev->slock, flags);
246*0b6e30bdSHans Verkuil }
247*0b6e30bdSHans Verkuil 
buf_init(struct vb2_buffer * vb)248*0b6e30bdSHans Verkuil static int buf_init(struct vb2_buffer *vb)
249*0b6e30bdSHans Verkuil {
250*0b6e30bdSHans Verkuil 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
251*0b6e30bdSHans Verkuil 	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
252*0b6e30bdSHans Verkuil 	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);
253*0b6e30bdSHans Verkuil 	struct scatterlist *list = sgt->sgl;
254*0b6e30bdSHans Verkuil 	int length = sgt->nents;
255*0b6e30bdSHans Verkuil 	struct vb2_queue *vq = vb->vb2_queue;
256*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(vq);
257*0b6e30bdSHans Verkuil 	int ret;
258*0b6e30bdSHans Verkuil 
259*0b6e30bdSHans Verkuil 	buf->activate = buffer_activate;
260*0b6e30bdSHans Verkuil 
261*0b6e30bdSHans Verkuil 	saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
262*0b6e30bdSHans Verkuil 
263*0b6e30bdSHans Verkuil 	ret = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
264*0b6e30bdSHans Verkuil 					   list, length);
265*0b6e30bdSHans Verkuil 	if (ret)
266*0b6e30bdSHans Verkuil 		saa7146_pgtable_free(dev->pci, &buf->pt[2]);
267*0b6e30bdSHans Verkuil 	return ret;
268*0b6e30bdSHans Verkuil }
269*0b6e30bdSHans Verkuil 
buf_prepare(struct vb2_buffer * vb)270*0b6e30bdSHans Verkuil static int buf_prepare(struct vb2_buffer *vb)
271*0b6e30bdSHans Verkuil {
272*0b6e30bdSHans Verkuil 	unsigned int size = 16 * 2 * vbi_pixel_to_capture;
273*0b6e30bdSHans Verkuil 
274*0b6e30bdSHans Verkuil 	if (vb2_plane_size(vb, 0) < size)
275*0b6e30bdSHans Verkuil 		return -EINVAL;
276*0b6e30bdSHans Verkuil 	vb2_set_plane_payload(vb, 0, size);
277*0b6e30bdSHans Verkuil 	return 0;
278*0b6e30bdSHans Verkuil }
279*0b6e30bdSHans Verkuil 
buf_cleanup(struct vb2_buffer * vb)280*0b6e30bdSHans Verkuil static void buf_cleanup(struct vb2_buffer *vb)
281*0b6e30bdSHans Verkuil {
282*0b6e30bdSHans Verkuil 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
283*0b6e30bdSHans Verkuil 	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);
284*0b6e30bdSHans Verkuil 	struct vb2_queue *vq = vb->vb2_queue;
285*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(vq);
286*0b6e30bdSHans Verkuil 
287*0b6e30bdSHans Verkuil 	saa7146_pgtable_free(dev->pci, &buf->pt[2]);
288*0b6e30bdSHans Verkuil }
289*0b6e30bdSHans Verkuil 
return_buffers(struct vb2_queue * q,int state)290*0b6e30bdSHans Verkuil static void return_buffers(struct vb2_queue *q, int state)
291*0b6e30bdSHans Verkuil {
292*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(q);
293*0b6e30bdSHans Verkuil 	struct saa7146_dmaqueue *dq = &dev->vv_data->vbi_dmaq;
294*0b6e30bdSHans Verkuil 	struct saa7146_buf *buf;
295*0b6e30bdSHans Verkuil 
296*0b6e30bdSHans Verkuil 	if (dq->curr) {
297*0b6e30bdSHans Verkuil 		buf = dq->curr;
298*0b6e30bdSHans Verkuil 		dq->curr = NULL;
299*0b6e30bdSHans Verkuil 		vb2_buffer_done(&buf->vb.vb2_buf, state);
300*0b6e30bdSHans Verkuil 	}
301*0b6e30bdSHans Verkuil 	while (!list_empty(&dq->queue)) {
302*0b6e30bdSHans Verkuil 		buf = list_entry(dq->queue.next, struct saa7146_buf, list);
303*0b6e30bdSHans Verkuil 		list_del(&buf->list);
304*0b6e30bdSHans Verkuil 		vb2_buffer_done(&buf->vb.vb2_buf, state);
305*0b6e30bdSHans Verkuil 	}
306*0b6e30bdSHans Verkuil }
307*0b6e30bdSHans Verkuil 
vbi_stop(struct saa7146_dev * dev)308*0b6e30bdSHans Verkuil static void vbi_stop(struct saa7146_dev *dev)
309*0b6e30bdSHans Verkuil {
31039d08ab9SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
31139d08ab9SHans Verkuil 	unsigned long flags;
312*0b6e30bdSHans Verkuil 	DEB_VBI("dev:%p\n", dev);
31339d08ab9SHans Verkuil 
31439d08ab9SHans Verkuil 	spin_lock_irqsave(&dev->slock,flags);
31539d08ab9SHans Verkuil 
31639d08ab9SHans Verkuil 	/* disable rps1  */
31739d08ab9SHans Verkuil 	saa7146_write(dev, MC1, MASK_29);
31839d08ab9SHans Verkuil 
31939d08ab9SHans Verkuil 	/* disable rps1 irqs */
32039d08ab9SHans Verkuil 	SAA7146_IER_DISABLE(dev, MASK_28);
32139d08ab9SHans Verkuil 
32239d08ab9SHans Verkuil 	/* shut down dma 3 transfers */
32339d08ab9SHans Verkuil 	saa7146_write(dev, MC1, MASK_20);
32439d08ab9SHans Verkuil 
32539d08ab9SHans Verkuil 	del_timer(&vv->vbi_dmaq.timeout);
32639d08ab9SHans Verkuil 	del_timer(&vv->vbi_read_timeout);
32739d08ab9SHans Verkuil 
32839d08ab9SHans Verkuil 	spin_unlock_irqrestore(&dev->slock, flags);
32939d08ab9SHans Verkuil }
33039d08ab9SHans Verkuil 
vbi_read_timeout(struct timer_list * t)33139d08ab9SHans Verkuil static void vbi_read_timeout(struct timer_list *t)
33239d08ab9SHans Verkuil {
33339d08ab9SHans Verkuil 	struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout);
334*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vv->vbi_dmaq.dev;
33539d08ab9SHans Verkuil 
33639d08ab9SHans Verkuil 	DEB_VBI("dev:%p\n", dev);
33739d08ab9SHans Verkuil 
338*0b6e30bdSHans Verkuil 	vbi_stop(dev);
33939d08ab9SHans Verkuil }
34039d08ab9SHans Verkuil 
vbi_begin(struct saa7146_dev * dev)341*0b6e30bdSHans Verkuil static int vbi_begin(struct saa7146_dev *dev)
34239d08ab9SHans Verkuil {
343acdb1573SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
34439d08ab9SHans Verkuil 	u32 arbtr_ctrl	= saa7146_read(dev, PCI_BT_V1);
34539d08ab9SHans Verkuil 	int ret = 0;
34639d08ab9SHans Verkuil 
347*0b6e30bdSHans Verkuil 	DEB_VBI("dev:%p\n", dev);
34839d08ab9SHans Verkuil 
349acdb1573SHans Verkuil 	ret = saa7146_res_get(dev, RESOURCE_DMA3_BRS);
35039d08ab9SHans Verkuil 	if (0 == ret) {
35139d08ab9SHans Verkuil 		DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n");
35239d08ab9SHans Verkuil 		return -EBUSY;
35339d08ab9SHans Verkuil 	}
35439d08ab9SHans Verkuil 
35539d08ab9SHans Verkuil 	/* adjust arbitrition control for video dma 3 */
35639d08ab9SHans Verkuil 	arbtr_ctrl &= ~0x1f0000;
35739d08ab9SHans Verkuil 	arbtr_ctrl |=  0x1d0000;
35839d08ab9SHans Verkuil 	saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
35939d08ab9SHans Verkuil 	saa7146_write(dev, MC2, (MASK_04|MASK_20));
36039d08ab9SHans Verkuil 
36139d08ab9SHans Verkuil 	vv->vbi_read_timeout.function = vbi_read_timeout;
36239d08ab9SHans Verkuil 
36339d08ab9SHans Verkuil 	/* initialize the brs */
36439d08ab9SHans Verkuil 	if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
36539d08ab9SHans Verkuil 		saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));
36639d08ab9SHans Verkuil 	} else {
36739d08ab9SHans Verkuil 		saa7146_write(dev, BRS_CTRL, 0x00000001);
36839d08ab9SHans Verkuil 
36939d08ab9SHans Verkuil 		if (0 != (ret = vbi_workaround(dev))) {
37039d08ab9SHans Verkuil 			DEB_VBI("vbi workaround failed!\n");
37139d08ab9SHans Verkuil 			/* return ret;*/
37239d08ab9SHans Verkuil 		}
37339d08ab9SHans Verkuil 	}
37439d08ab9SHans Verkuil 
37539d08ab9SHans Verkuil 	/* upload brs register */
37639d08ab9SHans Verkuil 	saa7146_write(dev, MC2, (MASK_08|MASK_24));
37739d08ab9SHans Verkuil 	return 0;
37839d08ab9SHans Verkuil }
37939d08ab9SHans Verkuil 
start_streaming(struct vb2_queue * q,unsigned int count)380*0b6e30bdSHans Verkuil static int start_streaming(struct vb2_queue *q, unsigned int count)
38139d08ab9SHans Verkuil {
382*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(q);
383*0b6e30bdSHans Verkuil 	int ret;
38439d08ab9SHans Verkuil 
385*0b6e30bdSHans Verkuil 	if (!vb2_is_streaming(&dev->vv_data->vbi_dmaq.q))
386*0b6e30bdSHans Verkuil 		dev->vv_data->seqnr = 0;
387*0b6e30bdSHans Verkuil 	ret = vbi_begin(dev);
388*0b6e30bdSHans Verkuil 	if (ret)
389*0b6e30bdSHans Verkuil 		return_buffers(q, VB2_BUF_STATE_QUEUED);
390*0b6e30bdSHans Verkuil 	return ret;
39139d08ab9SHans Verkuil }
392*0b6e30bdSHans Verkuil 
stop_streaming(struct vb2_queue * q)393*0b6e30bdSHans Verkuil static void stop_streaming(struct vb2_queue *q)
394*0b6e30bdSHans Verkuil {
395*0b6e30bdSHans Verkuil 	struct saa7146_dev *dev = vb2_get_drv_priv(q);
396*0b6e30bdSHans Verkuil 
397*0b6e30bdSHans Verkuil 	vbi_stop(dev);
398*0b6e30bdSHans Verkuil 	return_buffers(q, VB2_BUF_STATE_ERROR);
399acdb1573SHans Verkuil 	saa7146_res_free(dev, RESOURCE_DMA3_BRS);
40039d08ab9SHans Verkuil }
40139d08ab9SHans Verkuil 
402*0b6e30bdSHans Verkuil const struct vb2_ops vbi_qops = {
403*0b6e30bdSHans Verkuil 	.queue_setup	= queue_setup,
404*0b6e30bdSHans Verkuil 	.buf_queue	= buf_queue,
405*0b6e30bdSHans Verkuil 	.buf_init	= buf_init,
406*0b6e30bdSHans Verkuil 	.buf_prepare	= buf_prepare,
407*0b6e30bdSHans Verkuil 	.buf_cleanup	= buf_cleanup,
408*0b6e30bdSHans Verkuil 	.start_streaming = start_streaming,
409*0b6e30bdSHans Verkuil 	.stop_streaming = stop_streaming,
410*0b6e30bdSHans Verkuil 	.wait_prepare	= vb2_ops_wait_prepare,
411*0b6e30bdSHans Verkuil 	.wait_finish	= vb2_ops_wait_finish,
412*0b6e30bdSHans Verkuil };
413*0b6e30bdSHans Verkuil 
414*0b6e30bdSHans Verkuil /* ------------------------------------------------------------------ */
415*0b6e30bdSHans Verkuil 
vbi_init(struct saa7146_dev * dev,struct saa7146_vv * vv)416*0b6e30bdSHans Verkuil static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
417*0b6e30bdSHans Verkuil {
418*0b6e30bdSHans Verkuil 	DEB_VBI("dev:%p\n", dev);
419*0b6e30bdSHans Verkuil 
420*0b6e30bdSHans Verkuil 	INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
421*0b6e30bdSHans Verkuil 
422*0b6e30bdSHans Verkuil 	timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0);
423*0b6e30bdSHans Verkuil 	vv->vbi_dmaq.dev              = dev;
424*0b6e30bdSHans Verkuil 
425*0b6e30bdSHans Verkuil 	init_waitqueue_head(&vv->vbi_wq);
426*0b6e30bdSHans Verkuil }
427*0b6e30bdSHans Verkuil 
vbi_irq_done(struct saa7146_dev * dev,unsigned long status)42839d08ab9SHans Verkuil static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
42939d08ab9SHans Verkuil {
43039d08ab9SHans Verkuil 	struct saa7146_vv *vv = dev->vv_data;
43139d08ab9SHans Verkuil 	spin_lock(&dev->slock);
43239d08ab9SHans Verkuil 
43339d08ab9SHans Verkuil 	if (vv->vbi_dmaq.curr) {
43439d08ab9SHans Verkuil 		DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
435*0b6e30bdSHans Verkuil 		saa7146_buffer_finish(dev, &vv->vbi_dmaq, VB2_BUF_STATE_DONE);
43639d08ab9SHans Verkuil 	} else {
43739d08ab9SHans Verkuil 		DEB_VBI("dev:%p\n", dev);
43839d08ab9SHans Verkuil 	}
43939d08ab9SHans Verkuil 	saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
44039d08ab9SHans Verkuil 
44139d08ab9SHans Verkuil 	spin_unlock(&dev->slock);
44239d08ab9SHans Verkuil }
44339d08ab9SHans Verkuil 
44439d08ab9SHans Verkuil const struct saa7146_use_ops saa7146_vbi_uops = {
44539d08ab9SHans Verkuil 	.init		= vbi_init,
44639d08ab9SHans Verkuil 	.irq_done	= vbi_irq_done,
44739d08ab9SHans Verkuil };
448