blob: afcfe71e37928ca7558a6dad33ef27dea609a0b4 [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{
Duncan Sands3203f942006-04-02 04:14:57 -0300236 int dwords,rc,line,maxy,start,end,skip,nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 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
Duncan Sands3203f942006-04-02 04:14:57 -0300245 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300247 dwords = (3 * ov->nclips + 2) *
248 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
249 dwords += 4;
250 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 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);
279
280 /* write out risc code */
281 for (start = 0, skip = 0; start < ov->w.width; start = end) {
282 if (skip >= nskips) {
283 ri = BT848_RISC_WRITE;
284 end = ov->w.width;
285 } else if (start < skips[skip].start) {
286 ri = BT848_RISC_WRITE;
287 end = skips[skip].start;
288 } else {
289 ri = BT848_RISC_SKIP;
290 end = skips[skip].end;
291 skip++;
292 }
293 if (BT848_RISC_WRITE == ri)
294 ra = addr + (fmt->depth>>3)*start;
295 else
296 ra = 0;
297
298 if (0 == start)
299 ri |= BT848_RISC_SOL;
300 if (ov->w.width == end)
301 ri |= BT848_RISC_EOL;
302 ri |= (fmt->depth>>3) * (end-start);
303
304 *(rp++)=cpu_to_le32(ri);
305 if (0 != ra)
306 *(rp++)=cpu_to_le32(ra);
307 }
308 }
309
310 /* save pointer to jmp instruction address */
311 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300312 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 kfree(skips);
314 return 0;
315}
316
317/* ---------------------------------------------------------- */
318
319static void
320bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
321 int width, int height, int interleaved, int norm)
322{
323 const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800324 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 int vdelay;
326
327 int swidth = tvnorm->swidth;
328 int totalwidth = tvnorm->totalwidth;
329 int scaledtwidth = tvnorm->scaledtwidth;
330
331 if (bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
332 swidth = 720;
333 totalwidth = 858;
334 scaledtwidth = 858;
335 }
336
337 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800339 xsf = (width*scaledtwidth)/swidth;
340 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
341 geo->hdelay = tvnorm->hdelayx1;
342 geo->hdelay = (geo->hdelay*width)/swidth;
343 geo->hdelay &= 0x3fe;
344 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
345 geo->vscale = (0x10000UL-sr) & 0x1fff;
346 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
347 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
348 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
349 geo->vdelay = vdelay;
350 geo->width = width;
351 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 geo->vtotal = tvnorm->vtotal;
353
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800354 if (btv->opt_combfilter) {
355 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
356 geo->comb = (width < 769) ? 1 : 0;
357 } else {
358 geo->vtc = 0;
359 geo->comb = 0;
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
363static void
364bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
365{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800366 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 if (geo->comb)
369 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
370 else
371 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
372
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800373 btwrite(geo->vtc, BT848_E_VTC+off);
374 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
375 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
376 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
377 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
378 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
379 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
380 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
381 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
382 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800384 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
387/* ---------------------------------------------------------- */
388/* risc group / risc main loop / dma management */
389
390void
391bttv_set_dma(struct bttv *btv, int override)
392{
393 unsigned long cmd;
394 int capctl;
395
396 btv->cap_ctl = 0;
397 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
398 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
399 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
400
401 capctl = 0;
402 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
403 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
404 capctl |= override;
405
406 d2printk(KERN_DEBUG
407 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
408 btv->c.nr,capctl,btv->loop_irq,
409 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
410 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
411 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
412 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
413
414 cmd = BT848_RISC_JUMP;
415 if (btv->loop_irq) {
416 cmd |= BT848_RISC_IRQ;
417 cmd |= (btv->loop_irq & 0x0f) << 16;
418 cmd |= (~btv->loop_irq & 0x0f) << 20;
419 }
420 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
421 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
422 } else {
423 del_timer(&btv->timeout);
424 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800425 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426
427 btaor(capctl, ~0x0f, BT848_CAP_CTL);
428 if (capctl) {
429 if (btv->dma_on)
430 return;
431 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
432 btor(3, BT848_GPIO_DMA_CTL);
433 btv->dma_on = 1;
434 } else {
435 if (!btv->dma_on)
436 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800437 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 btv->dma_on = 0;
439 }
440 return;
441}
442
443int
444bttv_risc_init_main(struct bttv *btv)
445{
446 int rc;
447
448 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
449 return rc;
450 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
451 btv->c.nr,(unsigned long long)btv->main.dma);
452
453 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
454 BT848_FIFO_STATUS_VRE);
455 btv->main.cpu[1] = cpu_to_le32(0);
456 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
457 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
458
459 /* top field */
460 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
461 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
462 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
463 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
464
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800465 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800467 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800470 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800472 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
474
475 /* jump back to top field */
476 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800477 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479 return 0;
480}
481
482int
483bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
484 int irqflags)
485{
486 unsigned long cmd;
487 unsigned long next = btv->main.dma + ((slot+2) << 2);
488
489 if (NULL == risc) {
490 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
491 btv->c.nr,risc,slot);
492 btv->main.cpu[slot+1] = cpu_to_le32(next);
493 } else {
494 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
495 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
496 cmd = BT848_RISC_JUMP;
497 if (irqflags) {
498 cmd |= BT848_RISC_IRQ;
499 cmd |= (irqflags & 0x0f) << 16;
500 cmd |= (~irqflags & 0x0f) << 20;
501 }
502 risc->jmp[0] = cpu_to_le32(cmd);
503 risc->jmp[1] = cpu_to_le32(next);
504 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
505 }
506 return 0;
507}
508
509void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300510bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
Eric Sesterhennae246012006-03-13 13:17:11 -0300512 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300514 videobuf_dma_unmap(q, &buf->vb.dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 videobuf_dma_free(&buf->vb.dma);
516 btcx_riscmem_free(btv->c.pci,&buf->bottom);
517 btcx_riscmem_free(btv->c.pci,&buf->top);
518 buf->vb.state = STATE_NEEDS_INIT;
519}
520
521int
522bttv_buffer_activate_vbi(struct bttv *btv,
523 struct bttv_buffer *vbi)
524{
525 /* vbi capture */
526 if (vbi) {
527 vbi->vb.state = STATE_ACTIVE;
528 list_del(&vbi->vb.queue);
529 bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
530 bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
531 } else {
532 bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
533 bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
534 }
535 return 0;
536}
537
538int
539bttv_buffer_activate_video(struct bttv *btv,
540 struct bttv_buffer_set *set)
541{
542 /* video capture */
543 if (NULL != set->top && NULL != set->bottom) {
544 if (set->top == set->bottom) {
545 set->top->vb.state = STATE_ACTIVE;
546 if (set->top->vb.queue.next)
547 list_del(&set->top->vb.queue);
548 } else {
549 set->top->vb.state = STATE_ACTIVE;
550 set->bottom->vb.state = STATE_ACTIVE;
551 if (set->top->vb.queue.next)
552 list_del(&set->top->vb.queue);
553 if (set->bottom->vb.queue.next)
554 list_del(&set->bottom->vb.queue);
555 }
556 bttv_apply_geo(btv, &set->top->geo, 1);
557 bttv_apply_geo(btv, &set->bottom->geo,0);
558 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
559 set->top_irq);
560 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
561 set->frame_irq);
562 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
563 ~0xff, BT848_COLOR_FMT);
564 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
565 ~0x0f, BT848_COLOR_CTL);
566 } else if (NULL != set->top) {
567 set->top->vb.state = STATE_ACTIVE;
568 if (set->top->vb.queue.next)
569 list_del(&set->top->vb.queue);
570 bttv_apply_geo(btv, &set->top->geo,1);
571 bttv_apply_geo(btv, &set->top->geo,0);
572 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
573 set->frame_irq);
574 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
575 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
576 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
577 } else if (NULL != set->bottom) {
578 set->bottom->vb.state = STATE_ACTIVE;
579 if (set->bottom->vb.queue.next)
580 list_del(&set->bottom->vb.queue);
581 bttv_apply_geo(btv, &set->bottom->geo,1);
582 bttv_apply_geo(btv, &set->bottom->geo,0);
583 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
584 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
585 set->frame_irq);
586 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
587 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
588 } else {
589 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
590 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
591 }
592 return 0;
593}
594
595/* ---------------------------------------------------------- */
596
597/* calculate geometry, build risc code */
598int
599bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
600{
601 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
602
603 dprintk(KERN_DEBUG
604 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
605 btv->c.nr, v4l2_field_names[buf->vb.field],
606 buf->fmt->name, buf->vb.width, buf->vb.height);
607
608 /* packed pixel modes */
609 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
610 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
611 int bpf = bpl * (buf->vb.height >> 1);
612
613 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
614 V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
615
616 switch (buf->vb.field) {
617 case V4L2_FIELD_TOP:
618 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
619 0,bpl,0,buf->vb.height);
620 break;
621 case V4L2_FIELD_BOTTOM:
622 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
623 0,bpl,0,buf->vb.height);
624 break;
625 case V4L2_FIELD_INTERLACED:
626 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
627 0,bpl,bpl,buf->vb.height >> 1);
628 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
629 bpl,bpl,bpl,buf->vb.height >> 1);
630 break;
631 case V4L2_FIELD_SEQ_TB:
632 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
633 0,bpl,0,buf->vb.height >> 1);
634 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
635 bpf,bpl,0,buf->vb.height >> 1);
636 break;
637 default:
638 BUG();
639 }
640 }
641
642 /* planar modes */
643 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
644 int uoffset, voffset;
645 int ypadding, cpadding, lines;
646
647 /* calculate chroma offsets */
648 uoffset = buf->vb.width * buf->vb.height;
649 voffset = buf->vb.width * buf->vb.height;
650 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
651 /* Y-Cr-Cb plane order */
652 uoffset >>= buf->fmt->hshift;
653 uoffset >>= buf->fmt->vshift;
654 uoffset += voffset;
655 } else {
656 /* Y-Cb-Cr plane order */
657 voffset >>= buf->fmt->hshift;
658 voffset >>= buf->fmt->vshift;
659 voffset += uoffset;
660 }
661
662 switch (buf->vb.field) {
663 case V4L2_FIELD_TOP:
664 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
665 buf->vb.height,0,buf->tvnorm);
666 bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
667 0,buf->vb.width,0,buf->vb.height,
668 uoffset,voffset,buf->fmt->hshift,
669 buf->fmt->vshift,0);
670 break;
671 case V4L2_FIELD_BOTTOM:
672 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
673 buf->vb.height,0,buf->tvnorm);
674 bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
675 0,buf->vb.width,0,buf->vb.height,
676 uoffset,voffset,buf->fmt->hshift,
677 buf->fmt->vshift,0);
678 break;
679 case V4L2_FIELD_INTERLACED:
680 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
681 buf->vb.height,1,buf->tvnorm);
682 lines = buf->vb.height >> 1;
683 ypadding = buf->vb.width;
684 cpadding = buf->vb.width >> buf->fmt->hshift;
685 bttv_risc_planar(btv,&buf->top,
686 buf->vb.dma.sglist,
687 0,buf->vb.width,ypadding,lines,
688 uoffset,voffset,
689 buf->fmt->hshift,
690 buf->fmt->vshift,
691 cpadding);
692 bttv_risc_planar(btv,&buf->bottom,
693 buf->vb.dma.sglist,
694 ypadding,buf->vb.width,ypadding,lines,
695 uoffset+cpadding,
696 voffset+cpadding,
697 buf->fmt->hshift,
698 buf->fmt->vshift,
699 cpadding);
700 break;
701 case V4L2_FIELD_SEQ_TB:
702 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
703 buf->vb.height,1,buf->tvnorm);
704 lines = buf->vb.height >> 1;
705 ypadding = buf->vb.width;
706 cpadding = buf->vb.width >> buf->fmt->hshift;
707 bttv_risc_planar(btv,&buf->top,
708 buf->vb.dma.sglist,
709 0,buf->vb.width,0,lines,
710 uoffset >> 1,
711 voffset >> 1,
712 buf->fmt->hshift,
713 buf->fmt->vshift,
714 0);
715 bttv_risc_planar(btv,&buf->bottom,
716 buf->vb.dma.sglist,
717 lines * ypadding,buf->vb.width,0,lines,
718 lines * ypadding + (uoffset >> 1),
719 lines * ypadding + (voffset >> 1),
720 buf->fmt->hshift,
721 buf->fmt->vshift,
722 0);
723 break;
724 default:
725 BUG();
726 }
727 }
728
729 /* raw data */
730 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
731 /* build risc code */
732 buf->vb.field = V4L2_FIELD_SEQ_TB;
733 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
734 1,buf->tvnorm);
735 bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
736 0, RAW_BPL, 0, RAW_LINES);
737 bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
738 buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
739 }
740
741 /* copy format info */
742 buf->btformat = buf->fmt->btformat;
743 buf->btswap = buf->fmt->btswap;
744 return 0;
745}
746
747/* ---------------------------------------------------------- */
748
749/* calculate geometry, build risc code */
750int
751bttv_overlay_risc(struct bttv *btv,
752 struct bttv_overlay *ov,
753 const struct bttv_format *fmt,
754 struct bttv_buffer *buf)
755{
756 /* check interleave, bottom+top fields */
757 dprintk(KERN_DEBUG
758 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
759 btv->c.nr, v4l2_field_names[buf->vb.field],
760 fmt->name,ov->w.width,ov->w.height);
761
762 /* calculate geometry */
763 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
764 V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
765
766 /* build risc code */
767 switch (ov->field) {
768 case V4L2_FIELD_TOP:
769 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
770 break;
771 case V4L2_FIELD_BOTTOM:
772 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
773 break;
774 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
776 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
778 default:
779 BUG();
780 }
781
782 /* copy format info */
783 buf->btformat = fmt->btformat;
784 buf->btswap = fmt->btswap;
785 buf->vb.field = ov->field;
786 return 0;
787}
788
789/*
790 * Local variables:
791 * c-basic-offset: 8
792 * End:
793 */