blob: 0af586876e72f6f7f01295cb99381f159feec47e [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;
Al Virod8eaa582008-05-21 00:31:51 -030051 __le32 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 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;
Al Virod8eaa582008-05-21 00:31:51 -0300131 __le32 *rp;
132 u32 ri;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 struct scatterlist *ysg;
134 struct scatterlist *usg;
135 struct scatterlist *vsg;
136 int topfield = (0 == yoffset);
137 int rc;
138
139 /* estimate risc mem: worst case is one write per page border +
140 one write per scan line (5 dwords)
141 plus sync + jump (2 dwords) */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300142 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
143 / PAGE_SIZE) + ylines;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 instructions += 2;
145 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
146 return rc;
147
148 /* sync instruction */
149 rp = risc->cpu;
150 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
151 *(rp++) = cpu_to_le32(0);
152
153 /* scan lines */
154 ysg = sglist;
155 usg = sglist;
156 vsg = sglist;
157 for (line = 0; line < ylines; line++) {
158 if ((btv->opt_vcr_hack) &&
159 (line >= (ylines - VCR_HACK_LINES)))
160 continue;
161 switch (vshift) {
162 case 0:
163 chroma = 1;
164 break;
165 case 1:
166 if (topfield)
167 chroma = ((line & 1) == 0);
168 else
169 chroma = ((line & 1) == 1);
170 break;
171 case 2:
172 if (topfield)
173 chroma = ((line & 3) == 0);
174 else
175 chroma = ((line & 3) == 2);
176 break;
177 default:
178 chroma = 0;
179 break;
180 }
181
182 for (todo = ybpl; todo > 0; todo -= ylen) {
183 /* go to next sg entry if needed */
184 while (yoffset && yoffset >= sg_dma_len(ysg)) {
185 yoffset -= sg_dma_len(ysg);
186 ysg++;
187 }
188 while (uoffset && uoffset >= sg_dma_len(usg)) {
189 uoffset -= sg_dma_len(usg);
190 usg++;
191 }
192 while (voffset && voffset >= sg_dma_len(vsg)) {
193 voffset -= sg_dma_len(vsg);
194 vsg++;
195 }
196
197 /* calculate max number of bytes we can write */
198 ylen = todo;
199 if (yoffset + ylen > sg_dma_len(ysg))
200 ylen = sg_dma_len(ysg) - yoffset;
201 if (chroma) {
202 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
203 ylen = (sg_dma_len(usg) - uoffset) << hshift;
204 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
205 ylen = (sg_dma_len(vsg) - voffset) << hshift;
206 ri = BT848_RISC_WRITE123;
207 } else {
208 ri = BT848_RISC_WRITE1S23;
209 }
210 if (ybpl == todo)
211 ri |= BT848_RISC_SOL;
212 if (ylen == todo)
213 ri |= BT848_RISC_EOL;
214
215 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800216 *(rp++)=cpu_to_le32(ri | ylen);
217 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 (ylen >> hshift));
219 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
220 yoffset += ylen;
221 if (chroma) {
222 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
223 uoffset += ylen >> hshift;
224 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
225 voffset += ylen >> hshift;
226 }
227 }
228 yoffset += ypadding;
229 if (chroma) {
230 uoffset += cpadding;
231 voffset += cpadding;
232 }
233 }
234
235 /* save pointer to jmp instruction address */
236 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300237 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return 0;
239}
240
241static int
242bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
243 const struct bttv_format *fmt, struct bttv_overlay *ov,
244 int skip_even, int skip_odd)
245{
Duncan Sands3203f942006-04-02 04:14:57 -0300246 int dwords,rc,line,maxy,start,end,skip,nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 struct btcx_skiplist *skips;
Al Virod8eaa582008-05-21 00:31:51 -0300248 __le32 *rp;
249 u32 ri,ra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 u32 addr;
251
252 /* skip list for window clipping */
253 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
254 return -ENOMEM;
255
Duncan Sands3203f942006-04-02 04:14:57 -0300256 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300258 dwords = (3 * ov->nclips + 2) *
259 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
260 dwords += 4;
261 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 kfree(skips);
263 return rc;
264 }
265
266 /* sync instruction */
267 rp = risc->cpu;
268 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
269 *(rp++) = cpu_to_le32(0);
270
271 addr = (unsigned long)btv->fbuf.base;
272 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
273 addr += (fmt->depth >> 3) * ov->w.left;
274
275 /* scan lines */
276 for (maxy = -1, line = 0; line < ov->w.height;
277 line++, addr += btv->fbuf.fmt.bytesperline) {
278 if ((btv->opt_vcr_hack) &&
279 (line >= (ov->w.height - VCR_HACK_LINES)))
280 continue;
281 if ((line%2) == 0 && skip_even)
282 continue;
283 if ((line%2) == 1 && skip_odd)
284 continue;
285
286 /* calculate clipping */
287 if (line > maxy)
288 btcx_calc_skips(line, ov->w.width, &maxy,
289 skips, &nskips, ov->clips, ov->nclips);
290
291 /* write out risc code */
292 for (start = 0, skip = 0; start < ov->w.width; start = end) {
293 if (skip >= nskips) {
294 ri = BT848_RISC_WRITE;
295 end = ov->w.width;
296 } else if (start < skips[skip].start) {
297 ri = BT848_RISC_WRITE;
298 end = skips[skip].start;
299 } else {
300 ri = BT848_RISC_SKIP;
301 end = skips[skip].end;
302 skip++;
303 }
304 if (BT848_RISC_WRITE == ri)
305 ra = addr + (fmt->depth>>3)*start;
306 else
307 ra = 0;
308
309 if (0 == start)
310 ri |= BT848_RISC_SOL;
311 if (ov->w.width == end)
312 ri |= BT848_RISC_EOL;
313 ri |= (fmt->depth>>3) * (end-start);
314
315 *(rp++)=cpu_to_le32(ri);
316 if (0 != ra)
317 *(rp++)=cpu_to_le32(ra);
318 }
319 }
320
321 /* save pointer to jmp instruction address */
322 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300323 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 kfree(skips);
325 return 0;
326}
327
328/* ---------------------------------------------------------- */
329
330static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300331bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
332 int width, int height, int interleaved,
333 const struct bttv_tvnorm *tvnorm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800335 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 int vdelay;
337
338 int swidth = tvnorm->swidth;
339 int totalwidth = tvnorm->totalwidth;
340 int scaledtwidth = tvnorm->scaledtwidth;
341
342 if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
343 swidth = 720;
344 totalwidth = 858;
345 scaledtwidth = 858;
346 }
347
348 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800350 xsf = (width*scaledtwidth)/swidth;
351 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
352 geo->hdelay = tvnorm->hdelayx1;
353 geo->hdelay = (geo->hdelay*width)/swidth;
354 geo->hdelay &= 0x3fe;
355 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
356 geo->vscale = (0x10000UL-sr) & 0x1fff;
357 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
358 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
359 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
360 geo->vdelay = vdelay;
361 geo->width = width;
362 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 geo->vtotal = tvnorm->vtotal;
364
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800365 if (btv->opt_combfilter) {
366 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
367 geo->comb = (width < 769) ? 1 : 0;
368 } else {
369 geo->vtc = 0;
370 geo->comb = 0;
371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372}
373
374static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300375bttv_calc_geo (struct bttv * btv,
376 struct bttv_geometry * geo,
377 unsigned int width,
378 unsigned int height,
379 int both_fields,
380 const struct bttv_tvnorm * tvnorm,
381 const struct v4l2_rect * crop)
382{
383 unsigned int c_width;
384 unsigned int c_height;
385 u32 sr;
386
387 if ((crop->left == tvnorm->cropcap.defrect.left
388 && crop->top == tvnorm->cropcap.defrect.top
389 && crop->width == tvnorm->cropcap.defrect.width
390 && crop->height == tvnorm->cropcap.defrect.height
391 && width <= tvnorm->swidth /* see PAL-Nc et al */)
392 || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
393 bttv_calc_geo_old(btv, geo, width, height,
394 both_fields, tvnorm);
395 return;
396 }
397
398 /* For bug compatibility the image size checks permit scale
399 factors > 16. See bttv_crop_calc_limits(). */
400 c_width = min((unsigned int) crop->width, width * 16);
401 c_height = min((unsigned int) crop->height, height * 16);
402
403 geo->width = width;
404 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
405 /* Even to store Cb first, odd for Cr. */
406 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
407
408 geo->sheight = c_height;
409 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
410 sr = c_height >> !both_fields;
411 sr = (sr * 512U + (height >> 1)) / height - 512;
412 geo->vscale = (0x10000UL - sr) & 0x1fff;
413 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
414 geo->vtotal = tvnorm->vtotal;
415
416 geo->crop = (((geo->width >> 8) & 0x03) |
417 ((geo->hdelay >> 6) & 0x0c) |
418 ((geo->sheight >> 4) & 0x30) |
419 ((geo->vdelay >> 2) & 0xc0));
420
421 if (btv->opt_combfilter) {
422 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
423 geo->comb = (width < 769) ? 1 : 0;
424 } else {
425 geo->vtc = 0;
426 geo->comb = 0;
427 }
428}
429
430static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
432{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800433 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 if (geo->comb)
436 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
437 else
438 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
439
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800440 btwrite(geo->vtc, BT848_E_VTC+off);
441 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
442 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
443 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
444 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
445 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
446 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
447 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
448 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
449 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800451 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452}
453
454/* ---------------------------------------------------------- */
455/* risc group / risc main loop / dma management */
456
457void
458bttv_set_dma(struct bttv *btv, int override)
459{
460 unsigned long cmd;
461 int capctl;
462
463 btv->cap_ctl = 0;
464 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
465 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
466 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
467
468 capctl = 0;
469 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
470 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
471 capctl |= override;
472
473 d2printk(KERN_DEBUG
474 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
475 btv->c.nr,capctl,btv->loop_irq,
476 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
477 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
478 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
479 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
480
481 cmd = BT848_RISC_JUMP;
482 if (btv->loop_irq) {
483 cmd |= BT848_RISC_IRQ;
484 cmd |= (btv->loop_irq & 0x0f) << 16;
485 cmd |= (~btv->loop_irq & 0x0f) << 20;
486 }
487 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
488 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
489 } else {
490 del_timer(&btv->timeout);
491 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800492 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 btaor(capctl, ~0x0f, BT848_CAP_CTL);
495 if (capctl) {
496 if (btv->dma_on)
497 return;
498 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
499 btor(3, BT848_GPIO_DMA_CTL);
500 btv->dma_on = 1;
501 } else {
502 if (!btv->dma_on)
503 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800504 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 btv->dma_on = 0;
506 }
507 return;
508}
509
510int
511bttv_risc_init_main(struct bttv *btv)
512{
513 int rc;
514
515 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
516 return rc;
517 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
518 btv->c.nr,(unsigned long long)btv->main.dma);
519
520 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
521 BT848_FIFO_STATUS_VRE);
522 btv->main.cpu[1] = cpu_to_le32(0);
523 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
524 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
525
526 /* top field */
527 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
528 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
529 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
530 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
531
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800532 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800534 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800537 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800539 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
541
542 /* jump back to top field */
543 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800544 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 return 0;
547}
548
549int
550bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
551 int irqflags)
552{
553 unsigned long cmd;
554 unsigned long next = btv->main.dma + ((slot+2) << 2);
555
556 if (NULL == risc) {
557 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
558 btv->c.nr,risc,slot);
559 btv->main.cpu[slot+1] = cpu_to_le32(next);
560 } else {
561 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
562 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
563 cmd = BT848_RISC_JUMP;
564 if (irqflags) {
565 cmd |= BT848_RISC_IRQ;
566 cmd |= (irqflags & 0x0f) << 16;
567 cmd |= (~irqflags & 0x0f) << 20;
568 }
569 risc->jmp[0] = cpu_to_le32(cmd);
570 risc->jmp[1] = cpu_to_le32(next);
571 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
572 }
573 return 0;
574}
575
576void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300577bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300579 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
580
Eric Sesterhennae246012006-03-13 13:17:11 -0300581 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300583 videobuf_dma_unmap(q, dma);
584 videobuf_dma_free(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 btcx_riscmem_free(btv->c.pci,&buf->bottom);
586 btcx_riscmem_free(btv->c.pci,&buf->top);
Brandon Philips0fc06862007-11-06 20:02:36 -0300587 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588}
589
590int
591bttv_buffer_activate_vbi(struct bttv *btv,
592 struct bttv_buffer *vbi)
593{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300594 struct btcx_riscmem *top;
595 struct btcx_riscmem *bottom;
596 int top_irq_flags;
597 int bottom_irq_flags;
598
599 top = NULL;
600 bottom = NULL;
601 top_irq_flags = 0;
602 bottom_irq_flags = 0;
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (vbi) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300605 unsigned int crop, vdelay;
606
Brandon Philips0fc06862007-11-06 20:02:36 -0300607 vbi->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 list_del(&vbi->vb.queue);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300609
610 /* VDELAY is start of video, end of VBI capturing. */
611 crop = btread(BT848_E_CROP);
612 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
613
614 if (vbi->geo.vdelay > vdelay) {
615 vdelay = vbi->geo.vdelay & 0xfe;
616 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
617
618 btwrite(vdelay, BT848_E_VDELAY_LO);
619 btwrite(crop, BT848_E_CROP);
620 btwrite(vdelay, BT848_O_VDELAY_LO);
621 btwrite(crop, BT848_O_CROP);
622 }
623
624 if (vbi->vbi_count[0] > 0) {
625 top = &vbi->top;
626 top_irq_flags = 4;
627 }
628
629 if (vbi->vbi_count[1] > 0) {
630 top_irq_flags = 0;
631 bottom = &vbi->bottom;
632 bottom_irq_flags = 4;
633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300635
636 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
637 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640}
641
642int
643bttv_buffer_activate_video(struct bttv *btv,
644 struct bttv_buffer_set *set)
645{
646 /* video capture */
647 if (NULL != set->top && NULL != set->bottom) {
648 if (set->top == set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300649 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 if (set->top->vb.queue.next)
651 list_del(&set->top->vb.queue);
652 } else {
Brandon Philips0fc06862007-11-06 20:02:36 -0300653 set->top->vb.state = VIDEOBUF_ACTIVE;
654 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (set->top->vb.queue.next)
656 list_del(&set->top->vb.queue);
657 if (set->bottom->vb.queue.next)
658 list_del(&set->bottom->vb.queue);
659 }
660 bttv_apply_geo(btv, &set->top->geo, 1);
661 bttv_apply_geo(btv, &set->bottom->geo,0);
662 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
663 set->top_irq);
664 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
665 set->frame_irq);
666 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
667 ~0xff, BT848_COLOR_FMT);
668 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
669 ~0x0f, BT848_COLOR_CTL);
670 } else if (NULL != set->top) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300671 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (set->top->vb.queue.next)
673 list_del(&set->top->vb.queue);
674 bttv_apply_geo(btv, &set->top->geo,1);
675 bttv_apply_geo(btv, &set->top->geo,0);
676 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
677 set->frame_irq);
678 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
679 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
680 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
681 } else if (NULL != set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300682 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (set->bottom->vb.queue.next)
684 list_del(&set->bottom->vb.queue);
685 bttv_apply_geo(btv, &set->bottom->geo,1);
686 bttv_apply_geo(btv, &set->bottom->geo,0);
687 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
688 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
689 set->frame_irq);
690 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
691 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
692 } else {
693 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
694 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
695 }
696 return 0;
697}
698
699/* ---------------------------------------------------------- */
700
701/* calculate geometry, build risc code */
702int
703bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
704{
705 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300706 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 dprintk(KERN_DEBUG
709 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
710 btv->c.nr, v4l2_field_names[buf->vb.field],
711 buf->fmt->name, buf->vb.width, buf->vb.height);
712
713 /* packed pixel modes */
714 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
715 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
716 int bpf = bpl * (buf->vb.height >> 1);
717
718 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300719 V4L2_FIELD_HAS_BOTH(buf->vb.field),
720 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 switch (buf->vb.field) {
723 case V4L2_FIELD_TOP:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300724 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300725 /* offset */ 0,bpl,
726 /* padding */ 0,/* skip_lines */ 0,
727 buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 break;
729 case V4L2_FIELD_BOTTOM:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300730 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300731 0,bpl,0,0,buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 break;
733 case V4L2_FIELD_INTERLACED:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300734 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300735 0,bpl,bpl,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300736 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300737 bpl,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 break;
739 case V4L2_FIELD_SEQ_TB:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300740 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300741 0,bpl,0,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300742 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300743 bpf,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 break;
745 default:
746 BUG();
747 }
748 }
749
750 /* planar modes */
751 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
752 int uoffset, voffset;
753 int ypadding, cpadding, lines;
754
755 /* calculate chroma offsets */
756 uoffset = buf->vb.width * buf->vb.height;
757 voffset = buf->vb.width * buf->vb.height;
758 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
759 /* Y-Cr-Cb plane order */
760 uoffset >>= buf->fmt->hshift;
761 uoffset >>= buf->fmt->vshift;
762 uoffset += voffset;
763 } else {
764 /* Y-Cb-Cr plane order */
765 voffset >>= buf->fmt->hshift;
766 voffset >>= buf->fmt->vshift;
767 voffset += uoffset;
768 }
769
770 switch (buf->vb.field) {
771 case V4L2_FIELD_TOP:
772 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300773 buf->vb.height,/* both_fields */ 0,
774 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300775 bttv_risc_planar(btv, &buf->top, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 0,buf->vb.width,0,buf->vb.height,
777 uoffset,voffset,buf->fmt->hshift,
778 buf->fmt->vshift,0);
779 break;
780 case V4L2_FIELD_BOTTOM:
781 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300782 buf->vb.height,0,
783 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300784 bttv_risc_planar(btv, &buf->bottom, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 0,buf->vb.width,0,buf->vb.height,
786 uoffset,voffset,buf->fmt->hshift,
787 buf->fmt->vshift,0);
788 break;
789 case V4L2_FIELD_INTERLACED:
790 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300791 buf->vb.height,1,
792 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 lines = buf->vb.height >> 1;
794 ypadding = buf->vb.width;
795 cpadding = buf->vb.width >> buf->fmt->hshift;
796 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300797 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 0,buf->vb.width,ypadding,lines,
799 uoffset,voffset,
800 buf->fmt->hshift,
801 buf->fmt->vshift,
802 cpadding);
803 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300804 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 ypadding,buf->vb.width,ypadding,lines,
806 uoffset+cpadding,
807 voffset+cpadding,
808 buf->fmt->hshift,
809 buf->fmt->vshift,
810 cpadding);
811 break;
812 case V4L2_FIELD_SEQ_TB:
813 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300814 buf->vb.height,1,
815 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 lines = buf->vb.height >> 1;
817 ypadding = buf->vb.width;
818 cpadding = buf->vb.width >> buf->fmt->hshift;
819 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300820 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 0,buf->vb.width,0,lines,
822 uoffset >> 1,
823 voffset >> 1,
824 buf->fmt->hshift,
825 buf->fmt->vshift,
826 0);
827 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300828 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 lines * ypadding,buf->vb.width,0,lines,
830 lines * ypadding + (uoffset >> 1),
831 lines * ypadding + (voffset >> 1),
832 buf->fmt->hshift,
833 buf->fmt->vshift,
834 0);
835 break;
836 default:
837 BUG();
838 }
839 }
840
841 /* raw data */
842 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
843 /* build risc code */
844 buf->vb.field = V4L2_FIELD_SEQ_TB;
845 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300846 1,tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300847 bttv_risc_packed(btv, &buf->top, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300848 /* offset */ 0, RAW_BPL, /* padding */ 0,
849 /* skip_lines */ 0, RAW_LINES);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300850 bttv_risc_packed(btv, &buf->bottom, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300851 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
853
854 /* copy format info */
855 buf->btformat = buf->fmt->btformat;
856 buf->btswap = buf->fmt->btswap;
857 return 0;
858}
859
860/* ---------------------------------------------------------- */
861
862/* calculate geometry, build risc code */
863int
864bttv_overlay_risc(struct bttv *btv,
865 struct bttv_overlay *ov,
866 const struct bttv_format *fmt,
867 struct bttv_buffer *buf)
868{
869 /* check interleave, bottom+top fields */
870 dprintk(KERN_DEBUG
871 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
872 btv->c.nr, v4l2_field_names[buf->vb.field],
873 fmt->name,ov->w.width,ov->w.height);
874
875 /* calculate geometry */
876 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300877 V4L2_FIELD_HAS_BOTH(ov->field),
878 &bttv_tvnorms[ov->tvnorm],&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 /* build risc code */
881 switch (ov->field) {
882 case V4L2_FIELD_TOP:
883 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
884 break;
885 case V4L2_FIELD_BOTTOM:
886 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
887 break;
888 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
890 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 break;
892 default:
893 BUG();
894 }
895
896 /* copy format info */
897 buf->btformat = fmt->btformat;
898 buf->btswap = fmt->btswap;
899 buf->vb.field = ov->field;
900 return 0;
901}
902
903/*
904 * Local variables:
905 * c-basic-offset: 8
906 * End:
907 */