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