blob: d16af28363798d45a19336b3d621836b9b9dcb85 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3 bttv-risc.c -- interfaces to other kernel modules
4
5 bttv risc code handling
6 - memory management
7 - generation
8
9 (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25*/
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/pci.h>
30#include <linux/vmalloc.h>
31#include <linux/interrupt.h>
32#include <asm/page.h>
33#include <asm/pgtable.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030034#include <media/v4l2-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36#include "bttvp.h"
37
38#define VCR_HACK_LINES 4
39
40/* ---------------------------------------------------------- */
41/* risc code generators */
42
43int
44bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
45 struct scatterlist *sglist,
46 unsigned int offset, unsigned int bpl,
Michael Schimeke5bd0262007-01-18 16:17:39 -030047 unsigned int padding, unsigned int skip_lines,
48 unsigned int store_lines)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
50 u32 instructions,line,todo;
51 struct scatterlist *sg;
Al Virod8eaa582008-05-21 00:31:51 -030052 __le32 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 int rc;
54
55 /* estimate risc mem: worst case is one write per page border +
Duncan Sands4a287cf2006-02-27 00:09:48 -030056 one write per scan line + sync + jump (all 2 dwords). padding
57 can cause next bpl to start close to a page border. First DMA
58 region may be smaller than PAGE_SIZE */
Michael Schimeke5bd0262007-01-18 16:17:39 -030059 instructions = skip_lines * 4;
60 instructions += (1 + ((bpl + padding) * store_lines)
61 / PAGE_SIZE + store_lines) * 8;
62 instructions += 2 * 8;
63 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 return rc;
65
66 /* sync instruction */
67 rp = risc->cpu;
68 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
69 *(rp++) = cpu_to_le32(0);
70
Michael Schimeke5bd0262007-01-18 16:17:39 -030071 while (skip_lines-- > 0) {
72 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
73 BT848_RISC_EOL | bpl);
74 }
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 /* scan lines */
77 sg = sglist;
Michael Schimeke5bd0262007-01-18 16:17:39 -030078 for (line = 0; line < store_lines; line++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 if ((btv->opt_vcr_hack) &&
Michael Schimeke5bd0262007-01-18 16:17:39 -030080 (line >= (store_lines - VCR_HACK_LINES)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 continue;
82 while (offset && offset >= sg_dma_len(sg)) {
83 offset -= sg_dma_len(sg);
84 sg++;
85 }
86 if (bpl <= sg_dma_len(sg)-offset) {
87 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080088 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 BT848_RISC_EOL|bpl);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080090 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
91 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 } else {
93 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080094 todo = bpl;
95 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080097 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
98 todo -= (sg_dma_len(sg)-offset);
99 offset = 0;
100 sg++;
101 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800102 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800104 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 todo -= sg_dma_len(sg);
106 sg++;
107 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800108 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 todo);
110 *(rp++)=cpu_to_le32(sg_dma_address(sg));
111 offset += todo;
112 }
113 offset += padding;
114 }
115
116 /* save pointer to jmp instruction address */
117 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300118 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 return 0;
120}
121
122static int
123bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
124 struct scatterlist *sglist,
125 unsigned int yoffset, unsigned int ybpl,
126 unsigned int ypadding, unsigned int ylines,
127 unsigned int uoffset, unsigned int voffset,
128 unsigned int hshift, unsigned int vshift,
129 unsigned int cpadding)
130{
131 unsigned int instructions,line,todo,ylen,chroma;
Al Virod8eaa582008-05-21 00:31:51 -0300132 __le32 *rp;
133 u32 ri;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct scatterlist *ysg;
135 struct scatterlist *usg;
136 struct scatterlist *vsg;
137 int topfield = (0 == yoffset);
138 int rc;
139
140 /* estimate risc mem: worst case is one write per page border +
141 one write per scan line (5 dwords)
142 plus sync + jump (2 dwords) */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300143 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
144 / PAGE_SIZE) + ylines;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 instructions += 2;
146 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
147 return rc;
148
149 /* sync instruction */
150 rp = risc->cpu;
151 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
152 *(rp++) = cpu_to_le32(0);
153
154 /* scan lines */
155 ysg = sglist;
156 usg = sglist;
157 vsg = sglist;
158 for (line = 0; line < ylines; line++) {
159 if ((btv->opt_vcr_hack) &&
160 (line >= (ylines - VCR_HACK_LINES)))
161 continue;
162 switch (vshift) {
163 case 0:
164 chroma = 1;
165 break;
166 case 1:
167 if (topfield)
168 chroma = ((line & 1) == 0);
169 else
170 chroma = ((line & 1) == 1);
171 break;
172 case 2:
173 if (topfield)
174 chroma = ((line & 3) == 0);
175 else
176 chroma = ((line & 3) == 2);
177 break;
178 default:
179 chroma = 0;
180 break;
181 }
182
183 for (todo = ybpl; todo > 0; todo -= ylen) {
184 /* go to next sg entry if needed */
185 while (yoffset && yoffset >= sg_dma_len(ysg)) {
186 yoffset -= sg_dma_len(ysg);
187 ysg++;
188 }
189 while (uoffset && uoffset >= sg_dma_len(usg)) {
190 uoffset -= sg_dma_len(usg);
191 usg++;
192 }
193 while (voffset && voffset >= sg_dma_len(vsg)) {
194 voffset -= sg_dma_len(vsg);
195 vsg++;
196 }
197
198 /* calculate max number of bytes we can write */
199 ylen = todo;
200 if (yoffset + ylen > sg_dma_len(ysg))
201 ylen = sg_dma_len(ysg) - yoffset;
202 if (chroma) {
203 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
204 ylen = (sg_dma_len(usg) - uoffset) << hshift;
205 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
206 ylen = (sg_dma_len(vsg) - voffset) << hshift;
207 ri = BT848_RISC_WRITE123;
208 } else {
209 ri = BT848_RISC_WRITE1S23;
210 }
211 if (ybpl == todo)
212 ri |= BT848_RISC_SOL;
213 if (ylen == todo)
214 ri |= BT848_RISC_EOL;
215
216 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800217 *(rp++)=cpu_to_le32(ri | ylen);
218 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 (ylen >> hshift));
220 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
221 yoffset += ylen;
222 if (chroma) {
223 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
224 uoffset += ylen >> hshift;
225 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
226 voffset += ylen >> hshift;
227 }
228 }
229 yoffset += ypadding;
230 if (chroma) {
231 uoffset += cpadding;
232 voffset += cpadding;
233 }
234 }
235
236 /* save pointer to jmp instruction address */
237 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300238 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 return 0;
240}
241
242static int
243bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
244 const struct bttv_format *fmt, struct bttv_overlay *ov,
245 int skip_even, int skip_odd)
246{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300247 int dwords, rc, line, maxy, start, end;
248 unsigned skip, nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 struct btcx_skiplist *skips;
Al Virod8eaa582008-05-21 00:31:51 -0300250 __le32 *rp;
251 u32 ri,ra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 u32 addr;
253
254 /* skip list for window clipping */
255 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
256 return -ENOMEM;
257
Duncan Sands3203f942006-04-02 04:14:57 -0300258 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300260 dwords = (3 * ov->nclips + 2) *
261 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
262 dwords += 4;
263 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 kfree(skips);
265 return rc;
266 }
267
268 /* sync instruction */
269 rp = risc->cpu;
270 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
271 *(rp++) = cpu_to_le32(0);
272
273 addr = (unsigned long)btv->fbuf.base;
274 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
275 addr += (fmt->depth >> 3) * ov->w.left;
276
277 /* scan lines */
278 for (maxy = -1, line = 0; line < ov->w.height;
279 line++, addr += btv->fbuf.fmt.bytesperline) {
280 if ((btv->opt_vcr_hack) &&
281 (line >= (ov->w.height - VCR_HACK_LINES)))
282 continue;
283 if ((line%2) == 0 && skip_even)
284 continue;
285 if ((line%2) == 1 && skip_odd)
286 continue;
287
288 /* calculate clipping */
289 if (line > maxy)
290 btcx_calc_skips(line, ov->w.width, &maxy,
291 skips, &nskips, ov->clips, ov->nclips);
292
293 /* write out risc code */
294 for (start = 0, skip = 0; start < ov->w.width; start = end) {
295 if (skip >= nskips) {
296 ri = BT848_RISC_WRITE;
297 end = ov->w.width;
298 } else if (start < skips[skip].start) {
299 ri = BT848_RISC_WRITE;
300 end = skips[skip].start;
301 } else {
302 ri = BT848_RISC_SKIP;
303 end = skips[skip].end;
304 skip++;
305 }
306 if (BT848_RISC_WRITE == ri)
307 ra = addr + (fmt->depth>>3)*start;
308 else
309 ra = 0;
310
311 if (0 == start)
312 ri |= BT848_RISC_SOL;
313 if (ov->w.width == end)
314 ri |= BT848_RISC_EOL;
315 ri |= (fmt->depth>>3) * (end-start);
316
317 *(rp++)=cpu_to_le32(ri);
318 if (0 != ra)
319 *(rp++)=cpu_to_le32(ra);
320 }
321 }
322
323 /* save pointer to jmp instruction address */
324 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300325 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 kfree(skips);
327 return 0;
328}
329
330/* ---------------------------------------------------------- */
331
332static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300333bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
334 int width, int height, int interleaved,
335 const struct bttv_tvnorm *tvnorm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800337 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 int vdelay;
339
340 int swidth = tvnorm->swidth;
341 int totalwidth = tvnorm->totalwidth;
342 int scaledtwidth = tvnorm->scaledtwidth;
343
Trent Piepho5221e212009-01-28 21:32:59 -0300344 if (btv->input == btv->dig) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 swidth = 720;
346 totalwidth = 858;
347 scaledtwidth = 858;
348 }
349
350 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800352 xsf = (width*scaledtwidth)/swidth;
353 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
354 geo->hdelay = tvnorm->hdelayx1;
355 geo->hdelay = (geo->hdelay*width)/swidth;
356 geo->hdelay &= 0x3fe;
357 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
358 geo->vscale = (0x10000UL-sr) & 0x1fff;
359 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
360 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
361 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
362 geo->vdelay = vdelay;
363 geo->width = width;
364 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 geo->vtotal = tvnorm->vtotal;
366
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800367 if (btv->opt_combfilter) {
368 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
369 geo->comb = (width < 769) ? 1 : 0;
370 } else {
371 geo->vtc = 0;
372 geo->comb = 0;
373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
376static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300377bttv_calc_geo (struct bttv * btv,
378 struct bttv_geometry * geo,
379 unsigned int width,
380 unsigned int height,
381 int both_fields,
382 const struct bttv_tvnorm * tvnorm,
383 const struct v4l2_rect * crop)
384{
385 unsigned int c_width;
386 unsigned int c_height;
387 u32 sr;
388
389 if ((crop->left == tvnorm->cropcap.defrect.left
390 && crop->top == tvnorm->cropcap.defrect.top
391 && crop->width == tvnorm->cropcap.defrect.width
392 && crop->height == tvnorm->cropcap.defrect.height
393 && width <= tvnorm->swidth /* see PAL-Nc et al */)
Trent Piepho5221e212009-01-28 21:32:59 -0300394 || btv->input == btv->dig) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300395 bttv_calc_geo_old(btv, geo, width, height,
396 both_fields, tvnorm);
397 return;
398 }
399
400 /* For bug compatibility the image size checks permit scale
401 factors > 16. See bttv_crop_calc_limits(). */
402 c_width = min((unsigned int) crop->width, width * 16);
403 c_height = min((unsigned int) crop->height, height * 16);
404
405 geo->width = width;
406 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
407 /* Even to store Cb first, odd for Cr. */
408 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
409
410 geo->sheight = c_height;
411 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
412 sr = c_height >> !both_fields;
413 sr = (sr * 512U + (height >> 1)) / height - 512;
414 geo->vscale = (0x10000UL - sr) & 0x1fff;
415 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
416 geo->vtotal = tvnorm->vtotal;
417
418 geo->crop = (((geo->width >> 8) & 0x03) |
419 ((geo->hdelay >> 6) & 0x0c) |
420 ((geo->sheight >> 4) & 0x30) |
421 ((geo->vdelay >> 2) & 0xc0));
422
423 if (btv->opt_combfilter) {
424 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
425 geo->comb = (width < 769) ? 1 : 0;
426 } else {
427 geo->vtc = 0;
428 geo->comb = 0;
429 }
430}
431
432static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
434{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800435 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 if (geo->comb)
438 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
439 else
440 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
441
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800442 btwrite(geo->vtc, BT848_E_VTC+off);
443 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
444 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
445 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
446 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
447 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
448 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
449 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
450 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
451 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800453 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
456/* ---------------------------------------------------------- */
457/* risc group / risc main loop / dma management */
458
459void
460bttv_set_dma(struct bttv *btv, int override)
461{
462 unsigned long cmd;
463 int capctl;
464
465 btv->cap_ctl = 0;
466 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
467 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
468 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
469
470 capctl = 0;
471 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
472 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
473 capctl |= override;
474
475 d2printk(KERN_DEBUG
476 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
477 btv->c.nr,capctl,btv->loop_irq,
478 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
479 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
480 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
481 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
482
483 cmd = BT848_RISC_JUMP;
484 if (btv->loop_irq) {
485 cmd |= BT848_RISC_IRQ;
486 cmd |= (btv->loop_irq & 0x0f) << 16;
487 cmd |= (~btv->loop_irq & 0x0f) << 20;
488 }
489 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
490 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
491 } else {
492 del_timer(&btv->timeout);
493 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800494 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 btaor(capctl, ~0x0f, BT848_CAP_CTL);
497 if (capctl) {
498 if (btv->dma_on)
499 return;
500 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
501 btor(3, BT848_GPIO_DMA_CTL);
502 btv->dma_on = 1;
503 } else {
504 if (!btv->dma_on)
505 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800506 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 btv->dma_on = 0;
508 }
509 return;
510}
511
512int
513bttv_risc_init_main(struct bttv *btv)
514{
515 int rc;
516
517 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
518 return rc;
519 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
520 btv->c.nr,(unsigned long long)btv->main.dma);
521
522 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
523 BT848_FIFO_STATUS_VRE);
524 btv->main.cpu[1] = cpu_to_le32(0);
525 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
526 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
527
528 /* top field */
529 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
530 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
531 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
532 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
533
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800534 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800536 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800539 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800541 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
543
544 /* jump back to top field */
545 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800546 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 return 0;
549}
550
551int
552bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
553 int irqflags)
554{
555 unsigned long cmd;
556 unsigned long next = btv->main.dma + ((slot+2) << 2);
557
558 if (NULL == risc) {
559 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
560 btv->c.nr,risc,slot);
561 btv->main.cpu[slot+1] = cpu_to_le32(next);
562 } else {
563 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
564 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
565 cmd = BT848_RISC_JUMP;
566 if (irqflags) {
567 cmd |= BT848_RISC_IRQ;
568 cmd |= (irqflags & 0x0f) << 16;
569 cmd |= (~irqflags & 0x0f) << 20;
570 }
571 risc->jmp[0] = cpu_to_le32(cmd);
572 risc->jmp[1] = cpu_to_le32(next);
573 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
574 }
575 return 0;
576}
577
578void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300579bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300581 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
582
Eric Sesterhennae246012006-03-13 13:17:11 -0300583 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300585 videobuf_dma_unmap(q, dma);
586 videobuf_dma_free(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 btcx_riscmem_free(btv->c.pci,&buf->bottom);
588 btcx_riscmem_free(btv->c.pci,&buf->top);
Brandon Philips0fc06862007-11-06 20:02:36 -0300589 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590}
591
592int
593bttv_buffer_activate_vbi(struct bttv *btv,
594 struct bttv_buffer *vbi)
595{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300596 struct btcx_riscmem *top;
597 struct btcx_riscmem *bottom;
598 int top_irq_flags;
599 int bottom_irq_flags;
600
601 top = NULL;
602 bottom = NULL;
603 top_irq_flags = 0;
604 bottom_irq_flags = 0;
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (vbi) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300607 unsigned int crop, vdelay;
608
Brandon Philips0fc06862007-11-06 20:02:36 -0300609 vbi->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 list_del(&vbi->vb.queue);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300611
612 /* VDELAY is start of video, end of VBI capturing. */
613 crop = btread(BT848_E_CROP);
614 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
615
616 if (vbi->geo.vdelay > vdelay) {
617 vdelay = vbi->geo.vdelay & 0xfe;
618 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
619
620 btwrite(vdelay, BT848_E_VDELAY_LO);
621 btwrite(crop, BT848_E_CROP);
622 btwrite(vdelay, BT848_O_VDELAY_LO);
623 btwrite(crop, BT848_O_CROP);
624 }
625
626 if (vbi->vbi_count[0] > 0) {
627 top = &vbi->top;
628 top_irq_flags = 4;
629 }
630
631 if (vbi->vbi_count[1] > 0) {
632 top_irq_flags = 0;
633 bottom = &vbi->bottom;
634 bottom_irq_flags = 4;
635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300637
638 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
639 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642}
643
644int
645bttv_buffer_activate_video(struct bttv *btv,
646 struct bttv_buffer_set *set)
647{
648 /* video capture */
649 if (NULL != set->top && NULL != set->bottom) {
650 if (set->top == set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300651 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (set->top->vb.queue.next)
653 list_del(&set->top->vb.queue);
654 } else {
Brandon Philips0fc06862007-11-06 20:02:36 -0300655 set->top->vb.state = VIDEOBUF_ACTIVE;
656 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (set->top->vb.queue.next)
658 list_del(&set->top->vb.queue);
659 if (set->bottom->vb.queue.next)
660 list_del(&set->bottom->vb.queue);
661 }
662 bttv_apply_geo(btv, &set->top->geo, 1);
663 bttv_apply_geo(btv, &set->bottom->geo,0);
664 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
665 set->top_irq);
666 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
667 set->frame_irq);
668 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
669 ~0xff, BT848_COLOR_FMT);
670 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
671 ~0x0f, BT848_COLOR_CTL);
672 } else if (NULL != set->top) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300673 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (set->top->vb.queue.next)
675 list_del(&set->top->vb.queue);
676 bttv_apply_geo(btv, &set->top->geo,1);
677 bttv_apply_geo(btv, &set->top->geo,0);
678 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
679 set->frame_irq);
680 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
681 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
682 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
683 } else if (NULL != set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300684 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (set->bottom->vb.queue.next)
686 list_del(&set->bottom->vb.queue);
687 bttv_apply_geo(btv, &set->bottom->geo,1);
688 bttv_apply_geo(btv, &set->bottom->geo,0);
689 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
690 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
691 set->frame_irq);
692 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
693 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
694 } else {
695 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
696 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
697 }
698 return 0;
699}
700
701/* ---------------------------------------------------------- */
702
703/* calculate geometry, build risc code */
704int
705bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
706{
707 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300708 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 dprintk(KERN_DEBUG
711 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
712 btv->c.nr, v4l2_field_names[buf->vb.field],
713 buf->fmt->name, buf->vb.width, buf->vb.height);
714
715 /* packed pixel modes */
716 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
717 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
718 int bpf = bpl * (buf->vb.height >> 1);
719
720 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300721 V4L2_FIELD_HAS_BOTH(buf->vb.field),
722 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 switch (buf->vb.field) {
725 case V4L2_FIELD_TOP:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300726 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300727 /* offset */ 0,bpl,
728 /* padding */ 0,/* skip_lines */ 0,
729 buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 break;
731 case V4L2_FIELD_BOTTOM:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300732 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300733 0,bpl,0,0,buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 break;
735 case V4L2_FIELD_INTERLACED:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300736 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300737 0,bpl,bpl,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300738 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300739 bpl,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 break;
741 case V4L2_FIELD_SEQ_TB:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300742 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300743 0,bpl,0,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300744 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300745 bpf,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 break;
747 default:
748 BUG();
749 }
750 }
751
752 /* planar modes */
753 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
754 int uoffset, voffset;
755 int ypadding, cpadding, lines;
756
757 /* calculate chroma offsets */
758 uoffset = buf->vb.width * buf->vb.height;
759 voffset = buf->vb.width * buf->vb.height;
760 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
761 /* Y-Cr-Cb plane order */
762 uoffset >>= buf->fmt->hshift;
763 uoffset >>= buf->fmt->vshift;
764 uoffset += voffset;
765 } else {
766 /* Y-Cb-Cr plane order */
767 voffset >>= buf->fmt->hshift;
768 voffset >>= buf->fmt->vshift;
769 voffset += uoffset;
770 }
771
772 switch (buf->vb.field) {
773 case V4L2_FIELD_TOP:
774 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300775 buf->vb.height,/* both_fields */ 0,
776 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300777 bttv_risc_planar(btv, &buf->top, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 0,buf->vb.width,0,buf->vb.height,
779 uoffset,voffset,buf->fmt->hshift,
780 buf->fmt->vshift,0);
781 break;
782 case V4L2_FIELD_BOTTOM:
783 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300784 buf->vb.height,0,
785 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300786 bttv_risc_planar(btv, &buf->bottom, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 0,buf->vb.width,0,buf->vb.height,
788 uoffset,voffset,buf->fmt->hshift,
789 buf->fmt->vshift,0);
790 break;
791 case V4L2_FIELD_INTERLACED:
792 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300793 buf->vb.height,1,
794 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 lines = buf->vb.height >> 1;
796 ypadding = buf->vb.width;
797 cpadding = buf->vb.width >> buf->fmt->hshift;
798 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300799 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 0,buf->vb.width,ypadding,lines,
801 uoffset,voffset,
802 buf->fmt->hshift,
803 buf->fmt->vshift,
804 cpadding);
805 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300806 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 ypadding,buf->vb.width,ypadding,lines,
808 uoffset+cpadding,
809 voffset+cpadding,
810 buf->fmt->hshift,
811 buf->fmt->vshift,
812 cpadding);
813 break;
814 case V4L2_FIELD_SEQ_TB:
815 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300816 buf->vb.height,1,
817 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 lines = buf->vb.height >> 1;
819 ypadding = buf->vb.width;
820 cpadding = buf->vb.width >> buf->fmt->hshift;
821 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300822 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 0,buf->vb.width,0,lines,
824 uoffset >> 1,
825 voffset >> 1,
826 buf->fmt->hshift,
827 buf->fmt->vshift,
828 0);
829 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300830 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 lines * ypadding,buf->vb.width,0,lines,
832 lines * ypadding + (uoffset >> 1),
833 lines * ypadding + (voffset >> 1),
834 buf->fmt->hshift,
835 buf->fmt->vshift,
836 0);
837 break;
838 default:
839 BUG();
840 }
841 }
842
843 /* raw data */
844 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
845 /* build risc code */
846 buf->vb.field = V4L2_FIELD_SEQ_TB;
847 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300848 1,tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300849 bttv_risc_packed(btv, &buf->top, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300850 /* offset */ 0, RAW_BPL, /* padding */ 0,
851 /* skip_lines */ 0, RAW_LINES);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300852 bttv_risc_packed(btv, &buf->bottom, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300853 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855
856 /* copy format info */
857 buf->btformat = buf->fmt->btformat;
858 buf->btswap = buf->fmt->btswap;
859 return 0;
860}
861
862/* ---------------------------------------------------------- */
863
864/* calculate geometry, build risc code */
865int
866bttv_overlay_risc(struct bttv *btv,
867 struct bttv_overlay *ov,
868 const struct bttv_format *fmt,
869 struct bttv_buffer *buf)
870{
871 /* check interleave, bottom+top fields */
872 dprintk(KERN_DEBUG
873 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
874 btv->c.nr, v4l2_field_names[buf->vb.field],
875 fmt->name,ov->w.width,ov->w.height);
876
877 /* calculate geometry */
878 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300879 V4L2_FIELD_HAS_BOTH(ov->field),
880 &bttv_tvnorms[ov->tvnorm],&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 /* build risc code */
883 switch (ov->field) {
884 case V4L2_FIELD_TOP:
885 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
886 break;
887 case V4L2_FIELD_BOTTOM:
888 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
889 break;
890 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
892 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 break;
894 default:
895 BUG();
896 }
897
898 /* copy format info */
899 buf->btformat = fmt->btformat;
900 buf->btswap = fmt->btswap;
901 buf->vb.field = ov->field;
902 return 0;
903}
904
905/*
906 * Local variables:
907 * c-basic-offset: 8
908 * End:
909 */