Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     yuv support
0004 
0005     Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>
0006 
0007  */
0008 
0009 #include "ivtv-driver.h"
0010 #include "ivtv-udma.h"
0011 #include "ivtv-yuv.h"
0012 
0013 /* YUV buffer offsets */
0014 const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
0015     0x001a8600,
0016     0x00240400,
0017     0x002d8200,
0018     0x00370000,
0019     0x00029000,
0020     0x000C0E00,
0021     0x006B0400,
0022     0x00748200
0023 };
0024 
0025 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
0026                   struct ivtv_dma_frame *args)
0027 {
0028     struct ivtv_dma_page_info y_dma;
0029     struct ivtv_dma_page_info uv_dma;
0030     struct yuv_playback_info *yi = &itv->yuv_info;
0031     u8 frame = yi->draw_frame;
0032     struct yuv_frame_info *f = &yi->new_frame_info[frame];
0033     int y_pages, uv_pages;
0034     unsigned long y_buffer_offset, uv_buffer_offset;
0035     int y_decode_height, uv_decode_height, y_size;
0036 
0037     y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
0038     uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
0039 
0040     y_decode_height = uv_decode_height = f->src_h + f->src_y;
0041 
0042     if (f->offset_y)
0043         y_buffer_offset += 720 * 16;
0044 
0045     if (y_decode_height & 15)
0046         y_decode_height = (y_decode_height + 16) & ~15;
0047 
0048     if (uv_decode_height & 31)
0049         uv_decode_height = (uv_decode_height + 32) & ~31;
0050 
0051     y_size = 720 * y_decode_height;
0052 
0053     /* Still in USE */
0054     if (dma->SG_length || dma->page_count) {
0055         IVTV_DEBUG_WARN
0056             ("prep_user_dma: SG_length %d page_count %d still full?\n",
0057              dma->SG_length, dma->page_count);
0058         return -EBUSY;
0059     }
0060 
0061     ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
0062     ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
0063 
0064     /* Pin user pages for DMA Xfer */
0065     y_pages = pin_user_pages_unlocked(y_dma.uaddr,
0066             y_dma.page_count, &dma->map[0], FOLL_FORCE);
0067     uv_pages = 0; /* silence gcc. value is set and consumed only if: */
0068     if (y_pages == y_dma.page_count) {
0069         uv_pages = pin_user_pages_unlocked(uv_dma.uaddr,
0070                 uv_dma.page_count, &dma->map[y_pages],
0071                 FOLL_FORCE);
0072     }
0073 
0074     if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
0075         int rc = -EFAULT;
0076 
0077         if (y_pages == y_dma.page_count) {
0078             IVTV_DEBUG_WARN
0079                 ("failed to map uv user pages, returned %d expecting %d\n",
0080                  uv_pages, uv_dma.page_count);
0081 
0082             if (uv_pages >= 0) {
0083                 unpin_user_pages(&dma->map[y_pages], uv_pages);
0084                 rc = -EFAULT;
0085             } else {
0086                 rc = uv_pages;
0087             }
0088         } else {
0089             IVTV_DEBUG_WARN
0090                 ("failed to map y user pages, returned %d expecting %d\n",
0091                  y_pages, y_dma.page_count);
0092         }
0093         if (y_pages >= 0) {
0094             unpin_user_pages(dma->map, y_pages);
0095             /*
0096              * Inherit the -EFAULT from rc's
0097              * initialization, but allow it to be
0098              * overridden by uv_pages above if it was an
0099              * actual errno.
0100              */
0101         } else {
0102             rc = y_pages;
0103         }
0104         return rc;
0105     }
0106 
0107     dma->page_count = y_pages + uv_pages;
0108 
0109     /* Fill & map SG List */
0110     if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
0111         IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
0112         unpin_user_pages(dma->map, dma->page_count);
0113         dma->page_count = 0;
0114         return -ENOMEM;
0115     }
0116     dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
0117                     dma->page_count, DMA_TO_DEVICE);
0118 
0119     /* Fill SG Array with new values */
0120     ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
0121 
0122     /* If we've offset the y plane, ensure top area is blanked */
0123     if (f->offset_y && yi->blanking_dmaptr) {
0124         dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
0125         dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
0126         dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
0127         dma->SG_length++;
0128     }
0129 
0130     /* Tag SG Array with Interrupt Bit */
0131     dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
0132 
0133     ivtv_udma_sync_for_device(itv);
0134     return 0;
0135 }
0136 
0137 /* We rely on a table held in the firmware - Quick check. */
0138 int ivtv_yuv_filter_check(struct ivtv *itv)
0139 {
0140     int i, y, uv;
0141 
0142     for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
0143         if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
0144             (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
0145             IVTV_WARN ("YUV filter table not found in firmware.\n");
0146             return -1;
0147         }
0148     }
0149     return 0;
0150 }
0151 
0152 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
0153 {
0154     u32 i, line;
0155 
0156     /* If any filter is -1, then don't update it */
0157     if (h_filter > -1) {
0158         if (h_filter > 4)
0159             h_filter = 4;
0160         i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
0161         for (line = 0; line < 16; line++) {
0162             write_reg(read_dec(i), 0x02804);
0163             write_reg(read_dec(i), 0x0281c);
0164             i += 4;
0165             write_reg(read_dec(i), 0x02808);
0166             write_reg(read_dec(i), 0x02820);
0167             i += 4;
0168             write_reg(read_dec(i), 0x0280c);
0169             write_reg(read_dec(i), 0x02824);
0170             i += 4;
0171             write_reg(read_dec(i), 0x02810);
0172             write_reg(read_dec(i), 0x02828);
0173             i += 4;
0174             write_reg(read_dec(i), 0x02814);
0175             write_reg(read_dec(i), 0x0282c);
0176             i += 8;
0177             write_reg(0, 0x02818);
0178             write_reg(0, 0x02830);
0179         }
0180         IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
0181     }
0182 
0183     if (v_filter_1 > -1) {
0184         if (v_filter_1 > 4)
0185             v_filter_1 = 4;
0186         i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
0187         for (line = 0; line < 16; line++) {
0188             write_reg(read_dec(i), 0x02900);
0189             i += 4;
0190             write_reg(read_dec(i), 0x02904);
0191             i += 8;
0192             write_reg(0, 0x02908);
0193         }
0194         IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
0195     }
0196 
0197     if (v_filter_2 > -1) {
0198         if (v_filter_2 > 4)
0199             v_filter_2 = 4;
0200         i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
0201         for (line = 0; line < 16; line++) {
0202             write_reg(read_dec(i), 0x0290c);
0203             i += 4;
0204             write_reg(read_dec(i), 0x02910);
0205             i += 8;
0206             write_reg(0, 0x02914);
0207         }
0208         IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
0209     }
0210 }
0211 
0212 static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
0213 {
0214     struct yuv_playback_info *yi = &itv->yuv_info;
0215     u32 reg_2834, reg_2838, reg_283c;
0216     u32 reg_2844, reg_2854, reg_285c;
0217     u32 reg_2864, reg_2874, reg_2890;
0218     u32 reg_2870, reg_2870_base, reg_2870_offset;
0219     int x_cutoff;
0220     int h_filter;
0221     u32 master_width;
0222 
0223     IVTV_DEBUG_WARN
0224         ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
0225          f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
0226 
0227     /* How wide is the src image */
0228     x_cutoff = f->src_w + f->src_x;
0229 
0230     /* Set the display width */
0231     reg_2834 = f->dst_w;
0232     reg_2838 = reg_2834;
0233 
0234     /* Set the display position */
0235     reg_2890 = f->dst_x;
0236 
0237     /* Index into the image horizontally */
0238     reg_2870 = 0;
0239 
0240     /* 2870 is normally fudged to align video coords with osd coords.
0241        If running full screen, it causes an unwanted left shift
0242        Remove the fudge if we almost fill the screen.
0243        Gradually adjust the offset to avoid the video 'snapping'
0244        left/right if it gets dragged through this region.
0245        Only do this if osd is full width. */
0246     if (f->vis_w == 720) {
0247         if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
0248             reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
0249         else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
0250             reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
0251 
0252         if (f->dst_w >= f->src_w)
0253             reg_2870 = reg_2870 << 16 | reg_2870;
0254         else
0255             reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
0256     }
0257 
0258     if (f->dst_w < f->src_w)
0259         reg_2870 = 0x000d000e - reg_2870;
0260     else
0261         reg_2870 = 0x0012000e - reg_2870;
0262 
0263     /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
0264     reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
0265 
0266     if (f->dst_w >= f->src_w) {
0267         x_cutoff &= ~1;
0268         master_width = (f->src_w * 0x00200000) / (f->dst_w);
0269         if (master_width * f->dst_w != f->src_w * 0x00200000)
0270             master_width++;
0271         reg_2834 = (reg_2834 << 16) | x_cutoff;
0272         reg_2838 = (reg_2838 << 16) | x_cutoff;
0273         reg_283c = master_width >> 2;
0274         reg_2844 = master_width >> 2;
0275         reg_2854 = master_width;
0276         reg_285c = master_width >> 1;
0277         reg_2864 = master_width >> 1;
0278 
0279         /* We also need to factor in the scaling
0280            (src_w - dst_w) / (src_w / 4) */
0281         if (f->dst_w > f->src_w)
0282             reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
0283         else
0284             reg_2870_base = 0;
0285 
0286         reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
0287         reg_2874 = 0;
0288     } else if (f->dst_w < f->src_w / 2) {
0289         master_width = (f->src_w * 0x00080000) / f->dst_w;
0290         if (master_width * f->dst_w != f->src_w * 0x00080000)
0291             master_width++;
0292         reg_2834 = (reg_2834 << 16) | x_cutoff;
0293         reg_2838 = (reg_2838 << 16) | x_cutoff;
0294         reg_283c = master_width >> 2;
0295         reg_2844 = master_width >> 1;
0296         reg_2854 = master_width;
0297         reg_285c = master_width >> 1;
0298         reg_2864 = master_width >> 1;
0299         reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
0300         reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
0301         reg_2874 = 0x00000012;
0302     } else {
0303         master_width = (f->src_w * 0x00100000) / f->dst_w;
0304         if (master_width * f->dst_w != f->src_w * 0x00100000)
0305             master_width++;
0306         reg_2834 = (reg_2834 << 16) | x_cutoff;
0307         reg_2838 = (reg_2838 << 16) | x_cutoff;
0308         reg_283c = master_width >> 2;
0309         reg_2844 = master_width >> 1;
0310         reg_2854 = master_width;
0311         reg_285c = master_width >> 1;
0312         reg_2864 = master_width >> 1;
0313         reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
0314         reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
0315         reg_2874 = 0x00000001;
0316     }
0317 
0318     /* Select the horizontal filter */
0319     if (f->src_w == f->dst_w) {
0320         /* An exact size match uses filter 0 */
0321         h_filter = 0;
0322     } else {
0323         /* Figure out which filter to use */
0324         h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
0325         h_filter = (h_filter >> 1) + (h_filter & 1);
0326         /* Only an exact size match can use filter 0 */
0327         h_filter += !h_filter;
0328     }
0329 
0330     write_reg(reg_2834, 0x02834);
0331     write_reg(reg_2838, 0x02838);
0332     IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
0333                yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
0334 
0335     write_reg(reg_283c, 0x0283c);
0336     write_reg(reg_2844, 0x02844);
0337 
0338     IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
0339                yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
0340 
0341     write_reg(0x00080514, 0x02840);
0342     write_reg(0x00100514, 0x02848);
0343     IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
0344                yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
0345 
0346     write_reg(reg_2854, 0x02854);
0347     IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
0348                yi->reg_2854, reg_2854);
0349 
0350     write_reg(reg_285c, 0x0285c);
0351     write_reg(reg_2864, 0x02864);
0352     IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
0353                yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
0354 
0355     write_reg(reg_2874, 0x02874);
0356     IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
0357                yi->reg_2874, reg_2874);
0358 
0359     write_reg(reg_2870, 0x02870);
0360     IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
0361                yi->reg_2870, reg_2870);
0362 
0363     write_reg(reg_2890, 0x02890);
0364     IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
0365                yi->reg_2890, reg_2890);
0366 
0367     /* Only update the filter if we really need to */
0368     if (h_filter != yi->h_filter) {
0369         ivtv_yuv_filter(itv, h_filter, -1, -1);
0370         yi->h_filter = h_filter;
0371     }
0372 }
0373 
0374 static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
0375 {
0376     struct yuv_playback_info *yi = &itv->yuv_info;
0377     u32 master_height;
0378     u32 reg_2918, reg_291c, reg_2920, reg_2928;
0379     u32 reg_2930, reg_2934, reg_293c;
0380     u32 reg_2940, reg_2944, reg_294c;
0381     u32 reg_2950, reg_2954, reg_2958, reg_295c;
0382     u32 reg_2960, reg_2964, reg_2968, reg_296c;
0383     u32 reg_289c;
0384     u32 src_major_y, src_minor_y;
0385     u32 src_major_uv, src_minor_uv;
0386     u32 reg_2964_base, reg_2968_base;
0387     int v_filter_1, v_filter_2;
0388 
0389     IVTV_DEBUG_WARN
0390         ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
0391          f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
0392 
0393     /* What scaling mode is being used... */
0394     IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
0395                f->interlaced_y ? "Interlaced" : "Progressive");
0396 
0397     IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
0398                f->interlaced_uv ? "Interlaced" : "Progressive");
0399 
0400     /* What is the source video being treated as... */
0401     IVTV_DEBUG_WARN("Source video: %s\n",
0402             f->interlaced ? "Interlaced" : "Progressive");
0403 
0404     /* We offset into the image using two different index methods, so split
0405        the y source coord into two parts. */
0406     if (f->src_y < 8) {
0407         src_minor_uv = f->src_y;
0408         src_major_uv = 0;
0409     } else {
0410         src_minor_uv = 8;
0411         src_major_uv = f->src_y - 8;
0412     }
0413 
0414     src_minor_y = src_minor_uv;
0415     src_major_y = src_major_uv;
0416 
0417     if (f->offset_y)
0418         src_minor_y += 16;
0419 
0420     if (f->interlaced_y)
0421         reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
0422     else
0423         reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
0424 
0425     if (f->interlaced_uv)
0426         reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
0427     else
0428         reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
0429 
0430     reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
0431     reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
0432 
0433     if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
0434         master_height = (f->src_h * 0x00400000) / f->dst_h;
0435         if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
0436             master_height++;
0437         reg_2920 = master_height >> 2;
0438         reg_2928 = master_height >> 3;
0439         reg_2930 = master_height;
0440         reg_2940 = master_height >> 1;
0441         reg_2964_base >>= 3;
0442         reg_2968_base >>= 3;
0443         reg_296c = 0x00000000;
0444     } else if (f->dst_h >= f->src_h) {
0445         master_height = (f->src_h * 0x00400000) / f->dst_h;
0446         master_height = (master_height >> 1) + (master_height & 1);
0447         reg_2920 = master_height >> 2;
0448         reg_2928 = master_height >> 2;
0449         reg_2930 = master_height;
0450         reg_2940 = master_height >> 1;
0451         reg_296c = 0x00000000;
0452         if (f->interlaced_y) {
0453             reg_2964_base >>= 3;
0454         } else {
0455             reg_296c++;
0456             reg_2964_base >>= 2;
0457         }
0458         if (f->interlaced_uv)
0459             reg_2928 >>= 1;
0460         reg_2968_base >>= 3;
0461     } else if (f->dst_h >= f->src_h / 2) {
0462         master_height = (f->src_h * 0x00200000) / f->dst_h;
0463         master_height = (master_height >> 1) + (master_height & 1);
0464         reg_2920 = master_height >> 2;
0465         reg_2928 = master_height >> 2;
0466         reg_2930 = master_height;
0467         reg_2940 = master_height;
0468         reg_296c = 0x00000101;
0469         if (f->interlaced_y) {
0470             reg_2964_base >>= 2;
0471         } else {
0472             reg_296c++;
0473             reg_2964_base >>= 1;
0474         }
0475         if (f->interlaced_uv)
0476             reg_2928 >>= 1;
0477         reg_2968_base >>= 2;
0478     } else {
0479         master_height = (f->src_h * 0x00100000) / f->dst_h;
0480         master_height = (master_height >> 1) + (master_height & 1);
0481         reg_2920 = master_height >> 2;
0482         reg_2928 = master_height >> 2;
0483         reg_2930 = master_height;
0484         reg_2940 = master_height;
0485         reg_2964_base >>= 1;
0486         reg_2968_base >>= 2;
0487         reg_296c = 0x00000102;
0488     }
0489 
0490     /* FIXME These registers change depending on scaled / unscaled output
0491        We really need to work out what they should be */
0492     if (f->src_h == f->dst_h) {
0493         reg_2934 = 0x00020000;
0494         reg_293c = 0x00100000;
0495         reg_2944 = 0x00040000;
0496         reg_294c = 0x000b0000;
0497     } else {
0498         reg_2934 = 0x00000FF0;
0499         reg_293c = 0x00000FF0;
0500         reg_2944 = 0x00000FF0;
0501         reg_294c = 0x00000FF0;
0502     }
0503 
0504     /* The first line to be displayed */
0505     reg_2950 = 0x00010000 + src_major_y;
0506     if (f->interlaced_y)
0507         reg_2950 += 0x00010000;
0508     reg_2954 = reg_2950 + 1;
0509 
0510     reg_2958 = 0x00010000 + (src_major_y >> 1);
0511     if (f->interlaced_uv)
0512         reg_2958 += 0x00010000;
0513     reg_295c = reg_2958 + 1;
0514 
0515     if (yi->decode_height == 480)
0516         reg_289c = 0x011e0017;
0517     else
0518         reg_289c = 0x01500017;
0519 
0520     if (f->dst_y < 0)
0521         reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
0522     else
0523         reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
0524 
0525     /* How much of the source to decode.
0526        Take into account the source offset */
0527     reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
0528         (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
0529 
0530     /* Calculate correct value for register 2964 */
0531     if (f->src_h == f->dst_h) {
0532         reg_2964 = 1;
0533     } else {
0534         reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
0535         reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
0536     }
0537     reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
0538     reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
0539 
0540     /* Okay, we've wasted time working out the correct value,
0541        but if we use it, it fouls the the window alignment.
0542        Fudge it to what we want... */
0543     reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
0544     reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
0545 
0546     /* Deviate further from what it should be. I find the flicker headache
0547        inducing so try to reduce it slightly. Leave 2968 as-is otherwise
0548        colours foul. */
0549     if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
0550         reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
0551 
0552     if (!f->interlaced_y)
0553         reg_2964 -= 0x00010001;
0554     if (!f->interlaced_uv)
0555         reg_2968 -= 0x00010001;
0556 
0557     reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
0558     reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
0559 
0560     /* Select the vertical filter */
0561     if (f->src_h == f->dst_h) {
0562         /* An exact size match uses filter 0/1 */
0563         v_filter_1 = 0;
0564         v_filter_2 = 1;
0565     } else {
0566         /* Figure out which filter to use */
0567         v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
0568         v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
0569         /* Only an exact size match can use filter 0 */
0570         v_filter_1 += !v_filter_1;
0571         v_filter_2 = v_filter_1;
0572     }
0573 
0574     write_reg(reg_2934, 0x02934);
0575     write_reg(reg_293c, 0x0293c);
0576     IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
0577                yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
0578     write_reg(reg_2944, 0x02944);
0579     write_reg(reg_294c, 0x0294c);
0580     IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
0581                yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
0582 
0583     /* Ensure 2970 is 0 (does it ever change ?) */
0584 /*  write_reg(0,0x02970); */
0585 /*  IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
0586 
0587     write_reg(reg_2930, 0x02938);
0588     write_reg(reg_2930, 0x02930);
0589     IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
0590                yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
0591 
0592     write_reg(reg_2928, 0x02928);
0593     write_reg(reg_2928 + 0x514, 0x0292C);
0594     IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
0595                yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
0596 
0597     write_reg(reg_2920, 0x02920);
0598     write_reg(reg_2920 + 0x514, 0x02924);
0599     IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
0600                yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
0601 
0602     write_reg(reg_2918, 0x02918);
0603     write_reg(reg_291c, 0x0291C);
0604     IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
0605                yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
0606 
0607     write_reg(reg_296c, 0x0296c);
0608     IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
0609                yi->reg_296c, reg_296c);
0610 
0611     write_reg(reg_2940, 0x02948);
0612     write_reg(reg_2940, 0x02940);
0613     IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
0614                yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
0615 
0616     write_reg(reg_2950, 0x02950);
0617     write_reg(reg_2954, 0x02954);
0618     IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
0619                yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
0620 
0621     write_reg(reg_2958, 0x02958);
0622     write_reg(reg_295c, 0x0295C);
0623     IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
0624                yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
0625 
0626     write_reg(reg_2960, 0x02960);
0627     IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
0628                yi->reg_2960, reg_2960);
0629 
0630     write_reg(reg_2964, 0x02964);
0631     write_reg(reg_2968, 0x02968);
0632     IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
0633                yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
0634 
0635     write_reg(reg_289c, 0x0289c);
0636     IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
0637                yi->reg_289c, reg_289c);
0638 
0639     /* Only update filter 1 if we really need to */
0640     if (v_filter_1 != yi->v_filter_1) {
0641         ivtv_yuv_filter(itv, -1, v_filter_1, -1);
0642         yi->v_filter_1 = v_filter_1;
0643     }
0644 
0645     /* Only update filter 2 if we really need to */
0646     if (v_filter_2 != yi->v_filter_2) {
0647         ivtv_yuv_filter(itv, -1, -1, v_filter_2);
0648         yi->v_filter_2 = v_filter_2;
0649     }
0650 }
0651 
0652 /* Modify the supplied coordinate information to fit the visible osd area */
0653 static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
0654 {
0655     struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
0656     int osd_crop;
0657     u32 osd_scale;
0658     u32 yuv_update = 0;
0659 
0660     /* Sorry, but no negative coords for src */
0661     if (f->src_x < 0)
0662         f->src_x = 0;
0663     if (f->src_y < 0)
0664         f->src_y = 0;
0665 
0666     /* Can only reduce width down to 1/4 original size */
0667     if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
0668         f->src_x += osd_crop / 2;
0669         f->src_w = (f->src_w - osd_crop) & ~3;
0670         f->dst_w = f->src_w / 4;
0671         f->dst_w += f->dst_w & 1;
0672     }
0673 
0674     /* Can only reduce height down to 1/4 original size */
0675     if (f->src_h / f->dst_h >= 2) {
0676         /* Overflow may be because we're running progressive,
0677            so force mode switch */
0678         f->interlaced_y = 1;
0679         /* Make sure we're still within limits for interlace */
0680         if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
0681             /* If we reach here we'll have to force the height. */
0682             f->src_y += osd_crop / 2;
0683             f->src_h = (f->src_h - osd_crop) & ~3;
0684             f->dst_h = f->src_h / 4;
0685             f->dst_h += f->dst_h & 1;
0686         }
0687     }
0688 
0689     /* If there's nothing to safe to display, we may as well stop now */
0690     if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
0691         (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0692         return IVTV_YUV_UPDATE_INVALID;
0693     }
0694 
0695     /* Ensure video remains inside OSD area */
0696     osd_scale = (f->src_h << 16) / f->dst_h;
0697 
0698     if ((osd_crop = f->pan_y - f->dst_y) > 0) {
0699         /* Falls off the upper edge - crop */
0700         f->src_y += (osd_scale * osd_crop) >> 16;
0701         f->src_h -= (osd_scale * osd_crop) >> 16;
0702         f->dst_h -= osd_crop;
0703         f->dst_y = 0;
0704     } else {
0705         f->dst_y -= f->pan_y;
0706     }
0707 
0708     if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
0709         /* Falls off the lower edge - crop */
0710         f->dst_h -= osd_crop;
0711         f->src_h -= (osd_scale * osd_crop) >> 16;
0712     }
0713 
0714     osd_scale = (f->src_w << 16) / f->dst_w;
0715 
0716     if ((osd_crop = f->pan_x - f->dst_x) > 0) {
0717         /* Fall off the left edge - crop */
0718         f->src_x += (osd_scale * osd_crop) >> 16;
0719         f->src_w -= (osd_scale * osd_crop) >> 16;
0720         f->dst_w -= osd_crop;
0721         f->dst_x = 0;
0722     } else {
0723         f->dst_x -= f->pan_x;
0724     }
0725 
0726     if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
0727         /* Falls off the right edge - crop */
0728         f->dst_w -= osd_crop;
0729         f->src_w -= (osd_scale * osd_crop) >> 16;
0730     }
0731 
0732     if (itv->yuv_info.track_osd) {
0733         /* The OSD can be moved. Track to it */
0734         f->dst_x += itv->yuv_info.osd_x_offset;
0735         f->dst_y += itv->yuv_info.osd_y_offset;
0736     }
0737 
0738     /* Width & height for both src & dst must be even.
0739        Same for coordinates. */
0740     f->dst_w &= ~1;
0741     f->dst_x &= ~1;
0742 
0743     f->src_w += f->src_x & 1;
0744     f->src_x &= ~1;
0745 
0746     f->src_w &= ~1;
0747     f->dst_w &= ~1;
0748 
0749     f->dst_h &= ~1;
0750     f->dst_y &= ~1;
0751 
0752     f->src_h += f->src_y & 1;
0753     f->src_y &= ~1;
0754 
0755     f->src_h &= ~1;
0756     f->dst_h &= ~1;
0757 
0758     /* Due to rounding, we may have reduced the output size to <1/4 of
0759        the source. Check again, but this time just resize. Don't change
0760        source coordinates */
0761     if (f->dst_w < f->src_w / 4) {
0762         f->src_w &= ~3;
0763         f->dst_w = f->src_w / 4;
0764         f->dst_w += f->dst_w & 1;
0765     }
0766     if (f->dst_h < f->src_h / 4) {
0767         f->src_h &= ~3;
0768         f->dst_h = f->src_h / 4;
0769         f->dst_h += f->dst_h & 1;
0770     }
0771 
0772     /* Check again. If there's nothing to safe to display, stop now */
0773     if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
0774         (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0775         return IVTV_YUV_UPDATE_INVALID;
0776     }
0777 
0778     /* Both x offset & width are linked, so they have to be done together */
0779     if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
0780         (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
0781         (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
0782         yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
0783     }
0784 
0785     if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
0786         (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
0787         (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
0788         (of->lace_mode != f->lace_mode) ||
0789         (of->interlaced_y != f->interlaced_y) ||
0790         (of->interlaced_uv != f->interlaced_uv)) {
0791         yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
0792     }
0793 
0794     return yuv_update;
0795 }
0796 
0797 /* Update the scaling register to the requested value */
0798 void ivtv_yuv_work_handler(struct ivtv *itv)
0799 {
0800     struct yuv_playback_info *yi = &itv->yuv_info;
0801     struct yuv_frame_info f;
0802     int frame = yi->update_frame;
0803     u32 yuv_update;
0804 
0805     IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
0806     f = yi->new_frame_info[frame];
0807 
0808     if (yi->track_osd) {
0809         /* Snapshot the osd pan info */
0810         f.pan_x = yi->osd_x_pan;
0811         f.pan_y = yi->osd_y_pan;
0812         f.vis_w = yi->osd_vis_w;
0813         f.vis_h = yi->osd_vis_h;
0814     } else {
0815         /* Not tracking the osd, so assume full screen */
0816         f.pan_x = 0;
0817         f.pan_y = 0;
0818         f.vis_w = 720;
0819         f.vis_h = yi->decode_height;
0820     }
0821 
0822     /* Calculate the display window coordinates. Exit if nothing left */
0823     if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
0824         return;
0825 
0826     if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
0827         write_reg(0x01008080, 0x2898);
0828     } else if (yuv_update) {
0829         write_reg(0x00108080, 0x2898);
0830 
0831         if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
0832             ivtv_yuv_handle_horizontal(itv, &f);
0833 
0834         if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
0835             ivtv_yuv_handle_vertical(itv, &f);
0836     }
0837     yi->old_frame_info = f;
0838 }
0839 
0840 static void ivtv_yuv_init(struct ivtv *itv)
0841 {
0842     struct yuv_playback_info *yi = &itv->yuv_info;
0843 
0844     IVTV_DEBUG_YUV("ivtv_yuv_init\n");
0845 
0846     /* Take a snapshot of the current register settings */
0847     yi->reg_2834 = read_reg(0x02834);
0848     yi->reg_2838 = read_reg(0x02838);
0849     yi->reg_283c = read_reg(0x0283c);
0850     yi->reg_2840 = read_reg(0x02840);
0851     yi->reg_2844 = read_reg(0x02844);
0852     yi->reg_2848 = read_reg(0x02848);
0853     yi->reg_2854 = read_reg(0x02854);
0854     yi->reg_285c = read_reg(0x0285c);
0855     yi->reg_2864 = read_reg(0x02864);
0856     yi->reg_2870 = read_reg(0x02870);
0857     yi->reg_2874 = read_reg(0x02874);
0858     yi->reg_2898 = read_reg(0x02898);
0859     yi->reg_2890 = read_reg(0x02890);
0860 
0861     yi->reg_289c = read_reg(0x0289c);
0862     yi->reg_2918 = read_reg(0x02918);
0863     yi->reg_291c = read_reg(0x0291c);
0864     yi->reg_2920 = read_reg(0x02920);
0865     yi->reg_2924 = read_reg(0x02924);
0866     yi->reg_2928 = read_reg(0x02928);
0867     yi->reg_292c = read_reg(0x0292c);
0868     yi->reg_2930 = read_reg(0x02930);
0869     yi->reg_2934 = read_reg(0x02934);
0870     yi->reg_2938 = read_reg(0x02938);
0871     yi->reg_293c = read_reg(0x0293c);
0872     yi->reg_2940 = read_reg(0x02940);
0873     yi->reg_2944 = read_reg(0x02944);
0874     yi->reg_2948 = read_reg(0x02948);
0875     yi->reg_294c = read_reg(0x0294c);
0876     yi->reg_2950 = read_reg(0x02950);
0877     yi->reg_2954 = read_reg(0x02954);
0878     yi->reg_2958 = read_reg(0x02958);
0879     yi->reg_295c = read_reg(0x0295c);
0880     yi->reg_2960 = read_reg(0x02960);
0881     yi->reg_2964 = read_reg(0x02964);
0882     yi->reg_2968 = read_reg(0x02968);
0883     yi->reg_296c = read_reg(0x0296c);
0884     yi->reg_2970 = read_reg(0x02970);
0885 
0886     yi->v_filter_1 = -1;
0887     yi->v_filter_2 = -1;
0888     yi->h_filter = -1;
0889 
0890     /* Set some valid size info */
0891     yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
0892     yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
0893 
0894     /* Bit 2 of reg 2878 indicates current decoder output format
0895        0 : NTSC    1 : PAL */
0896     if (read_reg(0x2878) & 4)
0897         yi->decode_height = 576;
0898     else
0899         yi->decode_height = 480;
0900 
0901     if (!itv->osd_info) {
0902         yi->osd_vis_w = 720 - yi->osd_x_offset;
0903         yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
0904     } else {
0905         /* If no visible size set, assume full size */
0906         if (!yi->osd_vis_w)
0907             yi->osd_vis_w = 720 - yi->osd_x_offset;
0908 
0909         if (!yi->osd_vis_h) {
0910             yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
0911         } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
0912             /* If output video standard has changed, requested height may
0913                not be legal */
0914             IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
0915                     yi->osd_vis_h + yi->osd_y_offset,
0916                     yi->decode_height);
0917             yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
0918         }
0919     }
0920 
0921     /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
0922     yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN);
0923     if (yi->blanking_ptr) {
0924         yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev,
0925                              yi->blanking_ptr,
0926                              720 * 16, DMA_TO_DEVICE);
0927     } else {
0928         yi->blanking_dmaptr = 0;
0929         IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
0930     }
0931 
0932     /* Enable YUV decoder output */
0933     write_reg_sync(0x01, IVTV_REG_VDM);
0934 
0935     set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
0936     atomic_set(&yi->next_dma_frame, 0);
0937 }
0938 
0939 /* Get next available yuv buffer on PVR350 */
0940 static void ivtv_yuv_next_free(struct ivtv *itv)
0941 {
0942     int draw, display;
0943     struct yuv_playback_info *yi = &itv->yuv_info;
0944 
0945     if (atomic_read(&yi->next_dma_frame) == -1)
0946         ivtv_yuv_init(itv);
0947 
0948     draw = atomic_read(&yi->next_fill_frame);
0949     display = atomic_read(&yi->next_dma_frame);
0950 
0951     if (display > draw)
0952         display -= IVTV_YUV_BUFFERS;
0953 
0954     if (draw - display >= yi->max_frames_buffered)
0955         draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
0956     else
0957         yi->new_frame_info[draw].update = 0;
0958 
0959     yi->draw_frame = draw;
0960 }
0961 
0962 /* Set up frame according to ivtv_dma_frame parameters */
0963 static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
0964 {
0965     struct yuv_playback_info *yi = &itv->yuv_info;
0966     u8 frame = yi->draw_frame;
0967     u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
0968     struct yuv_frame_info *nf = &yi->new_frame_info[frame];
0969     struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
0970     int lace_threshold = yi->lace_threshold;
0971 
0972     /* Preserve old update flag in case we're overwriting a queued frame */
0973     int update = nf->update;
0974 
0975     /* Take a snapshot of the yuv coordinate information */
0976     nf->src_x = args->src.left;
0977     nf->src_y = args->src.top;
0978     nf->src_w = args->src.width;
0979     nf->src_h = args->src.height;
0980     nf->dst_x = args->dst.left;
0981     nf->dst_y = args->dst.top;
0982     nf->dst_w = args->dst.width;
0983     nf->dst_h = args->dst.height;
0984     nf->tru_x = args->dst.left;
0985     nf->tru_w = args->src_width;
0986     nf->tru_h = args->src_height;
0987 
0988     /* Are we going to offset the Y plane */
0989     nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
0990 
0991     nf->update = 0;
0992     nf->interlaced_y = 0;
0993     nf->interlaced_uv = 0;
0994     nf->delay = 0;
0995     nf->sync_field = 0;
0996     nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
0997 
0998     if (lace_threshold < 0)
0999         lace_threshold = yi->decode_height - 1;
1000 
1001     /* Work out the lace settings */
1002     switch (nf->lace_mode) {
1003     case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
1004         nf->interlaced = 0;
1005         if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
1006             nf->interlaced_y = 0;
1007         else
1008             nf->interlaced_y = 1;
1009 
1010         if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1011             nf->interlaced_uv = 0;
1012         else
1013             nf->interlaced_uv = 1;
1014         break;
1015 
1016     case IVTV_YUV_MODE_AUTO:
1017         if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
1018             nf->interlaced = 0;
1019             if ((nf->tru_h < 512) ||
1020                 (nf->tru_h > 576 && nf->tru_h < 1021) ||
1021                 (nf->tru_w > 720 && nf->tru_h < 1021))
1022                 nf->interlaced_y = 0;
1023             else
1024                 nf->interlaced_y = 1;
1025             if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1026                 nf->interlaced_uv = 0;
1027             else
1028                 nf->interlaced_uv = 1;
1029         } else {
1030             nf->interlaced = 1;
1031             nf->interlaced_y = 1;
1032             nf->interlaced_uv = 1;
1033         }
1034         break;
1035 
1036     case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1037     default:
1038         nf->interlaced = 1;
1039         nf->interlaced_y = 1;
1040         nf->interlaced_uv = 1;
1041         break;
1042     }
1043 
1044     if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1045         yi->old_frame_info_args = *nf;
1046         nf->update = 1;
1047         IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
1048     }
1049 
1050     nf->update |= update;
1051     nf->sync_field = yi->lace_sync_field;
1052     nf->delay = nf->sync_field != of->sync_field;
1053 }
1054 
1055 /* Frame is complete & ready for display */
1056 void ivtv_yuv_frame_complete(struct ivtv *itv)
1057 {
1058     atomic_set(&itv->yuv_info.next_fill_frame,
1059             (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1060 }
1061 
1062 static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1063 {
1064     DEFINE_WAIT(wait);
1065     int rc = 0;
1066     int got_sig = 0;
1067     /* DMA the frame */
1068     mutex_lock(&itv->udma.lock);
1069 
1070     if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1071         mutex_unlock(&itv->udma.lock);
1072         return rc;
1073     }
1074 
1075     ivtv_udma_prepare(itv);
1076     prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1077     /* if no UDMA is pending and no UDMA is in progress, then the DMA
1078        is finished */
1079     while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
1080            test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
1081         /* don't interrupt if the DMA is in progress but break off
1082            a still pending DMA. */
1083         got_sig = signal_pending(current);
1084         if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1085             break;
1086         got_sig = 0;
1087         schedule();
1088     }
1089     finish_wait(&itv->dma_waitq, &wait);
1090 
1091     /* Unmap Last DMA Xfer */
1092     ivtv_udma_unmap(itv);
1093 
1094     if (got_sig) {
1095         IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1096         mutex_unlock(&itv->udma.lock);
1097         return -EINTR;
1098     }
1099 
1100     ivtv_yuv_frame_complete(itv);
1101 
1102     mutex_unlock(&itv->udma.lock);
1103     return rc;
1104 }
1105 
1106 /* Setup frame according to V4L2 parameters */
1107 void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1108 {
1109     struct yuv_playback_info *yi = &itv->yuv_info;
1110     struct ivtv_dma_frame dma_args;
1111 
1112     ivtv_yuv_next_free(itv);
1113 
1114     /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
1115     dma_args.y_source = NULL;
1116     dma_args.uv_source = NULL;
1117     dma_args.src.left = 0;
1118     dma_args.src.top = 0;
1119     dma_args.src.width = yi->v4l2_src_w;
1120     dma_args.src.height = yi->v4l2_src_h;
1121     dma_args.dst = yi->main_rect;
1122     dma_args.src_width = yi->v4l2_src_w;
1123     dma_args.src_height = yi->v4l2_src_h;
1124 
1125     /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1126     ivtv_yuv_setup_frame(itv, &dma_args);
1127 
1128     if (!itv->dma_data_req_offset)
1129         itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1130 }
1131 
1132 /* Attempt to dma a frame from a user buffer */
1133 int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
1134 {
1135     struct yuv_playback_info *yi = &itv->yuv_info;
1136     struct ivtv_dma_frame dma_args;
1137     int res;
1138 
1139     ivtv_yuv_setup_stream_frame(itv);
1140 
1141     /* We only need to supply source addresses for this */
1142     dma_args.y_source = src;
1143     dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
1144     /* Wait for frame DMA. Note that serialize_lock is locked,
1145        so to allow other processes to access the driver while
1146        we are waiting unlock first and later lock again. */
1147     mutex_unlock(&itv->serialize_lock);
1148     res = ivtv_yuv_udma_frame(itv, &dma_args);
1149     mutex_lock(&itv->serialize_lock);
1150     return res;
1151 }
1152 
1153 /* IVTV_IOC_DMA_FRAME ioctl handler */
1154 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1155 {
1156     int res;
1157 
1158 /*  IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
1159     ivtv_yuv_next_free(itv);
1160     ivtv_yuv_setup_frame(itv, args);
1161     /* Wait for frame DMA. Note that serialize_lock is locked,
1162        so to allow other processes to access the driver while
1163        we are waiting unlock first and later lock again. */
1164     mutex_unlock(&itv->serialize_lock);
1165     res = ivtv_yuv_udma_frame(itv, args);
1166     mutex_lock(&itv->serialize_lock);
1167     return res;
1168 }
1169 
1170 void ivtv_yuv_close(struct ivtv *itv)
1171 {
1172     struct yuv_playback_info *yi = &itv->yuv_info;
1173     int h_filter, v_filter_1, v_filter_2;
1174 
1175     IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1176     mutex_unlock(&itv->serialize_lock);
1177     ivtv_waitq(&itv->vsync_waitq);
1178     mutex_lock(&itv->serialize_lock);
1179 
1180     yi->running = 0;
1181     atomic_set(&yi->next_dma_frame, -1);
1182     atomic_set(&yi->next_fill_frame, 0);
1183 
1184     /* Reset registers we have changed so mpeg playback works */
1185 
1186     /* If we fully restore this register, the display may remain active.
1187        Restore, but set one bit to blank the video. Firmware will always
1188        clear this bit when needed, so not a problem. */
1189     write_reg(yi->reg_2898 | 0x01000000, 0x2898);
1190 
1191     write_reg(yi->reg_2834, 0x02834);
1192     write_reg(yi->reg_2838, 0x02838);
1193     write_reg(yi->reg_283c, 0x0283c);
1194     write_reg(yi->reg_2840, 0x02840);
1195     write_reg(yi->reg_2844, 0x02844);
1196     write_reg(yi->reg_2848, 0x02848);
1197     write_reg(yi->reg_2854, 0x02854);
1198     write_reg(yi->reg_285c, 0x0285c);
1199     write_reg(yi->reg_2864, 0x02864);
1200     write_reg(yi->reg_2870, 0x02870);
1201     write_reg(yi->reg_2874, 0x02874);
1202     write_reg(yi->reg_2890, 0x02890);
1203     write_reg(yi->reg_289c, 0x0289c);
1204 
1205     write_reg(yi->reg_2918, 0x02918);
1206     write_reg(yi->reg_291c, 0x0291c);
1207     write_reg(yi->reg_2920, 0x02920);
1208     write_reg(yi->reg_2924, 0x02924);
1209     write_reg(yi->reg_2928, 0x02928);
1210     write_reg(yi->reg_292c, 0x0292c);
1211     write_reg(yi->reg_2930, 0x02930);
1212     write_reg(yi->reg_2934, 0x02934);
1213     write_reg(yi->reg_2938, 0x02938);
1214     write_reg(yi->reg_293c, 0x0293c);
1215     write_reg(yi->reg_2940, 0x02940);
1216     write_reg(yi->reg_2944, 0x02944);
1217     write_reg(yi->reg_2948, 0x02948);
1218     write_reg(yi->reg_294c, 0x0294c);
1219     write_reg(yi->reg_2950, 0x02950);
1220     write_reg(yi->reg_2954, 0x02954);
1221     write_reg(yi->reg_2958, 0x02958);
1222     write_reg(yi->reg_295c, 0x0295c);
1223     write_reg(yi->reg_2960, 0x02960);
1224     write_reg(yi->reg_2964, 0x02964);
1225     write_reg(yi->reg_2968, 0x02968);
1226     write_reg(yi->reg_296c, 0x0296c);
1227     write_reg(yi->reg_2970, 0x02970);
1228 
1229     /* Prepare to restore filters */
1230 
1231     /* First the horizontal filter */
1232     if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
1233         /* An exact size match uses filter 0 */
1234         h_filter = 0;
1235     } else {
1236         /* Figure out which filter to use */
1237         h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
1238         h_filter = (h_filter >> 1) + (h_filter & 1);
1239         /* Only an exact size match can use filter 0. */
1240         h_filter += !h_filter;
1241     }
1242 
1243     /* Now the vertical filter */
1244     if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
1245         /* An exact size match uses filter 0/1 */
1246         v_filter_1 = 0;
1247         v_filter_2 = 1;
1248     } else {
1249         /* Figure out which filter to use */
1250         v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
1251         v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1252         /* Only an exact size match can use filter 0 */
1253         v_filter_1 += !v_filter_1;
1254         v_filter_2 = v_filter_1;
1255     }
1256 
1257     /* Now restore the filters */
1258     ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
1259 
1260     /* and clear a few registers */
1261     write_reg(0, 0x02814);
1262     write_reg(0, 0x0282c);
1263     write_reg(0, 0x02904);
1264     write_reg(0, 0x02910);
1265 
1266     /* Release the blanking buffer */
1267     if (yi->blanking_ptr) {
1268         kfree(yi->blanking_ptr);
1269         yi->blanking_ptr = NULL;
1270         dma_unmap_single(&itv->pdev->dev, yi->blanking_dmaptr,
1271                  720 * 16, DMA_TO_DEVICE);
1272     }
1273 
1274     /* Invalidate the old dimension information */
1275     yi->old_frame_info.src_w = 0;
1276     yi->old_frame_info.src_h = 0;
1277     yi->old_frame_info_args.src_w = 0;
1278     yi->old_frame_info_args.src_h = 0;
1279 
1280     /* All done. */
1281     clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1282 }