174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 268de959fSMauro Carvalho Chehab /* 368de959fSMauro Carvalho Chehab 468de959fSMauro Carvalho Chehab bttv-risc.c -- interfaces to other kernel modules 568de959fSMauro Carvalho Chehab 668de959fSMauro Carvalho Chehab bttv risc code handling 768de959fSMauro Carvalho Chehab - memory management 868de959fSMauro Carvalho Chehab - generation 968de959fSMauro Carvalho Chehab 1068de959fSMauro Carvalho Chehab (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org> 1168de959fSMauro Carvalho Chehab 1268de959fSMauro Carvalho Chehab 1368de959fSMauro Carvalho Chehab */ 1468de959fSMauro Carvalho Chehab 1568de959fSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1668de959fSMauro Carvalho Chehab 1768de959fSMauro Carvalho Chehab #include <linux/module.h> 1868de959fSMauro Carvalho Chehab #include <linux/init.h> 1968de959fSMauro Carvalho Chehab #include <linux/slab.h> 2068de959fSMauro Carvalho Chehab #include <linux/pci.h> 2168de959fSMauro Carvalho Chehab #include <linux/vmalloc.h> 2268de959fSMauro Carvalho Chehab #include <linux/interrupt.h> 2368de959fSMauro Carvalho Chehab #include <asm/page.h> 2468de959fSMauro Carvalho Chehab #include <asm/pgtable.h> 2568de959fSMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 2668de959fSMauro Carvalho Chehab 2768de959fSMauro Carvalho Chehab #include "bttvp.h" 2868de959fSMauro Carvalho Chehab 2968de959fSMauro Carvalho Chehab #define VCR_HACK_LINES 4 3068de959fSMauro Carvalho Chehab 3168de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */ 3268de959fSMauro Carvalho Chehab /* risc code generators */ 3368de959fSMauro Carvalho Chehab 3468de959fSMauro Carvalho Chehab int 3568de959fSMauro Carvalho Chehab bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, 3668de959fSMauro Carvalho Chehab struct scatterlist *sglist, 3768de959fSMauro Carvalho Chehab unsigned int offset, unsigned int bpl, 3868de959fSMauro Carvalho Chehab unsigned int padding, unsigned int skip_lines, 3968de959fSMauro Carvalho Chehab unsigned int store_lines) 4068de959fSMauro Carvalho Chehab { 4168de959fSMauro Carvalho Chehab u32 instructions,line,todo; 4268de959fSMauro Carvalho Chehab struct scatterlist *sg; 4368de959fSMauro Carvalho Chehab __le32 *rp; 4468de959fSMauro Carvalho Chehab int rc; 4568de959fSMauro Carvalho Chehab 4668de959fSMauro Carvalho Chehab /* estimate risc mem: worst case is one write per page border + 4768de959fSMauro Carvalho Chehab one write per scan line + sync + jump (all 2 dwords). padding 4868de959fSMauro Carvalho Chehab can cause next bpl to start close to a page border. First DMA 4968de959fSMauro Carvalho Chehab region may be smaller than PAGE_SIZE */ 5068de959fSMauro Carvalho Chehab instructions = skip_lines * 4; 5168de959fSMauro Carvalho Chehab instructions += (1 + ((bpl + padding) * store_lines) 5268de959fSMauro Carvalho Chehab / PAGE_SIZE + store_lines) * 8; 5368de959fSMauro Carvalho Chehab instructions += 2 * 8; 5468de959fSMauro Carvalho Chehab if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0) 5568de959fSMauro Carvalho Chehab return rc; 5668de959fSMauro Carvalho Chehab 5768de959fSMauro Carvalho Chehab /* sync instruction */ 5868de959fSMauro Carvalho Chehab rp = risc->cpu; 5968de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 6068de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(0); 6168de959fSMauro Carvalho Chehab 6268de959fSMauro Carvalho Chehab while (skip_lines-- > 0) { 6368de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL | 6468de959fSMauro Carvalho Chehab BT848_RISC_EOL | bpl); 6568de959fSMauro Carvalho Chehab } 6668de959fSMauro Carvalho Chehab 6768de959fSMauro Carvalho Chehab /* scan lines */ 6868de959fSMauro Carvalho Chehab sg = sglist; 6968de959fSMauro Carvalho Chehab for (line = 0; line < store_lines; line++) { 7068de959fSMauro Carvalho Chehab if ((btv->opt_vcr_hack) && 7168de959fSMauro Carvalho Chehab (line >= (store_lines - VCR_HACK_LINES))) 7268de959fSMauro Carvalho Chehab continue; 7368de959fSMauro Carvalho Chehab while (offset && offset >= sg_dma_len(sg)) { 7468de959fSMauro Carvalho Chehab offset -= sg_dma_len(sg); 75872dfcfeSHans Verkuil sg = sg_next(sg); 7668de959fSMauro Carvalho Chehab } 7768de959fSMauro Carvalho Chehab if (bpl <= sg_dma_len(sg)-offset) { 7868de959fSMauro Carvalho Chehab /* fits into current chunk */ 7968de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| 8068de959fSMauro Carvalho Chehab BT848_RISC_EOL|bpl); 8168de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); 8268de959fSMauro Carvalho Chehab offset+=bpl; 8368de959fSMauro Carvalho Chehab } else { 8416790554SMauro Carvalho Chehab /* scanline needs to be split */ 8568de959fSMauro Carvalho Chehab todo = bpl; 8668de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| 8768de959fSMauro Carvalho Chehab (sg_dma_len(sg)-offset)); 8868de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); 8968de959fSMauro Carvalho Chehab todo -= (sg_dma_len(sg)-offset); 9068de959fSMauro Carvalho Chehab offset = 0; 91872dfcfeSHans Verkuil sg = sg_next(sg); 9268de959fSMauro Carvalho Chehab while (todo > sg_dma_len(sg)) { 9368de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(BT848_RISC_WRITE| 9468de959fSMauro Carvalho Chehab sg_dma_len(sg)); 9568de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(sg)); 9668de959fSMauro Carvalho Chehab todo -= sg_dma_len(sg); 97872dfcfeSHans Verkuil sg = sg_next(sg); 9868de959fSMauro Carvalho Chehab } 9968de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| 10068de959fSMauro Carvalho Chehab todo); 10168de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(sg)); 10268de959fSMauro Carvalho Chehab offset += todo; 10368de959fSMauro Carvalho Chehab } 10468de959fSMauro Carvalho Chehab offset += padding; 10568de959fSMauro Carvalho Chehab } 10668de959fSMauro Carvalho Chehab 10768de959fSMauro Carvalho Chehab /* save pointer to jmp instruction address */ 10868de959fSMauro Carvalho Chehab risc->jmp = rp; 10968de959fSMauro Carvalho Chehab BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); 11068de959fSMauro Carvalho Chehab return 0; 11168de959fSMauro Carvalho Chehab } 11268de959fSMauro Carvalho Chehab 11368de959fSMauro Carvalho Chehab static int 11468de959fSMauro Carvalho Chehab bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, 11568de959fSMauro Carvalho Chehab struct scatterlist *sglist, 11668de959fSMauro Carvalho Chehab unsigned int yoffset, unsigned int ybpl, 11768de959fSMauro Carvalho Chehab unsigned int ypadding, unsigned int ylines, 11868de959fSMauro Carvalho Chehab unsigned int uoffset, unsigned int voffset, 11968de959fSMauro Carvalho Chehab unsigned int hshift, unsigned int vshift, 12068de959fSMauro Carvalho Chehab unsigned int cpadding) 12168de959fSMauro Carvalho Chehab { 12268de959fSMauro Carvalho Chehab unsigned int instructions,line,todo,ylen,chroma; 12368de959fSMauro Carvalho Chehab __le32 *rp; 12468de959fSMauro Carvalho Chehab u32 ri; 12568de959fSMauro Carvalho Chehab struct scatterlist *ysg; 12668de959fSMauro Carvalho Chehab struct scatterlist *usg; 12768de959fSMauro Carvalho Chehab struct scatterlist *vsg; 12868de959fSMauro Carvalho Chehab int topfield = (0 == yoffset); 12968de959fSMauro Carvalho Chehab int rc; 13068de959fSMauro Carvalho Chehab 13168de959fSMauro Carvalho Chehab /* estimate risc mem: worst case is one write per page border + 13268de959fSMauro Carvalho Chehab one write per scan line (5 dwords) 13368de959fSMauro Carvalho Chehab plus sync + jump (2 dwords) */ 13468de959fSMauro Carvalho Chehab instructions = ((3 + (ybpl + ypadding) * ylines * 2) 13568de959fSMauro Carvalho Chehab / PAGE_SIZE) + ylines; 13668de959fSMauro Carvalho Chehab instructions += 2; 13768de959fSMauro Carvalho Chehab if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) 13868de959fSMauro Carvalho Chehab return rc; 13968de959fSMauro Carvalho Chehab 14068de959fSMauro Carvalho Chehab /* sync instruction */ 14168de959fSMauro Carvalho Chehab rp = risc->cpu; 14268de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); 14368de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(0); 14468de959fSMauro Carvalho Chehab 14568de959fSMauro Carvalho Chehab /* scan lines */ 14668de959fSMauro Carvalho Chehab ysg = sglist; 14768de959fSMauro Carvalho Chehab usg = sglist; 14868de959fSMauro Carvalho Chehab vsg = sglist; 14968de959fSMauro Carvalho Chehab for (line = 0; line < ylines; line++) { 15068de959fSMauro Carvalho Chehab if ((btv->opt_vcr_hack) && 15168de959fSMauro Carvalho Chehab (line >= (ylines - VCR_HACK_LINES))) 15268de959fSMauro Carvalho Chehab continue; 15368de959fSMauro Carvalho Chehab switch (vshift) { 15468de959fSMauro Carvalho Chehab case 0: 15568de959fSMauro Carvalho Chehab chroma = 1; 15668de959fSMauro Carvalho Chehab break; 15768de959fSMauro Carvalho Chehab case 1: 15868de959fSMauro Carvalho Chehab if (topfield) 15968de959fSMauro Carvalho Chehab chroma = ((line & 1) == 0); 16068de959fSMauro Carvalho Chehab else 16168de959fSMauro Carvalho Chehab chroma = ((line & 1) == 1); 16268de959fSMauro Carvalho Chehab break; 16368de959fSMauro Carvalho Chehab case 2: 16468de959fSMauro Carvalho Chehab if (topfield) 16568de959fSMauro Carvalho Chehab chroma = ((line & 3) == 0); 16668de959fSMauro Carvalho Chehab else 16768de959fSMauro Carvalho Chehab chroma = ((line & 3) == 2); 16868de959fSMauro Carvalho Chehab break; 16968de959fSMauro Carvalho Chehab default: 17068de959fSMauro Carvalho Chehab chroma = 0; 17168de959fSMauro Carvalho Chehab break; 17268de959fSMauro Carvalho Chehab } 17368de959fSMauro Carvalho Chehab 17468de959fSMauro Carvalho Chehab for (todo = ybpl; todo > 0; todo -= ylen) { 17568de959fSMauro Carvalho Chehab /* go to next sg entry if needed */ 17668de959fSMauro Carvalho Chehab while (yoffset && yoffset >= sg_dma_len(ysg)) { 17768de959fSMauro Carvalho Chehab yoffset -= sg_dma_len(ysg); 178872dfcfeSHans Verkuil ysg = sg_next(ysg); 17968de959fSMauro Carvalho Chehab } 1806f7e780bSSamuel Williams 1816f7e780bSSamuel Williams /* calculate max number of bytes we can write */ 1826f7e780bSSamuel Williams ylen = todo; 1836f7e780bSSamuel Williams if (yoffset + ylen > sg_dma_len(ysg)) 1846f7e780bSSamuel Williams ylen = sg_dma_len(ysg) - yoffset; 1856f7e780bSSamuel Williams if (chroma) { 18668de959fSMauro Carvalho Chehab while (uoffset && uoffset >= sg_dma_len(usg)) { 18768de959fSMauro Carvalho Chehab uoffset -= sg_dma_len(usg); 188872dfcfeSHans Verkuil usg = sg_next(usg); 18968de959fSMauro Carvalho Chehab } 19068de959fSMauro Carvalho Chehab while (voffset && voffset >= sg_dma_len(vsg)) { 19168de959fSMauro Carvalho Chehab voffset -= sg_dma_len(vsg); 192872dfcfeSHans Verkuil vsg = sg_next(vsg); 19368de959fSMauro Carvalho Chehab } 19468de959fSMauro Carvalho Chehab 19568de959fSMauro Carvalho Chehab if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) 19668de959fSMauro Carvalho Chehab ylen = (sg_dma_len(usg) - uoffset) << hshift; 19768de959fSMauro Carvalho Chehab if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) 19868de959fSMauro Carvalho Chehab ylen = (sg_dma_len(vsg) - voffset) << hshift; 19968de959fSMauro Carvalho Chehab ri = BT848_RISC_WRITE123; 20068de959fSMauro Carvalho Chehab } else { 20168de959fSMauro Carvalho Chehab ri = BT848_RISC_WRITE1S23; 20268de959fSMauro Carvalho Chehab } 20368de959fSMauro Carvalho Chehab if (ybpl == todo) 20468de959fSMauro Carvalho Chehab ri |= BT848_RISC_SOL; 20568de959fSMauro Carvalho Chehab if (ylen == todo) 20668de959fSMauro Carvalho Chehab ri |= BT848_RISC_EOL; 20768de959fSMauro Carvalho Chehab 20868de959fSMauro Carvalho Chehab /* write risc instruction */ 20968de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(ri | ylen); 21068de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | 21168de959fSMauro Carvalho Chehab (ylen >> hshift)); 21268de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); 21368de959fSMauro Carvalho Chehab yoffset += ylen; 21468de959fSMauro Carvalho Chehab if (chroma) { 21568de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); 21668de959fSMauro Carvalho Chehab uoffset += ylen >> hshift; 21768de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); 21868de959fSMauro Carvalho Chehab voffset += ylen >> hshift; 21968de959fSMauro Carvalho Chehab } 22068de959fSMauro Carvalho Chehab } 22168de959fSMauro Carvalho Chehab yoffset += ypadding; 22268de959fSMauro Carvalho Chehab if (chroma) { 22368de959fSMauro Carvalho Chehab uoffset += cpadding; 22468de959fSMauro Carvalho Chehab voffset += cpadding; 22568de959fSMauro Carvalho Chehab } 22668de959fSMauro Carvalho Chehab } 22768de959fSMauro Carvalho Chehab 22868de959fSMauro Carvalho Chehab /* save pointer to jmp instruction address */ 22968de959fSMauro Carvalho Chehab risc->jmp = rp; 23068de959fSMauro Carvalho Chehab BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); 23168de959fSMauro Carvalho Chehab return 0; 23268de959fSMauro Carvalho Chehab } 23368de959fSMauro Carvalho Chehab 23468de959fSMauro Carvalho Chehab static int 23568de959fSMauro Carvalho Chehab bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, 23668de959fSMauro Carvalho Chehab const struct bttv_format *fmt, struct bttv_overlay *ov, 23768de959fSMauro Carvalho Chehab int skip_even, int skip_odd) 23868de959fSMauro Carvalho Chehab { 23968de959fSMauro Carvalho Chehab int dwords, rc, line, maxy, start, end; 24068de959fSMauro Carvalho Chehab unsigned skip, nskips; 24168de959fSMauro Carvalho Chehab struct btcx_skiplist *skips; 24268de959fSMauro Carvalho Chehab __le32 *rp; 24368de959fSMauro Carvalho Chehab u32 ri,ra; 24468de959fSMauro Carvalho Chehab u32 addr; 24568de959fSMauro Carvalho Chehab 24668de959fSMauro Carvalho Chehab /* skip list for window clipping */ 2476da2ec56SKees Cook skips = kmalloc_array(ov->nclips, sizeof(*skips),GFP_KERNEL); 2486da2ec56SKees Cook if (NULL == skips) 24968de959fSMauro Carvalho Chehab return -ENOMEM; 25068de959fSMauro Carvalho Chehab 25168de959fSMauro Carvalho Chehab /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions 25268de959fSMauro Carvalho Chehab + sync + jump (all 2 dwords) */ 25368de959fSMauro Carvalho Chehab dwords = (3 * ov->nclips + 2) * 25468de959fSMauro Carvalho Chehab ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height); 25568de959fSMauro Carvalho Chehab dwords += 4; 25668de959fSMauro Carvalho Chehab if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) { 25768de959fSMauro Carvalho Chehab kfree(skips); 25868de959fSMauro Carvalho Chehab return rc; 25968de959fSMauro Carvalho Chehab } 26068de959fSMauro Carvalho Chehab 26168de959fSMauro Carvalho Chehab /* sync instruction */ 26268de959fSMauro Carvalho Chehab rp = risc->cpu; 26368de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 26468de959fSMauro Carvalho Chehab *(rp++) = cpu_to_le32(0); 26568de959fSMauro Carvalho Chehab 26668de959fSMauro Carvalho Chehab addr = (unsigned long)btv->fbuf.base; 26768de959fSMauro Carvalho Chehab addr += btv->fbuf.fmt.bytesperline * ov->w.top; 26868de959fSMauro Carvalho Chehab addr += (fmt->depth >> 3) * ov->w.left; 26968de959fSMauro Carvalho Chehab 27068de959fSMauro Carvalho Chehab /* scan lines */ 27168de959fSMauro Carvalho Chehab for (maxy = -1, line = 0; line < ov->w.height; 27268de959fSMauro Carvalho Chehab line++, addr += btv->fbuf.fmt.bytesperline) { 27368de959fSMauro Carvalho Chehab if ((btv->opt_vcr_hack) && 27468de959fSMauro Carvalho Chehab (line >= (ov->w.height - VCR_HACK_LINES))) 27568de959fSMauro Carvalho Chehab continue; 27668de959fSMauro Carvalho Chehab if ((line%2) == 0 && skip_even) 27768de959fSMauro Carvalho Chehab continue; 27868de959fSMauro Carvalho Chehab if ((line%2) == 1 && skip_odd) 27968de959fSMauro Carvalho Chehab continue; 28068de959fSMauro Carvalho Chehab 28168de959fSMauro Carvalho Chehab /* calculate clipping */ 28268de959fSMauro Carvalho Chehab if (line > maxy) 28368de959fSMauro Carvalho Chehab btcx_calc_skips(line, ov->w.width, &maxy, 28468de959fSMauro Carvalho Chehab skips, &nskips, ov->clips, ov->nclips); 28568de959fSMauro Carvalho Chehab 28668de959fSMauro Carvalho Chehab /* write out risc code */ 28768de959fSMauro Carvalho Chehab for (start = 0, skip = 0; start < ov->w.width; start = end) { 28868de959fSMauro Carvalho Chehab if (skip >= nskips) { 28968de959fSMauro Carvalho Chehab ri = BT848_RISC_WRITE; 29068de959fSMauro Carvalho Chehab end = ov->w.width; 29168de959fSMauro Carvalho Chehab } else if (start < skips[skip].start) { 29268de959fSMauro Carvalho Chehab ri = BT848_RISC_WRITE; 29368de959fSMauro Carvalho Chehab end = skips[skip].start; 29468de959fSMauro Carvalho Chehab } else { 29568de959fSMauro Carvalho Chehab ri = BT848_RISC_SKIP; 29668de959fSMauro Carvalho Chehab end = skips[skip].end; 29768de959fSMauro Carvalho Chehab skip++; 29868de959fSMauro Carvalho Chehab } 29968de959fSMauro Carvalho Chehab if (BT848_RISC_WRITE == ri) 30068de959fSMauro Carvalho Chehab ra = addr + (fmt->depth>>3)*start; 30168de959fSMauro Carvalho Chehab else 30268de959fSMauro Carvalho Chehab ra = 0; 30368de959fSMauro Carvalho Chehab 30468de959fSMauro Carvalho Chehab if (0 == start) 30568de959fSMauro Carvalho Chehab ri |= BT848_RISC_SOL; 30668de959fSMauro Carvalho Chehab if (ov->w.width == end) 30768de959fSMauro Carvalho Chehab ri |= BT848_RISC_EOL; 30868de959fSMauro Carvalho Chehab ri |= (fmt->depth>>3) * (end-start); 30968de959fSMauro Carvalho Chehab 31068de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(ri); 31168de959fSMauro Carvalho Chehab if (0 != ra) 31268de959fSMauro Carvalho Chehab *(rp++)=cpu_to_le32(ra); 31368de959fSMauro Carvalho Chehab } 31468de959fSMauro Carvalho Chehab } 31568de959fSMauro Carvalho Chehab 31668de959fSMauro Carvalho Chehab /* save pointer to jmp instruction address */ 31768de959fSMauro Carvalho Chehab risc->jmp = rp; 31868de959fSMauro Carvalho Chehab BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); 31968de959fSMauro Carvalho Chehab kfree(skips); 32068de959fSMauro Carvalho Chehab return 0; 32168de959fSMauro Carvalho Chehab } 32268de959fSMauro Carvalho Chehab 32368de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */ 32468de959fSMauro Carvalho Chehab 32568de959fSMauro Carvalho Chehab static void 32668de959fSMauro Carvalho Chehab bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo, 32768de959fSMauro Carvalho Chehab int width, int height, int interleaved, 32868de959fSMauro Carvalho Chehab const struct bttv_tvnorm *tvnorm) 32968de959fSMauro Carvalho Chehab { 33068de959fSMauro Carvalho Chehab u32 xsf, sr; 33168de959fSMauro Carvalho Chehab int vdelay; 33268de959fSMauro Carvalho Chehab 33368de959fSMauro Carvalho Chehab int swidth = tvnorm->swidth; 33468de959fSMauro Carvalho Chehab int totalwidth = tvnorm->totalwidth; 33568de959fSMauro Carvalho Chehab int scaledtwidth = tvnorm->scaledtwidth; 33668de959fSMauro Carvalho Chehab 33768de959fSMauro Carvalho Chehab if (btv->input == btv->dig) { 33868de959fSMauro Carvalho Chehab swidth = 720; 33968de959fSMauro Carvalho Chehab totalwidth = 858; 34068de959fSMauro Carvalho Chehab scaledtwidth = 858; 34168de959fSMauro Carvalho Chehab } 34268de959fSMauro Carvalho Chehab 34368de959fSMauro Carvalho Chehab vdelay = tvnorm->vdelay; 34468de959fSMauro Carvalho Chehab 34568de959fSMauro Carvalho Chehab xsf = (width*scaledtwidth)/swidth; 34668de959fSMauro Carvalho Chehab geo->hscale = ((totalwidth*4096UL)/xsf-4096); 34768de959fSMauro Carvalho Chehab geo->hdelay = tvnorm->hdelayx1; 34868de959fSMauro Carvalho Chehab geo->hdelay = (geo->hdelay*width)/swidth; 34968de959fSMauro Carvalho Chehab geo->hdelay &= 0x3fe; 35068de959fSMauro Carvalho Chehab sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; 35168de959fSMauro Carvalho Chehab geo->vscale = (0x10000UL-sr) & 0x1fff; 35268de959fSMauro Carvalho Chehab geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | 35368de959fSMauro Carvalho Chehab ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); 35468de959fSMauro Carvalho Chehab geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; 35568de959fSMauro Carvalho Chehab geo->vdelay = vdelay; 35668de959fSMauro Carvalho Chehab geo->width = width; 35768de959fSMauro Carvalho Chehab geo->sheight = tvnorm->sheight; 35868de959fSMauro Carvalho Chehab geo->vtotal = tvnorm->vtotal; 35968de959fSMauro Carvalho Chehab 36068de959fSMauro Carvalho Chehab if (btv->opt_combfilter) { 36168de959fSMauro Carvalho Chehab geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); 36268de959fSMauro Carvalho Chehab geo->comb = (width < 769) ? 1 : 0; 36368de959fSMauro Carvalho Chehab } else { 36468de959fSMauro Carvalho Chehab geo->vtc = 0; 36568de959fSMauro Carvalho Chehab geo->comb = 0; 36668de959fSMauro Carvalho Chehab } 36768de959fSMauro Carvalho Chehab } 36868de959fSMauro Carvalho Chehab 36968de959fSMauro Carvalho Chehab static void 37068de959fSMauro Carvalho Chehab bttv_calc_geo (struct bttv * btv, 37168de959fSMauro Carvalho Chehab struct bttv_geometry * geo, 37268de959fSMauro Carvalho Chehab unsigned int width, 37368de959fSMauro Carvalho Chehab unsigned int height, 37468de959fSMauro Carvalho Chehab int both_fields, 37568de959fSMauro Carvalho Chehab const struct bttv_tvnorm * tvnorm, 37668de959fSMauro Carvalho Chehab const struct v4l2_rect * crop) 37768de959fSMauro Carvalho Chehab { 37868de959fSMauro Carvalho Chehab unsigned int c_width; 37968de959fSMauro Carvalho Chehab unsigned int c_height; 38068de959fSMauro Carvalho Chehab u32 sr; 38168de959fSMauro Carvalho Chehab 38268de959fSMauro Carvalho Chehab if ((crop->left == tvnorm->cropcap.defrect.left 38368de959fSMauro Carvalho Chehab && crop->top == tvnorm->cropcap.defrect.top 38468de959fSMauro Carvalho Chehab && crop->width == tvnorm->cropcap.defrect.width 38568de959fSMauro Carvalho Chehab && crop->height == tvnorm->cropcap.defrect.height 38668de959fSMauro Carvalho Chehab && width <= tvnorm->swidth /* see PAL-Nc et al */) 38768de959fSMauro Carvalho Chehab || btv->input == btv->dig) { 38868de959fSMauro Carvalho Chehab bttv_calc_geo_old(btv, geo, width, height, 38968de959fSMauro Carvalho Chehab both_fields, tvnorm); 39068de959fSMauro Carvalho Chehab return; 39168de959fSMauro Carvalho Chehab } 39268de959fSMauro Carvalho Chehab 39368de959fSMauro Carvalho Chehab /* For bug compatibility the image size checks permit scale 39468de959fSMauro Carvalho Chehab factors > 16. See bttv_crop_calc_limits(). */ 39568de959fSMauro Carvalho Chehab c_width = min((unsigned int) crop->width, width * 16); 39668de959fSMauro Carvalho Chehab c_height = min((unsigned int) crop->height, height * 16); 39768de959fSMauro Carvalho Chehab 39868de959fSMauro Carvalho Chehab geo->width = width; 39968de959fSMauro Carvalho Chehab geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096; 40068de959fSMauro Carvalho Chehab /* Even to store Cb first, odd for Cr. */ 40168de959fSMauro Carvalho Chehab geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1; 40268de959fSMauro Carvalho Chehab 40368de959fSMauro Carvalho Chehab geo->sheight = c_height; 40468de959fSMauro Carvalho Chehab geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY; 40568de959fSMauro Carvalho Chehab sr = c_height >> !both_fields; 40668de959fSMauro Carvalho Chehab sr = (sr * 512U + (height >> 1)) / height - 512; 40768de959fSMauro Carvalho Chehab geo->vscale = (0x10000UL - sr) & 0x1fff; 40868de959fSMauro Carvalho Chehab geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0; 40968de959fSMauro Carvalho Chehab geo->vtotal = tvnorm->vtotal; 41068de959fSMauro Carvalho Chehab 41168de959fSMauro Carvalho Chehab geo->crop = (((geo->width >> 8) & 0x03) | 41268de959fSMauro Carvalho Chehab ((geo->hdelay >> 6) & 0x0c) | 41368de959fSMauro Carvalho Chehab ((geo->sheight >> 4) & 0x30) | 41468de959fSMauro Carvalho Chehab ((geo->vdelay >> 2) & 0xc0)); 41568de959fSMauro Carvalho Chehab 41668de959fSMauro Carvalho Chehab if (btv->opt_combfilter) { 41768de959fSMauro Carvalho Chehab geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); 41868de959fSMauro Carvalho Chehab geo->comb = (width < 769) ? 1 : 0; 41968de959fSMauro Carvalho Chehab } else { 42068de959fSMauro Carvalho Chehab geo->vtc = 0; 42168de959fSMauro Carvalho Chehab geo->comb = 0; 42268de959fSMauro Carvalho Chehab } 42368de959fSMauro Carvalho Chehab } 42468de959fSMauro Carvalho Chehab 42568de959fSMauro Carvalho Chehab static void 42668de959fSMauro Carvalho Chehab bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) 42768de959fSMauro Carvalho Chehab { 42868de959fSMauro Carvalho Chehab int off = odd ? 0x80 : 0x00; 42968de959fSMauro Carvalho Chehab 43068de959fSMauro Carvalho Chehab if (geo->comb) 43168de959fSMauro Carvalho Chehab btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); 43268de959fSMauro Carvalho Chehab else 43368de959fSMauro Carvalho Chehab btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); 43468de959fSMauro Carvalho Chehab 43568de959fSMauro Carvalho Chehab btwrite(geo->vtc, BT848_E_VTC+off); 43668de959fSMauro Carvalho Chehab btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); 43768de959fSMauro Carvalho Chehab btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); 43868de959fSMauro Carvalho Chehab btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); 43968de959fSMauro Carvalho Chehab btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); 44068de959fSMauro Carvalho Chehab btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); 44168de959fSMauro Carvalho Chehab btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); 44268de959fSMauro Carvalho Chehab btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off); 44368de959fSMauro Carvalho Chehab btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off); 44468de959fSMauro Carvalho Chehab btwrite(geo->crop, BT848_E_CROP+off); 44568de959fSMauro Carvalho Chehab btwrite(geo->vtotal>>8, BT848_VTOTAL_HI); 44668de959fSMauro Carvalho Chehab btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO); 44768de959fSMauro Carvalho Chehab } 44868de959fSMauro Carvalho Chehab 44968de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */ 45068de959fSMauro Carvalho Chehab /* risc group / risc main loop / dma management */ 45168de959fSMauro Carvalho Chehab 45268de959fSMauro Carvalho Chehab void 45368de959fSMauro Carvalho Chehab bttv_set_dma(struct bttv *btv, int override) 45468de959fSMauro Carvalho Chehab { 45568de959fSMauro Carvalho Chehab unsigned long cmd; 45668de959fSMauro Carvalho Chehab int capctl; 45768de959fSMauro Carvalho Chehab 45868de959fSMauro Carvalho Chehab btv->cap_ctl = 0; 45968de959fSMauro Carvalho Chehab if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; 46068de959fSMauro Carvalho Chehab if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; 46168de959fSMauro Carvalho Chehab if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; 46268de959fSMauro Carvalho Chehab 46368de959fSMauro Carvalho Chehab capctl = 0; 46468de959fSMauro Carvalho Chehab capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ 46568de959fSMauro Carvalho Chehab capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ 46668de959fSMauro Carvalho Chehab capctl |= override; 46768de959fSMauro Carvalho Chehab 46868de959fSMauro Carvalho Chehab d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n", 46968de959fSMauro Carvalho Chehab btv->c.nr,capctl,btv->loop_irq, 47068de959fSMauro Carvalho Chehab btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, 47168de959fSMauro Carvalho Chehab btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, 47268de959fSMauro Carvalho Chehab btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, 47368de959fSMauro Carvalho Chehab btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); 47468de959fSMauro Carvalho Chehab 47568de959fSMauro Carvalho Chehab cmd = BT848_RISC_JUMP; 47668de959fSMauro Carvalho Chehab if (btv->loop_irq) { 47768de959fSMauro Carvalho Chehab cmd |= BT848_RISC_IRQ; 47868de959fSMauro Carvalho Chehab cmd |= (btv->loop_irq & 0x0f) << 16; 47968de959fSMauro Carvalho Chehab cmd |= (~btv->loop_irq & 0x0f) << 20; 48068de959fSMauro Carvalho Chehab } 48168de959fSMauro Carvalho Chehab if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { 48268de959fSMauro Carvalho Chehab mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); 48368de959fSMauro Carvalho Chehab } else { 48468de959fSMauro Carvalho Chehab del_timer(&btv->timeout); 48568de959fSMauro Carvalho Chehab } 48668de959fSMauro Carvalho Chehab btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); 48768de959fSMauro Carvalho Chehab 48868de959fSMauro Carvalho Chehab btaor(capctl, ~0x0f, BT848_CAP_CTL); 48968de959fSMauro Carvalho Chehab if (capctl) { 49068de959fSMauro Carvalho Chehab if (btv->dma_on) 49168de959fSMauro Carvalho Chehab return; 49268de959fSMauro Carvalho Chehab btwrite(btv->main.dma, BT848_RISC_STRT_ADD); 49368de959fSMauro Carvalho Chehab btor(3, BT848_GPIO_DMA_CTL); 49468de959fSMauro Carvalho Chehab btv->dma_on = 1; 49568de959fSMauro Carvalho Chehab } else { 49668de959fSMauro Carvalho Chehab if (!btv->dma_on) 49768de959fSMauro Carvalho Chehab return; 49868de959fSMauro Carvalho Chehab btand(~3, BT848_GPIO_DMA_CTL); 49968de959fSMauro Carvalho Chehab btv->dma_on = 0; 50068de959fSMauro Carvalho Chehab } 50168de959fSMauro Carvalho Chehab return; 50268de959fSMauro Carvalho Chehab } 50368de959fSMauro Carvalho Chehab 50468de959fSMauro Carvalho Chehab int 50568de959fSMauro Carvalho Chehab bttv_risc_init_main(struct bttv *btv) 50668de959fSMauro Carvalho Chehab { 50768de959fSMauro Carvalho Chehab int rc; 50868de959fSMauro Carvalho Chehab 50968de959fSMauro Carvalho Chehab if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) 51068de959fSMauro Carvalho Chehab return rc; 51168de959fSMauro Carvalho Chehab dprintk("%d: risc main @ %08llx\n", 51268de959fSMauro Carvalho Chehab btv->c.nr, (unsigned long long)btv->main.dma); 51368de959fSMauro Carvalho Chehab 51468de959fSMauro Carvalho Chehab btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | 51568de959fSMauro Carvalho Chehab BT848_FIFO_STATUS_VRE); 51668de959fSMauro Carvalho Chehab btv->main.cpu[1] = cpu_to_le32(0); 51768de959fSMauro Carvalho Chehab btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); 51868de959fSMauro Carvalho Chehab btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); 51968de959fSMauro Carvalho Chehab 52068de959fSMauro Carvalho Chehab /* top field */ 52168de959fSMauro Carvalho Chehab btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); 52268de959fSMauro Carvalho Chehab btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); 52368de959fSMauro Carvalho Chehab btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); 52468de959fSMauro Carvalho Chehab btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); 52568de959fSMauro Carvalho Chehab 52668de959fSMauro Carvalho Chehab btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | 52768de959fSMauro Carvalho Chehab BT848_FIFO_STATUS_VRO); 52868de959fSMauro Carvalho Chehab btv->main.cpu[9] = cpu_to_le32(0); 52968de959fSMauro Carvalho Chehab 53068de959fSMauro Carvalho Chehab /* bottom field */ 53168de959fSMauro Carvalho Chehab btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); 53268de959fSMauro Carvalho Chehab btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); 53368de959fSMauro Carvalho Chehab btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); 53468de959fSMauro Carvalho Chehab btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); 53568de959fSMauro Carvalho Chehab 53668de959fSMauro Carvalho Chehab /* jump back to top field */ 53768de959fSMauro Carvalho Chehab btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); 53868de959fSMauro Carvalho Chehab btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); 53968de959fSMauro Carvalho Chehab 54068de959fSMauro Carvalho Chehab return 0; 54168de959fSMauro Carvalho Chehab } 54268de959fSMauro Carvalho Chehab 54368de959fSMauro Carvalho Chehab int 54468de959fSMauro Carvalho Chehab bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, 54568de959fSMauro Carvalho Chehab int irqflags) 54668de959fSMauro Carvalho Chehab { 54768de959fSMauro Carvalho Chehab unsigned long cmd; 54868de959fSMauro Carvalho Chehab unsigned long next = btv->main.dma + ((slot+2) << 2); 54968de959fSMauro Carvalho Chehab 55068de959fSMauro Carvalho Chehab if (NULL == risc) { 55168de959fSMauro Carvalho Chehab d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot); 55268de959fSMauro Carvalho Chehab btv->main.cpu[slot+1] = cpu_to_le32(next); 55368de959fSMauro Carvalho Chehab } else { 55468de959fSMauro Carvalho Chehab d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n", 55568de959fSMauro Carvalho Chehab btv->c.nr, risc, slot, 55668de959fSMauro Carvalho Chehab (unsigned long long)risc->dma, irqflags); 55768de959fSMauro Carvalho Chehab cmd = BT848_RISC_JUMP; 55868de959fSMauro Carvalho Chehab if (irqflags) { 55968de959fSMauro Carvalho Chehab cmd |= BT848_RISC_IRQ; 56068de959fSMauro Carvalho Chehab cmd |= (irqflags & 0x0f) << 16; 56168de959fSMauro Carvalho Chehab cmd |= (~irqflags & 0x0f) << 20; 56268de959fSMauro Carvalho Chehab } 56368de959fSMauro Carvalho Chehab risc->jmp[0] = cpu_to_le32(cmd); 56468de959fSMauro Carvalho Chehab risc->jmp[1] = cpu_to_le32(next); 56568de959fSMauro Carvalho Chehab btv->main.cpu[slot+1] = cpu_to_le32(risc->dma); 56668de959fSMauro Carvalho Chehab } 56768de959fSMauro Carvalho Chehab return 0; 56868de959fSMauro Carvalho Chehab } 56968de959fSMauro Carvalho Chehab 57068de959fSMauro Carvalho Chehab void 57168de959fSMauro Carvalho Chehab bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) 57268de959fSMauro Carvalho Chehab { 57368de959fSMauro Carvalho Chehab struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); 57468de959fSMauro Carvalho Chehab 57568de959fSMauro Carvalho Chehab BUG_ON(in_interrupt()); 57668de959fSMauro Carvalho Chehab videobuf_waiton(q, &buf->vb, 0, 0); 57768de959fSMauro Carvalho Chehab videobuf_dma_unmap(q->dev, dma); 57868de959fSMauro Carvalho Chehab videobuf_dma_free(dma); 57968de959fSMauro Carvalho Chehab btcx_riscmem_free(btv->c.pci,&buf->bottom); 58068de959fSMauro Carvalho Chehab btcx_riscmem_free(btv->c.pci,&buf->top); 58168de959fSMauro Carvalho Chehab buf->vb.state = VIDEOBUF_NEEDS_INIT; 58268de959fSMauro Carvalho Chehab } 58368de959fSMauro Carvalho Chehab 58468de959fSMauro Carvalho Chehab int 58568de959fSMauro Carvalho Chehab bttv_buffer_activate_vbi(struct bttv *btv, 58668de959fSMauro Carvalho Chehab struct bttv_buffer *vbi) 58768de959fSMauro Carvalho Chehab { 58868de959fSMauro Carvalho Chehab struct btcx_riscmem *top; 58968de959fSMauro Carvalho Chehab struct btcx_riscmem *bottom; 59068de959fSMauro Carvalho Chehab int top_irq_flags; 59168de959fSMauro Carvalho Chehab int bottom_irq_flags; 59268de959fSMauro Carvalho Chehab 59368de959fSMauro Carvalho Chehab top = NULL; 59468de959fSMauro Carvalho Chehab bottom = NULL; 59568de959fSMauro Carvalho Chehab top_irq_flags = 0; 59668de959fSMauro Carvalho Chehab bottom_irq_flags = 0; 59768de959fSMauro Carvalho Chehab 59868de959fSMauro Carvalho Chehab if (vbi) { 59968de959fSMauro Carvalho Chehab unsigned int crop, vdelay; 60068de959fSMauro Carvalho Chehab 60168de959fSMauro Carvalho Chehab vbi->vb.state = VIDEOBUF_ACTIVE; 60268de959fSMauro Carvalho Chehab list_del(&vbi->vb.queue); 60368de959fSMauro Carvalho Chehab 60468de959fSMauro Carvalho Chehab /* VDELAY is start of video, end of VBI capturing. */ 60568de959fSMauro Carvalho Chehab crop = btread(BT848_E_CROP); 60668de959fSMauro Carvalho Chehab vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); 60768de959fSMauro Carvalho Chehab 60868de959fSMauro Carvalho Chehab if (vbi->geo.vdelay > vdelay) { 60968de959fSMauro Carvalho Chehab vdelay = vbi->geo.vdelay & 0xfe; 61068de959fSMauro Carvalho Chehab crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); 61168de959fSMauro Carvalho Chehab 61268de959fSMauro Carvalho Chehab btwrite(vdelay, BT848_E_VDELAY_LO); 61368de959fSMauro Carvalho Chehab btwrite(crop, BT848_E_CROP); 61468de959fSMauro Carvalho Chehab btwrite(vdelay, BT848_O_VDELAY_LO); 61568de959fSMauro Carvalho Chehab btwrite(crop, BT848_O_CROP); 61668de959fSMauro Carvalho Chehab } 61768de959fSMauro Carvalho Chehab 61868de959fSMauro Carvalho Chehab if (vbi->vbi_count[0] > 0) { 61968de959fSMauro Carvalho Chehab top = &vbi->top; 62068de959fSMauro Carvalho Chehab top_irq_flags = 4; 62168de959fSMauro Carvalho Chehab } 62268de959fSMauro Carvalho Chehab 62368de959fSMauro Carvalho Chehab if (vbi->vbi_count[1] > 0) { 62468de959fSMauro Carvalho Chehab top_irq_flags = 0; 62568de959fSMauro Carvalho Chehab bottom = &vbi->bottom; 62668de959fSMauro Carvalho Chehab bottom_irq_flags = 4; 62768de959fSMauro Carvalho Chehab } 62868de959fSMauro Carvalho Chehab } 62968de959fSMauro Carvalho Chehab 63068de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); 63168de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); 63268de959fSMauro Carvalho Chehab 63368de959fSMauro Carvalho Chehab return 0; 63468de959fSMauro Carvalho Chehab } 63568de959fSMauro Carvalho Chehab 63668de959fSMauro Carvalho Chehab int 63768de959fSMauro Carvalho Chehab bttv_buffer_activate_video(struct bttv *btv, 63868de959fSMauro Carvalho Chehab struct bttv_buffer_set *set) 63968de959fSMauro Carvalho Chehab { 64068de959fSMauro Carvalho Chehab /* video capture */ 64168de959fSMauro Carvalho Chehab if (NULL != set->top && NULL != set->bottom) { 64268de959fSMauro Carvalho Chehab if (set->top == set->bottom) { 64368de959fSMauro Carvalho Chehab set->top->vb.state = VIDEOBUF_ACTIVE; 64468de959fSMauro Carvalho Chehab if (set->top->vb.queue.next) 64568de959fSMauro Carvalho Chehab list_del(&set->top->vb.queue); 64668de959fSMauro Carvalho Chehab } else { 64768de959fSMauro Carvalho Chehab set->top->vb.state = VIDEOBUF_ACTIVE; 64868de959fSMauro Carvalho Chehab set->bottom->vb.state = VIDEOBUF_ACTIVE; 64968de959fSMauro Carvalho Chehab if (set->top->vb.queue.next) 65068de959fSMauro Carvalho Chehab list_del(&set->top->vb.queue); 65168de959fSMauro Carvalho Chehab if (set->bottom->vb.queue.next) 65268de959fSMauro Carvalho Chehab list_del(&set->bottom->vb.queue); 65368de959fSMauro Carvalho Chehab } 65468de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->top->geo, 1); 65568de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->bottom->geo,0); 65668de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 65768de959fSMauro Carvalho Chehab set->top_irq); 65868de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 65968de959fSMauro Carvalho Chehab set->frame_irq); 66068de959fSMauro Carvalho Chehab btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), 66168de959fSMauro Carvalho Chehab ~0xff, BT848_COLOR_FMT); 66268de959fSMauro Carvalho Chehab btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), 66368de959fSMauro Carvalho Chehab ~0x0f, BT848_COLOR_CTL); 66468de959fSMauro Carvalho Chehab } else if (NULL != set->top) { 66568de959fSMauro Carvalho Chehab set->top->vb.state = VIDEOBUF_ACTIVE; 66668de959fSMauro Carvalho Chehab if (set->top->vb.queue.next) 66768de959fSMauro Carvalho Chehab list_del(&set->top->vb.queue); 66868de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->top->geo,1); 66968de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->top->geo,0); 67068de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 67168de959fSMauro Carvalho Chehab set->frame_irq); 67268de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); 67368de959fSMauro Carvalho Chehab btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); 67468de959fSMauro Carvalho Chehab btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); 67568de959fSMauro Carvalho Chehab } else if (NULL != set->bottom) { 67668de959fSMauro Carvalho Chehab set->bottom->vb.state = VIDEOBUF_ACTIVE; 67768de959fSMauro Carvalho Chehab if (set->bottom->vb.queue.next) 67868de959fSMauro Carvalho Chehab list_del(&set->bottom->vb.queue); 67968de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->bottom->geo,1); 68068de959fSMauro Carvalho Chehab bttv_apply_geo(btv, &set->bottom->geo,0); 68168de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); 68268de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 68368de959fSMauro Carvalho Chehab set->frame_irq); 68468de959fSMauro Carvalho Chehab btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); 68568de959fSMauro Carvalho Chehab btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); 68668de959fSMauro Carvalho Chehab } else { 68768de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); 68868de959fSMauro Carvalho Chehab bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); 68968de959fSMauro Carvalho Chehab } 69068de959fSMauro Carvalho Chehab return 0; 69168de959fSMauro Carvalho Chehab } 69268de959fSMauro Carvalho Chehab 69368de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */ 69468de959fSMauro Carvalho Chehab 69568de959fSMauro Carvalho Chehab /* calculate geometry, build risc code */ 69668de959fSMauro Carvalho Chehab int 69768de959fSMauro Carvalho Chehab bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) 69868de959fSMauro Carvalho Chehab { 69968de959fSMauro Carvalho Chehab const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; 70068de959fSMauro Carvalho Chehab struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); 70168de959fSMauro Carvalho Chehab 70268de959fSMauro Carvalho Chehab dprintk("%d: buffer field: %s format: %s size: %dx%d\n", 70368de959fSMauro Carvalho Chehab btv->c.nr, v4l2_field_names[buf->vb.field], 70468de959fSMauro Carvalho Chehab buf->fmt->name, buf->vb.width, buf->vb.height); 70568de959fSMauro Carvalho Chehab 70668de959fSMauro Carvalho Chehab /* packed pixel modes */ 70768de959fSMauro Carvalho Chehab if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { 70868de959fSMauro Carvalho Chehab int bpl = (buf->fmt->depth >> 3) * buf->vb.width; 70968de959fSMauro Carvalho Chehab int bpf = bpl * (buf->vb.height >> 1); 71068de959fSMauro Carvalho Chehab 71168de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, 71268de959fSMauro Carvalho Chehab V4L2_FIELD_HAS_BOTH(buf->vb.field), 71368de959fSMauro Carvalho Chehab tvnorm,&buf->crop); 71468de959fSMauro Carvalho Chehab 71568de959fSMauro Carvalho Chehab switch (buf->vb.field) { 71668de959fSMauro Carvalho Chehab case V4L2_FIELD_TOP: 71768de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->top,dma->sglist, 71868de959fSMauro Carvalho Chehab /* offset */ 0,bpl, 71968de959fSMauro Carvalho Chehab /* padding */ 0,/* skip_lines */ 0, 72068de959fSMauro Carvalho Chehab buf->vb.height); 72168de959fSMauro Carvalho Chehab break; 72268de959fSMauro Carvalho Chehab case V4L2_FIELD_BOTTOM: 72368de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->bottom,dma->sglist, 72468de959fSMauro Carvalho Chehab 0,bpl,0,0,buf->vb.height); 72568de959fSMauro Carvalho Chehab break; 72668de959fSMauro Carvalho Chehab case V4L2_FIELD_INTERLACED: 72768de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->top,dma->sglist, 72868de959fSMauro Carvalho Chehab 0,bpl,bpl,0,buf->vb.height >> 1); 72968de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->bottom,dma->sglist, 73068de959fSMauro Carvalho Chehab bpl,bpl,bpl,0,buf->vb.height >> 1); 73168de959fSMauro Carvalho Chehab break; 73268de959fSMauro Carvalho Chehab case V4L2_FIELD_SEQ_TB: 73368de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->top,dma->sglist, 73468de959fSMauro Carvalho Chehab 0,bpl,0,0,buf->vb.height >> 1); 73568de959fSMauro Carvalho Chehab bttv_risc_packed(btv,&buf->bottom,dma->sglist, 73668de959fSMauro Carvalho Chehab bpf,bpl,0,0,buf->vb.height >> 1); 73768de959fSMauro Carvalho Chehab break; 73868de959fSMauro Carvalho Chehab default: 73968de959fSMauro Carvalho Chehab BUG(); 74068de959fSMauro Carvalho Chehab } 74168de959fSMauro Carvalho Chehab } 74268de959fSMauro Carvalho Chehab 74368de959fSMauro Carvalho Chehab /* planar modes */ 74468de959fSMauro Carvalho Chehab if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { 74568de959fSMauro Carvalho Chehab int uoffset, voffset; 74668de959fSMauro Carvalho Chehab int ypadding, cpadding, lines; 74768de959fSMauro Carvalho Chehab 74868de959fSMauro Carvalho Chehab /* calculate chroma offsets */ 74968de959fSMauro Carvalho Chehab uoffset = buf->vb.width * buf->vb.height; 75068de959fSMauro Carvalho Chehab voffset = buf->vb.width * buf->vb.height; 75168de959fSMauro Carvalho Chehab if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { 75268de959fSMauro Carvalho Chehab /* Y-Cr-Cb plane order */ 75368de959fSMauro Carvalho Chehab uoffset >>= buf->fmt->hshift; 75468de959fSMauro Carvalho Chehab uoffset >>= buf->fmt->vshift; 75568de959fSMauro Carvalho Chehab uoffset += voffset; 75668de959fSMauro Carvalho Chehab } else { 75768de959fSMauro Carvalho Chehab /* Y-Cb-Cr plane order */ 75868de959fSMauro Carvalho Chehab voffset >>= buf->fmt->hshift; 75968de959fSMauro Carvalho Chehab voffset >>= buf->fmt->vshift; 76068de959fSMauro Carvalho Chehab voffset += uoffset; 76168de959fSMauro Carvalho Chehab } 76268de959fSMauro Carvalho Chehab 76368de959fSMauro Carvalho Chehab switch (buf->vb.field) { 76468de959fSMauro Carvalho Chehab case V4L2_FIELD_TOP: 76568de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,buf->vb.width, 76668de959fSMauro Carvalho Chehab buf->vb.height,/* both_fields */ 0, 76768de959fSMauro Carvalho Chehab tvnorm,&buf->crop); 76868de959fSMauro Carvalho Chehab bttv_risc_planar(btv, &buf->top, dma->sglist, 76968de959fSMauro Carvalho Chehab 0,buf->vb.width,0,buf->vb.height, 77068de959fSMauro Carvalho Chehab uoffset,voffset,buf->fmt->hshift, 77168de959fSMauro Carvalho Chehab buf->fmt->vshift,0); 77268de959fSMauro Carvalho Chehab break; 77368de959fSMauro Carvalho Chehab case V4L2_FIELD_BOTTOM: 77468de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,buf->vb.width, 77568de959fSMauro Carvalho Chehab buf->vb.height,0, 77668de959fSMauro Carvalho Chehab tvnorm,&buf->crop); 77768de959fSMauro Carvalho Chehab bttv_risc_planar(btv, &buf->bottom, dma->sglist, 77868de959fSMauro Carvalho Chehab 0,buf->vb.width,0,buf->vb.height, 77968de959fSMauro Carvalho Chehab uoffset,voffset,buf->fmt->hshift, 78068de959fSMauro Carvalho Chehab buf->fmt->vshift,0); 78168de959fSMauro Carvalho Chehab break; 78268de959fSMauro Carvalho Chehab case V4L2_FIELD_INTERLACED: 78368de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,buf->vb.width, 78468de959fSMauro Carvalho Chehab buf->vb.height,1, 78568de959fSMauro Carvalho Chehab tvnorm,&buf->crop); 78668de959fSMauro Carvalho Chehab lines = buf->vb.height >> 1; 78768de959fSMauro Carvalho Chehab ypadding = buf->vb.width; 78868de959fSMauro Carvalho Chehab cpadding = buf->vb.width >> buf->fmt->hshift; 78968de959fSMauro Carvalho Chehab bttv_risc_planar(btv,&buf->top, 79068de959fSMauro Carvalho Chehab dma->sglist, 79168de959fSMauro Carvalho Chehab 0,buf->vb.width,ypadding,lines, 79268de959fSMauro Carvalho Chehab uoffset,voffset, 79368de959fSMauro Carvalho Chehab buf->fmt->hshift, 79468de959fSMauro Carvalho Chehab buf->fmt->vshift, 79568de959fSMauro Carvalho Chehab cpadding); 79668de959fSMauro Carvalho Chehab bttv_risc_planar(btv,&buf->bottom, 79768de959fSMauro Carvalho Chehab dma->sglist, 79868de959fSMauro Carvalho Chehab ypadding,buf->vb.width,ypadding,lines, 79968de959fSMauro Carvalho Chehab uoffset+cpadding, 80068de959fSMauro Carvalho Chehab voffset+cpadding, 80168de959fSMauro Carvalho Chehab buf->fmt->hshift, 80268de959fSMauro Carvalho Chehab buf->fmt->vshift, 80368de959fSMauro Carvalho Chehab cpadding); 80468de959fSMauro Carvalho Chehab break; 80568de959fSMauro Carvalho Chehab case V4L2_FIELD_SEQ_TB: 80668de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,buf->vb.width, 80768de959fSMauro Carvalho Chehab buf->vb.height,1, 80868de959fSMauro Carvalho Chehab tvnorm,&buf->crop); 80968de959fSMauro Carvalho Chehab lines = buf->vb.height >> 1; 81068de959fSMauro Carvalho Chehab ypadding = buf->vb.width; 81168de959fSMauro Carvalho Chehab cpadding = buf->vb.width >> buf->fmt->hshift; 81268de959fSMauro Carvalho Chehab bttv_risc_planar(btv,&buf->top, 81368de959fSMauro Carvalho Chehab dma->sglist, 81468de959fSMauro Carvalho Chehab 0,buf->vb.width,0,lines, 81568de959fSMauro Carvalho Chehab uoffset >> 1, 81668de959fSMauro Carvalho Chehab voffset >> 1, 81768de959fSMauro Carvalho Chehab buf->fmt->hshift, 81868de959fSMauro Carvalho Chehab buf->fmt->vshift, 81968de959fSMauro Carvalho Chehab 0); 82068de959fSMauro Carvalho Chehab bttv_risc_planar(btv,&buf->bottom, 82168de959fSMauro Carvalho Chehab dma->sglist, 82268de959fSMauro Carvalho Chehab lines * ypadding,buf->vb.width,0,lines, 82368de959fSMauro Carvalho Chehab lines * ypadding + (uoffset >> 1), 82468de959fSMauro Carvalho Chehab lines * ypadding + (voffset >> 1), 82568de959fSMauro Carvalho Chehab buf->fmt->hshift, 82668de959fSMauro Carvalho Chehab buf->fmt->vshift, 82768de959fSMauro Carvalho Chehab 0); 82868de959fSMauro Carvalho Chehab break; 82968de959fSMauro Carvalho Chehab default: 83068de959fSMauro Carvalho Chehab BUG(); 83168de959fSMauro Carvalho Chehab } 83268de959fSMauro Carvalho Chehab } 83368de959fSMauro Carvalho Chehab 83468de959fSMauro Carvalho Chehab /* raw data */ 83568de959fSMauro Carvalho Chehab if (buf->fmt->flags & FORMAT_FLAGS_RAW) { 83668de959fSMauro Carvalho Chehab /* build risc code */ 83768de959fSMauro Carvalho Chehab buf->vb.field = V4L2_FIELD_SEQ_TB; 83868de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 83968de959fSMauro Carvalho Chehab 1,tvnorm,&buf->crop); 84068de959fSMauro Carvalho Chehab bttv_risc_packed(btv, &buf->top, dma->sglist, 84168de959fSMauro Carvalho Chehab /* offset */ 0, RAW_BPL, /* padding */ 0, 84268de959fSMauro Carvalho Chehab /* skip_lines */ 0, RAW_LINES); 84368de959fSMauro Carvalho Chehab bttv_risc_packed(btv, &buf->bottom, dma->sglist, 84468de959fSMauro Carvalho Chehab buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); 84568de959fSMauro Carvalho Chehab } 84668de959fSMauro Carvalho Chehab 84768de959fSMauro Carvalho Chehab /* copy format info */ 84868de959fSMauro Carvalho Chehab buf->btformat = buf->fmt->btformat; 84968de959fSMauro Carvalho Chehab buf->btswap = buf->fmt->btswap; 85068de959fSMauro Carvalho Chehab return 0; 85168de959fSMauro Carvalho Chehab } 85268de959fSMauro Carvalho Chehab 85368de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */ 85468de959fSMauro Carvalho Chehab 85568de959fSMauro Carvalho Chehab /* calculate geometry, build risc code */ 85668de959fSMauro Carvalho Chehab int 85768de959fSMauro Carvalho Chehab bttv_overlay_risc(struct bttv *btv, 85868de959fSMauro Carvalho Chehab struct bttv_overlay *ov, 85968de959fSMauro Carvalho Chehab const struct bttv_format *fmt, 86068de959fSMauro Carvalho Chehab struct bttv_buffer *buf) 86168de959fSMauro Carvalho Chehab { 86268de959fSMauro Carvalho Chehab /* check interleave, bottom+top fields */ 86368de959fSMauro Carvalho Chehab dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", 86468de959fSMauro Carvalho Chehab btv->c.nr, v4l2_field_names[buf->vb.field], 86568de959fSMauro Carvalho Chehab fmt->name, ov->w.width, ov->w.height); 86668de959fSMauro Carvalho Chehab 86768de959fSMauro Carvalho Chehab /* calculate geometry */ 86868de959fSMauro Carvalho Chehab bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, 86968de959fSMauro Carvalho Chehab V4L2_FIELD_HAS_BOTH(ov->field), 87068de959fSMauro Carvalho Chehab &bttv_tvnorms[ov->tvnorm],&buf->crop); 87168de959fSMauro Carvalho Chehab 87268de959fSMauro Carvalho Chehab /* build risc code */ 87368de959fSMauro Carvalho Chehab switch (ov->field) { 87468de959fSMauro Carvalho Chehab case V4L2_FIELD_TOP: 87568de959fSMauro Carvalho Chehab bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); 87668de959fSMauro Carvalho Chehab break; 87768de959fSMauro Carvalho Chehab case V4L2_FIELD_BOTTOM: 87868de959fSMauro Carvalho Chehab bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); 87968de959fSMauro Carvalho Chehab break; 88068de959fSMauro Carvalho Chehab case V4L2_FIELD_INTERLACED: 88168de959fSMauro Carvalho Chehab bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); 88268de959fSMauro Carvalho Chehab bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); 88368de959fSMauro Carvalho Chehab break; 88468de959fSMauro Carvalho Chehab default: 88568de959fSMauro Carvalho Chehab BUG(); 88668de959fSMauro Carvalho Chehab } 88768de959fSMauro Carvalho Chehab 88868de959fSMauro Carvalho Chehab /* copy format info */ 88968de959fSMauro Carvalho Chehab buf->btformat = fmt->btformat; 89068de959fSMauro Carvalho Chehab buf->btswap = fmt->btswap; 89168de959fSMauro Carvalho Chehab buf->vb.field = ov->field; 89268de959fSMauro Carvalho Chehab return 0; 89368de959fSMauro Carvalho Chehab } 894