blob: c24b1c100e13fe0fb1c225950c6427da7b50db7f [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/pci.h>
31#include <linux/vmalloc.h>
32#include <linux/interrupt.h>
33#include <asm/page.h>
34#include <asm/pgtable.h>
Hans Verkuil35ea11f2008-07-20 08:12:02 -030035#include <media/v4l2-ioctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include "bttvp.h"
38
39#define VCR_HACK_LINES 4
40
41/* ---------------------------------------------------------- */
42/* risc code generators */
43
44int
45bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
46 struct scatterlist *sglist,
47 unsigned int offset, unsigned int bpl,
Michael Schimeke5bd0262007-01-18 16:17:39 -030048 unsigned int padding, unsigned int skip_lines,
49 unsigned int store_lines)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 u32 instructions,line,todo;
52 struct scatterlist *sg;
Al Virod8eaa582008-05-21 00:31:51 -030053 __le32 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 int rc;
55
56 /* estimate risc mem: worst case is one write per page border +
Duncan Sands4a287cf2006-02-27 00:09:48 -030057 one write per scan line + sync + jump (all 2 dwords). padding
58 can cause next bpl to start close to a page border. First DMA
59 region may be smaller than PAGE_SIZE */
Michael Schimeke5bd0262007-01-18 16:17:39 -030060 instructions = skip_lines * 4;
61 instructions += (1 + ((bpl + padding) * store_lines)
62 / PAGE_SIZE + store_lines) * 8;
63 instructions += 2 * 8;
64 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 return rc;
66
67 /* sync instruction */
68 rp = risc->cpu;
69 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
70 *(rp++) = cpu_to_le32(0);
71
Michael Schimeke5bd0262007-01-18 16:17:39 -030072 while (skip_lines-- > 0) {
73 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
74 BT848_RISC_EOL | bpl);
75 }
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 /* scan lines */
78 sg = sglist;
Michael Schimeke5bd0262007-01-18 16:17:39 -030079 for (line = 0; line < store_lines; line++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 if ((btv->opt_vcr_hack) &&
Michael Schimeke5bd0262007-01-18 16:17:39 -030081 (line >= (store_lines - VCR_HACK_LINES)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 continue;
83 while (offset && offset >= sg_dma_len(sg)) {
84 offset -= sg_dma_len(sg);
85 sg++;
86 }
87 if (bpl <= sg_dma_len(sg)-offset) {
88 /* fits into current chunk */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080089 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 BT848_RISC_EOL|bpl);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080091 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
92 offset+=bpl;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 } else {
94 /* scanline needs to be splitted */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080095 todo = bpl;
96 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 (sg_dma_len(sg)-offset));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -080098 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
99 todo -= (sg_dma_len(sg)-offset);
100 offset = 0;
101 sg++;
102 while (todo > sg_dma_len(sg)) {
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800103 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 sg_dma_len(sg));
Mauro Carvalho Chehabf2421ca2005-11-08 21:37:45 -0800105 *(rp++)=cpu_to_le32(sg_dma_address(sg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 todo -= sg_dma_len(sg);
107 sg++;
108 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800109 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 todo);
111 *(rp++)=cpu_to_le32(sg_dma_address(sg));
112 offset += todo;
113 }
114 offset += padding;
115 }
116
117 /* save pointer to jmp instruction address */
118 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300119 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 return 0;
121}
122
123static int
124bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
125 struct scatterlist *sglist,
126 unsigned int yoffset, unsigned int ybpl,
127 unsigned int ypadding, unsigned int ylines,
128 unsigned int uoffset, unsigned int voffset,
129 unsigned int hshift, unsigned int vshift,
130 unsigned int cpadding)
131{
132 unsigned int instructions,line,todo,ylen,chroma;
Al Virod8eaa582008-05-21 00:31:51 -0300133 __le32 *rp;
134 u32 ri;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 struct scatterlist *ysg;
136 struct scatterlist *usg;
137 struct scatterlist *vsg;
138 int topfield = (0 == yoffset);
139 int rc;
140
141 /* estimate risc mem: worst case is one write per page border +
142 one write per scan line (5 dwords)
143 plus sync + jump (2 dwords) */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300144 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
145 / PAGE_SIZE) + ylines;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 instructions += 2;
147 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
148 return rc;
149
150 /* sync instruction */
151 rp = risc->cpu;
152 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);
153 *(rp++) = cpu_to_le32(0);
154
155 /* scan lines */
156 ysg = sglist;
157 usg = sglist;
158 vsg = sglist;
159 for (line = 0; line < ylines; line++) {
160 if ((btv->opt_vcr_hack) &&
161 (line >= (ylines - VCR_HACK_LINES)))
162 continue;
163 switch (vshift) {
164 case 0:
165 chroma = 1;
166 break;
167 case 1:
168 if (topfield)
169 chroma = ((line & 1) == 0);
170 else
171 chroma = ((line & 1) == 1);
172 break;
173 case 2:
174 if (topfield)
175 chroma = ((line & 3) == 0);
176 else
177 chroma = ((line & 3) == 2);
178 break;
179 default:
180 chroma = 0;
181 break;
182 }
183
184 for (todo = ybpl; todo > 0; todo -= ylen) {
185 /* go to next sg entry if needed */
186 while (yoffset && yoffset >= sg_dma_len(ysg)) {
187 yoffset -= sg_dma_len(ysg);
188 ysg++;
189 }
190 while (uoffset && uoffset >= sg_dma_len(usg)) {
191 uoffset -= sg_dma_len(usg);
192 usg++;
193 }
194 while (voffset && voffset >= sg_dma_len(vsg)) {
195 voffset -= sg_dma_len(vsg);
196 vsg++;
197 }
198
199 /* calculate max number of bytes we can write */
200 ylen = todo;
201 if (yoffset + ylen > sg_dma_len(ysg))
202 ylen = sg_dma_len(ysg) - yoffset;
203 if (chroma) {
204 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))
205 ylen = (sg_dma_len(usg) - uoffset) << hshift;
206 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))
207 ylen = (sg_dma_len(vsg) - voffset) << hshift;
208 ri = BT848_RISC_WRITE123;
209 } else {
210 ri = BT848_RISC_WRITE1S23;
211 }
212 if (ybpl == todo)
213 ri |= BT848_RISC_SOL;
214 if (ylen == todo)
215 ri |= BT848_RISC_EOL;
216
217 /* write risc instruction */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800218 *(rp++)=cpu_to_le32(ri | ylen);
219 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 (ylen >> hshift));
221 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
222 yoffset += ylen;
223 if (chroma) {
224 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);
225 uoffset += ylen >> hshift;
226 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);
227 voffset += ylen >> hshift;
228 }
229 }
230 yoffset += ypadding;
231 if (chroma) {
232 uoffset += cpadding;
233 voffset += cpadding;
234 }
235 }
236
237 /* save pointer to jmp instruction address */
238 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300239 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 return 0;
241}
242
243static int
244bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
245 const struct bttv_format *fmt, struct bttv_overlay *ov,
246 int skip_even, int skip_odd)
247{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300248 int dwords, rc, line, maxy, start, end;
249 unsigned skip, nskips;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 struct btcx_skiplist *skips;
Al Virod8eaa582008-05-21 00:31:51 -0300251 __le32 *rp;
252 u32 ri,ra;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 u32 addr;
254
255 /* skip list for window clipping */
256 if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL)))
257 return -ENOMEM;
258
Duncan Sands3203f942006-04-02 04:14:57 -0300259 /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 + sync + jump (all 2 dwords) */
Duncan Sands3203f942006-04-02 04:14:57 -0300261 dwords = (3 * ov->nclips + 2) *
262 ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height);
263 dwords += 4;
264 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 kfree(skips);
266 return rc;
267 }
268
269 /* sync instruction */
270 rp = risc->cpu;
271 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
272 *(rp++) = cpu_to_le32(0);
273
274 addr = (unsigned long)btv->fbuf.base;
275 addr += btv->fbuf.fmt.bytesperline * ov->w.top;
276 addr += (fmt->depth >> 3) * ov->w.left;
277
278 /* scan lines */
279 for (maxy = -1, line = 0; line < ov->w.height;
280 line++, addr += btv->fbuf.fmt.bytesperline) {
281 if ((btv->opt_vcr_hack) &&
282 (line >= (ov->w.height - VCR_HACK_LINES)))
283 continue;
284 if ((line%2) == 0 && skip_even)
285 continue;
286 if ((line%2) == 1 && skip_odd)
287 continue;
288
289 /* calculate clipping */
290 if (line > maxy)
291 btcx_calc_skips(line, ov->w.width, &maxy,
292 skips, &nskips, ov->clips, ov->nclips);
293
294 /* write out risc code */
295 for (start = 0, skip = 0; start < ov->w.width; start = end) {
296 if (skip >= nskips) {
297 ri = BT848_RISC_WRITE;
298 end = ov->w.width;
299 } else if (start < skips[skip].start) {
300 ri = BT848_RISC_WRITE;
301 end = skips[skip].start;
302 } else {
303 ri = BT848_RISC_SKIP;
304 end = skips[skip].end;
305 skip++;
306 }
307 if (BT848_RISC_WRITE == ri)
308 ra = addr + (fmt->depth>>3)*start;
309 else
310 ra = 0;
311
312 if (0 == start)
313 ri |= BT848_RISC_SOL;
314 if (ov->w.width == end)
315 ri |= BT848_RISC_EOL;
316 ri |= (fmt->depth>>3) * (end-start);
317
318 *(rp++)=cpu_to_le32(ri);
319 if (0 != ra)
320 *(rp++)=cpu_to_le32(ra);
321 }
322 }
323
324 /* save pointer to jmp instruction address */
325 risc->jmp = rp;
Duncan Sands4a287cf2006-02-27 00:09:48 -0300326 BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 kfree(skips);
328 return 0;
329}
330
331/* ---------------------------------------------------------- */
332
333static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300334bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
335 int width, int height, int interleaved,
336 const struct bttv_tvnorm *tvnorm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800338 u32 xsf, sr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 int vdelay;
340
341 int swidth = tvnorm->swidth;
342 int totalwidth = tvnorm->totalwidth;
343 int scaledtwidth = tvnorm->scaledtwidth;
344
Trent Piepho5221e212009-01-28 21:32:59 -0300345 if (btv->input == btv->dig) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 swidth = 720;
347 totalwidth = 858;
348 scaledtwidth = 858;
349 }
350
351 vdelay = tvnorm->vdelay;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800353 xsf = (width*scaledtwidth)/swidth;
354 geo->hscale = ((totalwidth*4096UL)/xsf-4096);
355 geo->hdelay = tvnorm->hdelayx1;
356 geo->hdelay = (geo->hdelay*width)/swidth;
357 geo->hdelay &= 0x3fe;
358 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
359 geo->vscale = (0x10000UL-sr) & 0x1fff;
360 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
361 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
362 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
363 geo->vdelay = vdelay;
364 geo->width = width;
365 geo->sheight = tvnorm->sheight;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 geo->vtotal = tvnorm->vtotal;
367
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800368 if (btv->opt_combfilter) {
369 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
370 geo->comb = (width < 769) ? 1 : 0;
371 } else {
372 geo->vtc = 0;
373 geo->comb = 0;
374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
377static void
Michael Schimeke5bd0262007-01-18 16:17:39 -0300378bttv_calc_geo (struct bttv * btv,
379 struct bttv_geometry * geo,
380 unsigned int width,
381 unsigned int height,
382 int both_fields,
383 const struct bttv_tvnorm * tvnorm,
384 const struct v4l2_rect * crop)
385{
386 unsigned int c_width;
387 unsigned int c_height;
388 u32 sr;
389
390 if ((crop->left == tvnorm->cropcap.defrect.left
391 && crop->top == tvnorm->cropcap.defrect.top
392 && crop->width == tvnorm->cropcap.defrect.width
393 && crop->height == tvnorm->cropcap.defrect.height
394 && width <= tvnorm->swidth /* see PAL-Nc et al */)
Trent Piepho5221e212009-01-28 21:32:59 -0300395 || btv->input == btv->dig) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300396 bttv_calc_geo_old(btv, geo, width, height,
397 both_fields, tvnorm);
398 return;
399 }
400
401 /* For bug compatibility the image size checks permit scale
402 factors > 16. See bttv_crop_calc_limits(). */
403 c_width = min((unsigned int) crop->width, width * 16);
404 c_height = min((unsigned int) crop->height, height * 16);
405
406 geo->width = width;
407 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
408 /* Even to store Cb first, odd for Cr. */
409 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
410
411 geo->sheight = c_height;
412 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
413 sr = c_height >> !both_fields;
414 sr = (sr * 512U + (height >> 1)) / height - 512;
415 geo->vscale = (0x10000UL - sr) & 0x1fff;
416 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
417 geo->vtotal = tvnorm->vtotal;
418
419 geo->crop = (((geo->width >> 8) & 0x03) |
420 ((geo->hdelay >> 6) & 0x0c) |
421 ((geo->sheight >> 4) & 0x30) |
422 ((geo->vdelay >> 2) & 0xc0));
423
424 if (btv->opt_combfilter) {
425 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
426 geo->comb = (width < 769) ? 1 : 0;
427 } else {
428 geo->vtc = 0;
429 geo->comb = 0;
430 }
431}
432
433static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
435{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800436 int off = odd ? 0x80 : 0x00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 if (geo->comb)
439 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
440 else
441 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
442
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800443 btwrite(geo->vtc, BT848_E_VTC+off);
444 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
445 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
446 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
447 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
448 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
449 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
450 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
451 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
452 btwrite(geo->crop, BT848_E_CROP+off);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800454 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
457/* ---------------------------------------------------------- */
458/* risc group / risc main loop / dma management */
459
460void
461bttv_set_dma(struct bttv *btv, int override)
462{
463 unsigned long cmd;
464 int capctl;
465
466 btv->cap_ctl = 0;
467 if (NULL != btv->curr.top) btv->cap_ctl |= 0x02;
468 if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01;
469 if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c;
470
471 capctl = 0;
472 capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */
473 capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */
474 capctl |= override;
475
476 d2printk(KERN_DEBUG
477 "bttv%d: capctl=%x lirq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n",
478 btv->c.nr,capctl,btv->loop_irq,
479 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
480 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
481 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,
482 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
483
484 cmd = BT848_RISC_JUMP;
485 if (btv->loop_irq) {
486 cmd |= BT848_RISC_IRQ;
487 cmd |= (btv->loop_irq & 0x0f) << 16;
488 cmd |= (~btv->loop_irq & 0x0f) << 20;
489 }
490 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) {
491 mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT);
492 } else {
493 del_timer(&btv->timeout);
494 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800495 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 btaor(capctl, ~0x0f, BT848_CAP_CTL);
498 if (capctl) {
499 if (btv->dma_on)
500 return;
501 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);
502 btor(3, BT848_GPIO_DMA_CTL);
503 btv->dma_on = 1;
504 } else {
505 if (!btv->dma_on)
506 return;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800507 btand(~3, BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 btv->dma_on = 0;
509 }
510 return;
511}
512
513int
514bttv_risc_init_main(struct bttv *btv)
515{
516 int rc;
517
518 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)
519 return rc;
520 dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n",
521 btv->c.nr,(unsigned long long)btv->main.dma);
522
523 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
524 BT848_FIFO_STATUS_VRE);
525 btv->main.cpu[1] = cpu_to_le32(0);
526 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);
527 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));
528
529 /* top field */
530 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);
531 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));
532 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
533 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
534
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800535 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 BT848_FIFO_STATUS_VRO);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800537 btv->main.cpu[9] = cpu_to_le32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 /* bottom field */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800540 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800542 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
544
545 /* jump back to top field */
546 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800547 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 return 0;
550}
551
552int
553bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
554 int irqflags)
555{
556 unsigned long cmd;
557 unsigned long next = btv->main.dma + ((slot+2) << 2);
558
559 if (NULL == risc) {
560 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=NULL\n",
561 btv->c.nr,risc,slot);
562 btv->main.cpu[slot+1] = cpu_to_le32(next);
563 } else {
564 d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n",
565 btv->c.nr,risc,slot,(unsigned long long)risc->dma,irqflags);
566 cmd = BT848_RISC_JUMP;
567 if (irqflags) {
568 cmd |= BT848_RISC_IRQ;
569 cmd |= (irqflags & 0x0f) << 16;
570 cmd |= (~irqflags & 0x0f) << 20;
571 }
572 risc->jmp[0] = cpu_to_le32(cmd);
573 risc->jmp[1] = cpu_to_le32(next);
574 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);
575 }
576 return 0;
577}
578
579void
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -0300580bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300582 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
583
Eric Sesterhennae246012006-03-13 13:17:11 -0300584 BUG_ON(in_interrupt());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 videobuf_waiton(&buf->vb,0,0);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300586 videobuf_dma_unmap(q, dma);
587 videobuf_dma_free(dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 btcx_riscmem_free(btv->c.pci,&buf->bottom);
589 btcx_riscmem_free(btv->c.pci,&buf->top);
Brandon Philips0fc06862007-11-06 20:02:36 -0300590 buf->vb.state = VIDEOBUF_NEEDS_INIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591}
592
593int
594bttv_buffer_activate_vbi(struct bttv *btv,
595 struct bttv_buffer *vbi)
596{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300597 struct btcx_riscmem *top;
598 struct btcx_riscmem *bottom;
599 int top_irq_flags;
600 int bottom_irq_flags;
601
602 top = NULL;
603 bottom = NULL;
604 top_irq_flags = 0;
605 bottom_irq_flags = 0;
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (vbi) {
Michael Schimeke5bd0262007-01-18 16:17:39 -0300608 unsigned int crop, vdelay;
609
Brandon Philips0fc06862007-11-06 20:02:36 -0300610 vbi->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 list_del(&vbi->vb.queue);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300612
613 /* VDELAY is start of video, end of VBI capturing. */
614 crop = btread(BT848_E_CROP);
615 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
616
617 if (vbi->geo.vdelay > vdelay) {
618 vdelay = vbi->geo.vdelay & 0xfe;
619 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
620
621 btwrite(vdelay, BT848_E_VDELAY_LO);
622 btwrite(crop, BT848_E_CROP);
623 btwrite(vdelay, BT848_O_VDELAY_LO);
624 btwrite(crop, BT848_O_CROP);
625 }
626
627 if (vbi->vbi_count[0] > 0) {
628 top = &vbi->top;
629 top_irq_flags = 4;
630 }
631
632 if (vbi->vbi_count[1] > 0) {
633 top_irq_flags = 0;
634 bottom = &vbi->bottom;
635 bottom_irq_flags = 4;
636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300638
639 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
640 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 return 0;
643}
644
645int
646bttv_buffer_activate_video(struct bttv *btv,
647 struct bttv_buffer_set *set)
648{
649 /* video capture */
650 if (NULL != set->top && NULL != set->bottom) {
651 if (set->top == set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300652 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 if (set->top->vb.queue.next)
654 list_del(&set->top->vb.queue);
655 } else {
Brandon Philips0fc06862007-11-06 20:02:36 -0300656 set->top->vb.state = VIDEOBUF_ACTIVE;
657 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if (set->top->vb.queue.next)
659 list_del(&set->top->vb.queue);
660 if (set->bottom->vb.queue.next)
661 list_del(&set->bottom->vb.queue);
662 }
663 bttv_apply_geo(btv, &set->top->geo, 1);
664 bttv_apply_geo(btv, &set->bottom->geo,0);
665 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
666 set->top_irq);
667 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
668 set->frame_irq);
669 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),
670 ~0xff, BT848_COLOR_FMT);
671 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
672 ~0x0f, BT848_COLOR_CTL);
673 } else if (NULL != set->top) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300674 set->top->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (set->top->vb.queue.next)
676 list_del(&set->top->vb.queue);
677 bttv_apply_geo(btv, &set->top->geo,1);
678 bttv_apply_geo(btv, &set->top->geo,0);
679 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,
680 set->frame_irq);
681 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
682 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
683 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
684 } else if (NULL != set->bottom) {
Brandon Philips0fc06862007-11-06 20:02:36 -0300685 set->bottom->vb.state = VIDEOBUF_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (set->bottom->vb.queue.next)
687 list_del(&set->bottom->vb.queue);
688 bttv_apply_geo(btv, &set->bottom->geo,1);
689 bttv_apply_geo(btv, &set->bottom->geo,0);
690 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
691 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,
692 set->frame_irq);
693 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
694 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);
695 } else {
696 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
697 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);
698 }
699 return 0;
700}
701
702/* ---------------------------------------------------------- */
703
704/* calculate geometry, build risc code */
705int
706bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
707{
708 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300709 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 dprintk(KERN_DEBUG
712 "bttv%d: buffer field: %s format: %s size: %dx%d\n",
713 btv->c.nr, v4l2_field_names[buf->vb.field],
714 buf->fmt->name, buf->vb.width, buf->vb.height);
715
716 /* packed pixel modes */
717 if (buf->fmt->flags & FORMAT_FLAGS_PACKED) {
718 int bpl = (buf->fmt->depth >> 3) * buf->vb.width;
719 int bpf = bpl * (buf->vb.height >> 1);
720
721 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300722 V4L2_FIELD_HAS_BOTH(buf->vb.field),
723 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 switch (buf->vb.field) {
726 case V4L2_FIELD_TOP:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300727 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300728 /* offset */ 0,bpl,
729 /* padding */ 0,/* skip_lines */ 0,
730 buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 break;
732 case V4L2_FIELD_BOTTOM:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300733 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300734 0,bpl,0,0,buf->vb.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 break;
736 case V4L2_FIELD_INTERLACED:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300737 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300738 0,bpl,bpl,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300739 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300740 bpl,bpl,bpl,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 break;
742 case V4L2_FIELD_SEQ_TB:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300743 bttv_risc_packed(btv,&buf->top,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300744 0,bpl,0,0,buf->vb.height >> 1);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300745 bttv_risc_packed(btv,&buf->bottom,dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300746 bpf,bpl,0,0,buf->vb.height >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 break;
748 default:
749 BUG();
750 }
751 }
752
753 /* planar modes */
754 if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) {
755 int uoffset, voffset;
756 int ypadding, cpadding, lines;
757
758 /* calculate chroma offsets */
759 uoffset = buf->vb.width * buf->vb.height;
760 voffset = buf->vb.width * buf->vb.height;
761 if (buf->fmt->flags & FORMAT_FLAGS_CrCb) {
762 /* Y-Cr-Cb plane order */
763 uoffset >>= buf->fmt->hshift;
764 uoffset >>= buf->fmt->vshift;
765 uoffset += voffset;
766 } else {
767 /* Y-Cb-Cr plane order */
768 voffset >>= buf->fmt->hshift;
769 voffset >>= buf->fmt->vshift;
770 voffset += uoffset;
771 }
772
773 switch (buf->vb.field) {
774 case V4L2_FIELD_TOP:
775 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300776 buf->vb.height,/* both_fields */ 0,
777 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300778 bttv_risc_planar(btv, &buf->top, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 0,buf->vb.width,0,buf->vb.height,
780 uoffset,voffset,buf->fmt->hshift,
781 buf->fmt->vshift,0);
782 break;
783 case V4L2_FIELD_BOTTOM:
784 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300785 buf->vb.height,0,
786 tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300787 bttv_risc_planar(btv, &buf->bottom, dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 0,buf->vb.width,0,buf->vb.height,
789 uoffset,voffset,buf->fmt->hshift,
790 buf->fmt->vshift,0);
791 break;
792 case V4L2_FIELD_INTERLACED:
793 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300794 buf->vb.height,1,
795 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 lines = buf->vb.height >> 1;
797 ypadding = buf->vb.width;
798 cpadding = buf->vb.width >> buf->fmt->hshift;
799 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300800 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 0,buf->vb.width,ypadding,lines,
802 uoffset,voffset,
803 buf->fmt->hshift,
804 buf->fmt->vshift,
805 cpadding);
806 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300807 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 ypadding,buf->vb.width,ypadding,lines,
809 uoffset+cpadding,
810 voffset+cpadding,
811 buf->fmt->hshift,
812 buf->fmt->vshift,
813 cpadding);
814 break;
815 case V4L2_FIELD_SEQ_TB:
816 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300817 buf->vb.height,1,
818 tvnorm,&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 lines = buf->vb.height >> 1;
820 ypadding = buf->vb.width;
821 cpadding = buf->vb.width >> buf->fmt->hshift;
822 bttv_risc_planar(btv,&buf->top,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300823 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 0,buf->vb.width,0,lines,
825 uoffset >> 1,
826 voffset >> 1,
827 buf->fmt->hshift,
828 buf->fmt->vshift,
829 0);
830 bttv_risc_planar(btv,&buf->bottom,
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300831 dma->sglist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 lines * ypadding,buf->vb.width,0,lines,
833 lines * ypadding + (uoffset >> 1),
834 lines * ypadding + (voffset >> 1),
835 buf->fmt->hshift,
836 buf->fmt->vshift,
837 0);
838 break;
839 default:
840 BUG();
841 }
842 }
843
844 /* raw data */
845 if (buf->fmt->flags & FORMAT_FLAGS_RAW) {
846 /* build risc code */
847 buf->vb.field = V4L2_FIELD_SEQ_TB;
848 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300849 1,tvnorm,&buf->crop);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300850 bttv_risc_packed(btv, &buf->top, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300851 /* offset */ 0, RAW_BPL, /* padding */ 0,
852 /* skip_lines */ 0, RAW_LINES);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -0300853 bttv_risc_packed(btv, &buf->bottom, dma->sglist,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300854 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
856
857 /* copy format info */
858 buf->btformat = buf->fmt->btformat;
859 buf->btswap = buf->fmt->btswap;
860 return 0;
861}
862
863/* ---------------------------------------------------------- */
864
865/* calculate geometry, build risc code */
866int
867bttv_overlay_risc(struct bttv *btv,
868 struct bttv_overlay *ov,
869 const struct bttv_format *fmt,
870 struct bttv_buffer *buf)
871{
872 /* check interleave, bottom+top fields */
873 dprintk(KERN_DEBUG
874 "bttv%d: overlay fields: %s format: %s size: %dx%d\n",
875 btv->c.nr, v4l2_field_names[buf->vb.field],
876 fmt->name,ov->w.width,ov->w.height);
877
878 /* calculate geometry */
879 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300880 V4L2_FIELD_HAS_BOTH(ov->field),
881 &bttv_tvnorms[ov->tvnorm],&buf->crop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 /* build risc code */
884 switch (ov->field) {
885 case V4L2_FIELD_TOP:
886 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0);
887 break;
888 case V4L2_FIELD_BOTTOM:
889 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
890 break;
891 case V4L2_FIELD_INTERLACED:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
893 bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 break;
895 default:
896 BUG();
897 }
898
899 /* copy format info */
900 buf->btformat = fmt->btformat;
901 buf->btswap = fmt->btswap;
902 buf->vb.field = ov->field;
903 return 0;
904}
905
906/*
907 * Local variables:
908 * c-basic-offset: 8
909 * End:
910 */