xref: /OK3568_Linux_fs/kernel/drivers/media/pci/bt8xx/bttv-risc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun     bttv-risc.c  --  interfaces to other kernel modules
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun     bttv risc code handling
7*4882a593Smuzhiyun 	- memory management
8*4882a593Smuzhiyun 	- generation
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun     (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/init.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/pci.h>
21*4882a593Smuzhiyun #include <linux/vmalloc.h>
22*4882a593Smuzhiyun #include <linux/interrupt.h>
23*4882a593Smuzhiyun #include <linux/pgtable.h>
24*4882a593Smuzhiyun #include <asm/page.h>
25*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "bttvp.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define VCR_HACK_LINES 4
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* ---------------------------------------------------------- */
32*4882a593Smuzhiyun /* risc code generators                                       */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 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)35*4882a593Smuzhiyun bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
36*4882a593Smuzhiyun 		 struct scatterlist *sglist,
37*4882a593Smuzhiyun 		 unsigned int offset, unsigned int bpl,
38*4882a593Smuzhiyun 		 unsigned int padding, unsigned int skip_lines,
39*4882a593Smuzhiyun 		 unsigned int store_lines)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	u32 instructions,line,todo;
42*4882a593Smuzhiyun 	struct scatterlist *sg;
43*4882a593Smuzhiyun 	__le32 *rp;
44*4882a593Smuzhiyun 	int rc;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/* estimate risc mem: worst case is one write per page border +
47*4882a593Smuzhiyun 	   one write per scan line + sync + jump (all 2 dwords).  padding
48*4882a593Smuzhiyun 	   can cause next bpl to start close to a page border.  First DMA
49*4882a593Smuzhiyun 	   region may be smaller than PAGE_SIZE */
50*4882a593Smuzhiyun 	instructions  = skip_lines * 4;
51*4882a593Smuzhiyun 	instructions += (1 + ((bpl + padding) * store_lines)
52*4882a593Smuzhiyun 			 / PAGE_SIZE + store_lines) * 8;
53*4882a593Smuzhiyun 	instructions += 2 * 8;
54*4882a593Smuzhiyun 	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
55*4882a593Smuzhiyun 		return rc;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* sync instruction */
58*4882a593Smuzhiyun 	rp = risc->cpu;
59*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
60*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(0);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	while (skip_lines-- > 0) {
63*4882a593Smuzhiyun 		*(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
64*4882a593Smuzhiyun 				      BT848_RISC_EOL | bpl);
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	/* scan lines */
68*4882a593Smuzhiyun 	sg = sglist;
69*4882a593Smuzhiyun 	for (line = 0; line < store_lines; line++) {
70*4882a593Smuzhiyun 		if ((btv->opt_vcr_hack) &&
71*4882a593Smuzhiyun 		    (line >= (store_lines - VCR_HACK_LINES)))
72*4882a593Smuzhiyun 			continue;
73*4882a593Smuzhiyun 		while (offset && offset >= sg_dma_len(sg)) {
74*4882a593Smuzhiyun 			offset -= sg_dma_len(sg);
75*4882a593Smuzhiyun 			sg = sg_next(sg);
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 		if (bpl <= sg_dma_len(sg)-offset) {
78*4882a593Smuzhiyun 			/* fits into current chunk */
79*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
80*4882a593Smuzhiyun 					    BT848_RISC_EOL|bpl);
81*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
82*4882a593Smuzhiyun 			offset+=bpl;
83*4882a593Smuzhiyun 		} else {
84*4882a593Smuzhiyun 			/* scanline needs to be split */
85*4882a593Smuzhiyun 			todo = bpl;
86*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
87*4882a593Smuzhiyun 					    (sg_dma_len(sg)-offset));
88*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
89*4882a593Smuzhiyun 			todo -= (sg_dma_len(sg)-offset);
90*4882a593Smuzhiyun 			offset = 0;
91*4882a593Smuzhiyun 			sg = sg_next(sg);
92*4882a593Smuzhiyun 			while (todo > sg_dma_len(sg)) {
93*4882a593Smuzhiyun 				*(rp++)=cpu_to_le32(BT848_RISC_WRITE|
94*4882a593Smuzhiyun 						    sg_dma_len(sg));
95*4882a593Smuzhiyun 				*(rp++)=cpu_to_le32(sg_dma_address(sg));
96*4882a593Smuzhiyun 				todo -= sg_dma_len(sg);
97*4882a593Smuzhiyun 				sg = sg_next(sg);
98*4882a593Smuzhiyun 			}
99*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
100*4882a593Smuzhiyun 					    todo);
101*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(sg_dma_address(sg));
102*4882a593Smuzhiyun 			offset += todo;
103*4882a593Smuzhiyun 		}
104*4882a593Smuzhiyun 		offset += padding;
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* save pointer to jmp instruction address */
108*4882a593Smuzhiyun 	risc->jmp = rp;
109*4882a593Smuzhiyun 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
110*4882a593Smuzhiyun 	return 0;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 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)114*4882a593Smuzhiyun bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
115*4882a593Smuzhiyun 		 struct scatterlist *sglist,
116*4882a593Smuzhiyun 		 unsigned int yoffset,  unsigned int ybpl,
117*4882a593Smuzhiyun 		 unsigned int ypadding, unsigned int ylines,
118*4882a593Smuzhiyun 		 unsigned int uoffset,  unsigned int voffset,
119*4882a593Smuzhiyun 		 unsigned int hshift,   unsigned int vshift,
120*4882a593Smuzhiyun 		 unsigned int cpadding)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	unsigned int instructions,line,todo,ylen,chroma;
123*4882a593Smuzhiyun 	__le32 *rp;
124*4882a593Smuzhiyun 	u32 ri;
125*4882a593Smuzhiyun 	struct scatterlist *ysg;
126*4882a593Smuzhiyun 	struct scatterlist *usg;
127*4882a593Smuzhiyun 	struct scatterlist *vsg;
128*4882a593Smuzhiyun 	int topfield = (0 == yoffset);
129*4882a593Smuzhiyun 	int rc;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* estimate risc mem: worst case is one write per page border +
132*4882a593Smuzhiyun 	   one write per scan line (5 dwords)
133*4882a593Smuzhiyun 	   plus sync + jump (2 dwords) */
134*4882a593Smuzhiyun 	instructions  = ((3 + (ybpl + ypadding) * ylines * 2)
135*4882a593Smuzhiyun 			 / PAGE_SIZE) + ylines;
136*4882a593Smuzhiyun 	instructions += 2;
137*4882a593Smuzhiyun 	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
138*4882a593Smuzhiyun 		return rc;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* sync instruction */
141*4882a593Smuzhiyun 	rp = risc->cpu;
142*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
143*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(0);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	/* scan lines */
146*4882a593Smuzhiyun 	ysg = sglist;
147*4882a593Smuzhiyun 	usg = sglist;
148*4882a593Smuzhiyun 	vsg = sglist;
149*4882a593Smuzhiyun 	for (line = 0; line < ylines; line++) {
150*4882a593Smuzhiyun 		if ((btv->opt_vcr_hack) &&
151*4882a593Smuzhiyun 		    (line >= (ylines - VCR_HACK_LINES)))
152*4882a593Smuzhiyun 			continue;
153*4882a593Smuzhiyun 		switch (vshift) {
154*4882a593Smuzhiyun 		case 0:
155*4882a593Smuzhiyun 			chroma = 1;
156*4882a593Smuzhiyun 			break;
157*4882a593Smuzhiyun 		case 1:
158*4882a593Smuzhiyun 			if (topfield)
159*4882a593Smuzhiyun 				chroma = ((line & 1) == 0);
160*4882a593Smuzhiyun 			else
161*4882a593Smuzhiyun 				chroma = ((line & 1) == 1);
162*4882a593Smuzhiyun 			break;
163*4882a593Smuzhiyun 		case 2:
164*4882a593Smuzhiyun 			if (topfield)
165*4882a593Smuzhiyun 				chroma = ((line & 3) == 0);
166*4882a593Smuzhiyun 			else
167*4882a593Smuzhiyun 				chroma = ((line & 3) == 2);
168*4882a593Smuzhiyun 			break;
169*4882a593Smuzhiyun 		default:
170*4882a593Smuzhiyun 			chroma = 0;
171*4882a593Smuzhiyun 			break;
172*4882a593Smuzhiyun 		}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		for (todo = ybpl; todo > 0; todo -= ylen) {
175*4882a593Smuzhiyun 			/* go to next sg entry if needed */
176*4882a593Smuzhiyun 			while (yoffset && yoffset >= sg_dma_len(ysg)) {
177*4882a593Smuzhiyun 				yoffset -= sg_dma_len(ysg);
178*4882a593Smuzhiyun 				ysg = sg_next(ysg);
179*4882a593Smuzhiyun 			}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 			/* calculate max number of bytes we can write */
182*4882a593Smuzhiyun 			ylen = todo;
183*4882a593Smuzhiyun 			if (yoffset + ylen > sg_dma_len(ysg))
184*4882a593Smuzhiyun 				ylen = sg_dma_len(ysg) - yoffset;
185*4882a593Smuzhiyun 			if (chroma) {
186*4882a593Smuzhiyun 				while (uoffset && uoffset >= sg_dma_len(usg)) {
187*4882a593Smuzhiyun 					uoffset -= sg_dma_len(usg);
188*4882a593Smuzhiyun 					usg = sg_next(usg);
189*4882a593Smuzhiyun 				}
190*4882a593Smuzhiyun 				while (voffset && voffset >= sg_dma_len(vsg)) {
191*4882a593Smuzhiyun 					voffset -= sg_dma_len(vsg);
192*4882a593Smuzhiyun 					vsg = sg_next(vsg);
193*4882a593Smuzhiyun 				}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 				if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
196*4882a593Smuzhiyun 					ylen = (sg_dma_len(usg) - uoffset) << hshift;
197*4882a593Smuzhiyun 				if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
198*4882a593Smuzhiyun 					ylen = (sg_dma_len(vsg) - voffset) << hshift;
199*4882a593Smuzhiyun 				ri = BT848_RISC_WRITE123;
200*4882a593Smuzhiyun 			} else {
201*4882a593Smuzhiyun 				ri = BT848_RISC_WRITE1S23;
202*4882a593Smuzhiyun 			}
203*4882a593Smuzhiyun 			if (ybpl == todo)
204*4882a593Smuzhiyun 				ri |= BT848_RISC_SOL;
205*4882a593Smuzhiyun 			if (ylen == todo)
206*4882a593Smuzhiyun 				ri |= BT848_RISC_EOL;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 			/* write risc instruction */
209*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(ri | ylen);
210*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
211*4882a593Smuzhiyun 					    (ylen >> hshift));
212*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
213*4882a593Smuzhiyun 			yoffset += ylen;
214*4882a593Smuzhiyun 			if (chroma) {
215*4882a593Smuzhiyun 				*(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
216*4882a593Smuzhiyun 				uoffset += ylen >> hshift;
217*4882a593Smuzhiyun 				*(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
218*4882a593Smuzhiyun 				voffset += ylen >> hshift;
219*4882a593Smuzhiyun 			}
220*4882a593Smuzhiyun 		}
221*4882a593Smuzhiyun 		yoffset += ypadding;
222*4882a593Smuzhiyun 		if (chroma) {
223*4882a593Smuzhiyun 			uoffset += cpadding;
224*4882a593Smuzhiyun 			voffset += cpadding;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/* save pointer to jmp instruction address */
229*4882a593Smuzhiyun 	risc->jmp = rp;
230*4882a593Smuzhiyun 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun static int
bttv_risc_overlay(struct bttv * btv,struct btcx_riscmem * risc,const struct bttv_format * fmt,struct bttv_overlay * ov,int skip_even,int skip_odd)235*4882a593Smuzhiyun bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
236*4882a593Smuzhiyun 		  const struct bttv_format *fmt, struct bttv_overlay *ov,
237*4882a593Smuzhiyun 		  int skip_even, int skip_odd)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	int dwords, rc, line, maxy, start, end;
240*4882a593Smuzhiyun 	unsigned skip, nskips;
241*4882a593Smuzhiyun 	struct btcx_skiplist *skips;
242*4882a593Smuzhiyun 	__le32 *rp;
243*4882a593Smuzhiyun 	u32 ri,ra;
244*4882a593Smuzhiyun 	u32 addr;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* skip list for window clipping */
247*4882a593Smuzhiyun 	skips = kmalloc_array(ov->nclips, sizeof(*skips),GFP_KERNEL);
248*4882a593Smuzhiyun 	if (NULL == skips)
249*4882a593Smuzhiyun 		return -ENOMEM;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
252*4882a593Smuzhiyun 	   + sync + jump (all 2 dwords) */
253*4882a593Smuzhiyun 	dwords  = (3 * ov->nclips + 2) *
254*4882a593Smuzhiyun 		((skip_even || skip_odd) ? (ov->w.height+1)>>1 :  ov->w.height);
255*4882a593Smuzhiyun 	dwords += 4;
256*4882a593Smuzhiyun 	if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
257*4882a593Smuzhiyun 		kfree(skips);
258*4882a593Smuzhiyun 		return rc;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	/* sync instruction */
262*4882a593Smuzhiyun 	rp = risc->cpu;
263*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
264*4882a593Smuzhiyun 	*(rp++) = cpu_to_le32(0);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	addr  = (unsigned long)btv->fbuf.base;
267*4882a593Smuzhiyun 	addr += btv->fbuf.fmt.bytesperline * ov->w.top;
268*4882a593Smuzhiyun 	addr += (fmt->depth >> 3)          * ov->w.left;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	/* scan lines */
271*4882a593Smuzhiyun 	for (maxy = -1, line = 0; line < ov->w.height;
272*4882a593Smuzhiyun 	     line++, addr += btv->fbuf.fmt.bytesperline) {
273*4882a593Smuzhiyun 		if ((btv->opt_vcr_hack) &&
274*4882a593Smuzhiyun 		     (line >= (ov->w.height - VCR_HACK_LINES)))
275*4882a593Smuzhiyun 			continue;
276*4882a593Smuzhiyun 		if ((line%2) == 0  &&  skip_even)
277*4882a593Smuzhiyun 			continue;
278*4882a593Smuzhiyun 		if ((line%2) == 1  &&  skip_odd)
279*4882a593Smuzhiyun 			continue;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 		/* calculate clipping */
282*4882a593Smuzhiyun 		if (line > maxy)
283*4882a593Smuzhiyun 			btcx_calc_skips(line, ov->w.width, &maxy,
284*4882a593Smuzhiyun 					skips, &nskips, ov->clips, ov->nclips);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		/* write out risc code */
287*4882a593Smuzhiyun 		for (start = 0, skip = 0; start < ov->w.width; start = end) {
288*4882a593Smuzhiyun 			if (skip >= nskips) {
289*4882a593Smuzhiyun 				ri  = BT848_RISC_WRITE;
290*4882a593Smuzhiyun 				end = ov->w.width;
291*4882a593Smuzhiyun 			} else if (start < skips[skip].start) {
292*4882a593Smuzhiyun 				ri  = BT848_RISC_WRITE;
293*4882a593Smuzhiyun 				end = skips[skip].start;
294*4882a593Smuzhiyun 			} else {
295*4882a593Smuzhiyun 				ri  = BT848_RISC_SKIP;
296*4882a593Smuzhiyun 				end = skips[skip].end;
297*4882a593Smuzhiyun 				skip++;
298*4882a593Smuzhiyun 			}
299*4882a593Smuzhiyun 			if (BT848_RISC_WRITE == ri)
300*4882a593Smuzhiyun 				ra = addr + (fmt->depth>>3)*start;
301*4882a593Smuzhiyun 			else
302*4882a593Smuzhiyun 				ra = 0;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 			if (0 == start)
305*4882a593Smuzhiyun 				ri |= BT848_RISC_SOL;
306*4882a593Smuzhiyun 			if (ov->w.width == end)
307*4882a593Smuzhiyun 				ri |= BT848_RISC_EOL;
308*4882a593Smuzhiyun 			ri |= (fmt->depth>>3) * (end-start);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 			*(rp++)=cpu_to_le32(ri);
311*4882a593Smuzhiyun 			if (0 != ra)
312*4882a593Smuzhiyun 				*(rp++)=cpu_to_le32(ra);
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	/* save pointer to jmp instruction address */
317*4882a593Smuzhiyun 	risc->jmp = rp;
318*4882a593Smuzhiyun 	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
319*4882a593Smuzhiyun 	kfree(skips);
320*4882a593Smuzhiyun 	return 0;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /* ---------------------------------------------------------- */
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun static void
bttv_calc_geo_old(struct bttv * btv,struct bttv_geometry * geo,int width,int height,int interleaved,const struct bttv_tvnorm * tvnorm)326*4882a593Smuzhiyun bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
327*4882a593Smuzhiyun 		  int width, int height, int interleaved,
328*4882a593Smuzhiyun 		  const struct bttv_tvnorm *tvnorm)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	u32 xsf, sr;
331*4882a593Smuzhiyun 	int vdelay;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	int swidth       = tvnorm->swidth;
334*4882a593Smuzhiyun 	int totalwidth   = tvnorm->totalwidth;
335*4882a593Smuzhiyun 	int scaledtwidth = tvnorm->scaledtwidth;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	if (btv->input == btv->dig) {
338*4882a593Smuzhiyun 		swidth       = 720;
339*4882a593Smuzhiyun 		totalwidth   = 858;
340*4882a593Smuzhiyun 		scaledtwidth = 858;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	vdelay = tvnorm->vdelay;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	xsf = (width*scaledtwidth)/swidth;
346*4882a593Smuzhiyun 	geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
347*4882a593Smuzhiyun 	geo->hdelay =  tvnorm->hdelayx1;
348*4882a593Smuzhiyun 	geo->hdelay =  (geo->hdelay*width)/swidth;
349*4882a593Smuzhiyun 	geo->hdelay &= 0x3fe;
350*4882a593Smuzhiyun 	sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
351*4882a593Smuzhiyun 	geo->vscale =  (0x10000UL-sr) & 0x1fff;
352*4882a593Smuzhiyun 	geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
353*4882a593Smuzhiyun 		((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
354*4882a593Smuzhiyun 	geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
355*4882a593Smuzhiyun 	geo->vdelay  =  vdelay;
356*4882a593Smuzhiyun 	geo->width   =  width;
357*4882a593Smuzhiyun 	geo->sheight =  tvnorm->sheight;
358*4882a593Smuzhiyun 	geo->vtotal  =  tvnorm->vtotal;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (btv->opt_combfilter) {
361*4882a593Smuzhiyun 		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
362*4882a593Smuzhiyun 		geo->comb = (width < 769) ? 1 : 0;
363*4882a593Smuzhiyun 	} else {
364*4882a593Smuzhiyun 		geo->vtc  = 0;
365*4882a593Smuzhiyun 		geo->comb = 0;
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 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)370*4882a593Smuzhiyun bttv_calc_geo		(struct bttv *                  btv,
371*4882a593Smuzhiyun 			 struct bttv_geometry *         geo,
372*4882a593Smuzhiyun 			 unsigned int                   width,
373*4882a593Smuzhiyun 			 unsigned int                   height,
374*4882a593Smuzhiyun 			 int                            both_fields,
375*4882a593Smuzhiyun 			 const struct bttv_tvnorm *     tvnorm,
376*4882a593Smuzhiyun 			 const struct v4l2_rect *       crop)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	unsigned int c_width;
379*4882a593Smuzhiyun 	unsigned int c_height;
380*4882a593Smuzhiyun 	u32 sr;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	if ((crop->left == tvnorm->cropcap.defrect.left
383*4882a593Smuzhiyun 	     && crop->top == tvnorm->cropcap.defrect.top
384*4882a593Smuzhiyun 	     && crop->width == tvnorm->cropcap.defrect.width
385*4882a593Smuzhiyun 	     && crop->height == tvnorm->cropcap.defrect.height
386*4882a593Smuzhiyun 	     && width <= tvnorm->swidth /* see PAL-Nc et al */)
387*4882a593Smuzhiyun 	    || btv->input == btv->dig) {
388*4882a593Smuzhiyun 		bttv_calc_geo_old(btv, geo, width, height,
389*4882a593Smuzhiyun 				  both_fields, tvnorm);
390*4882a593Smuzhiyun 		return;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/* For bug compatibility the image size checks permit scale
394*4882a593Smuzhiyun 	   factors > 16. See bttv_crop_calc_limits(). */
395*4882a593Smuzhiyun 	c_width = min((unsigned int) crop->width, width * 16);
396*4882a593Smuzhiyun 	c_height = min((unsigned int) crop->height, height * 16);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	geo->width = width;
399*4882a593Smuzhiyun 	geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
400*4882a593Smuzhiyun 	/* Even to store Cb first, odd for Cr. */
401*4882a593Smuzhiyun 	geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	geo->sheight = c_height;
404*4882a593Smuzhiyun 	geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
405*4882a593Smuzhiyun 	sr = c_height >> !both_fields;
406*4882a593Smuzhiyun 	sr = (sr * 512U + (height >> 1)) / height - 512;
407*4882a593Smuzhiyun 	geo->vscale = (0x10000UL - sr) & 0x1fff;
408*4882a593Smuzhiyun 	geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
409*4882a593Smuzhiyun 	geo->vtotal = tvnorm->vtotal;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	geo->crop = (((geo->width   >> 8) & 0x03) |
412*4882a593Smuzhiyun 		     ((geo->hdelay  >> 6) & 0x0c) |
413*4882a593Smuzhiyun 		     ((geo->sheight >> 4) & 0x30) |
414*4882a593Smuzhiyun 		     ((geo->vdelay  >> 2) & 0xc0));
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	if (btv->opt_combfilter) {
417*4882a593Smuzhiyun 		geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
418*4882a593Smuzhiyun 		geo->comb = (width < 769) ? 1 : 0;
419*4882a593Smuzhiyun 	} else {
420*4882a593Smuzhiyun 		geo->vtc  = 0;
421*4882a593Smuzhiyun 		geo->comb = 0;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun static void
bttv_apply_geo(struct bttv * btv,struct bttv_geometry * geo,int odd)426*4882a593Smuzhiyun bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	int off = odd ? 0x80 : 0x00;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (geo->comb)
431*4882a593Smuzhiyun 		btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
432*4882a593Smuzhiyun 	else
433*4882a593Smuzhiyun 		btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	btwrite(geo->vtc,             BT848_E_VTC+off);
436*4882a593Smuzhiyun 	btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
437*4882a593Smuzhiyun 	btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
438*4882a593Smuzhiyun 	btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
439*4882a593Smuzhiyun 	btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
440*4882a593Smuzhiyun 	btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
441*4882a593Smuzhiyun 	btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
442*4882a593Smuzhiyun 	btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
443*4882a593Smuzhiyun 	btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
444*4882a593Smuzhiyun 	btwrite(geo->crop,            BT848_E_CROP+off);
445*4882a593Smuzhiyun 	btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
446*4882a593Smuzhiyun 	btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /* ---------------------------------------------------------- */
450*4882a593Smuzhiyun /* risc group / risc main loop / dma management               */
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun void
bttv_set_dma(struct bttv * btv,int override)453*4882a593Smuzhiyun bttv_set_dma(struct bttv *btv, int override)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	unsigned long cmd;
456*4882a593Smuzhiyun 	int capctl;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	btv->cap_ctl = 0;
459*4882a593Smuzhiyun 	if (NULL != btv->curr.top)      btv->cap_ctl |= 0x02;
460*4882a593Smuzhiyun 	if (NULL != btv->curr.bottom)   btv->cap_ctl |= 0x01;
461*4882a593Smuzhiyun 	if (NULL != btv->cvbi)          btv->cap_ctl |= 0x0c;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	capctl  = 0;
464*4882a593Smuzhiyun 	capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00;  /* capture  */
465*4882a593Smuzhiyun 	capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00;  /* vbi data */
466*4882a593Smuzhiyun 	capctl |= override;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",
469*4882a593Smuzhiyun 		 btv->c.nr,capctl,btv->loop_irq,
470*4882a593Smuzhiyun 		 btv->cvbi         ? (unsigned long long)btv->cvbi->top.dma            : 0,
471*4882a593Smuzhiyun 		 btv->curr.top     ? (unsigned long long)btv->curr.top->top.dma        : 0,
472*4882a593Smuzhiyun 		 btv->cvbi         ? (unsigned long long)btv->cvbi->bottom.dma         : 0,
473*4882a593Smuzhiyun 		 btv->curr.bottom  ? (unsigned long long)btv->curr.bottom->bottom.dma  : 0);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	cmd = BT848_RISC_JUMP;
476*4882a593Smuzhiyun 	if (btv->loop_irq) {
477*4882a593Smuzhiyun 		cmd |= BT848_RISC_IRQ;
478*4882a593Smuzhiyun 		cmd |= (btv->loop_irq  & 0x0f) << 16;
479*4882a593Smuzhiyun 		cmd |= (~btv->loop_irq & 0x0f) << 20;
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 	if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
482*4882a593Smuzhiyun 		mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
483*4882a593Smuzhiyun 	} else {
484*4882a593Smuzhiyun 		del_timer(&btv->timeout);
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	btaor(capctl, ~0x0f, BT848_CAP_CTL);
489*4882a593Smuzhiyun 	if (capctl) {
490*4882a593Smuzhiyun 		if (btv->dma_on)
491*4882a593Smuzhiyun 			return;
492*4882a593Smuzhiyun 		btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
493*4882a593Smuzhiyun 		btor(3, BT848_GPIO_DMA_CTL);
494*4882a593Smuzhiyun 		btv->dma_on = 1;
495*4882a593Smuzhiyun 	} else {
496*4882a593Smuzhiyun 		if (!btv->dma_on)
497*4882a593Smuzhiyun 			return;
498*4882a593Smuzhiyun 		btand(~3, BT848_GPIO_DMA_CTL);
499*4882a593Smuzhiyun 		btv->dma_on = 0;
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 	return;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun int
bttv_risc_init_main(struct bttv * btv)505*4882a593Smuzhiyun bttv_risc_init_main(struct bttv *btv)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	int rc;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
510*4882a593Smuzhiyun 		return rc;
511*4882a593Smuzhiyun 	dprintk("%d: risc main @ %08llx\n",
512*4882a593Smuzhiyun 		btv->c.nr, (unsigned long long)btv->main.dma);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
515*4882a593Smuzhiyun 				       BT848_FIFO_STATUS_VRE);
516*4882a593Smuzhiyun 	btv->main.cpu[1] = cpu_to_le32(0);
517*4882a593Smuzhiyun 	btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
518*4882a593Smuzhiyun 	btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* top field */
521*4882a593Smuzhiyun 	btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
522*4882a593Smuzhiyun 	btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
523*4882a593Smuzhiyun 	btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
524*4882a593Smuzhiyun 	btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
527*4882a593Smuzhiyun 				       BT848_FIFO_STATUS_VRO);
528*4882a593Smuzhiyun 	btv->main.cpu[9] = cpu_to_le32(0);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	/* bottom field */
531*4882a593Smuzhiyun 	btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
532*4882a593Smuzhiyun 	btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
533*4882a593Smuzhiyun 	btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
534*4882a593Smuzhiyun 	btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	/* jump back to top field */
537*4882a593Smuzhiyun 	btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
538*4882a593Smuzhiyun 	btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun int
bttv_risc_hook(struct bttv * btv,int slot,struct btcx_riscmem * risc,int irqflags)544*4882a593Smuzhiyun bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
545*4882a593Smuzhiyun 	       int irqflags)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	unsigned long cmd;
548*4882a593Smuzhiyun 	unsigned long next = btv->main.dma + ((slot+2) << 2);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	if (NULL == risc) {
551*4882a593Smuzhiyun 		d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot);
552*4882a593Smuzhiyun 		btv->main.cpu[slot+1] = cpu_to_le32(next);
553*4882a593Smuzhiyun 	} else {
554*4882a593Smuzhiyun 		d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n",
555*4882a593Smuzhiyun 			 btv->c.nr, risc, slot,
556*4882a593Smuzhiyun 			 (unsigned long long)risc->dma, irqflags);
557*4882a593Smuzhiyun 		cmd = BT848_RISC_JUMP;
558*4882a593Smuzhiyun 		if (irqflags) {
559*4882a593Smuzhiyun 			cmd |= BT848_RISC_IRQ;
560*4882a593Smuzhiyun 			cmd |= (irqflags  & 0x0f) << 16;
561*4882a593Smuzhiyun 			cmd |= (~irqflags & 0x0f) << 20;
562*4882a593Smuzhiyun 		}
563*4882a593Smuzhiyun 		risc->jmp[0] = cpu_to_le32(cmd);
564*4882a593Smuzhiyun 		risc->jmp[1] = cpu_to_le32(next);
565*4882a593Smuzhiyun 		btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 	return 0;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun void
bttv_dma_free(struct videobuf_queue * q,struct bttv * btv,struct bttv_buffer * buf)571*4882a593Smuzhiyun bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	BUG_ON(in_interrupt());
576*4882a593Smuzhiyun 	videobuf_waiton(q, &buf->vb, 0, 0);
577*4882a593Smuzhiyun 	videobuf_dma_unmap(q->dev, dma);
578*4882a593Smuzhiyun 	videobuf_dma_free(dma);
579*4882a593Smuzhiyun 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
580*4882a593Smuzhiyun 	btcx_riscmem_free(btv->c.pci,&buf->top);
581*4882a593Smuzhiyun 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun int
bttv_buffer_activate_vbi(struct bttv * btv,struct bttv_buffer * vbi)585*4882a593Smuzhiyun bttv_buffer_activate_vbi(struct bttv *btv,
586*4882a593Smuzhiyun 			 struct bttv_buffer *vbi)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun 	struct btcx_riscmem *top;
589*4882a593Smuzhiyun 	struct btcx_riscmem *bottom;
590*4882a593Smuzhiyun 	int top_irq_flags;
591*4882a593Smuzhiyun 	int bottom_irq_flags;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	top = NULL;
594*4882a593Smuzhiyun 	bottom = NULL;
595*4882a593Smuzhiyun 	top_irq_flags = 0;
596*4882a593Smuzhiyun 	bottom_irq_flags = 0;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (vbi) {
599*4882a593Smuzhiyun 		unsigned int crop, vdelay;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 		vbi->vb.state = VIDEOBUF_ACTIVE;
602*4882a593Smuzhiyun 		list_del(&vbi->vb.queue);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 		/* VDELAY is start of video, end of VBI capturing. */
605*4882a593Smuzhiyun 		crop = btread(BT848_E_CROP);
606*4882a593Smuzhiyun 		vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 		if (vbi->geo.vdelay > vdelay) {
609*4882a593Smuzhiyun 			vdelay = vbi->geo.vdelay & 0xfe;
610*4882a593Smuzhiyun 			crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 			btwrite(vdelay, BT848_E_VDELAY_LO);
613*4882a593Smuzhiyun 			btwrite(crop,	BT848_E_CROP);
614*4882a593Smuzhiyun 			btwrite(vdelay, BT848_O_VDELAY_LO);
615*4882a593Smuzhiyun 			btwrite(crop,	BT848_O_CROP);
616*4882a593Smuzhiyun 		}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 		if (vbi->vbi_count[0] > 0) {
619*4882a593Smuzhiyun 			top = &vbi->top;
620*4882a593Smuzhiyun 			top_irq_flags = 4;
621*4882a593Smuzhiyun 		}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 		if (vbi->vbi_count[1] > 0) {
624*4882a593Smuzhiyun 			top_irq_flags = 0;
625*4882a593Smuzhiyun 			bottom = &vbi->bottom;
626*4882a593Smuzhiyun 			bottom_irq_flags = 4;
627*4882a593Smuzhiyun 		}
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
631*4882a593Smuzhiyun 	bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	return 0;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun int
bttv_buffer_activate_video(struct bttv * btv,struct bttv_buffer_set * set)637*4882a593Smuzhiyun bttv_buffer_activate_video(struct bttv *btv,
638*4882a593Smuzhiyun 			   struct bttv_buffer_set *set)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	/* video capture */
641*4882a593Smuzhiyun 	if (NULL != set->top  &&  NULL != set->bottom) {
642*4882a593Smuzhiyun 		if (set->top == set->bottom) {
643*4882a593Smuzhiyun 			set->top->vb.state    = VIDEOBUF_ACTIVE;
644*4882a593Smuzhiyun 			if (set->top->vb.queue.next)
645*4882a593Smuzhiyun 				list_del(&set->top->vb.queue);
646*4882a593Smuzhiyun 		} else {
647*4882a593Smuzhiyun 			set->top->vb.state    = VIDEOBUF_ACTIVE;
648*4882a593Smuzhiyun 			set->bottom->vb.state = VIDEOBUF_ACTIVE;
649*4882a593Smuzhiyun 			if (set->top->vb.queue.next)
650*4882a593Smuzhiyun 				list_del(&set->top->vb.queue);
651*4882a593Smuzhiyun 			if (set->bottom->vb.queue.next)
652*4882a593Smuzhiyun 				list_del(&set->bottom->vb.queue);
653*4882a593Smuzhiyun 		}
654*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->top->geo, 1);
655*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->bottom->geo,0);
656*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
657*4882a593Smuzhiyun 			       set->top_irq);
658*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
659*4882a593Smuzhiyun 			       set->frame_irq);
660*4882a593Smuzhiyun 		btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
661*4882a593Smuzhiyun 		      ~0xff, BT848_COLOR_FMT);
662*4882a593Smuzhiyun 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
663*4882a593Smuzhiyun 		      ~0x0f, BT848_COLOR_CTL);
664*4882a593Smuzhiyun 	} else if (NULL != set->top) {
665*4882a593Smuzhiyun 		set->top->vb.state  = VIDEOBUF_ACTIVE;
666*4882a593Smuzhiyun 		if (set->top->vb.queue.next)
667*4882a593Smuzhiyun 			list_del(&set->top->vb.queue);
668*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->top->geo,1);
669*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->top->geo,0);
670*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
671*4882a593Smuzhiyun 			       set->frame_irq);
672*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL,           0);
673*4882a593Smuzhiyun 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
674*4882a593Smuzhiyun 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
675*4882a593Smuzhiyun 	} else if (NULL != set->bottom) {
676*4882a593Smuzhiyun 		set->bottom->vb.state = VIDEOBUF_ACTIVE;
677*4882a593Smuzhiyun 		if (set->bottom->vb.queue.next)
678*4882a593Smuzhiyun 			list_del(&set->bottom->vb.queue);
679*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->bottom->geo,1);
680*4882a593Smuzhiyun 		bttv_apply_geo(btv, &set->bottom->geo,0);
681*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
682*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
683*4882a593Smuzhiyun 			       set->frame_irq);
684*4882a593Smuzhiyun 		btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
685*4882a593Smuzhiyun 		btaor(set->bottom->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
686*4882a593Smuzhiyun 	} else {
687*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
688*4882a593Smuzhiyun 		bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 	return 0;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun /* ---------------------------------------------------------- */
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun /* calculate geometry, build risc code */
696*4882a593Smuzhiyun int
bttv_buffer_risc(struct bttv * btv,struct bttv_buffer * buf)697*4882a593Smuzhiyun bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun 	const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
700*4882a593Smuzhiyun 	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	dprintk("%d: buffer field: %s  format: 0x%08x  size: %dx%d\n",
703*4882a593Smuzhiyun 		btv->c.nr, v4l2_field_names[buf->vb.field],
704*4882a593Smuzhiyun 		buf->fmt->fourcc, buf->vb.width, buf->vb.height);
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 	/* packed pixel modes */
707*4882a593Smuzhiyun 	if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
708*4882a593Smuzhiyun 		int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
709*4882a593Smuzhiyun 		int bpf = bpl * (buf->vb.height >> 1);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 		bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
712*4882a593Smuzhiyun 			      V4L2_FIELD_HAS_BOTH(buf->vb.field),
713*4882a593Smuzhiyun 			      tvnorm,&buf->crop);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 		switch (buf->vb.field) {
716*4882a593Smuzhiyun 		case V4L2_FIELD_TOP:
717*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->top,dma->sglist,
718*4882a593Smuzhiyun 					 /* offset */ 0,bpl,
719*4882a593Smuzhiyun 					 /* padding */ 0,/* skip_lines */ 0,
720*4882a593Smuzhiyun 					 buf->vb.height);
721*4882a593Smuzhiyun 			break;
722*4882a593Smuzhiyun 		case V4L2_FIELD_BOTTOM:
723*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
724*4882a593Smuzhiyun 					 0,bpl,0,0,buf->vb.height);
725*4882a593Smuzhiyun 			break;
726*4882a593Smuzhiyun 		case V4L2_FIELD_INTERLACED:
727*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->top,dma->sglist,
728*4882a593Smuzhiyun 					 0,bpl,bpl,0,buf->vb.height >> 1);
729*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
730*4882a593Smuzhiyun 					 bpl,bpl,bpl,0,buf->vb.height >> 1);
731*4882a593Smuzhiyun 			break;
732*4882a593Smuzhiyun 		case V4L2_FIELD_SEQ_TB:
733*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->top,dma->sglist,
734*4882a593Smuzhiyun 					 0,bpl,0,0,buf->vb.height >> 1);
735*4882a593Smuzhiyun 			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
736*4882a593Smuzhiyun 					 bpf,bpl,0,0,buf->vb.height >> 1);
737*4882a593Smuzhiyun 			break;
738*4882a593Smuzhiyun 		default:
739*4882a593Smuzhiyun 			BUG();
740*4882a593Smuzhiyun 		}
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* planar modes */
744*4882a593Smuzhiyun 	if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
745*4882a593Smuzhiyun 		int uoffset, voffset;
746*4882a593Smuzhiyun 		int ypadding, cpadding, lines;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 		/* calculate chroma offsets */
749*4882a593Smuzhiyun 		uoffset = buf->vb.width * buf->vb.height;
750*4882a593Smuzhiyun 		voffset = buf->vb.width * buf->vb.height;
751*4882a593Smuzhiyun 		if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
752*4882a593Smuzhiyun 			/* Y-Cr-Cb plane order */
753*4882a593Smuzhiyun 			uoffset >>= buf->fmt->hshift;
754*4882a593Smuzhiyun 			uoffset >>= buf->fmt->vshift;
755*4882a593Smuzhiyun 			uoffset  += voffset;
756*4882a593Smuzhiyun 		} else {
757*4882a593Smuzhiyun 			/* Y-Cb-Cr plane order */
758*4882a593Smuzhiyun 			voffset >>= buf->fmt->hshift;
759*4882a593Smuzhiyun 			voffset >>= buf->fmt->vshift;
760*4882a593Smuzhiyun 			voffset  += uoffset;
761*4882a593Smuzhiyun 		}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		switch (buf->vb.field) {
764*4882a593Smuzhiyun 		case V4L2_FIELD_TOP:
765*4882a593Smuzhiyun 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
766*4882a593Smuzhiyun 				      buf->vb.height,/* both_fields */ 0,
767*4882a593Smuzhiyun 				      tvnorm,&buf->crop);
768*4882a593Smuzhiyun 			bttv_risc_planar(btv, &buf->top, dma->sglist,
769*4882a593Smuzhiyun 					 0,buf->vb.width,0,buf->vb.height,
770*4882a593Smuzhiyun 					 uoffset,voffset,buf->fmt->hshift,
771*4882a593Smuzhiyun 					 buf->fmt->vshift,0);
772*4882a593Smuzhiyun 			break;
773*4882a593Smuzhiyun 		case V4L2_FIELD_BOTTOM:
774*4882a593Smuzhiyun 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
775*4882a593Smuzhiyun 				      buf->vb.height,0,
776*4882a593Smuzhiyun 				      tvnorm,&buf->crop);
777*4882a593Smuzhiyun 			bttv_risc_planar(btv, &buf->bottom, dma->sglist,
778*4882a593Smuzhiyun 					 0,buf->vb.width,0,buf->vb.height,
779*4882a593Smuzhiyun 					 uoffset,voffset,buf->fmt->hshift,
780*4882a593Smuzhiyun 					 buf->fmt->vshift,0);
781*4882a593Smuzhiyun 			break;
782*4882a593Smuzhiyun 		case V4L2_FIELD_INTERLACED:
783*4882a593Smuzhiyun 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
784*4882a593Smuzhiyun 				      buf->vb.height,1,
785*4882a593Smuzhiyun 				      tvnorm,&buf->crop);
786*4882a593Smuzhiyun 			lines    = buf->vb.height >> 1;
787*4882a593Smuzhiyun 			ypadding = buf->vb.width;
788*4882a593Smuzhiyun 			cpadding = buf->vb.width >> buf->fmt->hshift;
789*4882a593Smuzhiyun 			bttv_risc_planar(btv,&buf->top,
790*4882a593Smuzhiyun 					 dma->sglist,
791*4882a593Smuzhiyun 					 0,buf->vb.width,ypadding,lines,
792*4882a593Smuzhiyun 					 uoffset,voffset,
793*4882a593Smuzhiyun 					 buf->fmt->hshift,
794*4882a593Smuzhiyun 					 buf->fmt->vshift,
795*4882a593Smuzhiyun 					 cpadding);
796*4882a593Smuzhiyun 			bttv_risc_planar(btv,&buf->bottom,
797*4882a593Smuzhiyun 					 dma->sglist,
798*4882a593Smuzhiyun 					 ypadding,buf->vb.width,ypadding,lines,
799*4882a593Smuzhiyun 					 uoffset+cpadding,
800*4882a593Smuzhiyun 					 voffset+cpadding,
801*4882a593Smuzhiyun 					 buf->fmt->hshift,
802*4882a593Smuzhiyun 					 buf->fmt->vshift,
803*4882a593Smuzhiyun 					 cpadding);
804*4882a593Smuzhiyun 			break;
805*4882a593Smuzhiyun 		case V4L2_FIELD_SEQ_TB:
806*4882a593Smuzhiyun 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
807*4882a593Smuzhiyun 				      buf->vb.height,1,
808*4882a593Smuzhiyun 				      tvnorm,&buf->crop);
809*4882a593Smuzhiyun 			lines    = buf->vb.height >> 1;
810*4882a593Smuzhiyun 			ypadding = buf->vb.width;
811*4882a593Smuzhiyun 			cpadding = buf->vb.width >> buf->fmt->hshift;
812*4882a593Smuzhiyun 			bttv_risc_planar(btv,&buf->top,
813*4882a593Smuzhiyun 					 dma->sglist,
814*4882a593Smuzhiyun 					 0,buf->vb.width,0,lines,
815*4882a593Smuzhiyun 					 uoffset >> 1,
816*4882a593Smuzhiyun 					 voffset >> 1,
817*4882a593Smuzhiyun 					 buf->fmt->hshift,
818*4882a593Smuzhiyun 					 buf->fmt->vshift,
819*4882a593Smuzhiyun 					 0);
820*4882a593Smuzhiyun 			bttv_risc_planar(btv,&buf->bottom,
821*4882a593Smuzhiyun 					 dma->sglist,
822*4882a593Smuzhiyun 					 lines * ypadding,buf->vb.width,0,lines,
823*4882a593Smuzhiyun 					 lines * ypadding + (uoffset >> 1),
824*4882a593Smuzhiyun 					 lines * ypadding + (voffset >> 1),
825*4882a593Smuzhiyun 					 buf->fmt->hshift,
826*4882a593Smuzhiyun 					 buf->fmt->vshift,
827*4882a593Smuzhiyun 					 0);
828*4882a593Smuzhiyun 			break;
829*4882a593Smuzhiyun 		default:
830*4882a593Smuzhiyun 			BUG();
831*4882a593Smuzhiyun 		}
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	/* raw data */
835*4882a593Smuzhiyun 	if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
836*4882a593Smuzhiyun 		/* build risc code */
837*4882a593Smuzhiyun 		buf->vb.field = V4L2_FIELD_SEQ_TB;
838*4882a593Smuzhiyun 		bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
839*4882a593Smuzhiyun 			      1,tvnorm,&buf->crop);
840*4882a593Smuzhiyun 		bttv_risc_packed(btv, &buf->top,  dma->sglist,
841*4882a593Smuzhiyun 				 /* offset */ 0, RAW_BPL, /* padding */ 0,
842*4882a593Smuzhiyun 				 /* skip_lines */ 0, RAW_LINES);
843*4882a593Smuzhiyun 		bttv_risc_packed(btv, &buf->bottom, dma->sglist,
844*4882a593Smuzhiyun 				 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	/* copy format info */
848*4882a593Smuzhiyun 	buf->btformat = buf->fmt->btformat;
849*4882a593Smuzhiyun 	buf->btswap   = buf->fmt->btswap;
850*4882a593Smuzhiyun 	return 0;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun /* ---------------------------------------------------------- */
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun /* calculate geometry, build risc code */
856*4882a593Smuzhiyun int
bttv_overlay_risc(struct bttv * btv,struct bttv_overlay * ov,const struct bttv_format * fmt,struct bttv_buffer * buf)857*4882a593Smuzhiyun bttv_overlay_risc(struct bttv *btv,
858*4882a593Smuzhiyun 		  struct bttv_overlay *ov,
859*4882a593Smuzhiyun 		  const struct bttv_format *fmt,
860*4882a593Smuzhiyun 		  struct bttv_buffer *buf)
861*4882a593Smuzhiyun {
862*4882a593Smuzhiyun 	/* check interleave, bottom+top fields */
863*4882a593Smuzhiyun 	dprintk("%d: overlay fields: %s format: 0x%08x  size: %dx%d\n",
864*4882a593Smuzhiyun 		btv->c.nr, v4l2_field_names[buf->vb.field],
865*4882a593Smuzhiyun 		fmt->fourcc, ov->w.width, ov->w.height);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	/* calculate geometry */
868*4882a593Smuzhiyun 	bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
869*4882a593Smuzhiyun 		      V4L2_FIELD_HAS_BOTH(ov->field),
870*4882a593Smuzhiyun 		      &bttv_tvnorms[ov->tvnorm],&buf->crop);
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	/* build risc code */
873*4882a593Smuzhiyun 	switch (ov->field) {
874*4882a593Smuzhiyun 	case V4L2_FIELD_TOP:
875*4882a593Smuzhiyun 		bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 0);
876*4882a593Smuzhiyun 		break;
877*4882a593Smuzhiyun 	case V4L2_FIELD_BOTTOM:
878*4882a593Smuzhiyun 		bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
879*4882a593Smuzhiyun 		break;
880*4882a593Smuzhiyun 	case V4L2_FIELD_INTERLACED:
881*4882a593Smuzhiyun 		bttv_risc_overlay(btv, &buf->top,    fmt, ov, 0, 1);
882*4882a593Smuzhiyun 		bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
883*4882a593Smuzhiyun 		break;
884*4882a593Smuzhiyun 	default:
885*4882a593Smuzhiyun 		BUG();
886*4882a593Smuzhiyun 	}
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	/* copy format info */
889*4882a593Smuzhiyun 	buf->btformat = fmt->btformat;
890*4882a593Smuzhiyun 	buf->btswap   = fmt->btswap;
891*4882a593Smuzhiyun 	buf->vb.field = ov->field;
892*4882a593Smuzhiyun 	return 0;
893*4882a593Smuzhiyun }
894