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