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>
23ca5999fdSMike Rapoport #include <linux/pgtable.h>
2465fddcfcSMike Rapoport #include <asm/page.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
bttv_risc_packed(struct bttv * btv,struct btcx_riscmem * risc,struct scatterlist * sglist,unsigned int offset,unsigned int bpl,unsigned int padding,unsigned int skip_lines,unsigned int store_lines)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++) {
70b7ec3212SDeborah Brouwer 		if ((line >= (store_lines - VCR_HACK_LINES)) &&
71*861ab817SHans Verkuil 		    btv->opt_vcr_hack)
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;
109615c5450SDeborah Brouwer 	WARN_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
bttv_risc_planar(struct bttv * btv,struct btcx_riscmem * risc,struct scatterlist * sglist,unsigned int yoffset,unsigned int ybpl,unsigned int ypadding,unsigned int ylines,unsigned int uoffset,unsigned int voffset,unsigned int hshift,unsigned int vshift,unsigned int cpadding)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;
230615c5450SDeborah Brouwer 	WARN_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 /* ---------------------------------------------------------- */
23568de959fSMauro Carvalho Chehab 
23668de959fSMauro Carvalho Chehab static void
bttv_calc_geo_old(struct bttv * btv,struct bttv_geometry * geo,int width,int height,int interleaved,const struct bttv_tvnorm * tvnorm)23768de959fSMauro Carvalho Chehab bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
23868de959fSMauro Carvalho Chehab 		  int width, int height, int interleaved,
23968de959fSMauro Carvalho Chehab 		  const struct bttv_tvnorm *tvnorm)
24068de959fSMauro Carvalho Chehab {
24168de959fSMauro Carvalho Chehab 	u32 xsf, sr;
24268de959fSMauro Carvalho Chehab 	int vdelay;
24368de959fSMauro Carvalho Chehab 
24468de959fSMauro Carvalho Chehab 	int swidth       = tvnorm->swidth;
24568de959fSMauro Carvalho Chehab 	int totalwidth   = tvnorm->totalwidth;
24668de959fSMauro Carvalho Chehab 	int scaledtwidth = tvnorm->scaledtwidth;
24768de959fSMauro Carvalho Chehab 
24868de959fSMauro Carvalho Chehab 	if (btv->input == btv->dig) {
24968de959fSMauro Carvalho Chehab 		swidth       = 720;
25068de959fSMauro Carvalho Chehab 		totalwidth   = 858;
25168de959fSMauro Carvalho Chehab 		scaledtwidth = 858;
25268de959fSMauro Carvalho Chehab 	}
25368de959fSMauro Carvalho Chehab 
25468de959fSMauro Carvalho Chehab 	vdelay = tvnorm->vdelay;
25568de959fSMauro Carvalho Chehab 
25668de959fSMauro Carvalho Chehab 	xsf = (width*scaledtwidth)/swidth;
25768de959fSMauro Carvalho Chehab 	geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
25868de959fSMauro Carvalho Chehab 	geo->hdelay =  tvnorm->hdelayx1;
25968de959fSMauro Carvalho Chehab 	geo->hdelay =  (geo->hdelay*width)/swidth;
26068de959fSMauro Carvalho Chehab 	geo->hdelay &= 0x3fe;
26168de959fSMauro Carvalho Chehab 	sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
26268de959fSMauro Carvalho Chehab 	geo->vscale =  (0x10000UL-sr) & 0x1fff;
26368de959fSMauro Carvalho Chehab 	geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
26468de959fSMauro Carvalho Chehab 		((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
26568de959fSMauro Carvalho Chehab 	geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
26668de959fSMauro Carvalho Chehab 	geo->vdelay  =  vdelay;
26768de959fSMauro Carvalho Chehab 	geo->width   =  width;
26868de959fSMauro Carvalho Chehab 	geo->sheight =  tvnorm->sheight;
26968de959fSMauro Carvalho Chehab 	geo->vtotal  =  tvnorm->vtotal;
27068de959fSMauro Carvalho Chehab 
27168de959fSMauro Carvalho Chehab 	if (btv->opt_combfilter) {
27268de959fSMauro Carvalho Chehab 		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
27368de959fSMauro Carvalho Chehab 		geo->comb = (width < 769) ? 1 : 0;
27468de959fSMauro Carvalho Chehab 	} else {
27568de959fSMauro Carvalho Chehab 		geo->vtc  = 0;
27668de959fSMauro Carvalho Chehab 		geo->comb = 0;
27768de959fSMauro Carvalho Chehab 	}
27868de959fSMauro Carvalho Chehab }
27968de959fSMauro Carvalho Chehab 
28068de959fSMauro Carvalho Chehab static void
bttv_calc_geo(struct bttv * btv,struct bttv_geometry * geo,unsigned int width,unsigned int height,int both_fields,const struct bttv_tvnorm * tvnorm,const struct v4l2_rect * crop)28168de959fSMauro Carvalho Chehab bttv_calc_geo		(struct bttv *                  btv,
28268de959fSMauro Carvalho Chehab 			 struct bttv_geometry *         geo,
28368de959fSMauro Carvalho Chehab 			 unsigned int                   width,
28468de959fSMauro Carvalho Chehab 			 unsigned int                   height,
28568de959fSMauro Carvalho Chehab 			 int                            both_fields,
28668de959fSMauro Carvalho Chehab 			 const struct bttv_tvnorm *     tvnorm,
28768de959fSMauro Carvalho Chehab 			 const struct v4l2_rect *       crop)
28868de959fSMauro Carvalho Chehab {
28968de959fSMauro Carvalho Chehab 	unsigned int c_width;
29068de959fSMauro Carvalho Chehab 	unsigned int c_height;
29168de959fSMauro Carvalho Chehab 	u32 sr;
29268de959fSMauro Carvalho Chehab 
29368de959fSMauro Carvalho Chehab 	if ((crop->left == tvnorm->cropcap.defrect.left
29468de959fSMauro Carvalho Chehab 	     && crop->top == tvnorm->cropcap.defrect.top
29568de959fSMauro Carvalho Chehab 	     && crop->width == tvnorm->cropcap.defrect.width
29668de959fSMauro Carvalho Chehab 	     && crop->height == tvnorm->cropcap.defrect.height
29768de959fSMauro Carvalho Chehab 	     && width <= tvnorm->swidth /* see PAL-Nc et al */)
29868de959fSMauro Carvalho Chehab 	    || btv->input == btv->dig) {
29968de959fSMauro Carvalho Chehab 		bttv_calc_geo_old(btv, geo, width, height,
30068de959fSMauro Carvalho Chehab 				  both_fields, tvnorm);
30168de959fSMauro Carvalho Chehab 		return;
30268de959fSMauro Carvalho Chehab 	}
30368de959fSMauro Carvalho Chehab 
30468de959fSMauro Carvalho Chehab 	/* For bug compatibility the image size checks permit scale
30568de959fSMauro Carvalho Chehab 	   factors > 16. See bttv_crop_calc_limits(). */
30668de959fSMauro Carvalho Chehab 	c_width = min((unsigned int) crop->width, width * 16);
30768de959fSMauro Carvalho Chehab 	c_height = min((unsigned int) crop->height, height * 16);
30868de959fSMauro Carvalho Chehab 
30968de959fSMauro Carvalho Chehab 	geo->width = width;
31068de959fSMauro Carvalho Chehab 	geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
31168de959fSMauro Carvalho Chehab 	/* Even to store Cb first, odd for Cr. */
31268de959fSMauro Carvalho Chehab 	geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
31368de959fSMauro Carvalho Chehab 
31468de959fSMauro Carvalho Chehab 	geo->sheight = c_height;
31568de959fSMauro Carvalho Chehab 	geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
31668de959fSMauro Carvalho Chehab 	sr = c_height >> !both_fields;
31768de959fSMauro Carvalho Chehab 	sr = (sr * 512U + (height >> 1)) / height - 512;
31868de959fSMauro Carvalho Chehab 	geo->vscale = (0x10000UL - sr) & 0x1fff;
31968de959fSMauro Carvalho Chehab 	geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
32068de959fSMauro Carvalho Chehab 	geo->vtotal = tvnorm->vtotal;
32168de959fSMauro Carvalho Chehab 
32268de959fSMauro Carvalho Chehab 	geo->crop = (((geo->width   >> 8) & 0x03) |
32368de959fSMauro Carvalho Chehab 		     ((geo->hdelay  >> 6) & 0x0c) |
32468de959fSMauro Carvalho Chehab 		     ((geo->sheight >> 4) & 0x30) |
32568de959fSMauro Carvalho Chehab 		     ((geo->vdelay  >> 2) & 0xc0));
32668de959fSMauro Carvalho Chehab 
32768de959fSMauro Carvalho Chehab 	if (btv->opt_combfilter) {
32868de959fSMauro Carvalho Chehab 		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
32968de959fSMauro Carvalho Chehab 		geo->comb = (width < 769) ? 1 : 0;
33068de959fSMauro Carvalho Chehab 	} else {
33168de959fSMauro Carvalho Chehab 		geo->vtc  = 0;
33268de959fSMauro Carvalho Chehab 		geo->comb = 0;
33368de959fSMauro Carvalho Chehab 	}
33468de959fSMauro Carvalho Chehab }
33568de959fSMauro Carvalho Chehab 
33668de959fSMauro Carvalho Chehab static void
bttv_apply_geo(struct bttv * btv,struct bttv_geometry * geo,int odd)33768de959fSMauro Carvalho Chehab bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
33868de959fSMauro Carvalho Chehab {
33968de959fSMauro Carvalho Chehab 	int off = odd ? 0x80 : 0x00;
34068de959fSMauro Carvalho Chehab 
34168de959fSMauro Carvalho Chehab 	if (geo->comb)
34268de959fSMauro Carvalho Chehab 		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
34368de959fSMauro Carvalho Chehab 	else
34468de959fSMauro Carvalho Chehab 		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
34568de959fSMauro Carvalho Chehab 
34668de959fSMauro Carvalho Chehab 	btwrite(geo->vtc,             BT848_E_VTC+off);
34768de959fSMauro Carvalho Chehab 	btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
34868de959fSMauro Carvalho Chehab 	btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
34968de959fSMauro Carvalho Chehab 	btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
35068de959fSMauro Carvalho Chehab 	btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
35168de959fSMauro Carvalho Chehab 	btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
35268de959fSMauro Carvalho Chehab 	btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
35368de959fSMauro Carvalho Chehab 	btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
35468de959fSMauro Carvalho Chehab 	btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
35568de959fSMauro Carvalho Chehab 	btwrite(geo->crop,            BT848_E_CROP+off);
35668de959fSMauro Carvalho Chehab 	btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
35768de959fSMauro Carvalho Chehab 	btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
35868de959fSMauro Carvalho Chehab }
35968de959fSMauro Carvalho Chehab 
36068de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */
36168de959fSMauro Carvalho Chehab /* risc group / risc main loop / dma management               */
36268de959fSMauro Carvalho Chehab 
bttv_set_risc_status(struct bttv * btv)3637df8d5cfSDeborah Brouwer static void bttv_set_risc_status(struct bttv *btv)
36468de959fSMauro Carvalho Chehab {
3657df8d5cfSDeborah Brouwer 	unsigned long cmd = BT848_RISC_JUMP;
3667df8d5cfSDeborah Brouwer 	if (btv->loop_irq) {
3677df8d5cfSDeborah Brouwer 		cmd |= BT848_RISC_IRQ;
3687df8d5cfSDeborah Brouwer 		cmd |= (btv->loop_irq  & 0x0f) << 16;
3697df8d5cfSDeborah Brouwer 		cmd |= (~btv->loop_irq & 0x0f) << 20;
3707df8d5cfSDeborah Brouwer 	}
3717df8d5cfSDeborah Brouwer 	btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
3727df8d5cfSDeborah Brouwer }
37368de959fSMauro Carvalho Chehab 
bttv_set_irq_timer(struct bttv * btv)3747df8d5cfSDeborah Brouwer static void bttv_set_irq_timer(struct bttv *btv)
3757df8d5cfSDeborah Brouwer {
3767df8d5cfSDeborah Brouwer 	if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi)
3777df8d5cfSDeborah Brouwer 		mod_timer(&btv->timeout, jiffies + BTTV_TIMEOUT);
3787df8d5cfSDeborah Brouwer 	else
3797df8d5cfSDeborah Brouwer 		del_timer(&btv->timeout);
3807df8d5cfSDeborah Brouwer }
38168de959fSMauro Carvalho Chehab 
bttv_set_capture_control(struct bttv * btv,int start_capture)3827df8d5cfSDeborah Brouwer static int bttv_set_capture_control(struct bttv *btv, int start_capture)
3837df8d5cfSDeborah Brouwer {
3847df8d5cfSDeborah Brouwer 	int capctl = 0;
3857df8d5cfSDeborah Brouwer 
3867df8d5cfSDeborah Brouwer 	if (btv->curr.top || btv->curr.bottom)
3877df8d5cfSDeborah Brouwer 		capctl = BT848_CAP_CTL_CAPTURE_ODD |
3887df8d5cfSDeborah Brouwer 			 BT848_CAP_CTL_CAPTURE_EVEN;
3897df8d5cfSDeborah Brouwer 
3907df8d5cfSDeborah Brouwer 	if (btv->cvbi)
3917df8d5cfSDeborah Brouwer 		capctl |= BT848_CAP_CTL_CAPTURE_VBI_ODD |
3927df8d5cfSDeborah Brouwer 			  BT848_CAP_CTL_CAPTURE_VBI_EVEN;
3937df8d5cfSDeborah Brouwer 
3947df8d5cfSDeborah Brouwer 	capctl |= start_capture;
3957df8d5cfSDeborah Brouwer 
3967df8d5cfSDeborah Brouwer 	btaor(capctl, ~0x0f, BT848_CAP_CTL);
3977df8d5cfSDeborah Brouwer 
3987df8d5cfSDeborah Brouwer 	return capctl;
3997df8d5cfSDeborah Brouwer }
4007df8d5cfSDeborah Brouwer 
bttv_start_dma(struct bttv * btv)4017df8d5cfSDeborah Brouwer static void bttv_start_dma(struct bttv *btv)
4027df8d5cfSDeborah Brouwer {
4037df8d5cfSDeborah Brouwer 	if (btv->dma_on)
4047df8d5cfSDeborah Brouwer 		return;
4057df8d5cfSDeborah Brouwer 	btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
406b7ec3212SDeborah Brouwer 	btor(BT848_GPIO_DMA_CTL_RISC_ENABLE | BT848_GPIO_DMA_CTL_FIFO_ENABLE,
407b7ec3212SDeborah Brouwer 	     BT848_GPIO_DMA_CTL);
4087df8d5cfSDeborah Brouwer 	btv->dma_on = 1;
4097df8d5cfSDeborah Brouwer }
4107df8d5cfSDeborah Brouwer 
bttv_stop_dma(struct bttv * btv)4117df8d5cfSDeborah Brouwer static void bttv_stop_dma(struct bttv *btv)
4127df8d5cfSDeborah Brouwer {
4137df8d5cfSDeborah Brouwer 	if (!btv->dma_on)
4147df8d5cfSDeborah Brouwer 		return;
415b7ec3212SDeborah Brouwer 	btand(~(BT848_GPIO_DMA_CTL_RISC_ENABLE |
416b7ec3212SDeborah Brouwer 		BT848_GPIO_DMA_CTL_FIFO_ENABLE), BT848_GPIO_DMA_CTL);
4177df8d5cfSDeborah Brouwer 	btv->dma_on = 0;
4187df8d5cfSDeborah Brouwer }
4197df8d5cfSDeborah Brouwer 
bttv_set_dma(struct bttv * btv,int start_capture)4207df8d5cfSDeborah Brouwer void bttv_set_dma(struct bttv *btv, int start_capture)
4217df8d5cfSDeborah Brouwer {
4227df8d5cfSDeborah Brouwer 	int capctl = 0;
4237df8d5cfSDeborah Brouwer 
4247df8d5cfSDeborah Brouwer 	bttv_set_risc_status(btv);
4257df8d5cfSDeborah Brouwer 	bttv_set_irq_timer(btv);
4267df8d5cfSDeborah Brouwer 	capctl = bttv_set_capture_control(btv, start_capture);
4277df8d5cfSDeborah Brouwer 
4287df8d5cfSDeborah Brouwer 	if (capctl)
4297df8d5cfSDeborah Brouwer 		bttv_start_dma(btv);
4307df8d5cfSDeborah Brouwer 	else
4317df8d5cfSDeborah Brouwer 		bttv_stop_dma(btv);
43268de959fSMauro Carvalho Chehab 
43368de959fSMauro Carvalho Chehab 	d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
43468de959fSMauro Carvalho Chehab 		 btv->c.nr,capctl,btv->loop_irq,
43568de959fSMauro Carvalho Chehab 		 btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
43668de959fSMauro Carvalho Chehab 		 btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
43768de959fSMauro Carvalho Chehab 		 btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
43868de959fSMauro Carvalho Chehab 		 btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
43968de959fSMauro Carvalho Chehab }
44068de959fSMauro Carvalho Chehab 
44168de959fSMauro Carvalho Chehab int
bttv_risc_init_main(struct bttv * btv)44268de959fSMauro Carvalho Chehab bttv_risc_init_main(struct bttv *btv)
44368de959fSMauro Carvalho Chehab {
44468de959fSMauro Carvalho Chehab 	int rc;
44568de959fSMauro Carvalho Chehab 
44668de959fSMauro Carvalho Chehab 	if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
44768de959fSMauro Carvalho Chehab 		return rc;
44868de959fSMauro Carvalho Chehab 	dprintk("%d: risc main @ %08llx\n",
44968de959fSMauro Carvalho Chehab 		btv->c.nr, (unsigned long long)btv->main.dma);
45068de959fSMauro Carvalho Chehab 
45168de959fSMauro Carvalho Chehab 	btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
45268de959fSMauro Carvalho Chehab 				       BT848_FIFO_STATUS_VRE);
45368de959fSMauro Carvalho Chehab 	btv->main.cpu[1] = cpu_to_le32(0);
45468de959fSMauro Carvalho Chehab 	btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
45568de959fSMauro Carvalho Chehab 	btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
45668de959fSMauro Carvalho Chehab 
45768de959fSMauro Carvalho Chehab 	/* top field */
45868de959fSMauro Carvalho Chehab 	btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
45968de959fSMauro Carvalho Chehab 	btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
46068de959fSMauro Carvalho Chehab 	btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
46168de959fSMauro Carvalho Chehab 	btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
46268de959fSMauro Carvalho Chehab 
46368de959fSMauro Carvalho Chehab 	btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
46468de959fSMauro Carvalho Chehab 				       BT848_FIFO_STATUS_VRO);
46568de959fSMauro Carvalho Chehab 	btv->main.cpu[9] = cpu_to_le32(0);
46668de959fSMauro Carvalho Chehab 
46768de959fSMauro Carvalho Chehab 	/* bottom field */
46868de959fSMauro Carvalho Chehab 	btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
46968de959fSMauro Carvalho Chehab 	btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
47068de959fSMauro Carvalho Chehab 	btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
47168de959fSMauro Carvalho Chehab 	btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
47268de959fSMauro Carvalho Chehab 
47368de959fSMauro Carvalho Chehab 	/* jump back to top field */
47468de959fSMauro Carvalho Chehab 	btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
47568de959fSMauro Carvalho Chehab 	btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
47668de959fSMauro Carvalho Chehab 
47768de959fSMauro Carvalho Chehab 	return 0;
47868de959fSMauro Carvalho Chehab }
47968de959fSMauro Carvalho Chehab 
48068de959fSMauro Carvalho Chehab int
bttv_risc_hook(struct bttv * btv,int slot,struct btcx_riscmem * risc,int irqflags)48168de959fSMauro Carvalho Chehab bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
48268de959fSMauro Carvalho Chehab 	       int irqflags)
48368de959fSMauro Carvalho Chehab {
48468de959fSMauro Carvalho Chehab 	unsigned long cmd;
48568de959fSMauro Carvalho Chehab 	unsigned long next = btv->main.dma + ((slot+2) << 2);
48668de959fSMauro Carvalho Chehab 
48768de959fSMauro Carvalho Chehab 	if (NULL == risc) {
48868de959fSMauro Carvalho Chehab 		d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot);
48968de959fSMauro Carvalho Chehab 		btv->main.cpu[slot+1] = cpu_to_le32(next);
49068de959fSMauro Carvalho Chehab 	} else {
49168de959fSMauro Carvalho Chehab 		d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n",
49268de959fSMauro Carvalho Chehab 			 btv->c.nr, risc, slot,
49368de959fSMauro Carvalho Chehab 			 (unsigned long long)risc->dma, irqflags);
49468de959fSMauro Carvalho Chehab 		cmd = BT848_RISC_JUMP;
49568de959fSMauro Carvalho Chehab 		if (irqflags) {
49668de959fSMauro Carvalho Chehab 			cmd |= BT848_RISC_IRQ;
49768de959fSMauro Carvalho Chehab 			cmd |= (irqflags  & 0x0f) << 16;
49868de959fSMauro Carvalho Chehab 			cmd |= (~irqflags & 0x0f) << 20;
49968de959fSMauro Carvalho Chehab 		}
50068de959fSMauro Carvalho Chehab 		risc->jmp[0] = cpu_to_le32(cmd);
50168de959fSMauro Carvalho Chehab 		risc->jmp[1] = cpu_to_le32(next);
50268de959fSMauro Carvalho Chehab 		btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
50368de959fSMauro Carvalho Chehab 	}
50468de959fSMauro Carvalho Chehab 	return 0;
50568de959fSMauro Carvalho Chehab }
50668de959fSMauro Carvalho Chehab 
bttv_buffer_risc_vbi(struct bttv * btv,struct bttv_buffer * buf)507b7ec3212SDeborah Brouwer int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)
50868de959fSMauro Carvalho Chehab {
509b7ec3212SDeborah Brouwer 	int r = 0;
510b7ec3212SDeborah Brouwer 	unsigned int offset;
511b7ec3212SDeborah Brouwer 	unsigned int bpl = 2044; /* max. vbipack */
512b7ec3212SDeborah Brouwer 	unsigned int padding = VBI_BPL - bpl;
513b7ec3212SDeborah Brouwer 	unsigned int skip_lines0 = 0;
514b7ec3212SDeborah Brouwer 	unsigned int skip_lines1 = 0;
515b7ec3212SDeborah Brouwer 	unsigned int min_vdelay = MIN_VDELAY;
51668de959fSMauro Carvalho Chehab 
517b7ec3212SDeborah Brouwer 	const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;
518b7ec3212SDeborah Brouwer 	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
519b7ec3212SDeborah Brouwer 	struct scatterlist *list = sgt->sgl;
520b7ec3212SDeborah Brouwer 
521b7ec3212SDeborah Brouwer 	if (btv->vbi_fmt.fmt.count[0] > 0)
522b7ec3212SDeborah Brouwer 		skip_lines0 = max(0, (btv->vbi_fmt.fmt.start[0] -
523b7ec3212SDeborah Brouwer 					tvnorm->vbistart[0]));
524b7ec3212SDeborah Brouwer 	if (btv->vbi_fmt.fmt.count[1] > 0)
525b7ec3212SDeborah Brouwer 		skip_lines1 = max(0, (btv->vbi_fmt.fmt.start[1] -
526b7ec3212SDeborah Brouwer 					tvnorm->vbistart[1]));
527b7ec3212SDeborah Brouwer 
528b7ec3212SDeborah Brouwer 	if (btv->vbi_fmt.fmt.count[0] > 0) {
529b7ec3212SDeborah Brouwer 		r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, padding,
530b7ec3212SDeborah Brouwer 				     skip_lines0, btv->vbi_fmt.fmt.count[0]);
531b7ec3212SDeborah Brouwer 		if (r)
532b7ec3212SDeborah Brouwer 			return r;
533b7ec3212SDeborah Brouwer 	}
534b7ec3212SDeborah Brouwer 
535b7ec3212SDeborah Brouwer 	if (btv->vbi_fmt.fmt.count[1] > 0) {
536b7ec3212SDeborah Brouwer 		offset = btv->vbi_fmt.fmt.count[0] * VBI_BPL;
537b7ec3212SDeborah Brouwer 		r = bttv_risc_packed(btv, &buf->bottom, list, offset, bpl,
538b7ec3212SDeborah Brouwer 				     padding, skip_lines1,
539b7ec3212SDeborah Brouwer 				     btv->vbi_fmt.fmt.count[1]);
540b7ec3212SDeborah Brouwer 		if (r)
541b7ec3212SDeborah Brouwer 			return r;
542b7ec3212SDeborah Brouwer 	}
543b7ec3212SDeborah Brouwer 
544b7ec3212SDeborah Brouwer 	if (btv->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
545b7ec3212SDeborah Brouwer 		min_vdelay += btv->vbi_fmt.end - tvnorm->cropcap.bounds.top;
546b7ec3212SDeborah Brouwer 
547b7ec3212SDeborah Brouwer 	/* For bttv_buffer_activate_vbi(). */
548b7ec3212SDeborah Brouwer 	buf->geo.vdelay = min_vdelay;
549b7ec3212SDeborah Brouwer 
550b7ec3212SDeborah Brouwer 	return r;
55168de959fSMauro Carvalho Chehab }
55268de959fSMauro Carvalho Chehab 
55368de959fSMauro Carvalho Chehab int
bttv_buffer_activate_vbi(struct bttv * btv,struct bttv_buffer * vbi)55468de959fSMauro Carvalho Chehab bttv_buffer_activate_vbi(struct bttv *btv,
55568de959fSMauro Carvalho Chehab 			 struct bttv_buffer *vbi)
55668de959fSMauro Carvalho Chehab {
55768de959fSMauro Carvalho Chehab 	struct btcx_riscmem *top;
55868de959fSMauro Carvalho Chehab 	struct btcx_riscmem *bottom;
55968de959fSMauro Carvalho Chehab 	int top_irq_flags;
56068de959fSMauro Carvalho Chehab 	int bottom_irq_flags;
56168de959fSMauro Carvalho Chehab 
56268de959fSMauro Carvalho Chehab 	top = NULL;
56368de959fSMauro Carvalho Chehab 	bottom = NULL;
56468de959fSMauro Carvalho Chehab 	top_irq_flags = 0;
56568de959fSMauro Carvalho Chehab 	bottom_irq_flags = 0;
56668de959fSMauro Carvalho Chehab 
56768de959fSMauro Carvalho Chehab 	if (vbi) {
56868de959fSMauro Carvalho Chehab 		unsigned int crop, vdelay;
56968de959fSMauro Carvalho Chehab 
570b7ec3212SDeborah Brouwer 		list_del(&vbi->list);
57168de959fSMauro Carvalho Chehab 
57268de959fSMauro Carvalho Chehab 		/* VDELAY is start of video, end of VBI capturing. */
57368de959fSMauro Carvalho Chehab 		crop = btread(BT848_E_CROP);
57468de959fSMauro Carvalho Chehab 		vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
57568de959fSMauro Carvalho Chehab 
57668de959fSMauro Carvalho Chehab 		if (vbi->geo.vdelay > vdelay) {
57768de959fSMauro Carvalho Chehab 			vdelay = vbi->geo.vdelay & 0xfe;
57868de959fSMauro Carvalho Chehab 			crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
57968de959fSMauro Carvalho Chehab 
58068de959fSMauro Carvalho Chehab 			btwrite(vdelay, BT848_E_VDELAY_LO);
58168de959fSMauro Carvalho Chehab 			btwrite(crop,	BT848_E_CROP);
58268de959fSMauro Carvalho Chehab 			btwrite(vdelay, BT848_O_VDELAY_LO);
58368de959fSMauro Carvalho Chehab 			btwrite(crop,	BT848_O_CROP);
58468de959fSMauro Carvalho Chehab 		}
58568de959fSMauro Carvalho Chehab 
586c9c0df31SDeborah Brouwer 		if (btv->vbi_count[0] > 0) {
58768de959fSMauro Carvalho Chehab 			top = &vbi->top;
58868de959fSMauro Carvalho Chehab 			top_irq_flags = 4;
58968de959fSMauro Carvalho Chehab 		}
59068de959fSMauro Carvalho Chehab 
591c9c0df31SDeborah Brouwer 		if (btv->vbi_count[1] > 0) {
59268de959fSMauro Carvalho Chehab 			top_irq_flags = 0;
59368de959fSMauro Carvalho Chehab 			bottom = &vbi->bottom;
59468de959fSMauro Carvalho Chehab 			bottom_irq_flags = 4;
59568de959fSMauro Carvalho Chehab 		}
59668de959fSMauro Carvalho Chehab 	}
59768de959fSMauro Carvalho Chehab 
59868de959fSMauro Carvalho Chehab 	bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
59968de959fSMauro Carvalho Chehab 	bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
60068de959fSMauro Carvalho Chehab 
60168de959fSMauro Carvalho Chehab 	return 0;
60268de959fSMauro Carvalho Chehab }
60368de959fSMauro Carvalho Chehab 
60468de959fSMauro Carvalho Chehab int
bttv_buffer_activate_video(struct bttv * btv,struct bttv_buffer_set * set)60568de959fSMauro Carvalho Chehab bttv_buffer_activate_video(struct bttv *btv,
60668de959fSMauro Carvalho Chehab 			   struct bttv_buffer_set *set)
60768de959fSMauro Carvalho Chehab {
60868de959fSMauro Carvalho Chehab 	/* video capture */
60968de959fSMauro Carvalho Chehab 	if (NULL != set->top  &&  NULL != set->bottom) {
61068de959fSMauro Carvalho Chehab 		if (set->top == set->bottom) {
611b7ec3212SDeborah Brouwer 			if (set->top->list.next)
612b7ec3212SDeborah Brouwer 				list_del(&set->top->list);
61368de959fSMauro Carvalho Chehab 		} else {
614b7ec3212SDeborah Brouwer 			if (set->top->list.next)
615b7ec3212SDeborah Brouwer 				list_del(&set->top->list);
616b7ec3212SDeborah Brouwer 			if (set->bottom->list.next)
617b7ec3212SDeborah Brouwer 				list_del(&set->bottom->list);
61868de959fSMauro Carvalho Chehab 		}
61968de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->top->geo, 1);
62068de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->bottom->geo,0);
62168de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
62268de959fSMauro Carvalho Chehab 			       set->top_irq);
62368de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
62468de959fSMauro Carvalho Chehab 			       set->frame_irq);
62568de959fSMauro Carvalho Chehab 		btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
62668de959fSMauro Carvalho Chehab 		      ~0xff, BT848_COLOR_FMT);
62768de959fSMauro Carvalho Chehab 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
62868de959fSMauro Carvalho Chehab 		      ~0x0f, BT848_COLOR_CTL);
62968de959fSMauro Carvalho Chehab 	} else if (NULL != set->top) {
630b7ec3212SDeborah Brouwer 		if (set->top->list.next)
631b7ec3212SDeborah Brouwer 			list_del(&set->top->list);
63268de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->top->geo,1);
63368de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->top->geo,0);
63468de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
63568de959fSMauro Carvalho Chehab 			       set->frame_irq);
63668de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL,           0);
63768de959fSMauro Carvalho Chehab 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
63868de959fSMauro Carvalho Chehab 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
63968de959fSMauro Carvalho Chehab 	} else if (NULL != set->bottom) {
640b7ec3212SDeborah Brouwer 		if (set->bottom->list.next)
641b7ec3212SDeborah Brouwer 			list_del(&set->bottom->list);
64268de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->bottom->geo,1);
64368de959fSMauro Carvalho Chehab 		bttv_apply_geo(btv, &set->bottom->geo,0);
64468de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
64568de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
64668de959fSMauro Carvalho Chehab 			       set->frame_irq);
64768de959fSMauro Carvalho Chehab 		btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
64868de959fSMauro Carvalho Chehab 		btaor(set->bottom->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
64968de959fSMauro Carvalho Chehab 	} else {
65068de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
65168de959fSMauro Carvalho Chehab 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
65268de959fSMauro Carvalho Chehab 	}
65368de959fSMauro Carvalho Chehab 	return 0;
65468de959fSMauro Carvalho Chehab }
65568de959fSMauro Carvalho Chehab 
65668de959fSMauro Carvalho Chehab /* ---------------------------------------------------------- */
65768de959fSMauro Carvalho Chehab 
65868de959fSMauro Carvalho Chehab /* calculate geometry, build risc code */
65968de959fSMauro Carvalho Chehab int
bttv_buffer_risc(struct bttv * btv,struct bttv_buffer * buf)66068de959fSMauro Carvalho Chehab bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
66168de959fSMauro Carvalho Chehab {
662b7ec3212SDeborah Brouwer 	int r = 0;
66387df33beSDeborah Brouwer 	const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;
664b7ec3212SDeborah Brouwer 	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);
665b7ec3212SDeborah Brouwer 	struct scatterlist *list = sgt->sgl;
666b7ec3212SDeborah Brouwer 	unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;
66768de959fSMauro Carvalho Chehab 
66868de959fSMauro Carvalho Chehab 	/* packed pixel modes */
6699764252dSDeborah Brouwer 	if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {
670b7ec3212SDeborah Brouwer 		int bpl = (btv->fmt->depth >> 3) * btv->width;
671b7ec3212SDeborah Brouwer 		int bpf = bpl * (btv->height >> 1);
67268de959fSMauro Carvalho Chehab 
673b7ec3212SDeborah Brouwer 		bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
674b7ec3212SDeborah Brouwer 			      V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,
675b7ec3212SDeborah Brouwer 			      &btv->crop[!!btv->do_crop].rect);
676b7ec3212SDeborah Brouwer 		switch (buf->vbuf.field) {
67768de959fSMauro Carvalho Chehab 		case V4L2_FIELD_TOP:
678b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
679b7ec3212SDeborah Brouwer 					     0, btv->height);
68068de959fSMauro Carvalho Chehab 			break;
68168de959fSMauro Carvalho Chehab 		case V4L2_FIELD_BOTTOM:
682b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,
683b7ec3212SDeborah Brouwer 					     0, 0, btv->height);
68468de959fSMauro Carvalho Chehab 			break;
68568de959fSMauro Carvalho Chehab 		case V4L2_FIELD_INTERLACED:
686b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,
687b7ec3212SDeborah Brouwer 					     bpl, 0, btv->height >> 1);
688b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->bottom, list, bpl,
689b7ec3212SDeborah Brouwer 					     bpl, bpl, 0, btv->height >> 1);
69068de959fSMauro Carvalho Chehab 			break;
69168de959fSMauro Carvalho Chehab 		case V4L2_FIELD_SEQ_TB:
692b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,
693b7ec3212SDeborah Brouwer 					     0, btv->height >> 1);
694b7ec3212SDeborah Brouwer 			r = bttv_risc_packed(btv, &buf->bottom, list, bpf,
695b7ec3212SDeborah Brouwer 					     bpl, 0, 0, btv->height >> 1);
69668de959fSMauro Carvalho Chehab 			break;
69768de959fSMauro Carvalho Chehab 		default:
698615c5450SDeborah Brouwer 			WARN_ON(1);
699b7ec3212SDeborah Brouwer 			return -EINVAL;
70068de959fSMauro Carvalho Chehab 		}
70168de959fSMauro Carvalho Chehab 	}
70268de959fSMauro Carvalho Chehab 	/* planar modes */
7039764252dSDeborah Brouwer 	if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {
70468de959fSMauro Carvalho Chehab 		int uoffset, voffset;
70568de959fSMauro Carvalho Chehab 		int ypadding, cpadding, lines;
70668de959fSMauro Carvalho Chehab 
70768de959fSMauro Carvalho Chehab 		/* calculate chroma offsets */
708b7ec3212SDeborah Brouwer 		uoffset = btv->width * btv->height;
709b7ec3212SDeborah Brouwer 		voffset = btv->width * btv->height;
7109764252dSDeborah Brouwer 		if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {
71168de959fSMauro Carvalho Chehab 			/* Y-Cr-Cb plane order */
7129764252dSDeborah Brouwer 			uoffset >>= btv->fmt->hshift;
7139764252dSDeborah Brouwer 			uoffset >>= btv->fmt->vshift;
71468de959fSMauro Carvalho Chehab 			uoffset  += voffset;
71568de959fSMauro Carvalho Chehab 		} else {
71668de959fSMauro Carvalho Chehab 			/* Y-Cb-Cr plane order */
7179764252dSDeborah Brouwer 			voffset >>= btv->fmt->hshift;
7189764252dSDeborah Brouwer 			voffset >>= btv->fmt->vshift;
71968de959fSMauro Carvalho Chehab 			voffset  += uoffset;
72068de959fSMauro Carvalho Chehab 		}
721b7ec3212SDeborah Brouwer 		switch (buf->vbuf.field) {
72268de959fSMauro Carvalho Chehab 		case V4L2_FIELD_TOP:
723b7ec3212SDeborah Brouwer 			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
724b7ec3212SDeborah Brouwer 				      0, tvnorm,
725b7ec3212SDeborah Brouwer 				      &btv->crop[!!btv->do_crop].rect);
726b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->top, list, 0,
727b7ec3212SDeborah Brouwer 					     btv->width, 0, btv->height,
728b7ec3212SDeborah Brouwer 					     uoffset, voffset,
729b7ec3212SDeborah Brouwer 					     btv->fmt->hshift,
7309764252dSDeborah Brouwer 					     btv->fmt->vshift, 0);
73168de959fSMauro Carvalho Chehab 			break;
73268de959fSMauro Carvalho Chehab 		case V4L2_FIELD_BOTTOM:
733b7ec3212SDeborah Brouwer 			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
734b7ec3212SDeborah Brouwer 				      0, tvnorm,
735b7ec3212SDeborah Brouwer 				      &btv->crop[!!btv->do_crop].rect);
736b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->bottom, list, 0,
737b7ec3212SDeborah Brouwer 					     btv->width, 0, btv->height,
738b7ec3212SDeborah Brouwer 					     uoffset, voffset,
739b7ec3212SDeborah Brouwer 					     btv->fmt->hshift,
7409764252dSDeborah Brouwer 					     btv->fmt->vshift, 0);
74168de959fSMauro Carvalho Chehab 			break;
74268de959fSMauro Carvalho Chehab 		case V4L2_FIELD_INTERLACED:
743b7ec3212SDeborah Brouwer 			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
744b7ec3212SDeborah Brouwer 				      1, tvnorm,
745b7ec3212SDeborah Brouwer 				      &btv->crop[!!btv->do_crop].rect);
746b7ec3212SDeborah Brouwer 			lines = btv->height >> 1;
747b7ec3212SDeborah Brouwer 			ypadding = btv->width;
748b7ec3212SDeborah Brouwer 			cpadding = btv->width >> btv->fmt->hshift;
749b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->top, list, 0,
750b7ec3212SDeborah Brouwer 					     btv->width, ypadding, lines,
75168de959fSMauro Carvalho Chehab 					     uoffset, voffset,
7529764252dSDeborah Brouwer 					     btv->fmt->hshift,
753b7ec3212SDeborah Brouwer 					     btv->fmt->vshift, cpadding);
754b7ec3212SDeborah Brouwer 
755b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->bottom, list,
756b7ec3212SDeborah Brouwer 					     ypadding, btv->width, ypadding,
757b7ec3212SDeborah Brouwer 					     lines,  uoffset + cpadding,
75868de959fSMauro Carvalho Chehab 					     voffset + cpadding,
7599764252dSDeborah Brouwer 					     btv->fmt->hshift,
760b7ec3212SDeborah Brouwer 					     btv->fmt->vshift, cpadding);
76168de959fSMauro Carvalho Chehab 			break;
76268de959fSMauro Carvalho Chehab 		case V4L2_FIELD_SEQ_TB:
763b7ec3212SDeborah Brouwer 			bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,
764b7ec3212SDeborah Brouwer 				      1, tvnorm,
765b7ec3212SDeborah Brouwer 				      &btv->crop[!!btv->do_crop].rect);
766b7ec3212SDeborah Brouwer 			lines = btv->height >> 1;
767b7ec3212SDeborah Brouwer 			ypadding = btv->width;
768b7ec3212SDeborah Brouwer 			cpadding = btv->width >> btv->fmt->hshift;
769b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->top, list, 0,
770b7ec3212SDeborah Brouwer 					     btv->width, 0, lines,
771b7ec3212SDeborah Brouwer 					     uoffset >> 1, voffset >> 1,
7729764252dSDeborah Brouwer 					     btv->fmt->hshift,
773b7ec3212SDeborah Brouwer 					     btv->fmt->vshift, 0);
774b7ec3212SDeborah Brouwer 			r = bttv_risc_planar(btv, &buf->bottom, list,
775b7ec3212SDeborah Brouwer 					     lines * ypadding,
776b7ec3212SDeborah Brouwer 					     btv->width, 0, lines,
77768de959fSMauro Carvalho Chehab 					     lines * ypadding + (uoffset >> 1),
77868de959fSMauro Carvalho Chehab 					     lines * ypadding + (voffset >> 1),
7799764252dSDeborah Brouwer 					     btv->fmt->hshift,
780b7ec3212SDeborah Brouwer 					     btv->fmt->vshift, 0);
78168de959fSMauro Carvalho Chehab 			break;
78268de959fSMauro Carvalho Chehab 		default:
783615c5450SDeborah Brouwer 			WARN_ON(1);
784b7ec3212SDeborah Brouwer 			return -EINVAL;
78568de959fSMauro Carvalho Chehab 		}
78668de959fSMauro Carvalho Chehab 	}
78768de959fSMauro Carvalho Chehab 	/* raw data */
7889764252dSDeborah Brouwer 	if (btv->fmt->flags & FORMAT_FLAGS_RAW) {
78968de959fSMauro Carvalho Chehab 		/* build risc code */
790b7ec3212SDeborah Brouwer 		buf->vbuf.field = V4L2_FIELD_SEQ_TB;
79168de959fSMauro Carvalho Chehab 		bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,
7920f5f12e4SDeborah Brouwer 			      1, tvnorm, &btv->crop[!!btv->do_crop].rect);
793b7ec3212SDeborah Brouwer 		r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,
794b7ec3212SDeborah Brouwer 				     RAW_LINES);
795b7ec3212SDeborah Brouwer 		r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,
796b7ec3212SDeborah Brouwer 				     RAW_BPL, 0, 0, RAW_LINES);
79768de959fSMauro Carvalho Chehab 	}
79868de959fSMauro Carvalho Chehab 
79968de959fSMauro Carvalho Chehab 	/* copy format info */
8009764252dSDeborah Brouwer 	buf->btformat = btv->fmt->btformat;
8019764252dSDeborah Brouwer 	buf->btswap   = btv->fmt->btswap;
802b7ec3212SDeborah Brouwer 
803b7ec3212SDeborah Brouwer 	return r;
80468de959fSMauro Carvalho Chehab }
805