805 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 4 bttv-risc.c -- interfaces to other kernel modules5 6 bttv risc code handling7 - memory management8 - generation9 10 (c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>11 12 13*/14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt16 17#include <linux/module.h>18#include <linux/init.h>19#include <linux/slab.h>20#include <linux/pci.h>21#include <linux/vmalloc.h>22#include <linux/interrupt.h>23#include <linux/pgtable.h>24#include <asm/page.h>25#include <media/v4l2-ioctl.h>26 27#include "bttvp.h"28 29#define VCR_HACK_LINES 430 31/* ---------------------------------------------------------- */32/* risc code generators */33 34int35bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,36 struct scatterlist *sglist,37 unsigned int offset, unsigned int bpl,38 unsigned int padding, unsigned int skip_lines,39 unsigned int store_lines)40{41 u32 instructions,line,todo;42 struct scatterlist *sg;43 __le32 *rp;44 int rc;45 46 /* estimate risc mem: worst case is one write per page border +47 one write per scan line + sync + jump (all 2 dwords). padding48 can cause next bpl to start close to a page border. First DMA49 region may be smaller than PAGE_SIZE */50 instructions = skip_lines * 4;51 instructions += (1 + ((bpl + padding) * store_lines)52 / PAGE_SIZE + store_lines) * 8;53 instructions += 2 * 8;54 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)55 return rc;56 57 /* sync instruction */58 rp = risc->cpu;59 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);60 *(rp++) = cpu_to_le32(0);61 62 while (skip_lines-- > 0) {63 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |64 BT848_RISC_EOL | bpl);65 }66 67 /* scan lines */68 sg = sglist;69 for (line = 0; line < store_lines; line++) {70 if ((line >= (store_lines - VCR_HACK_LINES)) &&71 btv->opt_vcr_hack)72 continue;73 while (offset && offset >= sg_dma_len(sg)) {74 offset -= sg_dma_len(sg);75 sg = sg_next(sg);76 }77 if (bpl <= sg_dma_len(sg)-offset) {78 /* fits into current chunk */79 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|80 BT848_RISC_EOL|bpl);81 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);82 offset+=bpl;83 } else {84 /* scanline needs to be split */85 todo = bpl;86 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|87 (sg_dma_len(sg)-offset));88 *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);89 todo -= (sg_dma_len(sg)-offset);90 offset = 0;91 sg = sg_next(sg);92 while (todo > sg_dma_len(sg)) {93 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|94 sg_dma_len(sg));95 *(rp++)=cpu_to_le32(sg_dma_address(sg));96 todo -= sg_dma_len(sg);97 sg = sg_next(sg);98 }99 *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|100 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;109 WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);110 return 0;111}112 113static int114bttv_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 __le32 *rp;124 u32 ri;125 struct scatterlist *ysg;126 struct scatterlist *usg;127 struct scatterlist *vsg;128 int topfield = (0 == yoffset);129 int rc;130 131 /* estimate risc mem: worst case is one write per page border +132 one write per scan line (5 dwords)133 plus sync + jump (2 dwords) */134 instructions = ((3 + (ybpl + ypadding) * ylines * 2)135 / PAGE_SIZE) + ylines;136 instructions += 2;137 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)138 return rc;139 140 /* sync instruction */141 rp = risc->cpu;142 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3);143 *(rp++) = cpu_to_le32(0);144 145 /* scan lines */146 ysg = sglist;147 usg = sglist;148 vsg = sglist;149 for (line = 0; line < ylines; line++) {150 if ((btv->opt_vcr_hack) &&151 (line >= (ylines - VCR_HACK_LINES)))152 continue;153 switch (vshift) {154 case 0:155 chroma = 1;156 break;157 case 1:158 if (topfield)159 chroma = ((line & 1) == 0);160 else161 chroma = ((line & 1) == 1);162 break;163 case 2:164 if (topfield)165 chroma = ((line & 3) == 0);166 else167 chroma = ((line & 3) == 2);168 break;169 default:170 chroma = 0;171 break;172 }173 174 for (todo = ybpl; todo > 0; todo -= ylen) {175 /* go to next sg entry if needed */176 while (yoffset && yoffset >= sg_dma_len(ysg)) {177 yoffset -= sg_dma_len(ysg);178 ysg = sg_next(ysg);179 }180 181 /* calculate max number of bytes we can write */182 ylen = todo;183 if (yoffset + ylen > sg_dma_len(ysg))184 ylen = sg_dma_len(ysg) - yoffset;185 if (chroma) {186 while (uoffset && uoffset >= sg_dma_len(usg)) {187 uoffset -= sg_dma_len(usg);188 usg = sg_next(usg);189 }190 while (voffset && voffset >= sg_dma_len(vsg)) {191 voffset -= sg_dma_len(vsg);192 vsg = sg_next(vsg);193 }194 195 if (uoffset + (ylen>>hshift) > sg_dma_len(usg))196 ylen = (sg_dma_len(usg) - uoffset) << hshift;197 if (voffset + (ylen>>hshift) > sg_dma_len(vsg))198 ylen = (sg_dma_len(vsg) - voffset) << hshift;199 ri = BT848_RISC_WRITE123;200 } else {201 ri = BT848_RISC_WRITE1S23;202 }203 if (ybpl == todo)204 ri |= BT848_RISC_SOL;205 if (ylen == todo)206 ri |= BT848_RISC_EOL;207 208 /* write risc instruction */209 *(rp++)=cpu_to_le32(ri | ylen);210 *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |211 (ylen >> hshift));212 *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);213 yoffset += ylen;214 if (chroma) {215 *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset);216 uoffset += ylen >> hshift;217 *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset);218 voffset += ylen >> hshift;219 }220 }221 yoffset += ypadding;222 if (chroma) {223 uoffset += cpadding;224 voffset += cpadding;225 }226 }227 228 /* save pointer to jmp instruction address */229 risc->jmp = rp;230 WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);231 return 0;232}233 234/* ---------------------------------------------------------- */235 236static void237bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,238 int width, int height, int interleaved,239 const struct bttv_tvnorm *tvnorm)240{241 u32 xsf, sr;242 int vdelay;243 244 int swidth = tvnorm->swidth;245 int totalwidth = tvnorm->totalwidth;246 int scaledtwidth = tvnorm->scaledtwidth;247 248 if (btv->input == btv->dig) {249 swidth = 720;250 totalwidth = 858;251 scaledtwidth = 858;252 }253 254 vdelay = tvnorm->vdelay;255 256 xsf = (width*scaledtwidth)/swidth;257 geo->hscale = ((totalwidth*4096UL)/xsf-4096);258 geo->hdelay = tvnorm->hdelayx1;259 geo->hdelay = (geo->hdelay*width)/swidth;260 geo->hdelay &= 0x3fe;261 sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;262 geo->vscale = (0x10000UL-sr) & 0x1fff;263 geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |264 ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);265 geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;266 geo->vdelay = vdelay;267 geo->width = width;268 geo->sheight = tvnorm->sheight;269 geo->vtotal = tvnorm->vtotal;270 271 if (btv->opt_combfilter) {272 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);273 geo->comb = (width < 769) ? 1 : 0;274 } else {275 geo->vtc = 0;276 geo->comb = 0;277 }278}279 280static void281bttv_calc_geo (struct bttv * btv,282 struct bttv_geometry * geo,283 unsigned int width,284 unsigned int height,285 int both_fields,286 const struct bttv_tvnorm * tvnorm,287 const struct v4l2_rect * crop)288{289 unsigned int c_width;290 unsigned int c_height;291 u32 sr;292 293 if ((crop->left == tvnorm->cropcap.defrect.left294 && crop->top == tvnorm->cropcap.defrect.top295 && crop->width == tvnorm->cropcap.defrect.width296 && crop->height == tvnorm->cropcap.defrect.height297 && width <= tvnorm->swidth /* see PAL-Nc et al */)298 || btv->input == btv->dig) {299 bttv_calc_geo_old(btv, geo, width, height,300 both_fields, tvnorm);301 return;302 }303 304 /* For bug compatibility the image size checks permit scale305 factors > 16. See bttv_crop_calc_limits(). */306 c_width = min((unsigned int) crop->width, width * 16);307 c_height = min((unsigned int) crop->height, height * 16);308 309 geo->width = width;310 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;311 /* Even to store Cb first, odd for Cr. */312 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;313 314 geo->sheight = c_height;315 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;316 sr = c_height >> !both_fields;317 sr = (sr * 512U + (height >> 1)) / height - 512;318 geo->vscale = (0x10000UL - sr) & 0x1fff;319 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;320 geo->vtotal = tvnorm->vtotal;321 322 geo->crop = (((geo->width >> 8) & 0x03) |323 ((geo->hdelay >> 6) & 0x0c) |324 ((geo->sheight >> 4) & 0x30) |325 ((geo->vdelay >> 2) & 0xc0));326 327 if (btv->opt_combfilter) {328 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);329 geo->comb = (width < 769) ? 1 : 0;330 } else {331 geo->vtc = 0;332 geo->comb = 0;333 }334}335 336static void337bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)338{339 int off = odd ? 0x80 : 0x00;340 341 if (geo->comb)342 btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);343 else344 btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);345 346 btwrite(geo->vtc, BT848_E_VTC+off);347 btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);348 btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);349 btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);350 btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);351 btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);352 btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);353 btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);354 btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);355 btwrite(geo->crop, BT848_E_CROP+off);356 btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);357 btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);358}359 360/* ---------------------------------------------------------- */361/* risc group / risc main loop / dma management */362 363static void bttv_set_risc_status(struct bttv *btv)364{365 unsigned long cmd = BT848_RISC_JUMP;366 if (btv->loop_irq) {367 cmd |= BT848_RISC_IRQ;368 cmd |= (btv->loop_irq & 0x0f) << 16;369 cmd |= (~btv->loop_irq & 0x0f) << 20;370 }371 btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);372}373 374static void bttv_set_irq_timer(struct bttv *btv)375{376 if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi)377 mod_timer(&btv->timeout, jiffies + BTTV_TIMEOUT);378 else379 del_timer(&btv->timeout);380}381 382static int bttv_set_capture_control(struct bttv *btv, int start_capture)383{384 int capctl = 0;385 386 if (btv->curr.top || btv->curr.bottom)387 capctl = BT848_CAP_CTL_CAPTURE_ODD |388 BT848_CAP_CTL_CAPTURE_EVEN;389 390 if (btv->cvbi)391 capctl |= BT848_CAP_CTL_CAPTURE_VBI_ODD |392 BT848_CAP_CTL_CAPTURE_VBI_EVEN;393 394 capctl |= start_capture;395 396 btaor(capctl, ~0x0f, BT848_CAP_CTL);397 398 return capctl;399}400 401static void bttv_start_dma(struct bttv *btv)402{403 if (btv->dma_on)404 return;405 btwrite(btv->main.dma, BT848_RISC_STRT_ADD);406 btor(BT848_GPIO_DMA_CTL_RISC_ENABLE | BT848_GPIO_DMA_CTL_FIFO_ENABLE,407 BT848_GPIO_DMA_CTL);408 btv->dma_on = 1;409}410 411static void bttv_stop_dma(struct bttv *btv)412{413 if (!btv->dma_on)414 return;415 btand(~(BT848_GPIO_DMA_CTL_RISC_ENABLE |416 BT848_GPIO_DMA_CTL_FIFO_ENABLE), BT848_GPIO_DMA_CTL);417 btv->dma_on = 0;418}419 420void bttv_set_dma(struct bttv *btv, int start_capture)421{422 int capctl = 0;423 424 bttv_set_risc_status(btv);425 bttv_set_irq_timer(btv);426 capctl = bttv_set_capture_control(btv, start_capture);427 428 if (capctl)429 bttv_start_dma(btv);430 else431 bttv_stop_dma(btv);432 433 d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n",434 btv->c.nr,capctl,btv->loop_irq,435 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,436 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,437 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0,438 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);439}440 441int442bttv_risc_init_main(struct bttv *btv)443{444 int rc;445 446 if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0)447 return rc;448 dprintk("%d: risc main @ %08llx\n",449 btv->c.nr, (unsigned long long)btv->main.dma);450 451 btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |452 BT848_FIFO_STATUS_VRE);453 btv->main.cpu[1] = cpu_to_le32(0);454 btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP);455 btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2));456 457 /* top field */458 btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP);459 btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2));460 btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);461 btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));462 463 btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |464 BT848_FIFO_STATUS_VRO);465 btv->main.cpu[9] = cpu_to_le32(0);466 467 /* bottom field */468 btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);469 btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));470 btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);471 btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));472 473 /* jump back to top field */474 btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);475 btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));476 477 return 0;478}479 480int481bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,482 int irqflags)483{484 unsigned long cmd;485 unsigned long next = btv->main.dma + ((slot+2) << 2);486 487 if (NULL == risc) {488 d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot);489 btv->main.cpu[slot+1] = cpu_to_le32(next);490 } else {491 d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n",492 btv->c.nr, risc, slot,493 (unsigned long long)risc->dma, irqflags);494 cmd = BT848_RISC_JUMP;495 if (irqflags) {496 cmd |= BT848_RISC_IRQ;497 cmd |= (irqflags & 0x0f) << 16;498 cmd |= (~irqflags & 0x0f) << 20;499 }500 risc->jmp[0] = cpu_to_le32(cmd);501 risc->jmp[1] = cpu_to_le32(next);502 btv->main.cpu[slot+1] = cpu_to_le32(risc->dma);503 }504 return 0;505}506 507int bttv_buffer_risc_vbi(struct bttv *btv, struct bttv_buffer *buf)508{509 int r = 0;510 unsigned int offset;511 unsigned int bpl = 2044; /* max. vbipack */512 unsigned int padding = VBI_BPL - bpl;513 unsigned int skip_lines0 = 0;514 unsigned int skip_lines1 = 0;515 unsigned int min_vdelay = MIN_VDELAY;516 517 const struct bttv_tvnorm *tvnorm = btv->vbi_fmt.tvnorm;518 struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);519 struct scatterlist *list = sgt->sgl;520 521 if (btv->vbi_fmt.fmt.count[0] > 0)522 skip_lines0 = max(0, (btv->vbi_fmt.fmt.start[0] -523 tvnorm->vbistart[0]));524 if (btv->vbi_fmt.fmt.count[1] > 0)525 skip_lines1 = max(0, (btv->vbi_fmt.fmt.start[1] -526 tvnorm->vbistart[1]));527 528 if (btv->vbi_fmt.fmt.count[0] > 0) {529 r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, padding,530 skip_lines0, btv->vbi_fmt.fmt.count[0]);531 if (r)532 return r;533 }534 535 if (btv->vbi_fmt.fmt.count[1] > 0) {536 offset = btv->vbi_fmt.fmt.count[0] * VBI_BPL;537 r = bttv_risc_packed(btv, &buf->bottom, list, offset, bpl,538 padding, skip_lines1,539 btv->vbi_fmt.fmt.count[1]);540 if (r)541 return r;542 }543 544 if (btv->vbi_fmt.end >= tvnorm->cropcap.bounds.top)545 min_vdelay += btv->vbi_fmt.end - tvnorm->cropcap.bounds.top;546 547 /* For bttv_buffer_activate_vbi(). */548 buf->geo.vdelay = min_vdelay;549 550 return r;551}552 553int554bttv_buffer_activate_vbi(struct bttv *btv,555 struct bttv_buffer *vbi)556{557 struct btcx_riscmem *top;558 struct btcx_riscmem *bottom;559 int top_irq_flags;560 int bottom_irq_flags;561 562 top = NULL;563 bottom = NULL;564 top_irq_flags = 0;565 bottom_irq_flags = 0;566 567 if (vbi) {568 unsigned int crop, vdelay;569 570 list_del(&vbi->list);571 572 /* VDELAY is start of video, end of VBI capturing. */573 crop = btread(BT848_E_CROP);574 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);575 576 if (vbi->geo.vdelay > vdelay) {577 vdelay = vbi->geo.vdelay & 0xfe;578 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);579 580 btwrite(vdelay, BT848_E_VDELAY_LO);581 btwrite(crop, BT848_E_CROP);582 btwrite(vdelay, BT848_O_VDELAY_LO);583 btwrite(crop, BT848_O_CROP);584 }585 586 if (btv->vbi_count[0] > 0) {587 top = &vbi->top;588 top_irq_flags = 4;589 }590 591 if (btv->vbi_count[1] > 0) {592 top_irq_flags = 0;593 bottom = &vbi->bottom;594 bottom_irq_flags = 4;595 }596 }597 598 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);599 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);600 601 return 0;602}603 604int605bttv_buffer_activate_video(struct bttv *btv,606 struct bttv_buffer_set *set)607{608 /* video capture */609 if (NULL != set->top && NULL != set->bottom) {610 if (set->top == set->bottom) {611 if (set->top->list.next)612 list_del(&set->top->list);613 } else {614 if (set->top->list.next)615 list_del(&set->top->list);616 if (set->bottom->list.next)617 list_del(&set->bottom->list);618 }619 bttv_apply_geo(btv, &set->top->geo, 1);620 bttv_apply_geo(btv, &set->bottom->geo,0);621 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,622 set->top_irq);623 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,624 set->frame_irq);625 btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f),626 ~0xff, BT848_COLOR_FMT);627 btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),628 ~0x0f, BT848_COLOR_CTL);629 } else if (NULL != set->top) {630 if (set->top->list.next)631 list_del(&set->top->list);632 bttv_apply_geo(btv, &set->top->geo,1);633 bttv_apply_geo(btv, &set->top->geo,0);634 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top,635 set->frame_irq);636 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);637 btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);638 btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);639 } else if (NULL != set->bottom) {640 if (set->bottom->list.next)641 list_del(&set->bottom->list);642 bttv_apply_geo(btv, &set->bottom->geo,1);643 bttv_apply_geo(btv, &set->bottom->geo,0);644 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);645 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom,646 set->frame_irq);647 btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT);648 btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL);649 } else {650 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);651 bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0);652 }653 return 0;654}655 656/* ---------------------------------------------------------- */657 658/* calculate geometry, build risc code */659int660bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)661{662 int r = 0;663 const struct bttv_tvnorm *tvnorm = bttv_tvnorms + btv->tvnorm;664 struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vbuf.vb2_buf, 0);665 struct scatterlist *list = sgt->sgl;666 unsigned long size = (btv->fmt->depth * btv->width * btv->height) >> 3;667 668 /* packed pixel modes */669 if (btv->fmt->flags & FORMAT_FLAGS_PACKED) {670 int bpl = (btv->fmt->depth >> 3) * btv->width;671 int bpf = bpl * (btv->height >> 1);672 673 bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,674 V4L2_FIELD_HAS_BOTH(buf->vbuf.field), tvnorm,675 &btv->crop[!!btv->do_crop].rect);676 switch (buf->vbuf.field) {677 case V4L2_FIELD_TOP:678 r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,679 0, btv->height);680 break;681 case V4L2_FIELD_BOTTOM:682 r = bttv_risc_packed(btv, &buf->bottom, list, 0, bpl,683 0, 0, btv->height);684 break;685 case V4L2_FIELD_INTERLACED:686 r = bttv_risc_packed(btv, &buf->top, list, 0, bpl,687 bpl, 0, btv->height >> 1);688 r = bttv_risc_packed(btv, &buf->bottom, list, bpl,689 bpl, bpl, 0, btv->height >> 1);690 break;691 case V4L2_FIELD_SEQ_TB:692 r = bttv_risc_packed(btv, &buf->top, list, 0, bpl, 0,693 0, btv->height >> 1);694 r = bttv_risc_packed(btv, &buf->bottom, list, bpf,695 bpl, 0, 0, btv->height >> 1);696 break;697 default:698 WARN_ON(1);699 return -EINVAL;700 }701 }702 /* planar modes */703 if (btv->fmt->flags & FORMAT_FLAGS_PLANAR) {704 int uoffset, voffset;705 int ypadding, cpadding, lines;706 707 /* calculate chroma offsets */708 uoffset = btv->width * btv->height;709 voffset = btv->width * btv->height;710 if (btv->fmt->flags & FORMAT_FLAGS_CrCb) {711 /* Y-Cr-Cb plane order */712 uoffset >>= btv->fmt->hshift;713 uoffset >>= btv->fmt->vshift;714 uoffset += voffset;715 } else {716 /* Y-Cb-Cr plane order */717 voffset >>= btv->fmt->hshift;718 voffset >>= btv->fmt->vshift;719 voffset += uoffset;720 }721 switch (buf->vbuf.field) {722 case V4L2_FIELD_TOP:723 bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,724 0, tvnorm,725 &btv->crop[!!btv->do_crop].rect);726 r = bttv_risc_planar(btv, &buf->top, list, 0,727 btv->width, 0, btv->height,728 uoffset, voffset,729 btv->fmt->hshift,730 btv->fmt->vshift, 0);731 break;732 case V4L2_FIELD_BOTTOM:733 bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,734 0, tvnorm,735 &btv->crop[!!btv->do_crop].rect);736 r = bttv_risc_planar(btv, &buf->bottom, list, 0,737 btv->width, 0, btv->height,738 uoffset, voffset,739 btv->fmt->hshift,740 btv->fmt->vshift, 0);741 break;742 case V4L2_FIELD_INTERLACED:743 bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,744 1, tvnorm,745 &btv->crop[!!btv->do_crop].rect);746 lines = btv->height >> 1;747 ypadding = btv->width;748 cpadding = btv->width >> btv->fmt->hshift;749 r = bttv_risc_planar(btv, &buf->top, list, 0,750 btv->width, ypadding, lines,751 uoffset, voffset,752 btv->fmt->hshift,753 btv->fmt->vshift, cpadding);754 755 r = bttv_risc_planar(btv, &buf->bottom, list,756 ypadding, btv->width, ypadding,757 lines, uoffset + cpadding,758 voffset + cpadding,759 btv->fmt->hshift,760 btv->fmt->vshift, cpadding);761 break;762 case V4L2_FIELD_SEQ_TB:763 bttv_calc_geo(btv, &buf->geo, btv->width, btv->height,764 1, tvnorm,765 &btv->crop[!!btv->do_crop].rect);766 lines = btv->height >> 1;767 ypadding = btv->width;768 cpadding = btv->width >> btv->fmt->hshift;769 r = bttv_risc_planar(btv, &buf->top, list, 0,770 btv->width, 0, lines,771 uoffset >> 1, voffset >> 1,772 btv->fmt->hshift,773 btv->fmt->vshift, 0);774 r = bttv_risc_planar(btv, &buf->bottom, list,775 lines * ypadding,776 btv->width, 0, lines,777 lines * ypadding + (uoffset >> 1),778 lines * ypadding + (voffset >> 1),779 btv->fmt->hshift,780 btv->fmt->vshift, 0);781 break;782 default:783 WARN_ON(1);784 return -EINVAL;785 }786 }787 /* raw data */788 if (btv->fmt->flags & FORMAT_FLAGS_RAW) {789 /* build risc code */790 buf->vbuf.field = V4L2_FIELD_SEQ_TB;791 bttv_calc_geo(btv, &buf->geo, tvnorm->swidth, tvnorm->sheight,792 1, tvnorm, &btv->crop[!!btv->do_crop].rect);793 r = bttv_risc_packed(btv, &buf->top, list, 0, RAW_BPL, 0, 0,794 RAW_LINES);795 r = bttv_risc_packed(btv, &buf->bottom, list, size / 2,796 RAW_BPL, 0, 0, RAW_LINES);797 }798 799 /* copy format info */800 buf->btformat = btv->fmt->btformat;801 buf->btswap = btv->fmt->btswap;802 803 return r;804}805