162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <media/drv-intf/saa7146_vv.h> 362306a36Sopenharmony_ci 462306a36Sopenharmony_cistatic int vbi_pixel_to_capture = 720 * 2; 562306a36Sopenharmony_ci 662306a36Sopenharmony_cistatic int vbi_workaround(struct saa7146_dev *dev) 762306a36Sopenharmony_ci{ 862306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci u32 *cpu; 1162306a36Sopenharmony_ci dma_addr_t dma_addr; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci int count = 0; 1462306a36Sopenharmony_ci int i; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* once again, a bug in the saa7146: the brs acquisition 2162306a36Sopenharmony_ci is buggy and especially the BXO-counter does not work 2262306a36Sopenharmony_ci as specified. there is this workaround, but please 2362306a36Sopenharmony_ci don't let me explain it. ;-) */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci cpu = dma_alloc_coherent(&dev->pci->dev, 4096, &dma_addr, GFP_KERNEL); 2662306a36Sopenharmony_ci if (NULL == cpu) 2762306a36Sopenharmony_ci return -ENOMEM; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* setup some basic programming, just for the workaround */ 3062306a36Sopenharmony_ci saa7146_write(dev, BASE_EVEN3, dma_addr); 3162306a36Sopenharmony_ci saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); 3262306a36Sopenharmony_ci saa7146_write(dev, PROT_ADDR3, dma_addr+4096); 3362306a36Sopenharmony_ci saa7146_write(dev, PITCH3, vbi_pixel_to_capture); 3462306a36Sopenharmony_ci saa7146_write(dev, BASE_PAGE3, 0x0); 3562306a36Sopenharmony_ci saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); 3662306a36Sopenharmony_ci saa7146_write(dev, MC2, MASK_04|MASK_20); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* load brs-control register */ 3962306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); 4062306a36Sopenharmony_ci /* BXO = 1h, BRS to outbound */ 4162306a36Sopenharmony_ci WRITE_RPS1(0xc000008c); 4262306a36Sopenharmony_ci /* wait for vbi_a or vbi_b*/ 4362306a36Sopenharmony_ci if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { 4462306a36Sopenharmony_ci DEB_D("...using port b\n"); 4562306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); 4662306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | MASK_09); 4962306a36Sopenharmony_ci*/ 5062306a36Sopenharmony_ci } else { 5162306a36Sopenharmony_ci DEB_D("...using port a\n"); 5262306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | MASK_10); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci /* upload brs */ 5562306a36Sopenharmony_ci WRITE_RPS1(CMD_UPLOAD | MASK_08); 5662306a36Sopenharmony_ci /* load brs-control register */ 5762306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); 5862306a36Sopenharmony_ci /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */ 5962306a36Sopenharmony_ci WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); 6062306a36Sopenharmony_ci /* wait for brs_done */ 6162306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | MASK_08); 6262306a36Sopenharmony_ci /* upload brs */ 6362306a36Sopenharmony_ci WRITE_RPS1(CMD_UPLOAD | MASK_08); 6462306a36Sopenharmony_ci /* load video-dma3 NumLines3 and NumBytes3 */ 6562306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); 6662306a36Sopenharmony_ci /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */ 6762306a36Sopenharmony_ci WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); 6862306a36Sopenharmony_ci /* load brs-control register */ 6962306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); 7062306a36Sopenharmony_ci /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */ 7162306a36Sopenharmony_ci WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start 7262306a36Sopenharmony_ci /* wait for brs_done */ 7362306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | MASK_08); 7462306a36Sopenharmony_ci /* upload brs and video-dma3*/ 7562306a36Sopenharmony_ci WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); 7662306a36Sopenharmony_ci /* load mc2 register: enable dma3 */ 7762306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); 7862306a36Sopenharmony_ci WRITE_RPS1(MASK_20 | MASK_04); 7962306a36Sopenharmony_ci /* generate interrupt */ 8062306a36Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 8162306a36Sopenharmony_ci /* stop rps1 */ 8262306a36Sopenharmony_ci WRITE_RPS1(CMD_STOP); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* we have to do the workaround twice to be sure that 8562306a36Sopenharmony_ci everything is ok */ 8662306a36Sopenharmony_ci for(i = 0; i < 2; i++) { 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* indicate to the irq handler that we do the workaround */ 8962306a36Sopenharmony_ci saa7146_write(dev, MC2, MASK_31|MASK_15); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); 9262306a36Sopenharmony_ci saa7146_write(dev, MC2, MASK_04|MASK_20); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* enable rps1 irqs */ 9562306a36Sopenharmony_ci SAA7146_IER_ENABLE(dev,MASK_28); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* prepare to wait to be woken up by the irq-handler */ 9862306a36Sopenharmony_ci add_wait_queue(&vv->vbi_wq, &wait); 9962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* start rps1 to enable workaround */ 10262306a36Sopenharmony_ci saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); 10362306a36Sopenharmony_ci saa7146_write(dev, MC1, (MASK_13 | MASK_29)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci schedule(); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci DEB_VBI("brs bug workaround %d/1\n", i); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci remove_wait_queue(&vv->vbi_wq, &wait); 11062306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* disable rps1 irqs */ 11362306a36Sopenharmony_ci SAA7146_IER_DISABLE(dev,MASK_28); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* stop video-dma3 */ 11662306a36Sopenharmony_ci saa7146_write(dev, MC1, MASK_20); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if(signal_pending(current)) { 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci DEB_VBI("aborted (rps:0x%08x)\n", 12162306a36Sopenharmony_ci saa7146_read(dev, RPS_ADDR1)); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* stop rps1 for sure */ 12462306a36Sopenharmony_ci saa7146_write(dev, MC1, MASK_29); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr); 12762306a36Sopenharmony_ci return -EINTR; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci dma_free_coherent(&dev->pci->dev, 4096, cpu, dma_addr); 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci struct saa7146_video_dma vdma3; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci int count = 0; 14262306a36Sopenharmony_ci unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B; 14362306a36Sopenharmony_ci unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci vdma3.base_even = 0xc8000000+2560*70; 14762306a36Sopenharmony_ci vdma3.base_odd = 0xc8000000; 14862306a36Sopenharmony_ci vdma3.prot_addr = 0xc8000000+2560*164; 14962306a36Sopenharmony_ci vdma3.pitch = 2560; 15062306a36Sopenharmony_ci vdma3.base_page = 0; 15162306a36Sopenharmony_ci vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above! 15262306a36Sopenharmony_ci*/ 15362306a36Sopenharmony_ci vdma3.base_even = buf->pt[2].offset; 15462306a36Sopenharmony_ci vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture; 15562306a36Sopenharmony_ci vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture; 15662306a36Sopenharmony_ci vdma3.pitch = vbi_pixel_to_capture; 15762306a36Sopenharmony_ci vdma3.base_page = buf->pt[2].dma | ME1; 15862306a36Sopenharmony_ci vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci saa7146_write_out_dma(dev, 3, &vdma3); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* write beginning of rps-program */ 16362306a36Sopenharmony_ci count = 0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* we don't wait here for the first field anymore. this is different from the video 16862306a36Sopenharmony_ci capture and might cause that the first buffer is only half filled (with only 16962306a36Sopenharmony_ci one field). but since this is some sort of streaming data, this is not that negative. 17062306a36Sopenharmony_ci but by doing this, we can use the whole engine from videobuf-dma-sg.c... */ 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait); 17462306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait); 17562306a36Sopenharmony_ci*/ 17662306a36Sopenharmony_ci /* set bit 1 */ 17762306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4)); 17862306a36Sopenharmony_ci WRITE_RPS1(MASK_28 | MASK_12); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* turn on video-dma3 */ 18162306a36Sopenharmony_ci WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4)); 18262306a36Sopenharmony_ci WRITE_RPS1(MASK_04 | MASK_20); /* => mask */ 18362306a36Sopenharmony_ci WRITE_RPS1(MASK_04 | MASK_20); /* => values */ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* wait for o_fid_a/b / e_fid_a/b toggle */ 18662306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | o_wait); 18762306a36Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | e_wait); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* generate interrupt */ 19062306a36Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* stop */ 19362306a36Sopenharmony_ci WRITE_RPS1(CMD_STOP); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* enable rps1 irqs */ 19662306a36Sopenharmony_ci SAA7146_IER_ENABLE(dev, MASK_28); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* write the address of the rps-program */ 19962306a36Sopenharmony_ci saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* turn on rps */ 20262306a36Sopenharmony_ci saa7146_write(dev, MC1, (MASK_13 | MASK_29)); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int buffer_activate(struct saa7146_dev *dev, 20662306a36Sopenharmony_ci struct saa7146_buf *buf, 20762306a36Sopenharmony_ci struct saa7146_buf *next) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next); 21262306a36Sopenharmony_ci saa7146_set_vbi_capture(dev,buf,next); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT); 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int queue_setup(struct vb2_queue *q, 22162306a36Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 22262306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci unsigned int size = 16 * 2 * vbi_pixel_to_capture; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (*num_planes) 22762306a36Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 22862306a36Sopenharmony_ci *num_planes = 1; 22962306a36Sopenharmony_ci sizes[0] = size; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void buf_queue(struct vb2_buffer *vb) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 23762306a36Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 23862306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(vq); 23962306a36Sopenharmony_ci struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); 24062306a36Sopenharmony_ci unsigned long flags; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci saa7146_buffer_queue(dev, &dev->vv_data->vbi_dmaq, buf); 24562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int buf_init(struct vb2_buffer *vb) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 25162306a36Sopenharmony_ci struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); 25262306a36Sopenharmony_ci struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); 25362306a36Sopenharmony_ci struct scatterlist *list = sgt->sgl; 25462306a36Sopenharmony_ci int length = sgt->nents; 25562306a36Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 25662306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(vq); 25762306a36Sopenharmony_ci int ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci buf->activate = buffer_activate; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ret = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], 26462306a36Sopenharmony_ci list, length); 26562306a36Sopenharmony_ci if (ret) 26662306a36Sopenharmony_ci saa7146_pgtable_free(dev->pci, &buf->pt[2]); 26762306a36Sopenharmony_ci return ret; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int buf_prepare(struct vb2_buffer *vb) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci unsigned int size = 16 * 2 * vbi_pixel_to_capture; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) 27562306a36Sopenharmony_ci return -EINVAL; 27662306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void buf_cleanup(struct vb2_buffer *vb) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 28362306a36Sopenharmony_ci struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb); 28462306a36Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 28562306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(vq); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci saa7146_pgtable_free(dev->pci, &buf->pt[2]); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void return_buffers(struct vb2_queue *q, int state) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(q); 29362306a36Sopenharmony_ci struct saa7146_dmaqueue *dq = &dev->vv_data->vbi_dmaq; 29462306a36Sopenharmony_ci struct saa7146_buf *buf; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (dq->curr) { 29762306a36Sopenharmony_ci buf = dq->curr; 29862306a36Sopenharmony_ci dq->curr = NULL; 29962306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, state); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci while (!list_empty(&dq->queue)) { 30262306a36Sopenharmony_ci buf = list_entry(dq->queue.next, struct saa7146_buf, list); 30362306a36Sopenharmony_ci list_del(&buf->list); 30462306a36Sopenharmony_ci vb2_buffer_done(&buf->vb.vb2_buf, state); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void vbi_stop(struct saa7146_dev *dev) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 31162306a36Sopenharmony_ci unsigned long flags; 31262306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock_irqsave(&dev->slock,flags); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* disable rps1 */ 31762306a36Sopenharmony_ci saa7146_write(dev, MC1, MASK_29); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* disable rps1 irqs */ 32062306a36Sopenharmony_ci SAA7146_IER_DISABLE(dev, MASK_28); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* shut down dma 3 transfers */ 32362306a36Sopenharmony_ci saa7146_write(dev, MC1, MASK_20); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci del_timer(&vv->vbi_dmaq.timeout); 32662306a36Sopenharmony_ci del_timer(&vv->vbi_read_timeout); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void vbi_read_timeout(struct timer_list *t) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout); 33462306a36Sopenharmony_ci struct saa7146_dev *dev = vv->vbi_dmaq.dev; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci vbi_stop(dev); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int vbi_begin(struct saa7146_dev *dev) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 34462306a36Sopenharmony_ci u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1); 34562306a36Sopenharmony_ci int ret = 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret = saa7146_res_get(dev, RESOURCE_DMA3_BRS); 35062306a36Sopenharmony_ci if (0 == ret) { 35162306a36Sopenharmony_ci DEB_S("cannot get vbi RESOURCE_DMA3_BRS resource\n"); 35262306a36Sopenharmony_ci return -EBUSY; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* adjust arbitrition control for video dma 3 */ 35662306a36Sopenharmony_ci arbtr_ctrl &= ~0x1f0000; 35762306a36Sopenharmony_ci arbtr_ctrl |= 0x1d0000; 35862306a36Sopenharmony_ci saa7146_write(dev, PCI_BT_V1, arbtr_ctrl); 35962306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_04|MASK_20)); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci vv->vbi_read_timeout.function = vbi_read_timeout; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* initialize the brs */ 36462306a36Sopenharmony_ci if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { 36562306a36Sopenharmony_ci saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19)); 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci saa7146_write(dev, BRS_CTRL, 0x00000001); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (0 != (ret = vbi_workaround(dev))) { 37062306a36Sopenharmony_ci DEB_VBI("vbi workaround failed!\n"); 37162306a36Sopenharmony_ci /* return ret;*/ 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* upload brs register */ 37662306a36Sopenharmony_ci saa7146_write(dev, MC2, (MASK_08|MASK_24)); 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int start_streaming(struct vb2_queue *q, unsigned int count) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(q); 38362306a36Sopenharmony_ci int ret; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!vb2_is_streaming(&dev->vv_data->vbi_dmaq.q)) 38662306a36Sopenharmony_ci dev->vv_data->seqnr = 0; 38762306a36Sopenharmony_ci ret = vbi_begin(dev); 38862306a36Sopenharmony_ci if (ret) 38962306a36Sopenharmony_ci return_buffers(q, VB2_BUF_STATE_QUEUED); 39062306a36Sopenharmony_ci return ret; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void stop_streaming(struct vb2_queue *q) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct saa7146_dev *dev = vb2_get_drv_priv(q); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci vbi_stop(dev); 39862306a36Sopenharmony_ci return_buffers(q, VB2_BUF_STATE_ERROR); 39962306a36Sopenharmony_ci saa7146_res_free(dev, RESOURCE_DMA3_BRS); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciconst struct vb2_ops vbi_qops = { 40362306a36Sopenharmony_ci .queue_setup = queue_setup, 40462306a36Sopenharmony_ci .buf_queue = buf_queue, 40562306a36Sopenharmony_ci .buf_init = buf_init, 40662306a36Sopenharmony_ci .buf_prepare = buf_prepare, 40762306a36Sopenharmony_ci .buf_cleanup = buf_cleanup, 40862306a36Sopenharmony_ci .start_streaming = start_streaming, 40962306a36Sopenharmony_ci .stop_streaming = stop_streaming, 41062306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 41162306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 41262306a36Sopenharmony_ci}; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci INIT_LIST_HEAD(&vv->vbi_dmaq.queue); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); 42362306a36Sopenharmony_ci vv->vbi_dmaq.dev = dev; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci init_waitqueue_head(&vv->vbi_wq); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct saa7146_vv *vv = dev->vv_data; 43162306a36Sopenharmony_ci spin_lock(&dev->slock); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (vv->vbi_dmaq.curr) { 43462306a36Sopenharmony_ci DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr); 43562306a36Sopenharmony_ci saa7146_buffer_finish(dev, &vv->vbi_dmaq, VB2_BUF_STATE_DONE); 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci DEB_VBI("dev:%p\n", dev); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci saa7146_buffer_next(dev, &vv->vbi_dmaq, 1); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci spin_unlock(&dev->slock); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ciconst struct saa7146_use_ops saa7146_vbi_uops = { 44562306a36Sopenharmony_ci .init = vbi_init, 44662306a36Sopenharmony_ci .irq_done = vbi_irq_done, 44762306a36Sopenharmony_ci}; 448