blob: e7104d9cb4bd14d14da412c4ac644e09cd6ab167 [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>
34
35#include "bttvp.h"
36
37#define VCR_HACK_LINES 4
38
39/* ---------------------------------------------------------- */
40/* risc code generators */
41
42int
43bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
44 struct scatterlist *sglist,
45 unsigned int offset, unsigned int bpl,
Michael Schimeke5bd0262007-01-18 16:17:39 -030046 unsigned int padding, unsigned int skip_lines,
47 unsigned int store_lines)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
49 u32 instructions,line,todo;
50 struct scatterlist *sg;
51 u32 *rp;
52 int rc;
53
54 /* estimate risc mem: worst case is one write per page border +
Duncan Sands4a287cf2006-02-27 00:09:48 -030055 one write per scan line + sync + jump (all 2 dwords). padding
56 can cause next bpl to start close to a page border. First DMA
57 region may be smaller than PAGE_SIZE */
Michael Schimeke5bd0262007-01-18 16:17:39 -030058 instructions = skip_lines * 4;
59 instructions += (1 + ((bpl + padding) * store_lines)
60 / PAGE_SIZE + store_lines) * 8;
61 instructions += 2 * 8;
62 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return rc;
64
65 /* sync instruction */
66 rp = risc->cpu;
67 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
68 *(rp++) = cpu_to_le32(0);
69
Michael Schimeke5bd0262007-01-18 16:17:39 -030070 while (skip_lines-- > 0) {
71 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
72 BT848_RISC_EOL | bpl);
73 }
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 /* scan lines */
76 sg = sglist;
Michael Schimeke5bd0262007-01-18 16:17:39 -030077 for (line = 0; line < store_lines; line++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 if ((btv->opt_vcr_hack) &&
Michael Schimeke5bd0262007-01-18 16:17:39 -030079 (line >= (store_lines - VCR_HACK_LINES)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 continue;
81 while (offset && offset >= sg_dma_len(sg)) {
82 offset -= sg_dma_len(sg);
83 sg++;
84 }
85 if (bpl <= sg_dma_len(sg)-offset) {
86 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080087 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 BT848_RISC_EOL|bpl);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080089 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
90 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 } else {
92 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080093 todo = bpl;
94 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080096 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
97 todo -= (sg_dma_len(sg)-offset);
98 offset = 0;
99 sg++;
100 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800101 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800103 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 todo -= sg_dma_len(sg);
105 sg++;
106 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800107 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 todo);
109 *(rp++)=cpu_to_le32(sg_dma_address(sg));
110 offset += todo;
111 }
112 offset += padding;
113 }
114
115 /* save pointer to jmp instruction address */
116 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300117 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 return 0;
119}
120
121static int
122bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
123 struct scatterlist *sglist,
124 unsigned int yoffset, unsigned int ybpl,
125 unsigned int ypadding, unsigned int ylines,
126 unsigned int uoffset, unsigned int voffset,
127 unsigned int hshift, unsigned int vshift,
128 unsigned int cpadding)
129{
130 unsigned int instructions,line,todo,ylen,chroma;
131 u32 *rp,ri;
132 struct scatterlist *ysg;
133 struct scatterlist *usg;
134 struct scatterlist *vsg;
135 int topfield = (0 == yoffset);
136 int rc;
137
138 /* estimate risc mem: worst case is one write per page border +
139 one write per scan line (5 dwords)
140 plus sync + jump (2 dwords) */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300141 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
142 / PAGE_SIZE) + ylines;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 instructions += 2;
144 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
145 return rc;
146
147 /* sync instruction */
148 rp = risc->cpu;
149 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
150 *(rp++) = cpu_to_le32(0);
151
152 /* scan lines */
153 ysg = sglist;
154 usg = sglist;
155 vsg = sglist;
156 for (line = 0; line < ylines; line++) {
157 if ((btv->opt_vcr_hack) &&
158 (line >= (ylines - VCR_HACK_LINES)))
159 continue;
160 switch (vshift) {
161 case 0:
162 chroma = 1;
163 break;
164 case 1:
165 if (topfield)
166 chroma = ((line & 1) == 0);
167 else
168 chroma = ((line & 1) == 1);
169 break;
170 case 2:
171 if (topfield)
172 chroma = ((line & 3) == 0);
173 else
174 chroma = ((line & 3) == 2);
175 break;
176 default:
177 chroma = 0;
178 break;
179 }
180
181 for (todo = ybpl; todo > 0; todo -= ylen) {
182 /* go to next sg entry if needed */
183 while (yoffset && yoffset >= sg_dma_len(ysg)) {
184 yoffset -= sg_dma_len(ysg);
185 ysg++;
186 }
187 while (uoffset && uoffset >= sg_dma_len(usg)) {
188 uoffset -= sg_dma_len(usg);
189 usg++;
190 }
191 while (voffset && voffset >= sg_dma_len(vsg)) {
192 voffset -= sg_dma_len(vsg);
193 vsg++;
194 }
195
196 /* calculate max number of bytes we can write */
197 ylen = todo;
198 if (yoffset + ylen > sg_dma_len(ysg))
199 ylen = sg_dma_len(ysg) - yoffset;
200 if (chroma) {
201 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
202 ylen = (sg_dma_len(usg) - uoffset) << hshift;
203 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
204 ylen = (sg_dma_len(vsg) - voffset) << hshift;
205 ri = BT848_RISC_WRITE123;
206 } else {
207 ri = BT848_RISC_WRITE1S23;
208 }
209 if (ybpl == todo)
210 ri |= BT848_RISC_SOL;
211 if (ylen == todo)
212 ri |= BT848_RISC_EOL;
213
214 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800215 *(rp++)=cpu_to_le32(ri | ylen);
216 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 (ylen >> hshift));
218 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
219 yoffset += ylen;
220 if (chroma) {
221 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
222 uoffset += ylen >> hshift;
223 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
224 voffset += ylen >> hshift;
225 }
226 }
227 yoffset += ypadding;
228 if (chroma) {
229 uoffset += cpadding;
230 voffset += cpadding;
231 }
232 }
233
234 /* save pointer to jmp instruction address */
235 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300236 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return 0;
238}
239
240static int
241bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
242 const struct bttv_format *fmt, struct bttv_overlay *ov,
243 int skip_even, int skip_odd)
244{
Duncan Sands3203f942006-04-02 04:14:57 -0300245 int dwords,rc,line,maxy,start,end,skip,nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 struct btcx_skiplist *skips;
247 u32 *rp,ri,ra;
248 u32 addr;
249
250 /* skip list for window clipping */
251 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
252 return -ENOMEM;
253
Duncan Sands3203f942006-04-02 04:14:57 -0300254 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300256 dwords = (3 * ov->nclips + 2) *
257 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
258 dwords += 4;
259 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 kfree(skips);
261 return rc;
262 }
263
264 /* sync instruction */
265 rp = risc->cpu;
266 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
267 *(rp++) = cpu_to_le32(0);
268
269 addr = (unsigned long)btv->fbuf.base;
270 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
271 addr += (fmt->depth >> 3) * ov->w.left;
272
273 /* scan lines */
274 for (maxy = -1, line = 0; line < ov->w.height;
275 line++, addr += btv->fbuf.fmt.bytesperline) {
276 if ((btv->opt_vcr_hack) &&
277 (line >= (ov->w.height - VCR_HACK_LINES)))
278 continue;
279 if ((line%2) == 0 && skip_even)
280 continue;
281 if ((line%2) == 1 && skip_odd)
282 continue;
283
284 /* calculate clipping */
285 if (line > maxy)
286 btcx_calc_skips(line, ov->w.width, &maxy,
287 skips, &nskips, ov->clips, ov->nclips);
288
289 /* write out risc code */
290 for (start = 0, skip = 0; start < ov->w.width; start = end) {
291 if (skip >= nskips) {
292 ri = BT848_RISC_WRITE;
293 end = ov->w.width;
294 } else if (start < skips[skip].start) {
295 ri = BT848_RISC_WRITE;
296 end = skips[skip].start;
297 } else {
298 ri = BT848_RISC_SKIP;
299 end = skips[skip].end;
300 skip++;
301 }
302 if (BT848_RISC_WRITE == ri)
303 ra = addr + (fmt->depth>>3)*start;
304 else
305 ra = 0;
306
307 if (0 == start)
308 ri |= BT848_RISC_SOL;
309 if (ov->w.width == end)
310 ri |= BT848_RISC_EOL;
311 ri |= (fmt->depth>>3) * (end-start);
312
313 *(rp++)=cpu_to_le32(ri);
314 if (0 != ra)
315 *(rp++)=cpu_to_le32(ra);
316 }
317 }
318
319 /* save pointer to jmp instruction address */
320 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300321 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 kfree(skips);
323 return 0;
324}
325
326/* ---------------------------------------------------------- */
327
328static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300329bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
330 int width, int height, int interleaved,
331 const struct bttv_tvnorm *tvnorm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800333 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 int vdelay;
335
336 int swidth = tvnorm->swidth;
337 int totalwidth = tvnorm->totalwidth;
338 int scaledtwidth = tvnorm->scaledtwidth;
339
340 if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
341 swidth = 720;
342 totalwidth = 858;
343 scaledtwidth = 858;
344 }
345
346 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800348 xsf = (width*scaledtwidth)/swidth;
349 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
350 geo->hdelay = tvnorm->hdelayx1;
351 geo->hdelay = (geo->hdelay*width)/swidth;
352 geo->hdelay &= 0x3fe;
353 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
354 geo->vscale = (0x10000UL-sr) & 0x1fff;
355 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
356 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
357 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
358 geo->vdelay = vdelay;
359 geo->width = width;
360 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 geo->vtotal = tvnorm->vtotal;
362
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800363 if (btv->opt_combfilter) {
364 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
365 geo->comb = (width < 769) ? 1 : 0;
366 } else {
367 geo->vtc = 0;
368 geo->comb = 0;
369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
372static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300373bttv_calc_geo (struct bttv * btv,
374 struct bttv_geometry * geo,
375 unsigned int width,
376 unsigned int height,
377 int both_fields,
378 const struct bttv_tvnorm * tvnorm,
379 const struct v4l2_rect * crop)
380{
381 unsigned int c_width;
382 unsigned int c_height;
383 u32 sr;
384
385 if ((crop->left == tvnorm->cropcap.defrect.left
386 && crop->top == tvnorm->cropcap.defrect.top
387 && crop->width == tvnorm->cropcap.defrect.width
388 && crop->height == tvnorm->cropcap.defrect.height
389 && width <= tvnorm->swidth /* see PAL-Nc et al */)
390 || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
391 bttv_calc_geo_old(btv, geo, width, height,
392 both_fields, tvnorm);
393 return;
394 }
395
396 /* For bug compatibility the image size checks permit scale
397 factors > 16. See bttv_crop_calc_limits(). */
398 c_width = min((unsigned int) crop->width, width * 16);
399 c_height = min((unsigned int) crop->height, height * 16);
400
401 geo->width = width;
402 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
403 /* Even to store Cb first, odd for Cr. */
404 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
405
406 geo->sheight = c_height;
407 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
408 sr = c_height >> !both_fields;
409 sr = (sr * 512U + (height >> 1)) / height - 512;
410 geo->vscale = (0x10000UL - sr) & 0x1fff;
411 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
412 geo->vtotal = tvnorm->vtotal;
413
414 geo->crop = (((geo->width >> 8) & 0x03) |
415 ((geo->hdelay >> 6) & 0x0c) |
416 ((geo->sheight >> 4) & 0x30) |
417 ((geo->vdelay >> 2) & 0xc0));
418
419 if (btv->opt_combfilter) {
420 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
421 geo->comb = (width < 769) ? 1 : 0;
422 } else {
423 geo->vtc = 0;
424 geo->comb = 0;
425 }
426}
427
428static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
430{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800431 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 if (geo->comb)
434 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
435 else
436 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
437
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800438 btwrite(geo->vtc, BT848_E_VTC+off);
439 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
440 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
441 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
442 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
443 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
444 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
445 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
446 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
447 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800449 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
452/* ---------------------------------------------------------- */
453/* risc group / risc main loop / dma management */
454
455void
456bttv_set_dma(struct bttv *btv, int override)
457{
458 unsigned long cmd;
459 int capctl;
460
461 btv->cap_ctl = 0;
462 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
463 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
464 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
465
466 capctl = 0;
467 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
468 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
469 capctl |= override;
470
471 d2printk(KERN_DEBUG
472 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
473 btv->c.nr,capctl,btv->loop_irq,
474 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
475 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
476 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
477 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
478
479 cmd = BT848_RISC_JUMP;
480 if (btv->loop_irq) {
481 cmd |= BT848_RISC_IRQ;
482 cmd |= (btv->loop_irq & 0x0f) << 16;
483 cmd |= (~btv->loop_irq & 0x0f) << 20;
484 }
485 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
486 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
487 } else {
488 del_timer(&btv->timeout);
489 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800490 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 btaor(capctl, ~0x0f, BT848_CAP_CTL);
493 if (capctl) {
494 if (btv->dma_on)
495 return;
496 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
497 btor(3, BT848_GPIO_DMA_CTL);
498 btv->dma_on = 1;
499 } else {
500 if (!btv->dma_on)
501 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800502 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 btv->dma_on = 0;
504 }
505 return;
506}
507
508int
509bttv_risc_init_main(struct bttv *btv)
510{
511 int rc;
512
513 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
514 return rc;
515 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
516 btv->c.nr,(unsigned long long)btv->main.dma);
517
518 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
519 BT848_FIFO_STATUS_VRE);
520 btv->main.cpu[1] = cpu_to_le32(0);
521 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
522 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
523
524 /* top field */
525 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
526 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
527 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
528 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
529
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800530 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800532 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800535 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800537 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
539
540 /* jump back to top field */
541 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800542 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 return 0;
545}
546
547int
548bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
549 int irqflags)
550{
551 unsigned long cmd;
552 unsigned long next = btv->main.dma + ((slot+2) << 2);
553
554 if (NULL == risc) {
555 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
556 btv->c.nr,risc,slot);
557 btv->main.cpu[slot+1] = cpu_to_le32(next);
558 } else {
559 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
560 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
561 cmd = BT848_RISC_JUMP;
562 if (irqflags) {
563 cmd |= BT848_RISC_IRQ;
564 cmd |= (irqflags & 0x0f) << 16;
565 cmd |= (~irqflags & 0x0f) << 20;
566 }
567 risc->jmp[0] = cpu_to_le32(cmd);
568 risc->jmp[1] = cpu_to_le32(next);
569 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
570 }
571 return 0;
572}
573
574void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300575bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Eric Sesterhennae246012006-03-13 13:17:11 -0300577 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300579 videobuf_dma_unmap(q, &buf->vb.dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 videobuf_dma_free(&buf->vb.dma);
581 btcx_riscmem_free(btv->c.pci,&buf->bottom);
582 btcx_riscmem_free(btv->c.pci,&buf->top);
583 buf->vb.state = STATE_NEEDS_INIT;
584}
585
586int
587bttv_buffer_activate_vbi(struct bttv *btv,
588 struct bttv_buffer *vbi)
589{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300590 struct btcx_riscmem *top;
591 struct btcx_riscmem *bottom;
592 int top_irq_flags;
593 int bottom_irq_flags;
594
595 top = NULL;
596 bottom = NULL;
597 top_irq_flags = 0;
598 bottom_irq_flags = 0;
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (vbi) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300601 unsigned int crop, vdelay;
602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 vbi->vb.state = STATE_ACTIVE;
604 list_del(&vbi->vb.queue);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300605
606 /* VDELAY is start of video, end of VBI capturing. */
607 crop = btread(BT848_E_CROP);
608 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
609
610 if (vbi->geo.vdelay > vdelay) {
611 vdelay = vbi->geo.vdelay & 0xfe;
612 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
613
614 btwrite(vdelay, BT848_E_VDELAY_LO);
615 btwrite(crop, BT848_E_CROP);
616 btwrite(vdelay, BT848_O_VDELAY_LO);
617 btwrite(crop, BT848_O_CROP);
618 }
619
620 if (vbi->vbi_count[0] > 0) {
621 top = &vbi->top;
622 top_irq_flags = 4;
623 }
624
625 if (vbi->vbi_count[1] > 0) {
626 top_irq_flags = 0;
627 bottom = &vbi->bottom;
628 bottom_irq_flags = 4;
629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300631
632 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
633 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return 0;
636}
637
638int
639bttv_buffer_activate_video(struct bttv *btv,
640 struct bttv_buffer_set *set)
641{
642 /* video capture */
643 if (NULL != set->top && NULL != set->bottom) {
644 if (set->top == set->bottom) {
645 set->top->vb.state = STATE_ACTIVE;
646 if (set->top->vb.queue.next)
647 list_del(&set->top->vb.queue);
648 } else {
649 set->top->vb.state = STATE_ACTIVE;
650 set->bottom->vb.state = STATE_ACTIVE;
651 if (set->top->vb.queue.next)
652 list_del(&set->top->vb.queue);
653 if (set->bottom->vb.queue.next)
654 list_del(&set->bottom->vb.queue);
655 }
656 bttv_apply_geo(btv, &set->top->geo, 1);
657 bttv_apply_geo(btv, &set->bottom->geo,0);
658 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
659 set->top_irq);
660 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
661 set->frame_irq);
662 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
663 ~0xff, BT848_COLOR_FMT);
664 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
665 ~0x0f, BT848_COLOR_CTL);
666 } else if (NULL != set->top) {
667 set->top->vb.state = STATE_ACTIVE;
668 if (set->top->vb.queue.next)
669 list_del(&set->top->vb.queue);
670 bttv_apply_geo(btv, &set->top->geo,1);
671 bttv_apply_geo(btv, &set->top->geo,0);
672 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
673 set->frame_irq);
674 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
675 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
676 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
677 } else if (NULL != set->bottom) {
678 set->bottom->vb.state = STATE_ACTIVE;
679 if (set->bottom->vb.queue.next)
680 list_del(&set->bottom->vb.queue);
681 bttv_apply_geo(btv, &set->bottom->geo,1);
682 bttv_apply_geo(btv, &set->bottom->geo,0);
683 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
684 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
685 set->frame_irq);
686 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
687 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
688 } else {
689 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
690 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
691 }
692 return 0;
693}
694
695/* ---------------------------------------------------------- */
696
697/* calculate geometry, build risc code */
698int
699bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
700{
701 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
702
703 dprintk(KERN_DEBUG
704 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
705 btv->c.nr, v4l2_field_names[buf->vb.field],
706 buf->fmt->name, buf->vb.width, buf->vb.height);
707
708 /* packed pixel modes */
709 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
710 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
711 int bpf = bpl * (buf->vb.height >> 1);
712
713 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300714 V4L2_FIELD_HAS_BOTH(buf->vb.field),
715 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 switch (buf->vb.field) {
718 case V4L2_FIELD_TOP:
719 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300720 /* offset */ 0,bpl,
721 /* padding */ 0,/* skip_lines */ 0,
722 buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 break;
724 case V4L2_FIELD_BOTTOM:
725 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300726 0,bpl,0,0,buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 break;
728 case V4L2_FIELD_INTERLACED:
729 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300730 0,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300732 bpl,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 break;
734 case V4L2_FIELD_SEQ_TB:
735 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300736 0,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300738 bpf,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 break;
740 default:
741 BUG();
742 }
743 }
744
745 /* planar modes */
746 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
747 int uoffset, voffset;
748 int ypadding, cpadding, lines;
749
750 /* calculate chroma offsets */
751 uoffset = buf->vb.width * buf->vb.height;
752 voffset = buf->vb.width * buf->vb.height;
753 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
754 /* Y-Cr-Cb plane order */
755 uoffset >>= buf->fmt->hshift;
756 uoffset >>= buf->fmt->vshift;
757 uoffset += voffset;
758 } else {
759 /* Y-Cb-Cr plane order */
760 voffset >>= buf->fmt->hshift;
761 voffset >>= buf->fmt->vshift;
762 voffset += uoffset;
763 }
764
765 switch (buf->vb.field) {
766 case V4L2_FIELD_TOP:
767 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300768 buf->vb.height,/* both_fields */ 0,
769 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
771 0,buf->vb.width,0,buf->vb.height,
772 uoffset,voffset,buf->fmt->hshift,
773 buf->fmt->vshift,0);
774 break;
775 case V4L2_FIELD_BOTTOM:
776 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300777 buf->vb.height,0,
778 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
780 0,buf->vb.width,0,buf->vb.height,
781 uoffset,voffset,buf->fmt->hshift,
782 buf->fmt->vshift,0);
783 break;
784 case V4L2_FIELD_INTERLACED:
785 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300786 buf->vb.height,1,
787 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 lines = buf->vb.height >> 1;
789 ypadding = buf->vb.width;
790 cpadding = buf->vb.width >> buf->fmt->hshift;
791 bttv_risc_planar(btv,&buf->top,
792 buf->vb.dma.sglist,
793 0,buf->vb.width,ypadding,lines,
794 uoffset,voffset,
795 buf->fmt->hshift,
796 buf->fmt->vshift,
797 cpadding);
798 bttv_risc_planar(btv,&buf->bottom,
799 buf->vb.dma.sglist,
800 ypadding,buf->vb.width,ypadding,lines,
801 uoffset+cpadding,
802 voffset+cpadding,
803 buf->fmt->hshift,
804 buf->fmt->vshift,
805 cpadding);
806 break;
807 case V4L2_FIELD_SEQ_TB:
808 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300809 buf->vb.height,1,
810 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 lines = buf->vb.height >> 1;
812 ypadding = buf->vb.width;
813 cpadding = buf->vb.width >> buf->fmt->hshift;
814 bttv_risc_planar(btv,&buf->top,
815 buf->vb.dma.sglist,
816 0,buf->vb.width,0,lines,
817 uoffset >> 1,
818 voffset >> 1,
819 buf->fmt->hshift,
820 buf->fmt->vshift,
821 0);
822 bttv_risc_planar(btv,&buf->bottom,
823 buf->vb.dma.sglist,
824 lines * ypadding,buf->vb.width,0,lines,
825 lines * ypadding + (uoffset >> 1),
826 lines * ypadding + (voffset >> 1),
827 buf->fmt->hshift,
828 buf->fmt->vshift,
829 0);
830 break;
831 default:
832 BUG();
833 }
834 }
835
836 /* raw data */
837 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
838 /* build risc code */
839 buf->vb.field = V4L2_FIELD_SEQ_TB;
840 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300841 1,tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300843 /* offset */ 0, RAW_BPL, /* padding */ 0,
844 /* skip_lines */ 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300846 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848
849 /* copy format info */
850 buf->btformat = buf->fmt->btformat;
851 buf->btswap = buf->fmt->btswap;
852 return 0;
853}
854
855/* ---------------------------------------------------------- */
856
857/* calculate geometry, build risc code */
858int
859bttv_overlay_risc(struct bttv *btv,
860 struct bttv_overlay *ov,
861 const struct bttv_format *fmt,
862 struct bttv_buffer *buf)
863{
864 /* check interleave, bottom+top fields */
865 dprintk(KERN_DEBUG
866 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
867 btv->c.nr, v4l2_field_names[buf->vb.field],
868 fmt->name,ov->w.width,ov->w.height);
869
870 /* calculate geometry */
871 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300872 V4L2_FIELD_HAS_BOTH(ov->field),
873 &bttv_tvnorms[ov->tvnorm],&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 /* build risc code */
876 switch (ov->field) {
877 case V4L2_FIELD_TOP:
878 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
879 break;
880 case V4L2_FIELD_BOTTOM:
881 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
882 break;
883 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
885 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 break;
887 default:
888 BUG();
889 }
890
891 /* copy format info */
892 buf->btformat = fmt->btformat;
893 buf->btswap = fmt->btswap;
894 buf->vb.field = ov->field;
895 return 0;
896}
897
898/*
899 * Local variables:
900 * c-basic-offset: 8
901 * End:
902 */