Path: blob/master/drivers/media/video/ivtv/ivtv-yuv.c
17900 views
/*1yuv support23Copyright (C) 2007 Ian Armstrong <[email protected]>45This program is free software; you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation; either version 2 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program; if not, write to the Free Software17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#include "ivtv-driver.h"21#include "ivtv-udma.h"22#include "ivtv-yuv.h"2324/* YUV buffer offsets */25const u32 yuv_offset[IVTV_YUV_BUFFERS] = {260x001a8600,270x00240400,280x002d8200,290x00370000,300x00029000,310x000C0E00,320x006B0400,330x0074820034};3536static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,37struct ivtv_dma_frame *args)38{39struct ivtv_dma_page_info y_dma;40struct ivtv_dma_page_info uv_dma;41struct yuv_playback_info *yi = &itv->yuv_info;42u8 frame = yi->draw_frame;43struct yuv_frame_info *f = &yi->new_frame_info[frame];44int i;45int y_pages, uv_pages;46unsigned long y_buffer_offset, uv_buffer_offset;47int y_decode_height, uv_decode_height, y_size;4849y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];50uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;5152y_decode_height = uv_decode_height = f->src_h + f->src_y;5354if (f->offset_y)55y_buffer_offset += 720 * 16;5657if (y_decode_height & 15)58y_decode_height = (y_decode_height + 16) & ~15;5960if (uv_decode_height & 31)61uv_decode_height = (uv_decode_height + 32) & ~31;6263y_size = 720 * y_decode_height;6465/* Still in USE */66if (dma->SG_length || dma->page_count) {67IVTV_DEBUG_WARN68("prep_user_dma: SG_length %d page_count %d still full?\n",69dma->SG_length, dma->page_count);70return -EBUSY;71}7273ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);74ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);7576/* Get user pages for DMA Xfer */77down_read(¤t->mm->mmap_sem);78y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);79uv_pages = 0; /* silence gcc. value is set and consumed only if: */80if (y_pages == y_dma.page_count) {81uv_pages = get_user_pages(current, current->mm,82uv_dma.uaddr, uv_dma.page_count, 0, 1,83&dma->map[y_pages], NULL);84}85up_read(¤t->mm->mmap_sem);8687if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {88int rc = -EFAULT;8990if (y_pages == y_dma.page_count) {91IVTV_DEBUG_WARN92("failed to map uv user pages, returned %d "93"expecting %d\n", uv_pages, uv_dma.page_count);9495if (uv_pages >= 0) {96for (i = 0; i < uv_pages; i++)97put_page(dma->map[y_pages + i]);98rc = -EFAULT;99} else {100rc = uv_pages;101}102} else {103IVTV_DEBUG_WARN104("failed to map y user pages, returned %d "105"expecting %d\n", y_pages, y_dma.page_count);106}107if (y_pages >= 0) {108for (i = 0; i < y_pages; i++)109put_page(dma->map[i]);110/*111* Inherit the -EFAULT from rc's112* initialization, but allow it to be113* overriden by uv_pages above if it was an114* actual errno.115*/116} else {117rc = y_pages;118}119return rc;120}121122dma->page_count = y_pages + uv_pages;123124/* Fill & map SG List */125if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {126IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");127for (i = 0; i < dma->page_count; i++) {128put_page(dma->map[i]);129}130dma->page_count = 0;131return -ENOMEM;132}133dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);134135/* Fill SG Array with new values */136ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);137138/* If we've offset the y plane, ensure top area is blanked */139if (f->offset_y && yi->blanking_dmaptr) {140dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);141dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);142dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);143dma->SG_length++;144}145146/* Tag SG Array with Interrupt Bit */147dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);148149ivtv_udma_sync_for_device(itv);150return 0;151}152153/* We rely on a table held in the firmware - Quick check. */154int ivtv_yuv_filter_check(struct ivtv *itv)155{156int i, y, uv;157158for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {159if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||160(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {161IVTV_WARN ("YUV filter table not found in firmware.\n");162return -1;163}164}165return 0;166}167168static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)169{170u32 i, line;171172/* If any filter is -1, then don't update it */173if (h_filter > -1) {174if (h_filter > 4)175h_filter = 4;176i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);177for (line = 0; line < 16; line++) {178write_reg(read_dec(i), 0x02804);179write_reg(read_dec(i), 0x0281c);180i += 4;181write_reg(read_dec(i), 0x02808);182write_reg(read_dec(i), 0x02820);183i += 4;184write_reg(read_dec(i), 0x0280c);185write_reg(read_dec(i), 0x02824);186i += 4;187write_reg(read_dec(i), 0x02810);188write_reg(read_dec(i), 0x02828);189i += 4;190write_reg(read_dec(i), 0x02814);191write_reg(read_dec(i), 0x0282c);192i += 8;193write_reg(0, 0x02818);194write_reg(0, 0x02830);195}196IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);197}198199if (v_filter_1 > -1) {200if (v_filter_1 > 4)201v_filter_1 = 4;202i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);203for (line = 0; line < 16; line++) {204write_reg(read_dec(i), 0x02900);205i += 4;206write_reg(read_dec(i), 0x02904);207i += 8;208write_reg(0, 0x02908);209}210IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);211}212213if (v_filter_2 > -1) {214if (v_filter_2 > 4)215v_filter_2 = 4;216i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);217for (line = 0; line < 16; line++) {218write_reg(read_dec(i), 0x0290c);219i += 4;220write_reg(read_dec(i), 0x02910);221i += 8;222write_reg(0, 0x02914);223}224IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);225}226}227228static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)229{230struct yuv_playback_info *yi = &itv->yuv_info;231u32 reg_2834, reg_2838, reg_283c;232u32 reg_2844, reg_2854, reg_285c;233u32 reg_2864, reg_2874, reg_2890;234u32 reg_2870, reg_2870_base, reg_2870_offset;235int x_cutoff;236int h_filter;237u32 master_width;238239IVTV_DEBUG_WARN240("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",241f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);242243/* How wide is the src image */244x_cutoff = f->src_w + f->src_x;245246/* Set the display width */247reg_2834 = f->dst_w;248reg_2838 = reg_2834;249250/* Set the display position */251reg_2890 = f->dst_x;252253/* Index into the image horizontally */254reg_2870 = 0;255256/* 2870 is normally fudged to align video coords with osd coords.257If running full screen, it causes an unwanted left shift258Remove the fudge if we almost fill the screen.259Gradually adjust the offset to avoid the video 'snapping'260left/right if it gets dragged through this region.261Only do this if osd is full width. */262if (f->vis_w == 720) {263if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))264reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;265else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))266reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);267268if (f->dst_w >= f->src_w)269reg_2870 = reg_2870 << 16 | reg_2870;270else271reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);272}273274if (f->dst_w < f->src_w)275reg_2870 = 0x000d000e - reg_2870;276else277reg_2870 = 0x0012000e - reg_2870;278279/* We're also using 2870 to shift the image left (src_x & negative dst_x) */280reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;281282if (f->dst_w >= f->src_w) {283x_cutoff &= ~1;284master_width = (f->src_w * 0x00200000) / (f->dst_w);285if (master_width * f->dst_w != f->src_w * 0x00200000)286master_width++;287reg_2834 = (reg_2834 << 16) | x_cutoff;288reg_2838 = (reg_2838 << 16) | x_cutoff;289reg_283c = master_width >> 2;290reg_2844 = master_width >> 2;291reg_2854 = master_width;292reg_285c = master_width >> 1;293reg_2864 = master_width >> 1;294295/* We also need to factor in the scaling296(src_w - dst_w) / (src_w / 4) */297if (f->dst_w > f->src_w)298reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);299else300reg_2870_base = 0;301302reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);303reg_2874 = 0;304} else if (f->dst_w < f->src_w / 2) {305master_width = (f->src_w * 0x00080000) / f->dst_w;306if (master_width * f->dst_w != f->src_w * 0x00080000)307master_width++;308reg_2834 = (reg_2834 << 16) | x_cutoff;309reg_2838 = (reg_2838 << 16) | x_cutoff;310reg_283c = master_width >> 2;311reg_2844 = master_width >> 1;312reg_2854 = master_width;313reg_285c = master_width >> 1;314reg_2864 = master_width >> 1;315reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;316reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;317reg_2874 = 0x00000012;318} else {319master_width = (f->src_w * 0x00100000) / f->dst_w;320if (master_width * f->dst_w != f->src_w * 0x00100000)321master_width++;322reg_2834 = (reg_2834 << 16) | x_cutoff;323reg_2838 = (reg_2838 << 16) | x_cutoff;324reg_283c = master_width >> 2;325reg_2844 = master_width >> 1;326reg_2854 = master_width;327reg_285c = master_width >> 1;328reg_2864 = master_width >> 1;329reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;330reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;331reg_2874 = 0x00000001;332}333334/* Select the horizontal filter */335if (f->src_w == f->dst_w) {336/* An exact size match uses filter 0 */337h_filter = 0;338} else {339/* Figure out which filter to use */340h_filter = ((f->src_w << 16) / f->dst_w) >> 15;341h_filter = (h_filter >> 1) + (h_filter & 1);342/* Only an exact size match can use filter 0 */343h_filter += !h_filter;344}345346write_reg(reg_2834, 0x02834);347write_reg(reg_2838, 0x02838);348IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",349yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);350351write_reg(reg_283c, 0x0283c);352write_reg(reg_2844, 0x02844);353354IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",355yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);356357write_reg(0x00080514, 0x02840);358write_reg(0x00100514, 0x02848);359IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",360yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);361362write_reg(reg_2854, 0x02854);363IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",364yi->reg_2854, reg_2854);365366write_reg(reg_285c, 0x0285c);367write_reg(reg_2864, 0x02864);368IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",369yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);370371write_reg(reg_2874, 0x02874);372IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",373yi->reg_2874, reg_2874);374375write_reg(reg_2870, 0x02870);376IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",377yi->reg_2870, reg_2870);378379write_reg(reg_2890, 0x02890);380IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",381yi->reg_2890, reg_2890);382383/* Only update the filter if we really need to */384if (h_filter != yi->h_filter) {385ivtv_yuv_filter(itv, h_filter, -1, -1);386yi->h_filter = h_filter;387}388}389390static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)391{392struct yuv_playback_info *yi = &itv->yuv_info;393u32 master_height;394u32 reg_2918, reg_291c, reg_2920, reg_2928;395u32 reg_2930, reg_2934, reg_293c;396u32 reg_2940, reg_2944, reg_294c;397u32 reg_2950, reg_2954, reg_2958, reg_295c;398u32 reg_2960, reg_2964, reg_2968, reg_296c;399u32 reg_289c;400u32 src_major_y, src_minor_y;401u32 src_major_uv, src_minor_uv;402u32 reg_2964_base, reg_2968_base;403int v_filter_1, v_filter_2;404405IVTV_DEBUG_WARN406("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",407f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);408409/* What scaling mode is being used... */410IVTV_DEBUG_YUV("Scaling mode Y: %s\n",411f->interlaced_y ? "Interlaced" : "Progressive");412413IVTV_DEBUG_YUV("Scaling mode UV: %s\n",414f->interlaced_uv ? "Interlaced" : "Progressive");415416/* What is the source video being treated as... */417IVTV_DEBUG_WARN("Source video: %s\n",418f->interlaced ? "Interlaced" : "Progressive");419420/* We offset into the image using two different index methods, so split421the y source coord into two parts. */422if (f->src_y < 8) {423src_minor_uv = f->src_y;424src_major_uv = 0;425} else {426src_minor_uv = 8;427src_major_uv = f->src_y - 8;428}429430src_minor_y = src_minor_uv;431src_major_y = src_major_uv;432433if (f->offset_y)434src_minor_y += 16;435436if (f->interlaced_y)437reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);438else439reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);440441if (f->interlaced_uv)442reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);443else444reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);445446reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;447reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;448449if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {450master_height = (f->src_h * 0x00400000) / f->dst_h;451if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)452master_height++;453reg_2920 = master_height >> 2;454reg_2928 = master_height >> 3;455reg_2930 = master_height;456reg_2940 = master_height >> 1;457reg_2964_base >>= 3;458reg_2968_base >>= 3;459reg_296c = 0x00000000;460} else if (f->dst_h >= f->src_h) {461master_height = (f->src_h * 0x00400000) / f->dst_h;462master_height = (master_height >> 1) + (master_height & 1);463reg_2920 = master_height >> 2;464reg_2928 = master_height >> 2;465reg_2930 = master_height;466reg_2940 = master_height >> 1;467reg_296c = 0x00000000;468if (f->interlaced_y) {469reg_2964_base >>= 3;470} else {471reg_296c++;472reg_2964_base >>= 2;473}474if (f->interlaced_uv)475reg_2928 >>= 1;476reg_2968_base >>= 3;477} else if (f->dst_h >= f->src_h / 2) {478master_height = (f->src_h * 0x00200000) / f->dst_h;479master_height = (master_height >> 1) + (master_height & 1);480reg_2920 = master_height >> 2;481reg_2928 = master_height >> 2;482reg_2930 = master_height;483reg_2940 = master_height;484reg_296c = 0x00000101;485if (f->interlaced_y) {486reg_2964_base >>= 2;487} else {488reg_296c++;489reg_2964_base >>= 1;490}491if (f->interlaced_uv)492reg_2928 >>= 1;493reg_2968_base >>= 2;494} else {495master_height = (f->src_h * 0x00100000) / f->dst_h;496master_height = (master_height >> 1) + (master_height & 1);497reg_2920 = master_height >> 2;498reg_2928 = master_height >> 2;499reg_2930 = master_height;500reg_2940 = master_height;501reg_2964_base >>= 1;502reg_2968_base >>= 2;503reg_296c = 0x00000102;504}505506/* FIXME These registers change depending on scaled / unscaled output507We really need to work out what they should be */508if (f->src_h == f->dst_h) {509reg_2934 = 0x00020000;510reg_293c = 0x00100000;511reg_2944 = 0x00040000;512reg_294c = 0x000b0000;513} else {514reg_2934 = 0x00000FF0;515reg_293c = 0x00000FF0;516reg_2944 = 0x00000FF0;517reg_294c = 0x00000FF0;518}519520/* The first line to be displayed */521reg_2950 = 0x00010000 + src_major_y;522if (f->interlaced_y)523reg_2950 += 0x00010000;524reg_2954 = reg_2950 + 1;525526reg_2958 = 0x00010000 + (src_major_y >> 1);527if (f->interlaced_uv)528reg_2958 += 0x00010000;529reg_295c = reg_2958 + 1;530531if (yi->decode_height == 480)532reg_289c = 0x011e0017;533else534reg_289c = 0x01500017;535536if (f->dst_y < 0)537reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);538else539reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);540541/* How much of the source to decode.542Take into account the source offset */543reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |544(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);545546/* Calculate correct value for register 2964 */547if (f->src_h == f->dst_h) {548reg_2964 = 1;549} else {550reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);551reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);552}553reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);554reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);555556/* Okay, we've wasted time working out the correct value,557but if we use it, it fouls the the window alignment.558Fudge it to what we want... */559reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));560reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));561562/* Deviate further from what it should be. I find the flicker headache563inducing so try to reduce it slightly. Leave 2968 as-is otherwise564colours foul. */565if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))566reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);567568if (!f->interlaced_y)569reg_2964 -= 0x00010001;570if (!f->interlaced_uv)571reg_2968 -= 0x00010001;572573reg_2964 += ((reg_2964_base << 16) | reg_2964_base);574reg_2968 += ((reg_2968_base << 16) | reg_2968_base);575576/* Select the vertical filter */577if (f->src_h == f->dst_h) {578/* An exact size match uses filter 0/1 */579v_filter_1 = 0;580v_filter_2 = 1;581} else {582/* Figure out which filter to use */583v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;584v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);585/* Only an exact size match can use filter 0 */586v_filter_1 += !v_filter_1;587v_filter_2 = v_filter_1;588}589590write_reg(reg_2934, 0x02934);591write_reg(reg_293c, 0x0293c);592IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",593yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);594write_reg(reg_2944, 0x02944);595write_reg(reg_294c, 0x0294c);596IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",597yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);598599/* Ensure 2970 is 0 (does it ever change ?) */600/* write_reg(0,0x02970); */601/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */602603write_reg(reg_2930, 0x02938);604write_reg(reg_2930, 0x02930);605IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",606yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);607608write_reg(reg_2928, 0x02928);609write_reg(reg_2928 + 0x514, 0x0292C);610IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",611yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);612613write_reg(reg_2920, 0x02920);614write_reg(reg_2920 + 0x514, 0x02924);615IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",616yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);617618write_reg(reg_2918, 0x02918);619write_reg(reg_291c, 0x0291C);620IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",621yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);622623write_reg(reg_296c, 0x0296c);624IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",625yi->reg_296c, reg_296c);626627write_reg(reg_2940, 0x02948);628write_reg(reg_2940, 0x02940);629IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",630yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);631632write_reg(reg_2950, 0x02950);633write_reg(reg_2954, 0x02954);634IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",635yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);636637write_reg(reg_2958, 0x02958);638write_reg(reg_295c, 0x0295C);639IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",640yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);641642write_reg(reg_2960, 0x02960);643IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",644yi->reg_2960, reg_2960);645646write_reg(reg_2964, 0x02964);647write_reg(reg_2968, 0x02968);648IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",649yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);650651write_reg(reg_289c, 0x0289c);652IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",653yi->reg_289c, reg_289c);654655/* Only update filter 1 if we really need to */656if (v_filter_1 != yi->v_filter_1) {657ivtv_yuv_filter(itv, -1, v_filter_1, -1);658yi->v_filter_1 = v_filter_1;659}660661/* Only update filter 2 if we really need to */662if (v_filter_2 != yi->v_filter_2) {663ivtv_yuv_filter(itv, -1, -1, v_filter_2);664yi->v_filter_2 = v_filter_2;665}666}667668/* Modify the supplied coordinate information to fit the visible osd area */669static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)670{671struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;672int osd_crop;673u32 osd_scale;674u32 yuv_update = 0;675676/* Sorry, but no negative coords for src */677if (f->src_x < 0)678f->src_x = 0;679if (f->src_y < 0)680f->src_y = 0;681682/* Can only reduce width down to 1/4 original size */683if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {684f->src_x += osd_crop / 2;685f->src_w = (f->src_w - osd_crop) & ~3;686f->dst_w = f->src_w / 4;687f->dst_w += f->dst_w & 1;688}689690/* Can only reduce height down to 1/4 original size */691if (f->src_h / f->dst_h >= 2) {692/* Overflow may be because we're running progressive,693so force mode switch */694f->interlaced_y = 1;695/* Make sure we're still within limits for interlace */696if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {697/* If we reach here we'll have to force the height. */698f->src_y += osd_crop / 2;699f->src_h = (f->src_h - osd_crop) & ~3;700f->dst_h = f->src_h / 4;701f->dst_h += f->dst_h & 1;702}703}704705/* If there's nothing to safe to display, we may as well stop now */706if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||707(int)f->src_w <= 2 || (int)f->src_h <= 2) {708return IVTV_YUV_UPDATE_INVALID;709}710711/* Ensure video remains inside OSD area */712osd_scale = (f->src_h << 16) / f->dst_h;713714if ((osd_crop = f->pan_y - f->dst_y) > 0) {715/* Falls off the upper edge - crop */716f->src_y += (osd_scale * osd_crop) >> 16;717f->src_h -= (osd_scale * osd_crop) >> 16;718f->dst_h -= osd_crop;719f->dst_y = 0;720} else {721f->dst_y -= f->pan_y;722}723724if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {725/* Falls off the lower edge - crop */726f->dst_h -= osd_crop;727f->src_h -= (osd_scale * osd_crop) >> 16;728}729730osd_scale = (f->src_w << 16) / f->dst_w;731732if ((osd_crop = f->pan_x - f->dst_x) > 0) {733/* Fall off the left edge - crop */734f->src_x += (osd_scale * osd_crop) >> 16;735f->src_w -= (osd_scale * osd_crop) >> 16;736f->dst_w -= osd_crop;737f->dst_x = 0;738} else {739f->dst_x -= f->pan_x;740}741742if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {743/* Falls off the right edge - crop */744f->dst_w -= osd_crop;745f->src_w -= (osd_scale * osd_crop) >> 16;746}747748if (itv->yuv_info.track_osd) {749/* The OSD can be moved. Track to it */750f->dst_x += itv->yuv_info.osd_x_offset;751f->dst_y += itv->yuv_info.osd_y_offset;752}753754/* Width & height for both src & dst must be even.755Same for coordinates. */756f->dst_w &= ~1;757f->dst_x &= ~1;758759f->src_w += f->src_x & 1;760f->src_x &= ~1;761762f->src_w &= ~1;763f->dst_w &= ~1;764765f->dst_h &= ~1;766f->dst_y &= ~1;767768f->src_h += f->src_y & 1;769f->src_y &= ~1;770771f->src_h &= ~1;772f->dst_h &= ~1;773774/* Due to rounding, we may have reduced the output size to <1/4 of775the source. Check again, but this time just resize. Don't change776source coordinates */777if (f->dst_w < f->src_w / 4) {778f->src_w &= ~3;779f->dst_w = f->src_w / 4;780f->dst_w += f->dst_w & 1;781}782if (f->dst_h < f->src_h / 4) {783f->src_h &= ~3;784f->dst_h = f->src_h / 4;785f->dst_h += f->dst_h & 1;786}787788/* Check again. If there's nothing to safe to display, stop now */789if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||790(int)f->src_w <= 2 || (int)f->src_h <= 2) {791return IVTV_YUV_UPDATE_INVALID;792}793794/* Both x offset & width are linked, so they have to be done together */795if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||796(of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||797(of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {798yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;799}800801if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||802(of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||803(of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||804(of->lace_mode != f->lace_mode) ||805(of->interlaced_y != f->interlaced_y) ||806(of->interlaced_uv != f->interlaced_uv)) {807yuv_update |= IVTV_YUV_UPDATE_VERTICAL;808}809810return yuv_update;811}812813/* Update the scaling register to the requested value */814void ivtv_yuv_work_handler(struct ivtv *itv)815{816struct yuv_playback_info *yi = &itv->yuv_info;817struct yuv_frame_info f;818int frame = yi->update_frame;819u32 yuv_update;820821IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);822f = yi->new_frame_info[frame];823824if (yi->track_osd) {825/* Snapshot the osd pan info */826f.pan_x = yi->osd_x_pan;827f.pan_y = yi->osd_y_pan;828f.vis_w = yi->osd_vis_w;829f.vis_h = yi->osd_vis_h;830} else {831/* Not tracking the osd, so assume full screen */832f.pan_x = 0;833f.pan_y = 0;834f.vis_w = 720;835f.vis_h = yi->decode_height;836}837838/* Calculate the display window coordinates. Exit if nothing left */839if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))840return;841842if (yuv_update & IVTV_YUV_UPDATE_INVALID) {843write_reg(0x01008080, 0x2898);844} else if (yuv_update) {845write_reg(0x00108080, 0x2898);846847if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)848ivtv_yuv_handle_horizontal(itv, &f);849850if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)851ivtv_yuv_handle_vertical(itv, &f);852}853yi->old_frame_info = f;854}855856static void ivtv_yuv_init(struct ivtv *itv)857{858struct yuv_playback_info *yi = &itv->yuv_info;859860IVTV_DEBUG_YUV("ivtv_yuv_init\n");861862/* Take a snapshot of the current register settings */863yi->reg_2834 = read_reg(0x02834);864yi->reg_2838 = read_reg(0x02838);865yi->reg_283c = read_reg(0x0283c);866yi->reg_2840 = read_reg(0x02840);867yi->reg_2844 = read_reg(0x02844);868yi->reg_2848 = read_reg(0x02848);869yi->reg_2854 = read_reg(0x02854);870yi->reg_285c = read_reg(0x0285c);871yi->reg_2864 = read_reg(0x02864);872yi->reg_2870 = read_reg(0x02870);873yi->reg_2874 = read_reg(0x02874);874yi->reg_2898 = read_reg(0x02898);875yi->reg_2890 = read_reg(0x02890);876877yi->reg_289c = read_reg(0x0289c);878yi->reg_2918 = read_reg(0x02918);879yi->reg_291c = read_reg(0x0291c);880yi->reg_2920 = read_reg(0x02920);881yi->reg_2924 = read_reg(0x02924);882yi->reg_2928 = read_reg(0x02928);883yi->reg_292c = read_reg(0x0292c);884yi->reg_2930 = read_reg(0x02930);885yi->reg_2934 = read_reg(0x02934);886yi->reg_2938 = read_reg(0x02938);887yi->reg_293c = read_reg(0x0293c);888yi->reg_2940 = read_reg(0x02940);889yi->reg_2944 = read_reg(0x02944);890yi->reg_2948 = read_reg(0x02948);891yi->reg_294c = read_reg(0x0294c);892yi->reg_2950 = read_reg(0x02950);893yi->reg_2954 = read_reg(0x02954);894yi->reg_2958 = read_reg(0x02958);895yi->reg_295c = read_reg(0x0295c);896yi->reg_2960 = read_reg(0x02960);897yi->reg_2964 = read_reg(0x02964);898yi->reg_2968 = read_reg(0x02968);899yi->reg_296c = read_reg(0x0296c);900yi->reg_2970 = read_reg(0x02970);901902yi->v_filter_1 = -1;903yi->v_filter_2 = -1;904yi->h_filter = -1;905906/* Set some valid size info */907yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;908yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;909910/* Bit 2 of reg 2878 indicates current decoder output format9110 : NTSC 1 : PAL */912if (read_reg(0x2878) & 4)913yi->decode_height = 576;914else915yi->decode_height = 480;916917if (!itv->osd_info) {918yi->osd_vis_w = 720 - yi->osd_x_offset;919yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;920} else {921/* If no visible size set, assume full size */922if (!yi->osd_vis_w)923yi->osd_vis_w = 720 - yi->osd_x_offset;924925if (!yi->osd_vis_h) {926yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;927} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {928/* If output video standard has changed, requested height may929not be legal */930IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",931yi->osd_vis_h + yi->osd_y_offset,932yi->decode_height);933yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;934}935}936937/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */938yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);939if (yi->blanking_ptr) {940yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);941} else {942yi->blanking_dmaptr = 0;943IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");944}945946/* Enable YUV decoder output */947write_reg_sync(0x01, IVTV_REG_VDM);948949set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);950atomic_set(&yi->next_dma_frame, 0);951}952953/* Get next available yuv buffer on PVR350 */954static void ivtv_yuv_next_free(struct ivtv *itv)955{956int draw, display;957struct yuv_playback_info *yi = &itv->yuv_info;958959if (atomic_read(&yi->next_dma_frame) == -1)960ivtv_yuv_init(itv);961962draw = atomic_read(&yi->next_fill_frame);963display = atomic_read(&yi->next_dma_frame);964965if (display > draw)966display -= IVTV_YUV_BUFFERS;967968if (draw - display >= yi->max_frames_buffered)969draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;970else971yi->new_frame_info[draw].update = 0;972973yi->draw_frame = draw;974}975976/* Set up frame according to ivtv_dma_frame parameters */977static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)978{979struct yuv_playback_info *yi = &itv->yuv_info;980u8 frame = yi->draw_frame;981u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;982struct yuv_frame_info *nf = &yi->new_frame_info[frame];983struct yuv_frame_info *of = &yi->new_frame_info[last_frame];984int lace_threshold = yi->lace_threshold;985986/* Preserve old update flag in case we're overwriting a queued frame */987int update = nf->update;988989/* Take a snapshot of the yuv coordinate information */990nf->src_x = args->src.left;991nf->src_y = args->src.top;992nf->src_w = args->src.width;993nf->src_h = args->src.height;994nf->dst_x = args->dst.left;995nf->dst_y = args->dst.top;996nf->dst_w = args->dst.width;997nf->dst_h = args->dst.height;998nf->tru_x = args->dst.left;999nf->tru_w = args->src_width;1000nf->tru_h = args->src_height;10011002/* Are we going to offset the Y plane */1003nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;10041005nf->update = 0;1006nf->interlaced_y = 0;1007nf->interlaced_uv = 0;1008nf->delay = 0;1009nf->sync_field = 0;1010nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;10111012if (lace_threshold < 0)1013lace_threshold = yi->decode_height - 1;10141015/* Work out the lace settings */1016switch (nf->lace_mode) {1017case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */1018nf->interlaced = 0;1019if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))1020nf->interlaced_y = 0;1021else1022nf->interlaced_y = 1;10231024if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))1025nf->interlaced_uv = 0;1026else1027nf->interlaced_uv = 1;1028break;10291030case IVTV_YUV_MODE_AUTO:1031if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {1032nf->interlaced = 0;1033if ((nf->tru_h < 512) ||1034(nf->tru_h > 576 && nf->tru_h < 1021) ||1035(nf->tru_w > 720 && nf->tru_h < 1021))1036nf->interlaced_y = 0;1037else1038nf->interlaced_y = 1;1039if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))1040nf->interlaced_uv = 0;1041else1042nf->interlaced_uv = 1;1043} else {1044nf->interlaced = 1;1045nf->interlaced_y = 1;1046nf->interlaced_uv = 1;1047}1048break;10491050case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */1051default:1052nf->interlaced = 1;1053nf->interlaced_y = 1;1054nf->interlaced_uv = 1;1055break;1056}10571058if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {1059yi->old_frame_info_args = *nf;1060nf->update = 1;1061IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);1062}10631064nf->update |= update;1065nf->sync_field = yi->lace_sync_field;1066nf->delay = nf->sync_field != of->sync_field;1067}10681069/* Frame is complete & ready for display */1070void ivtv_yuv_frame_complete(struct ivtv *itv)1071{1072atomic_set(&itv->yuv_info.next_fill_frame,1073(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);1074}10751076static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)1077{1078DEFINE_WAIT(wait);1079int rc = 0;1080int got_sig = 0;1081/* DMA the frame */1082mutex_lock(&itv->udma.lock);10831084if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {1085mutex_unlock(&itv->udma.lock);1086return rc;1087}10881089ivtv_udma_prepare(itv);1090prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);1091/* if no UDMA is pending and no UDMA is in progress, then the DMA1092is finished */1093while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||1094test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {1095/* don't interrupt if the DMA is in progress but break off1096a still pending DMA. */1097got_sig = signal_pending(current);1098if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))1099break;1100got_sig = 0;1101schedule();1102}1103finish_wait(&itv->dma_waitq, &wait);11041105/* Unmap Last DMA Xfer */1106ivtv_udma_unmap(itv);11071108if (got_sig) {1109IVTV_DEBUG_INFO("User stopped YUV UDMA\n");1110mutex_unlock(&itv->udma.lock);1111return -EINTR;1112}11131114ivtv_yuv_frame_complete(itv);11151116mutex_unlock(&itv->udma.lock);1117return rc;1118}11191120/* Setup frame according to V4L2 parameters */1121void ivtv_yuv_setup_stream_frame(struct ivtv *itv)1122{1123struct yuv_playback_info *yi = &itv->yuv_info;1124struct ivtv_dma_frame dma_args;11251126ivtv_yuv_next_free(itv);11271128/* Copy V4L2 parameters to an ivtv_dma_frame struct... */1129dma_args.y_source = NULL;1130dma_args.uv_source = NULL;1131dma_args.src.left = 0;1132dma_args.src.top = 0;1133dma_args.src.width = yi->v4l2_src_w;1134dma_args.src.height = yi->v4l2_src_h;1135dma_args.dst = yi->main_rect;1136dma_args.src_width = yi->v4l2_src_w;1137dma_args.src_height = yi->v4l2_src_h;11381139/* ... and use the same setup routine as ivtv_yuv_prep_frame */1140ivtv_yuv_setup_frame(itv, &dma_args);11411142if (!itv->dma_data_req_offset)1143itv->dma_data_req_offset = yuv_offset[yi->draw_frame];1144}11451146/* Attempt to dma a frame from a user buffer */1147int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)1148{1149struct yuv_playback_info *yi = &itv->yuv_info;1150struct ivtv_dma_frame dma_args;11511152ivtv_yuv_setup_stream_frame(itv);11531154/* We only need to supply source addresses for this */1155dma_args.y_source = src;1156dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);1157return ivtv_yuv_udma_frame(itv, &dma_args);1158}11591160/* IVTV_IOC_DMA_FRAME ioctl handler */1161int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)1162{1163/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */11641165ivtv_yuv_next_free(itv);1166ivtv_yuv_setup_frame(itv, args);1167return ivtv_yuv_udma_frame(itv, args);1168}11691170void ivtv_yuv_close(struct ivtv *itv)1171{1172struct yuv_playback_info *yi = &itv->yuv_info;1173int h_filter, v_filter_1, v_filter_2;11741175IVTV_DEBUG_YUV("ivtv_yuv_close\n");1176ivtv_waitq(&itv->vsync_waitq);11771178yi->running = 0;1179atomic_set(&yi->next_dma_frame, -1);1180atomic_set(&yi->next_fill_frame, 0);11811182/* Reset registers we have changed so mpeg playback works */11831184/* If we fully restore this register, the display may remain active.1185Restore, but set one bit to blank the video. Firmware will always1186clear this bit when needed, so not a problem. */1187write_reg(yi->reg_2898 | 0x01000000, 0x2898);11881189write_reg(yi->reg_2834, 0x02834);1190write_reg(yi->reg_2838, 0x02838);1191write_reg(yi->reg_283c, 0x0283c);1192write_reg(yi->reg_2840, 0x02840);1193write_reg(yi->reg_2844, 0x02844);1194write_reg(yi->reg_2848, 0x02848);1195write_reg(yi->reg_2854, 0x02854);1196write_reg(yi->reg_285c, 0x0285c);1197write_reg(yi->reg_2864, 0x02864);1198write_reg(yi->reg_2870, 0x02870);1199write_reg(yi->reg_2874, 0x02874);1200write_reg(yi->reg_2890, 0x02890);1201write_reg(yi->reg_289c, 0x0289c);12021203write_reg(yi->reg_2918, 0x02918);1204write_reg(yi->reg_291c, 0x0291c);1205write_reg(yi->reg_2920, 0x02920);1206write_reg(yi->reg_2924, 0x02924);1207write_reg(yi->reg_2928, 0x02928);1208write_reg(yi->reg_292c, 0x0292c);1209write_reg(yi->reg_2930, 0x02930);1210write_reg(yi->reg_2934, 0x02934);1211write_reg(yi->reg_2938, 0x02938);1212write_reg(yi->reg_293c, 0x0293c);1213write_reg(yi->reg_2940, 0x02940);1214write_reg(yi->reg_2944, 0x02944);1215write_reg(yi->reg_2948, 0x02948);1216write_reg(yi->reg_294c, 0x0294c);1217write_reg(yi->reg_2950, 0x02950);1218write_reg(yi->reg_2954, 0x02954);1219write_reg(yi->reg_2958, 0x02958);1220write_reg(yi->reg_295c, 0x0295c);1221write_reg(yi->reg_2960, 0x02960);1222write_reg(yi->reg_2964, 0x02964);1223write_reg(yi->reg_2968, 0x02968);1224write_reg(yi->reg_296c, 0x0296c);1225write_reg(yi->reg_2970, 0x02970);12261227/* Prepare to restore filters */12281229/* First the horizontal filter */1230if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {1231/* An exact size match uses filter 0 */1232h_filter = 0;1233} else {1234/* Figure out which filter to use */1235h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;1236h_filter = (h_filter >> 1) + (h_filter & 1);1237/* Only an exact size match can use filter 0. */1238h_filter += !h_filter;1239}12401241/* Now the vertical filter */1242if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {1243/* An exact size match uses filter 0/1 */1244v_filter_1 = 0;1245v_filter_2 = 1;1246} else {1247/* Figure out which filter to use */1248v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;1249v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);1250/* Only an exact size match can use filter 0 */1251v_filter_1 += !v_filter_1;1252v_filter_2 = v_filter_1;1253}12541255/* Now restore the filters */1256ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);12571258/* and clear a few registers */1259write_reg(0, 0x02814);1260write_reg(0, 0x0282c);1261write_reg(0, 0x02904);1262write_reg(0, 0x02910);12631264/* Release the blanking buffer */1265if (yi->blanking_ptr) {1266kfree(yi->blanking_ptr);1267yi->blanking_ptr = NULL;1268pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);1269}12701271/* Invalidate the old dimension information */1272yi->old_frame_info.src_w = 0;1273yi->old_frame_info.src_h = 0;1274yi->old_frame_info_args.src_w = 0;1275yi->old_frame_info_args.src_h = 0;12761277/* All done. */1278clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);1279}128012811282