blob: 649682aac1acebf4ff3a4bc45033f897258f875f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3 bttv-risc.c -- interfaces to other kernel modules
4
5 bttv risc code handling
6 - memory management
7 - generation
8
9 (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25*/
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/pci.h>
30#include <linux/vmalloc.h>
31#include <linux/interrupt.h>
32#include <asm/page.h>
33#include <asm/pgtable.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030034#include <media/v4l2-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include "bttvp.h"
37
38#define VCR_HACK_LINES 4
39
40/* ---------------------------------------------------------- */
41/* risc code generators */
42
43int
44bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
45 struct scatterlist *sglist,
46 unsigned int offset, unsigned int bpl,
Michael Schimeke5bd0262007-01-18 16:17:39 -030047 unsigned int padding, unsigned int skip_lines,
48 unsigned int store_lines)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
50 u32 instructions,line,todo;
51 struct scatterlist *sg;
Al Virod8eaa582008-05-21 00:31:51 -030052 __le32 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 int rc;
54
55 /* estimate risc mem: worst case is one write per page border +
Duncan Sands4a287cf2006-02-27 00:09:48 -030056 one write per scan line + sync + jump (all 2 dwords). padding
57 can cause next bpl to start close to a page border. First DMA
58 region may be smaller than PAGE_SIZE */
Michael Schimeke5bd0262007-01-18 16:17:39 -030059 instructions = skip_lines * 4;
60 instructions += (1 + ((bpl + padding) * store_lines)
61 / PAGE_SIZE + store_lines) * 8;
62 instructions += 2 * 8;
63 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 return rc;
65
66 /* sync instruction */
67 rp = risc->cpu;
68 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
69 *(rp++) = cpu_to_le32(0);
70
Michael Schimeke5bd0262007-01-18 16:17:39 -030071 while (skip_lines-- > 0) {
72 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
73 BT848_RISC_EOL | bpl);
74 }
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 /* scan lines */
77 sg = sglist;
Michael Schimeke5bd0262007-01-18 16:17:39 -030078 for (line = 0; line < store_lines; line++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 if ((btv->opt_vcr_hack) &&
Michael Schimeke5bd0262007-01-18 16:17:39 -030080 (line >= (store_lines - VCR_HACK_LINES)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 continue;
82 while (offset && offset >= sg_dma_len(sg)) {
83 offset -= sg_dma_len(sg);
84 sg++;
85 }
86 if (bpl <= sg_dma_len(sg)-offset) {
87 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080088 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 BT848_RISC_EOL|bpl);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080090 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
91 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 } else {
93 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080094 todo = bpl;
95 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080097 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
98 todo -= (sg_dma_len(sg)-offset);
99 offset = 0;
100 sg++;
101 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800102 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800104 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 todo -= sg_dma_len(sg);
106 sg++;
107 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800108 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 todo);
110 *(rp++)=cpu_to_le32(sg_dma_address(sg));
111 offset += todo;
112 }
113 offset += padding;
114 }
115
116 /* save pointer to jmp instruction address */
117 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300118 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 return 0;
120}
121
122static int
123bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
124 struct scatterlist *sglist,
125 unsigned int yoffset, unsigned int ybpl,
126 unsigned int ypadding, unsigned int ylines,
127 unsigned int uoffset, unsigned int voffset,
128 unsigned int hshift, unsigned int vshift,
129 unsigned int cpadding)
130{
131 unsigned int instructions,line,todo,ylen,chroma;
Al Virod8eaa582008-05-21 00:31:51 -0300132 __le32 *rp;
133 u32 ri;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct scatterlist *ysg;
135 struct scatterlist *usg;
136 struct scatterlist *vsg;
137 int topfield = (0 == yoffset);
138 int rc;
139
140 /* estimate risc mem: worst case is one write per page border +
141 one write per scan line (5 dwords)
142 plus sync + jump (2 dwords) */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300143 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
144 / PAGE_SIZE) + ylines;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 instructions += 2;
146 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
147 return rc;
148
149 /* sync instruction */
150 rp = risc->cpu;
151 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
152 *(rp++) = cpu_to_le32(0);
153
154 /* scan lines */
155 ysg = sglist;
156 usg = sglist;
157 vsg = sglist;
158 for (line = 0; line < ylines; line++) {
159 if ((btv->opt_vcr_hack) &&
160 (line >= (ylines - VCR_HACK_LINES)))
161 continue;
162 switch (vshift) {
163 case 0:
164 chroma = 1;
165 break;
166 case 1:
167 if (topfield)
168 chroma = ((line & 1) == 0);
169 else
170 chroma = ((line & 1) == 1);
171 break;
172 case 2:
173 if (topfield)
174 chroma = ((line & 3) == 0);
175 else
176 chroma = ((line & 3) == 2);
177 break;
178 default:
179 chroma = 0;
180 break;
181 }
182
183 for (todo = ybpl; todo > 0; todo -= ylen) {
184 /* go to next sg entry if needed */
185 while (yoffset && yoffset >= sg_dma_len(ysg)) {
186 yoffset -= sg_dma_len(ysg);
187 ysg++;
188 }
189 while (uoffset && uoffset >= sg_dma_len(usg)) {
190 uoffset -= sg_dma_len(usg);
191 usg++;
192 }
193 while (voffset && voffset >= sg_dma_len(vsg)) {
194 voffset -= sg_dma_len(vsg);
195 vsg++;
196 }
197
198 /* calculate max number of bytes we can write */
199 ylen = todo;
200 if (yoffset + ylen > sg_dma_len(ysg))
201 ylen = sg_dma_len(ysg) - yoffset;
202 if (chroma) {
203 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
204 ylen = (sg_dma_len(usg) - uoffset) << hshift;
205 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
206 ylen = (sg_dma_len(vsg) - voffset) << hshift;
207 ri = BT848_RISC_WRITE123;
208 } else {
209 ri = BT848_RISC_WRITE1S23;
210 }
211 if (ybpl == todo)
212 ri |= BT848_RISC_SOL;
213 if (ylen == todo)
214 ri |= BT848_RISC_EOL;
215
216 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800217 *(rp++)=cpu_to_le32(ri | ylen);
218 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 (ylen >> hshift));
220 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
221 yoffset += ylen;
222 if (chroma) {
223 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
224 uoffset += ylen >> hshift;
225 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
226 voffset += ylen >> hshift;
227 }
228 }
229 yoffset += ypadding;
230 if (chroma) {
231 uoffset += cpadding;
232 voffset += cpadding;
233 }
234 }
235
236 /* save pointer to jmp instruction address */
237 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300238 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 return 0;
240}
241
242static int
243bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
244 const struct bttv_format *fmt, struct bttv_overlay *ov,
245 int skip_even, int skip_odd)
246{
Duncan Sands3203f942006-04-02 04:14:57 -0300247 int dwords,rc,line,maxy,start,end,skip,nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 struct btcx_skiplist *skips;
Al Virod8eaa582008-05-21 00:31:51 -0300249 __le32 *rp;
250 u32 ri,ra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 u32 addr;
252
253 /* skip list for window clipping */
254 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
255 return -ENOMEM;
256
Duncan Sands3203f942006-04-02 04:14:57 -0300257 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300259 dwords = (3 * ov->nclips + 2) *
260 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
261 dwords += 4;
262 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 kfree(skips);
264 return rc;
265 }
266
267 /* sync instruction */
268 rp = risc->cpu;
269 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
270 *(rp++) = cpu_to_le32(0);
271
272 addr = (unsigned long)btv->fbuf.base;
273 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
274 addr += (fmt->depth >> 3) * ov->w.left;
275
276 /* scan lines */
277 for (maxy = -1, line = 0; line < ov->w.height;
278 line++, addr += btv->fbuf.fmt.bytesperline) {
279 if ((btv->opt_vcr_hack) &&
280 (line >= (ov->w.height - VCR_HACK_LINES)))
281 continue;
282 if ((line%2) == 0 && skip_even)
283 continue;
284 if ((line%2) == 1 && skip_odd)
285 continue;
286
287 /* calculate clipping */
288 if (line > maxy)
289 btcx_calc_skips(line, ov->w.width, &maxy,
290 skips, &nskips, ov->clips, ov->nclips);
291
292 /* write out risc code */
293 for (start = 0, skip = 0; start < ov->w.width; start = end) {
294 if (skip >= nskips) {
295 ri = BT848_RISC_WRITE;
296 end = ov->w.width;
297 } else if (start < skips[skip].start) {
298 ri = BT848_RISC_WRITE;
299 end = skips[skip].start;
300 } else {
301 ri = BT848_RISC_SKIP;
302 end = skips[skip].end;
303 skip++;
304 }
305 if (BT848_RISC_WRITE == ri)
306 ra = addr + (fmt->depth>>3)*start;
307 else
308 ra = 0;
309
310 if (0 == start)
311 ri |= BT848_RISC_SOL;
312 if (ov->w.width == end)
313 ri |= BT848_RISC_EOL;
314 ri |= (fmt->depth>>3) * (end-start);
315
316 *(rp++)=cpu_to_le32(ri);
317 if (0 != ra)
318 *(rp++)=cpu_to_le32(ra);
319 }
320 }
321
322 /* save pointer to jmp instruction address */
323 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300324 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 kfree(skips);
326 return 0;
327}
328
329/* ---------------------------------------------------------- */
330
331static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300332bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
333 int width, int height, int interleaved,
334 const struct bttv_tvnorm *tvnorm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800336 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 int vdelay;
338
339 int swidth = tvnorm->swidth;
340 int totalwidth = tvnorm->totalwidth;
341 int scaledtwidth = tvnorm->scaledtwidth;
342
343 if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
344 swidth = 720;
345 totalwidth = 858;
346 scaledtwidth = 858;
347 }
348
349 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800351 xsf = (width*scaledtwidth)/swidth;
352 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
353 geo->hdelay = tvnorm->hdelayx1;
354 geo->hdelay = (geo->hdelay*width)/swidth;
355 geo->hdelay &= 0x3fe;
356 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
357 geo->vscale = (0x10000UL-sr) & 0x1fff;
358 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
359 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
360 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
361 geo->vdelay = vdelay;
362 geo->width = width;
363 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 geo->vtotal = tvnorm->vtotal;
365
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800366 if (btv->opt_combfilter) {
367 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
368 geo->comb = (width < 769) ? 1 : 0;
369 } else {
370 geo->vtc = 0;
371 geo->comb = 0;
372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373}
374
375static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300376bttv_calc_geo (struct bttv * btv,
377 struct bttv_geometry * geo,
378 unsigned int width,
379 unsigned int height,
380 int both_fields,
381 const struct bttv_tvnorm * tvnorm,
382 const struct v4l2_rect * crop)
383{
384 unsigned int c_width;
385 unsigned int c_height;
386 u32 sr;
387
388 if ((crop->left == tvnorm->cropcap.defrect.left
389 && crop->top == tvnorm->cropcap.defrect.top
390 && crop->width == tvnorm->cropcap.defrect.width
391 && crop->height == tvnorm->cropcap.defrect.height
392 && width <= tvnorm->swidth /* see PAL-Nc et al */)
393 || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
394 bttv_calc_geo_old(btv, geo, width, height,
395 both_fields, tvnorm);
396 return;
397 }
398
399 /* For bug compatibility the image size checks permit scale
400 factors > 16. See bttv_crop_calc_limits(). */
401 c_width = min((unsigned int) crop->width, width * 16);
402 c_height = min((unsigned int) crop->height, height * 16);
403
404 geo->width = width;
405 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
406 /* Even to store Cb first, odd for Cr. */
407 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
408
409 geo->sheight = c_height;
410 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
411 sr = c_height >> !both_fields;
412 sr = (sr * 512U + (height >> 1)) / height - 512;
413 geo->vscale = (0x10000UL - sr) & 0x1fff;
414 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
415 geo->vtotal = tvnorm->vtotal;
416
417 geo->crop = (((geo->width >> 8) & 0x03) |
418 ((geo->hdelay >> 6) & 0x0c) |
419 ((geo->sheight >> 4) & 0x30) |
420 ((geo->vdelay >> 2) & 0xc0));
421
422 if (btv->opt_combfilter) {
423 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
424 geo->comb = (width < 769) ? 1 : 0;
425 } else {
426 geo->vtc = 0;
427 geo->comb = 0;
428 }
429}
430
431static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
433{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800434 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 if (geo->comb)
437 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
438 else
439 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
440
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800441 btwrite(geo->vtc, BT848_E_VTC+off);
442 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
443 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
444 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
445 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
446 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
447 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
448 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
449 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
450 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800452 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453}
454
455/* ---------------------------------------------------------- */
456/* risc group / risc main loop / dma management */
457
458void
459bttv_set_dma(struct bttv *btv, int override)
460{
461 unsigned long cmd;
462 int capctl;
463
464 btv->cap_ctl = 0;
465 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
466 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
467 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
468
469 capctl = 0;
470 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
471 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
472 capctl |= override;
473
474 d2printk(KERN_DEBUG
475 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
476 btv->c.nr,capctl,btv->loop_irq,
477 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
478 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
479 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
480 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
481
482 cmd = BT848_RISC_JUMP;
483 if (btv->loop_irq) {
484 cmd |= BT848_RISC_IRQ;
485 cmd |= (btv->loop_irq & 0x0f) << 16;
486 cmd |= (~btv->loop_irq & 0x0f) << 20;
487 }
488 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
489 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
490 } else {
491 del_timer(&btv->timeout);
492 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800493 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 btaor(capctl, ~0x0f, BT848_CAP_CTL);
496 if (capctl) {
497 if (btv->dma_on)
498 return;
499 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
500 btor(3, BT848_GPIO_DMA_CTL);
501 btv->dma_on = 1;
502 } else {
503 if (!btv->dma_on)
504 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800505 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 btv->dma_on = 0;
507 }
508 return;
509}
510
511int
512bttv_risc_init_main(struct bttv *btv)
513{
514 int rc;
515
516 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
517 return rc;
518 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
519 btv->c.nr,(unsigned long long)btv->main.dma);
520
521 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
522 BT848_FIFO_STATUS_VRE);
523 btv->main.cpu[1] = cpu_to_le32(0);
524 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
525 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
526
527 /* top field */
528 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
529 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
530 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
531 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
532
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800533 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800535 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
537 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800538 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800540 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
542
543 /* jump back to top field */
544 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800545 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 return 0;
548}
549
550int
551bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
552 int irqflags)
553{
554 unsigned long cmd;
555 unsigned long next = btv->main.dma + ((slot+2) << 2);
556
557 if (NULL == risc) {
558 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
559 btv->c.nr,risc,slot);
560 btv->main.cpu[slot+1] = cpu_to_le32(next);
561 } else {
562 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
563 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
564 cmd = BT848_RISC_JUMP;
565 if (irqflags) {
566 cmd |= BT848_RISC_IRQ;
567 cmd |= (irqflags & 0x0f) << 16;
568 cmd |= (~irqflags & 0x0f) << 20;
569 }
570 risc->jmp[0] = cpu_to_le32(cmd);
571 risc->jmp[1] = cpu_to_le32(next);
572 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
573 }
574 return 0;
575}
576
577void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300578bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300580 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
581
Eric Sesterhennae246012006-03-13 13:17:11 -0300582 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300584 videobuf_dma_unmap(q, dma);
585 videobuf_dma_free(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 btcx_riscmem_free(btv->c.pci,&buf->bottom);
587 btcx_riscmem_free(btv->c.pci,&buf->top);
Brandon Philips0fc06862007-11-06 20:02:36 -0300588 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589}
590
591int
592bttv_buffer_activate_vbi(struct bttv *btv,
593 struct bttv_buffer *vbi)
594{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300595 struct btcx_riscmem *top;
596 struct btcx_riscmem *bottom;
597 int top_irq_flags;
598 int bottom_irq_flags;
599
600 top = NULL;
601 bottom = NULL;
602 top_irq_flags = 0;
603 bottom_irq_flags = 0;
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 if (vbi) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300606 unsigned int crop, vdelay;
607
Brandon Philips0fc06862007-11-06 20:02:36 -0300608 vbi->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 list_del(&vbi->vb.queue);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300610
611 /* VDELAY is start of video, end of VBI capturing. */
612 crop = btread(BT848_E_CROP);
613 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
614
615 if (vbi->geo.vdelay > vdelay) {
616 vdelay = vbi->geo.vdelay & 0xfe;
617 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
618
619 btwrite(vdelay, BT848_E_VDELAY_LO);
620 btwrite(crop, BT848_E_CROP);
621 btwrite(vdelay, BT848_O_VDELAY_LO);
622 btwrite(crop, BT848_O_CROP);
623 }
624
625 if (vbi->vbi_count[0] > 0) {
626 top = &vbi->top;
627 top_irq_flags = 4;
628 }
629
630 if (vbi->vbi_count[1] > 0) {
631 top_irq_flags = 0;
632 bottom = &vbi->bottom;
633 bottom_irq_flags = 4;
634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300636
637 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
638 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return 0;
641}
642
643int
644bttv_buffer_activate_video(struct bttv *btv,
645 struct bttv_buffer_set *set)
646{
647 /* video capture */
648 if (NULL != set->top && NULL != set->bottom) {
649 if (set->top == set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300650 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (set->top->vb.queue.next)
652 list_del(&set->top->vb.queue);
653 } else {
Brandon Philips0fc06862007-11-06 20:02:36 -0300654 set->top->vb.state = VIDEOBUF_ACTIVE;
655 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if (set->top->vb.queue.next)
657 list_del(&set->top->vb.queue);
658 if (set->bottom->vb.queue.next)
659 list_del(&set->bottom->vb.queue);
660 }
661 bttv_apply_geo(btv, &set->top->geo, 1);
662 bttv_apply_geo(btv, &set->bottom->geo,0);
663 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
664 set->top_irq);
665 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
666 set->frame_irq);
667 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
668 ~0xff, BT848_COLOR_FMT);
669 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
670 ~0x0f, BT848_COLOR_CTL);
671 } else if (NULL != set->top) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300672 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (set->top->vb.queue.next)
674 list_del(&set->top->vb.queue);
675 bttv_apply_geo(btv, &set->top->geo,1);
676 bttv_apply_geo(btv, &set->top->geo,0);
677 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
678 set->frame_irq);
679 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
680 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
681 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
682 } else if (NULL != set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300683 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (set->bottom->vb.queue.next)
685 list_del(&set->bottom->vb.queue);
686 bttv_apply_geo(btv, &set->bottom->geo,1);
687 bttv_apply_geo(btv, &set->bottom->geo,0);
688 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
689 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
690 set->frame_irq);
691 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
692 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
693 } else {
694 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
695 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
696 }
697 return 0;
698}
699
700/* ---------------------------------------------------------- */
701
702/* calculate geometry, build risc code */
703int
704bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
705{
706 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300707 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 dprintk(KERN_DEBUG
710 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
711 btv->c.nr, v4l2_field_names[buf->vb.field],
712 buf->fmt->name, buf->vb.width, buf->vb.height);
713
714 /* packed pixel modes */
715 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
716 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
717 int bpf = bpl * (buf->vb.height >> 1);
718
719 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300720 V4L2_FIELD_HAS_BOTH(buf->vb.field),
721 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723 switch (buf->vb.field) {
724 case V4L2_FIELD_TOP:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300725 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300726 /* offset */ 0,bpl,
727 /* padding */ 0,/* skip_lines */ 0,
728 buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 break;
730 case V4L2_FIELD_BOTTOM:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300731 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300732 0,bpl,0,0,buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 break;
734 case V4L2_FIELD_INTERLACED:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300735 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300736 0,bpl,bpl,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300737 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300738 bpl,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 break;
740 case V4L2_FIELD_SEQ_TB:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300741 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300742 0,bpl,0,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300743 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300744 bpf,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 break;
746 default:
747 BUG();
748 }
749 }
750
751 /* planar modes */
752 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
753 int uoffset, voffset;
754 int ypadding, cpadding, lines;
755
756 /* calculate chroma offsets */
757 uoffset = buf->vb.width * buf->vb.height;
758 voffset = buf->vb.width * buf->vb.height;
759 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
760 /* Y-Cr-Cb plane order */
761 uoffset >>= buf->fmt->hshift;
762 uoffset >>= buf->fmt->vshift;
763 uoffset += voffset;
764 } else {
765 /* Y-Cb-Cr plane order */
766 voffset >>= buf->fmt->hshift;
767 voffset >>= buf->fmt->vshift;
768 voffset += uoffset;
769 }
770
771 switch (buf->vb.field) {
772 case V4L2_FIELD_TOP:
773 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300774 buf->vb.height,/* both_fields */ 0,
775 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300776 bttv_risc_planar(btv, &buf->top, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 0,buf->vb.width,0,buf->vb.height,
778 uoffset,voffset,buf->fmt->hshift,
779 buf->fmt->vshift,0);
780 break;
781 case V4L2_FIELD_BOTTOM:
782 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300783 buf->vb.height,0,
784 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300785 bttv_risc_planar(btv, &buf->bottom, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 0,buf->vb.width,0,buf->vb.height,
787 uoffset,voffset,buf->fmt->hshift,
788 buf->fmt->vshift,0);
789 break;
790 case V4L2_FIELD_INTERLACED:
791 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300792 buf->vb.height,1,
793 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 lines = buf->vb.height >> 1;
795 ypadding = buf->vb.width;
796 cpadding = buf->vb.width >> buf->fmt->hshift;
797 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300798 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 0,buf->vb.width,ypadding,lines,
800 uoffset,voffset,
801 buf->fmt->hshift,
802 buf->fmt->vshift,
803 cpadding);
804 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300805 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 ypadding,buf->vb.width,ypadding,lines,
807 uoffset+cpadding,
808 voffset+cpadding,
809 buf->fmt->hshift,
810 buf->fmt->vshift,
811 cpadding);
812 break;
813 case V4L2_FIELD_SEQ_TB:
814 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300815 buf->vb.height,1,
816 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 lines = buf->vb.height >> 1;
818 ypadding = buf->vb.width;
819 cpadding = buf->vb.width >> buf->fmt->hshift;
820 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300821 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 0,buf->vb.width,0,lines,
823 uoffset >> 1,
824 voffset >> 1,
825 buf->fmt->hshift,
826 buf->fmt->vshift,
827 0);
828 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300829 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 lines * ypadding,buf->vb.width,0,lines,
831 lines * ypadding + (uoffset >> 1),
832 lines * ypadding + (voffset >> 1),
833 buf->fmt->hshift,
834 buf->fmt->vshift,
835 0);
836 break;
837 default:
838 BUG();
839 }
840 }
841
842 /* raw data */
843 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
844 /* build risc code */
845 buf->vb.field = V4L2_FIELD_SEQ_TB;
846 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300847 1,tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300848 bttv_risc_packed(btv, &buf->top, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300849 /* offset */ 0, RAW_BPL, /* padding */ 0,
850 /* skip_lines */ 0, RAW_LINES);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300851 bttv_risc_packed(btv, &buf->bottom, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300852 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854
855 /* copy format info */
856 buf->btformat = buf->fmt->btformat;
857 buf->btswap = buf->fmt->btswap;
858 return 0;
859}
860
861/* ---------------------------------------------------------- */
862
863/* calculate geometry, build risc code */
864int
865bttv_overlay_risc(struct bttv *btv,
866 struct bttv_overlay *ov,
867 const struct bttv_format *fmt,
868 struct bttv_buffer *buf)
869{
870 /* check interleave, bottom+top fields */
871 dprintk(KERN_DEBUG
872 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
873 btv->c.nr, v4l2_field_names[buf->vb.field],
874 fmt->name,ov->w.width,ov->w.height);
875
876 /* calculate geometry */
877 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300878 V4L2_FIELD_HAS_BOTH(ov->field),
879 &bttv_tvnorms[ov->tvnorm],&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 /* build risc code */
882 switch (ov->field) {
883 case V4L2_FIELD_TOP:
884 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
885 break;
886 case V4L2_FIELD_BOTTOM:
887 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
888 break;
889 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
891 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 break;
893 default:
894 BUG();
895 }
896
897 /* copy format info */
898 buf->btformat = fmt->btformat;
899 buf->btswap = fmt->btswap;
900 buf->vb.field = ov->field;
901 return 0;
902}
903
904/*
905 * Local variables:
906 * c-basic-offset: 8
907 * End:
908 */