blob: 5c746110df6295a84f0fa5b830d3e2651c55edc6 [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,
46 unsigned int padding, unsigned int lines)
47{
48 u32 instructions,line,todo;
49 struct scatterlist *sg;
50 u32 *rp;
51 int rc;
52
53 /* estimate risc mem: worst case is one write per page border +
Duncan Sands4a287cf2006-02-27 00:09:48 -030054 one write per scan line + sync + jump (all 2 dwords). padding
55 can cause next bpl to start close to a page border. First DMA
56 region may be smaller than PAGE_SIZE */
57 instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 instructions += 2;
59 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
60 return rc;
61
62 /* sync instruction */
63 rp = risc->cpu;
64 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
65 *(rp++) = cpu_to_le32(0);
66
67 /* scan lines */
68 sg = sglist;
69 for (line = 0; line < lines; line++) {
70 if ((btv->opt_vcr_hack) &&
71 (line >= (lines - VCR_HACK_LINES)))
72 continue;
73 while (offset && offset >= sg_dma_len(sg)) {
74 offset -= sg_dma_len(sg);
75 sg++;
76 }
77 if (bpl <= sg_dma_len(sg)-offset) {
78 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080079 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 BT848_RISC_EOL|bpl);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080081 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
82 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 } else {
84 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080085 todo = bpl;
86 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080088 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
89 todo -= (sg_dma_len(sg)-offset);
90 offset = 0;
91 sg++;
92 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -080093 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -080095 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 todo -= sg_dma_len(sg);
97 sg++;
98 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080099 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 todo);
101 *(rp++)=cpu_to_le32(sg_dma_address(sg));
102 offset += todo;
103 }
104 offset += padding;
105 }
106
107 /* save pointer to jmp instruction address */
108 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300109 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return 0;
111}
112
113static int
114bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
115 struct scatterlist *sglist,
116 unsigned int yoffset, unsigned int ybpl,
117 unsigned int ypadding, unsigned int ylines,
118 unsigned int uoffset, unsigned int voffset,
119 unsigned int hshift, unsigned int vshift,
120 unsigned int cpadding)
121{
122 unsigned int instructions,line,todo,ylen,chroma;
123 u32 *rp,ri;
124 struct scatterlist *ysg;
125 struct scatterlist *usg;
126 struct scatterlist *vsg;
127 int topfield = (0 == yoffset);
128 int rc;
129
130 /* estimate risc mem: worst case is one write per page border +
131 one write per scan line (5 dwords)
132 plus sync + jump (2 dwords) */
133 instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
134 instructions += 2;
135 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
136 return rc;
137
138 /* sync instruction */
139 rp = risc->cpu;
140 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
141 *(rp++) = cpu_to_le32(0);
142
143 /* scan lines */
144 ysg = sglist;
145 usg = sglist;
146 vsg = sglist;
147 for (line = 0; line < ylines; line++) {
148 if ((btv->opt_vcr_hack) &&
149 (line >= (ylines - VCR_HACK_LINES)))
150 continue;
151 switch (vshift) {
152 case 0:
153 chroma = 1;
154 break;
155 case 1:
156 if (topfield)
157 chroma = ((line & 1) == 0);
158 else
159 chroma = ((line & 1) == 1);
160 break;
161 case 2:
162 if (topfield)
163 chroma = ((line & 3) == 0);
164 else
165 chroma = ((line & 3) == 2);
166 break;
167 default:
168 chroma = 0;
169 break;
170 }
171
172 for (todo = ybpl; todo > 0; todo -= ylen) {
173 /* go to next sg entry if needed */
174 while (yoffset && yoffset >= sg_dma_len(ysg)) {
175 yoffset -= sg_dma_len(ysg);
176 ysg++;
177 }
178 while (uoffset && uoffset >= sg_dma_len(usg)) {
179 uoffset -= sg_dma_len(usg);
180 usg++;
181 }
182 while (voffset && voffset >= sg_dma_len(vsg)) {
183 voffset -= sg_dma_len(vsg);
184 vsg++;
185 }
186
187 /* calculate max number of bytes we can write */
188 ylen = todo;
189 if (yoffset + ylen > sg_dma_len(ysg))
190 ylen = sg_dma_len(ysg) - yoffset;
191 if (chroma) {
192 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
193 ylen = (sg_dma_len(usg) - uoffset) << hshift;
194 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
195 ylen = (sg_dma_len(vsg) - voffset) << hshift;
196 ri = BT848_RISC_WRITE123;
197 } else {
198 ri = BT848_RISC_WRITE1S23;
199 }
200 if (ybpl == todo)
201 ri |= BT848_RISC_SOL;
202 if (ylen == todo)
203 ri |= BT848_RISC_EOL;
204
205 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800206 *(rp++)=cpu_to_le32(ri | ylen);
207 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 (ylen >> hshift));
209 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
210 yoffset += ylen;
211 if (chroma) {
212 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
213 uoffset += ylen >> hshift;
214 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
215 voffset += ylen >> hshift;
216 }
217 }
218 yoffset += ypadding;
219 if (chroma) {
220 uoffset += cpadding;
221 voffset += cpadding;
222 }
223 }
224
225 /* save pointer to jmp instruction address */
226 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300227 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 return 0;
229}
230
231static int
232bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
233 const struct bttv_format *fmt, struct bttv_overlay *ov,
234 int skip_even, int skip_odd)
235{
236 int instructions,rc,line,maxy,start,end,skip,nskips;
237 struct btcx_skiplist *skips;
238 u32 *rp,ri,ra;
239 u32 addr;
240
241 /* skip list for window clipping */
242 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
243 return -ENOMEM;
244
245 /* estimate risc mem: worst case is (clip+1) * lines instructions
246 + sync + jump (all 2 dwords) */
247 instructions = (ov->nclips + 1) *
248 ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height);
249 instructions += 2;
250 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) {
251 kfree(skips);
252 return rc;
253 }
254
255 /* sync instruction */
256 rp = risc->cpu;
257 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
258 *(rp++) = cpu_to_le32(0);
259
260 addr = (unsigned long)btv->fbuf.base;
261 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
262 addr += (fmt->depth >> 3) * ov->w.left;
263
264 /* scan lines */
265 for (maxy = -1, line = 0; line < ov->w.height;
266 line++, addr += btv->fbuf.fmt.bytesperline) {
267 if ((btv->opt_vcr_hack) &&
268 (line >= (ov->w.height - VCR_HACK_LINES)))
269 continue;
270 if ((line%2) == 0 && skip_even)
271 continue;
272 if ((line%2) == 1 && skip_odd)
273 continue;
274
275 /* calculate clipping */
276 if (line > maxy)
277 btcx_calc_skips(line, ov->w.width, &maxy,
278 skips, &nskips, ov->clips, ov->nclips);
Duncan Sands99ca9992006-03-09 11:20:14 -0300279 else
280 nskips = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282 /* write out risc code */
283 for (start = 0, skip = 0; start < ov->w.width; start = end) {
284 if (skip >= nskips) {
285 ri = BT848_RISC_WRITE;
286 end = ov->w.width;
287 } else if (start < skips[skip].start) {
288 ri = BT848_RISC_WRITE;
289 end = skips[skip].start;
290 } else {
291 ri = BT848_RISC_SKIP;
292 end = skips[skip].end;
293 skip++;
294 }
295 if (BT848_RISC_WRITE == ri)
296 ra = addr + (fmt->depth>>3)*start;
297 else
298 ra = 0;
299
300 if (0 == start)
301 ri |= BT848_RISC_SOL;
302 if (ov->w.width == end)
303 ri |= BT848_RISC_EOL;
304 ri |= (fmt->depth>>3) * (end-start);
305
306 *(rp++)=cpu_to_le32(ri);
307 if (0 != ra)
308 *(rp++)=cpu_to_le32(ra);
309 }
310 }
311
312 /* save pointer to jmp instruction address */
313 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300314 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 kfree(skips);
316 return 0;
317}
318
319/* ---------------------------------------------------------- */
320
321static void
322bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
323 int width, int height, int interleaved, int norm)
324{
325 const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800326 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 int vdelay;
328
329 int swidth = tvnorm->swidth;
330 int totalwidth = tvnorm->totalwidth;
331 int scaledtwidth = tvnorm->scaledtwidth;
332
333 if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
334 swidth = 720;
335 totalwidth = 858;
336 scaledtwidth = 858;
337 }
338
339 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800341 xsf = (width*scaledtwidth)/swidth;
342 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
343 geo->hdelay = tvnorm->hdelayx1;
344 geo->hdelay = (geo->hdelay*width)/swidth;
345 geo->hdelay &= 0x3fe;
346 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
347 geo->vscale = (0x10000UL-sr) & 0x1fff;
348 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
349 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
350 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
351 geo->vdelay = vdelay;
352 geo->width = width;
353 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 geo->vtotal = tvnorm->vtotal;
355
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800356 if (btv->opt_combfilter) {
357 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
358 geo->comb = (width < 769) ? 1 : 0;
359 } else {
360 geo->vtc = 0;
361 geo->comb = 0;
362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363}
364
365static void
366bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
367{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800368 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370 if (geo->comb)
371 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
372 else
373 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
374
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800375 btwrite(geo->vtc, BT848_E_VTC+off);
376 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
377 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
378 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
379 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
380 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
381 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
382 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
383 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
384 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800386 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
389/* ---------------------------------------------------------- */
390/* risc group / risc main loop / dma management */
391
392void
393bttv_set_dma(struct bttv *btv, int override)
394{
395 unsigned long cmd;
396 int capctl;
397
398 btv->cap_ctl = 0;
399 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
400 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
401 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
402
403 capctl = 0;
404 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
405 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
406 capctl |= override;
407
408 d2printk(KERN_DEBUG
409 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
410 btv->c.nr,capctl,btv->loop_irq,
411 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
412 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
413 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
414 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
415
416 cmd = BT848_RISC_JUMP;
417 if (btv->loop_irq) {
418 cmd |= BT848_RISC_IRQ;
419 cmd |= (btv->loop_irq & 0x0f) << 16;
420 cmd |= (~btv->loop_irq & 0x0f) << 20;
421 }
422 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
423 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
424 } else {
425 del_timer(&btv->timeout);
426 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800427 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 btaor(capctl, ~0x0f, BT848_CAP_CTL);
430 if (capctl) {
431 if (btv->dma_on)
432 return;
433 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
434 btor(3, BT848_GPIO_DMA_CTL);
435 btv->dma_on = 1;
436 } else {
437 if (!btv->dma_on)
438 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800439 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 btv->dma_on = 0;
441 }
442 return;
443}
444
445int
446bttv_risc_init_main(struct bttv *btv)
447{
448 int rc;
449
450 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
451 return rc;
452 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
453 btv->c.nr,(unsigned long long)btv->main.dma);
454
455 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
456 BT848_FIFO_STATUS_VRE);
457 btv->main.cpu[1] = cpu_to_le32(0);
458 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
459 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
460
461 /* top field */
462 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
463 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
464 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
465 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
466
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800467 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800469 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800472 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800474 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
476
477 /* jump back to top field */
478 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800479 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 return 0;
482}
483
484int
485bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
486 int irqflags)
487{
488 unsigned long cmd;
489 unsigned long next = btv->main.dma + ((slot+2) << 2);
490
491 if (NULL == risc) {
492 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
493 btv->c.nr,risc,slot);
494 btv->main.cpu[slot+1] = cpu_to_le32(next);
495 } else {
496 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
497 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
498 cmd = BT848_RISC_JUMP;
499 if (irqflags) {
500 cmd |= BT848_RISC_IRQ;
501 cmd |= (irqflags & 0x0f) << 16;
502 cmd |= (~irqflags & 0x0f) << 20;
503 }
504 risc->jmp[0] = cpu_to_le32(cmd);
505 risc->jmp[1] = cpu_to_le32(next);
506 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
507 }
508 return 0;
509}
510
511void
512bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf)
513{
514 if (in_interrupt())
515 BUG();
516 videobuf_waiton(&buf->vb,0,0);
517 videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma);
518 videobuf_dma_free(&buf->vb.dma);
519 btcx_riscmem_free(btv->c.pci,&buf->bottom);
520 btcx_riscmem_free(btv->c.pci,&buf->top);
521 buf->vb.state = STATE_NEEDS_INIT;
522}
523
524int
525bttv_buffer_activate_vbi(struct bttv *btv,
526 struct bttv_buffer *vbi)
527{
528 /* vbi capture */
529 if (vbi) {
530 vbi->vb.state = STATE_ACTIVE;
531 list_del(&vbi->vb.queue);
532 bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
533 bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
534 } else {
535 bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
536 bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
537 }
538 return 0;
539}
540
541int
542bttv_buffer_activate_video(struct bttv *btv,
543 struct bttv_buffer_set *set)
544{
545 /* video capture */
546 if (NULL != set->top && NULL != set->bottom) {
547 if (set->top == set->bottom) {
548 set->top->vb.state = STATE_ACTIVE;
549 if (set->top->vb.queue.next)
550 list_del(&set->top->vb.queue);
551 } else {
552 set->top->vb.state = STATE_ACTIVE;
553 set->bottom->vb.state = STATE_ACTIVE;
554 if (set->top->vb.queue.next)
555 list_del(&set->top->vb.queue);
556 if (set->bottom->vb.queue.next)
557 list_del(&set->bottom->vb.queue);
558 }
559 bttv_apply_geo(btv, &set->top->geo, 1);
560 bttv_apply_geo(btv, &set->bottom->geo,0);
561 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
562 set->top_irq);
563 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
564 set->frame_irq);
565 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
566 ~0xff, BT848_COLOR_FMT);
567 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
568 ~0x0f, BT848_COLOR_CTL);
569 } else if (NULL != set->top) {
570 set->top->vb.state = STATE_ACTIVE;
571 if (set->top->vb.queue.next)
572 list_del(&set->top->vb.queue);
573 bttv_apply_geo(btv, &set->top->geo,1);
574 bttv_apply_geo(btv, &set->top->geo,0);
575 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
576 set->frame_irq);
577 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
578 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
579 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
580 } else if (NULL != set->bottom) {
581 set->bottom->vb.state = STATE_ACTIVE;
582 if (set->bottom->vb.queue.next)
583 list_del(&set->bottom->vb.queue);
584 bttv_apply_geo(btv, &set->bottom->geo,1);
585 bttv_apply_geo(btv, &set->bottom->geo,0);
586 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
587 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
588 set->frame_irq);
589 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
590 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
591 } else {
592 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
593 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
594 }
595 return 0;
596}
597
598/* ---------------------------------------------------------- */
599
600/* calculate geometry, build risc code */
601int
602bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
603{
604 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
605
606 dprintk(KERN_DEBUG
607 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
608 btv->c.nr, v4l2_field_names[buf->vb.field],
609 buf->fmt->name, buf->vb.width, buf->vb.height);
610
611 /* packed pixel modes */
612 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
613 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
614 int bpf = bpl * (buf->vb.height >> 1);
615
616 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
617 V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
618
619 switch (buf->vb.field) {
620 case V4L2_FIELD_TOP:
621 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
622 0,bpl,0,buf->vb.height);
623 break;
624 case V4L2_FIELD_BOTTOM:
625 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
626 0,bpl,0,buf->vb.height);
627 break;
628 case V4L2_FIELD_INTERLACED:
629 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
630 0,bpl,bpl,buf->vb.height >> 1);
631 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
632 bpl,bpl,bpl,buf->vb.height >> 1);
633 break;
634 case V4L2_FIELD_SEQ_TB:
635 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
636 0,bpl,0,buf->vb.height >> 1);
637 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
638 bpf,bpl,0,buf->vb.height >> 1);
639 break;
640 default:
641 BUG();
642 }
643 }
644
645 /* planar modes */
646 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
647 int uoffset, voffset;
648 int ypadding, cpadding, lines;
649
650 /* calculate chroma offsets */
651 uoffset = buf->vb.width * buf->vb.height;
652 voffset = buf->vb.width * buf->vb.height;
653 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
654 /* Y-Cr-Cb plane order */
655 uoffset >>= buf->fmt->hshift;
656 uoffset >>= buf->fmt->vshift;
657 uoffset += voffset;
658 } else {
659 /* Y-Cb-Cr plane order */
660 voffset >>= buf->fmt->hshift;
661 voffset >>= buf->fmt->vshift;
662 voffset += uoffset;
663 }
664
665 switch (buf->vb.field) {
666 case V4L2_FIELD_TOP:
667 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
668 buf->vb.height,0,buf->tvnorm);
669 bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
670 0,buf->vb.width,0,buf->vb.height,
671 uoffset,voffset,buf->fmt->hshift,
672 buf->fmt->vshift,0);
673 break;
674 case V4L2_FIELD_BOTTOM:
675 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
676 buf->vb.height,0,buf->tvnorm);
677 bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
678 0,buf->vb.width,0,buf->vb.height,
679 uoffset,voffset,buf->fmt->hshift,
680 buf->fmt->vshift,0);
681 break;
682 case V4L2_FIELD_INTERLACED:
683 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
684 buf->vb.height,1,buf->tvnorm);
685 lines = buf->vb.height >> 1;
686 ypadding = buf->vb.width;
687 cpadding = buf->vb.width >> buf->fmt->hshift;
688 bttv_risc_planar(btv,&buf->top,
689 buf->vb.dma.sglist,
690 0,buf->vb.width,ypadding,lines,
691 uoffset,voffset,
692 buf->fmt->hshift,
693 buf->fmt->vshift,
694 cpadding);
695 bttv_risc_planar(btv,&buf->bottom,
696 buf->vb.dma.sglist,
697 ypadding,buf->vb.width,ypadding,lines,
698 uoffset+cpadding,
699 voffset+cpadding,
700 buf->fmt->hshift,
701 buf->fmt->vshift,
702 cpadding);
703 break;
704 case V4L2_FIELD_SEQ_TB:
705 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
706 buf->vb.height,1,buf->tvnorm);
707 lines = buf->vb.height >> 1;
708 ypadding = buf->vb.width;
709 cpadding = buf->vb.width >> buf->fmt->hshift;
710 bttv_risc_planar(btv,&buf->top,
711 buf->vb.dma.sglist,
712 0,buf->vb.width,0,lines,
713 uoffset >> 1,
714 voffset >> 1,
715 buf->fmt->hshift,
716 buf->fmt->vshift,
717 0);
718 bttv_risc_planar(btv,&buf->bottom,
719 buf->vb.dma.sglist,
720 lines * ypadding,buf->vb.width,0,lines,
721 lines * ypadding + (uoffset >> 1),
722 lines * ypadding + (voffset >> 1),
723 buf->fmt->hshift,
724 buf->fmt->vshift,
725 0);
726 break;
727 default:
728 BUG();
729 }
730 }
731
732 /* raw data */
733 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
734 /* build risc code */
735 buf->vb.field = V4L2_FIELD_SEQ_TB;
736 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
737 1,buf->tvnorm);
738 bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
739 0, RAW_BPL, 0, RAW_LINES);
740 bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
741 buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
742 }
743
744 /* copy format info */
745 buf->btformat = buf->fmt->btformat;
746 buf->btswap = buf->fmt->btswap;
747 return 0;
748}
749
750/* ---------------------------------------------------------- */
751
752/* calculate geometry, build risc code */
753int
754bttv_overlay_risc(struct bttv *btv,
755 struct bttv_overlay *ov,
756 const struct bttv_format *fmt,
757 struct bttv_buffer *buf)
758{
759 /* check interleave, bottom+top fields */
760 dprintk(KERN_DEBUG
761 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
762 btv->c.nr, v4l2_field_names[buf->vb.field],
763 fmt->name,ov->w.width,ov->w.height);
764
765 /* calculate geometry */
766 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
767 V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
768
769 /* build risc code */
770 switch (ov->field) {
771 case V4L2_FIELD_TOP:
772 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
773 break;
774 case V4L2_FIELD_BOTTOM:
775 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
776 break;
777 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
779 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 break;
781 default:
782 BUG();
783 }
784
785 /* copy format info */
786 buf->btformat = fmt->btformat;
787 buf->btswap = fmt->btswap;
788 buf->vb.field = ov->field;
789 return 0;
790}
791
792/*
793 * Local variables:
794 * c-basic-offset: 8
795 * End:
796 */