Path: blob/master/drivers/media/common/saa7146_vbi.c
15112 views
#include <media/saa7146_vv.h>12static int vbi_pixel_to_capture = 720 * 2;34static int vbi_workaround(struct saa7146_dev *dev)5{6struct saa7146_vv *vv = dev->vv_data;78u32 *cpu;9dma_addr_t dma_addr;1011int count = 0;12int i;1314DECLARE_WAITQUEUE(wait, current);1516DEB_VBI(("dev:%p\n",dev));1718/* once again, a bug in the saa7146: the brs acquisition19is buggy and especially the BXO-counter does not work20as specified. there is this workaround, but please21don't let me explain it. ;-) */2223cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr);24if (NULL == cpu)25return -ENOMEM;2627/* setup some basic programming, just for the workaround */28saa7146_write(dev, BASE_EVEN3, dma_addr);29saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture);30saa7146_write(dev, PROT_ADDR3, dma_addr+4096);31saa7146_write(dev, PITCH3, vbi_pixel_to_capture);32saa7146_write(dev, BASE_PAGE3, 0x0);33saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0));34saa7146_write(dev, MC2, MASK_04|MASK_20);3536/* load brs-control register */37WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));38/* BXO = 1h, BRS to outbound */39WRITE_RPS1(0xc000008c);40/* wait for vbi_a or vbi_b*/41if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {42DEB_D(("...using port b\n"));43WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B);44WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B);45/*46WRITE_RPS1(CMD_PAUSE | MASK_09);47*/48} else {49DEB_D(("...using port a\n"));50WRITE_RPS1(CMD_PAUSE | MASK_10);51}52/* upload brs */53WRITE_RPS1(CMD_UPLOAD | MASK_08);54/* load brs-control register */55WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));56/* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */57WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19);58/* wait for brs_done */59WRITE_RPS1(CMD_PAUSE | MASK_08);60/* upload brs */61WRITE_RPS1(CMD_UPLOAD | MASK_08);62/* load video-dma3 NumLines3 and NumBytes3 */63WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4));64/* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */65WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture));66/* load brs-control register */67WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4));68/* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */69WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start70/* wait for brs_done */71WRITE_RPS1(CMD_PAUSE | MASK_08);72/* upload brs and video-dma3*/73WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04);74/* load mc2 register: enable dma3 */75WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4));76WRITE_RPS1(MASK_20 | MASK_04);77/* generate interrupt */78WRITE_RPS1(CMD_INTERRUPT);79/* stop rps1 */80WRITE_RPS1(CMD_STOP);8182/* we have to do the workaround twice to be sure that83everything is ok */84for(i = 0; i < 2; i++) {8586/* indicate to the irq handler that we do the workaround */87saa7146_write(dev, MC2, MASK_31|MASK_15);8889saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0));90saa7146_write(dev, MC2, MASK_04|MASK_20);9192/* enable rps1 irqs */93SAA7146_IER_ENABLE(dev,MASK_28);9495/* prepare to wait to be woken up by the irq-handler */96add_wait_queue(&vv->vbi_wq, &wait);97current->state = TASK_INTERRUPTIBLE;9899/* start rps1 to enable workaround */100saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);101saa7146_write(dev, MC1, (MASK_13 | MASK_29));102103schedule();104105DEB_VBI(("brs bug workaround %d/1.\n",i));106107remove_wait_queue(&vv->vbi_wq, &wait);108current->state = TASK_RUNNING;109110/* disable rps1 irqs */111SAA7146_IER_DISABLE(dev,MASK_28);112113/* stop video-dma3 */114saa7146_write(dev, MC1, MASK_20);115116if(signal_pending(current)) {117118DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1)));119120/* stop rps1 for sure */121saa7146_write(dev, MC1, MASK_29);122123pci_free_consistent(dev->pci, 4096, cpu, dma_addr);124return -EINTR;125}126}127128pci_free_consistent(dev->pci, 4096, cpu, dma_addr);129return 0;130}131132static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)133{134struct saa7146_vv *vv = dev->vv_data;135136struct saa7146_video_dma vdma3;137138int count = 0;139unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;140unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;141142/*143vdma3.base_even = 0xc8000000+2560*70;144vdma3.base_odd = 0xc8000000;145vdma3.prot_addr = 0xc8000000+2560*164;146vdma3.pitch = 2560;147vdma3.base_page = 0;148vdma3.num_line_byte = (64<<16)|((vbi_pixel_to_capture)<<0); // set above!149*/150vdma3.base_even = buf->pt[2].offset;151vdma3.base_odd = buf->pt[2].offset + 16 * vbi_pixel_to_capture;152vdma3.prot_addr = buf->pt[2].offset + 16 * 2 * vbi_pixel_to_capture;153vdma3.pitch = vbi_pixel_to_capture;154vdma3.base_page = buf->pt[2].dma | ME1;155vdma3.num_line_byte = (16 << 16) | vbi_pixel_to_capture;156157saa7146_write_out_dma(dev, 3, &vdma3);158159/* write beginning of rps-program */160count = 0;161162/* wait for o_fid_a/b / e_fid_a/b toggle only if bit 1 is not set */163164/* we don't wait here for the first field anymore. this is different from the video165capture and might cause that the first buffer is only half filled (with only166one field). but since this is some sort of streaming data, this is not that negative.167but by doing this, we can use the whole engine from videobuf-dma-sg.c... */168169/*170WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);171WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | o_wait);172*/173/* set bit 1 */174WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC2/4));175WRITE_RPS1(MASK_28 | MASK_12);176177/* turn on video-dma3 */178WRITE_RPS1(CMD_WR_REG_MASK | (MC1/4));179WRITE_RPS1(MASK_04 | MASK_20); /* => mask */180WRITE_RPS1(MASK_04 | MASK_20); /* => values */181182/* wait for o_fid_a/b / e_fid_a/b toggle */183WRITE_RPS1(CMD_PAUSE | o_wait);184WRITE_RPS1(CMD_PAUSE | e_wait);185186/* generate interrupt */187WRITE_RPS1(CMD_INTERRUPT);188189/* stop */190WRITE_RPS1(CMD_STOP);191192/* enable rps1 irqs */193SAA7146_IER_ENABLE(dev, MASK_28);194195/* write the address of the rps-program */196saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);197198/* turn on rps */199saa7146_write(dev, MC1, (MASK_13 | MASK_29));200}201202static int buffer_activate(struct saa7146_dev *dev,203struct saa7146_buf *buf,204struct saa7146_buf *next)205{206struct saa7146_vv *vv = dev->vv_data;207buf->vb.state = VIDEOBUF_ACTIVE;208209DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));210saa7146_set_vbi_capture(dev,buf,next);211212mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);213return 0;214}215216static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field)217{218struct file *file = q->priv_data;219struct saa7146_fh *fh = file->private_data;220struct saa7146_dev *dev = fh->dev;221struct saa7146_buf *buf = (struct saa7146_buf *)vb;222223int err = 0;224int lines, llength, size;225226lines = 16 * 2 ; /* 2 fields */227llength = vbi_pixel_to_capture;228size = lines * llength;229230DEB_VBI(("vb:%p\n",vb));231232if (0 != buf->vb.baddr && buf->vb.bsize < size) {233DEB_VBI(("size mismatch.\n"));234return -EINVAL;235}236237if (buf->vb.size != size)238saa7146_dma_free(dev,q,buf);239240if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {241struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);242243buf->vb.width = llength;244buf->vb.height = lines;245buf->vb.size = size;246buf->vb.field = field; // FIXME: check this247248saa7146_pgtable_free(dev->pci, &buf->pt[2]);249saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);250251err = videobuf_iolock(q,&buf->vb, NULL);252if (err)253goto oops;254err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],255dma->sglist, dma->sglen);256if (0 != err)257return err;258}259buf->vb.state = VIDEOBUF_PREPARED;260buf->activate = buffer_activate;261262return 0;263264oops:265DEB_VBI(("error out.\n"));266saa7146_dma_free(dev,q,buf);267268return err;269}270271static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)272{273int llength,lines;274275lines = 16 * 2 ; /* 2 fields */276llength = vbi_pixel_to_capture;277278*size = lines * llength;279*count = 2;280281DEB_VBI(("count:%d, size:%d\n",*count,*size));282283return 0;284}285286static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)287{288struct file *file = q->priv_data;289struct saa7146_fh *fh = file->private_data;290struct saa7146_dev *dev = fh->dev;291struct saa7146_vv *vv = dev->vv_data;292struct saa7146_buf *buf = (struct saa7146_buf *)vb;293294DEB_VBI(("vb:%p\n",vb));295saa7146_buffer_queue(dev,&vv->vbi_q,buf);296}297298static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)299{300struct file *file = q->priv_data;301struct saa7146_fh *fh = file->private_data;302struct saa7146_dev *dev = fh->dev;303struct saa7146_buf *buf = (struct saa7146_buf *)vb;304305DEB_VBI(("vb:%p\n",vb));306saa7146_dma_free(dev,q,buf);307}308309static struct videobuf_queue_ops vbi_qops = {310.buf_setup = buffer_setup,311.buf_prepare = buffer_prepare,312.buf_queue = buffer_queue,313.buf_release = buffer_release,314};315316/* ------------------------------------------------------------------ */317318static void vbi_stop(struct saa7146_fh *fh, struct file *file)319{320struct saa7146_dev *dev = fh->dev;321struct saa7146_vv *vv = dev->vv_data;322unsigned long flags;323DEB_VBI(("dev:%p, fh:%p\n",dev, fh));324325spin_lock_irqsave(&dev->slock,flags);326327/* disable rps1 */328saa7146_write(dev, MC1, MASK_29);329330/* disable rps1 irqs */331SAA7146_IER_DISABLE(dev, MASK_28);332333/* shut down dma 3 transfers */334saa7146_write(dev, MC1, MASK_20);335336if (vv->vbi_q.curr) {337saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);338}339340videobuf_queue_cancel(&fh->vbi_q);341342vv->vbi_streaming = NULL;343344del_timer(&vv->vbi_q.timeout);345del_timer(&fh->vbi_read_timeout);346347spin_unlock_irqrestore(&dev->slock, flags);348}349350static void vbi_read_timeout(unsigned long data)351{352struct file *file = (struct file*)data;353struct saa7146_fh *fh = file->private_data;354struct saa7146_dev *dev = fh->dev;355356DEB_VBI(("dev:%p, fh:%p\n",dev, fh));357358vbi_stop(fh, file);359}360361static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)362{363DEB_VBI(("dev:%p\n",dev));364365INIT_LIST_HEAD(&vv->vbi_q.queue);366367init_timer(&vv->vbi_q.timeout);368vv->vbi_q.timeout.function = saa7146_buffer_timeout;369vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q);370vv->vbi_q.dev = dev;371372init_waitqueue_head(&vv->vbi_wq);373}374375static int vbi_open(struct saa7146_dev *dev, struct file *file)376{377struct saa7146_fh *fh = file->private_data;378379u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);380int ret = 0;381382DEB_VBI(("dev:%p, fh:%p\n",dev,fh));383384ret = saa7146_res_get(fh, RESOURCE_DMA3_BRS);385if (0 == ret) {386DEB_S(("cannot get vbi RESOURCE_DMA3_BRS resource\n"));387return -EBUSY;388}389390/* adjust arbitrition control for video dma 3 */391arbtr_ctrl &= ~0x1f0000;392arbtr_ctrl |= 0x1d0000;393saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);394saa7146_write(dev, MC2, (MASK_04|MASK_20));395396memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));397398fh->vbi_fmt.sampling_rate = 27000000;399fh->vbi_fmt.offset = 248; /* todo */400fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture;401fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY;402403/* fixme: this only works for PAL */404fh->vbi_fmt.start[0] = 5;405fh->vbi_fmt.count[0] = 16;406fh->vbi_fmt.start[1] = 312;407fh->vbi_fmt.count[1] = 16;408409videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,410&dev->pci->dev, &dev->slock,411V4L2_BUF_TYPE_VBI_CAPTURE,412V4L2_FIELD_SEQ_TB, // FIXME: does this really work?413sizeof(struct saa7146_buf),414file, &dev->v4l2_lock);415416init_timer(&fh->vbi_read_timeout);417fh->vbi_read_timeout.function = vbi_read_timeout;418fh->vbi_read_timeout.data = (unsigned long)file;419420/* initialize the brs */421if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {422saa7146_write(dev, BRS_CTRL, MASK_30|MASK_29 | (7 << 19));423} else {424saa7146_write(dev, BRS_CTRL, 0x00000001);425426if (0 != (ret = vbi_workaround(dev))) {427DEB_VBI(("vbi workaround failed!\n"));428/* return ret;*/429}430}431432/* upload brs register */433saa7146_write(dev, MC2, (MASK_08|MASK_24));434return 0;435}436437static void vbi_close(struct saa7146_dev *dev, struct file *file)438{439struct saa7146_fh *fh = file->private_data;440struct saa7146_vv *vv = dev->vv_data;441DEB_VBI(("dev:%p, fh:%p\n",dev,fh));442443if( fh == vv->vbi_streaming ) {444vbi_stop(fh, file);445}446saa7146_res_free(fh, RESOURCE_DMA3_BRS);447}448449static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)450{451struct saa7146_vv *vv = dev->vv_data;452spin_lock(&dev->slock);453454if (vv->vbi_q.curr) {455DEB_VBI(("dev:%p, curr:%p\n",dev,vv->vbi_q.curr));456/* this must be += 2, one count for each field */457vv->vbi_fieldcount+=2;458vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;459saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);460} else {461DEB_VBI(("dev:%p\n",dev));462}463saa7146_buffer_next(dev,&vv->vbi_q,1);464465spin_unlock(&dev->slock);466}467468static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)469{470struct saa7146_fh *fh = file->private_data;471struct saa7146_dev *dev = fh->dev;472struct saa7146_vv *vv = dev->vv_data;473ssize_t ret = 0;474475DEB_VBI(("dev:%p, fh:%p\n",dev,fh));476477if( NULL == vv->vbi_streaming ) {478// fixme: check if dma3 is available479// fixme: activate vbi engine here if necessary. (really?)480vv->vbi_streaming = fh;481}482483if( fh != vv->vbi_streaming ) {484DEB_VBI(("open %p is already using vbi capture.",vv->vbi_streaming));485return -EBUSY;486}487488mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);489ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,490file->f_flags & O_NONBLOCK);491/*492printk("BASE_ODD3: 0x%08x\n", saa7146_read(dev, BASE_ODD3));493printk("BASE_EVEN3: 0x%08x\n", saa7146_read(dev, BASE_EVEN3));494printk("PROT_ADDR3: 0x%08x\n", saa7146_read(dev, PROT_ADDR3));495printk("PITCH3: 0x%08x\n", saa7146_read(dev, PITCH3));496printk("BASE_PAGE3: 0x%08x\n", saa7146_read(dev, BASE_PAGE3));497printk("NUM_LINE_BYTE3: 0x%08x\n", saa7146_read(dev, NUM_LINE_BYTE3));498printk("BRS_CTRL: 0x%08x\n", saa7146_read(dev, BRS_CTRL));499*/500return ret;501}502503struct saa7146_use_ops saa7146_vbi_uops = {504.init = vbi_init,505.open = vbi_open,506.release = vbi_close,507.irq_done = vbi_irq_done,508.read = vbi_read,509};510511512