1*b285192aSMauro Carvalho Chehab /* 2*b285192aSMauro Carvalho Chehab yuv support 3*b285192aSMauro Carvalho Chehab 4*b285192aSMauro Carvalho Chehab Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk> 5*b285192aSMauro Carvalho Chehab 6*b285192aSMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 7*b285192aSMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 8*b285192aSMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 9*b285192aSMauro Carvalho Chehab (at your option) any later version. 10*b285192aSMauro Carvalho Chehab 11*b285192aSMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 12*b285192aSMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 13*b285192aSMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*b285192aSMauro Carvalho Chehab GNU General Public License for more details. 15*b285192aSMauro Carvalho Chehab 16*b285192aSMauro Carvalho Chehab You should have received a copy of the GNU General Public License 17*b285192aSMauro Carvalho Chehab along with this program; if not, write to the Free Software 18*b285192aSMauro Carvalho Chehab Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*b285192aSMauro Carvalho Chehab */ 20*b285192aSMauro Carvalho Chehab 21*b285192aSMauro Carvalho Chehab #include "ivtv-driver.h" 22*b285192aSMauro Carvalho Chehab #include "ivtv-udma.h" 23*b285192aSMauro Carvalho Chehab #include "ivtv-yuv.h" 24*b285192aSMauro Carvalho Chehab 25*b285192aSMauro Carvalho Chehab /* YUV buffer offsets */ 26*b285192aSMauro Carvalho Chehab const u32 yuv_offset[IVTV_YUV_BUFFERS] = { 27*b285192aSMauro Carvalho Chehab 0x001a8600, 28*b285192aSMauro Carvalho Chehab 0x00240400, 29*b285192aSMauro Carvalho Chehab 0x002d8200, 30*b285192aSMauro Carvalho Chehab 0x00370000, 31*b285192aSMauro Carvalho Chehab 0x00029000, 32*b285192aSMauro Carvalho Chehab 0x000C0E00, 33*b285192aSMauro Carvalho Chehab 0x006B0400, 34*b285192aSMauro Carvalho Chehab 0x00748200 35*b285192aSMauro Carvalho Chehab }; 36*b285192aSMauro Carvalho Chehab 37*b285192aSMauro Carvalho Chehab static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, 38*b285192aSMauro Carvalho Chehab struct ivtv_dma_frame *args) 39*b285192aSMauro Carvalho Chehab { 40*b285192aSMauro Carvalho Chehab struct ivtv_dma_page_info y_dma; 41*b285192aSMauro Carvalho Chehab struct ivtv_dma_page_info uv_dma; 42*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 43*b285192aSMauro Carvalho Chehab u8 frame = yi->draw_frame; 44*b285192aSMauro Carvalho Chehab struct yuv_frame_info *f = &yi->new_frame_info[frame]; 45*b285192aSMauro Carvalho Chehab int i; 46*b285192aSMauro Carvalho Chehab int y_pages, uv_pages; 47*b285192aSMauro Carvalho Chehab unsigned long y_buffer_offset, uv_buffer_offset; 48*b285192aSMauro Carvalho Chehab int y_decode_height, uv_decode_height, y_size; 49*b285192aSMauro Carvalho Chehab 50*b285192aSMauro Carvalho Chehab y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; 51*b285192aSMauro Carvalho Chehab uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; 52*b285192aSMauro Carvalho Chehab 53*b285192aSMauro Carvalho Chehab y_decode_height = uv_decode_height = f->src_h + f->src_y; 54*b285192aSMauro Carvalho Chehab 55*b285192aSMauro Carvalho Chehab if (f->offset_y) 56*b285192aSMauro Carvalho Chehab y_buffer_offset += 720 * 16; 57*b285192aSMauro Carvalho Chehab 58*b285192aSMauro Carvalho Chehab if (y_decode_height & 15) 59*b285192aSMauro Carvalho Chehab y_decode_height = (y_decode_height + 16) & ~15; 60*b285192aSMauro Carvalho Chehab 61*b285192aSMauro Carvalho Chehab if (uv_decode_height & 31) 62*b285192aSMauro Carvalho Chehab uv_decode_height = (uv_decode_height + 32) & ~31; 63*b285192aSMauro Carvalho Chehab 64*b285192aSMauro Carvalho Chehab y_size = 720 * y_decode_height; 65*b285192aSMauro Carvalho Chehab 66*b285192aSMauro Carvalho Chehab /* Still in USE */ 67*b285192aSMauro Carvalho Chehab if (dma->SG_length || dma->page_count) { 68*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN 69*b285192aSMauro Carvalho Chehab ("prep_user_dma: SG_length %d page_count %d still full?\n", 70*b285192aSMauro Carvalho Chehab dma->SG_length, dma->page_count); 71*b285192aSMauro Carvalho Chehab return -EBUSY; 72*b285192aSMauro Carvalho Chehab } 73*b285192aSMauro Carvalho Chehab 74*b285192aSMauro Carvalho Chehab ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); 75*b285192aSMauro Carvalho Chehab ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); 76*b285192aSMauro Carvalho Chehab 77*b285192aSMauro Carvalho Chehab /* Get user pages for DMA Xfer */ 78*b285192aSMauro Carvalho Chehab down_read(¤t->mm->mmap_sem); 79*b285192aSMauro Carvalho Chehab y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); 80*b285192aSMauro Carvalho Chehab uv_pages = 0; /* silence gcc. value is set and consumed only if: */ 81*b285192aSMauro Carvalho Chehab if (y_pages == y_dma.page_count) { 82*b285192aSMauro Carvalho Chehab uv_pages = get_user_pages(current, current->mm, 83*b285192aSMauro Carvalho Chehab uv_dma.uaddr, uv_dma.page_count, 0, 1, 84*b285192aSMauro Carvalho Chehab &dma->map[y_pages], NULL); 85*b285192aSMauro Carvalho Chehab } 86*b285192aSMauro Carvalho Chehab up_read(¤t->mm->mmap_sem); 87*b285192aSMauro Carvalho Chehab 88*b285192aSMauro Carvalho Chehab if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) { 89*b285192aSMauro Carvalho Chehab int rc = -EFAULT; 90*b285192aSMauro Carvalho Chehab 91*b285192aSMauro Carvalho Chehab if (y_pages == y_dma.page_count) { 92*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN 93*b285192aSMauro Carvalho Chehab ("failed to map uv user pages, returned %d " 94*b285192aSMauro Carvalho Chehab "expecting %d\n", uv_pages, uv_dma.page_count); 95*b285192aSMauro Carvalho Chehab 96*b285192aSMauro Carvalho Chehab if (uv_pages >= 0) { 97*b285192aSMauro Carvalho Chehab for (i = 0; i < uv_pages; i++) 98*b285192aSMauro Carvalho Chehab put_page(dma->map[y_pages + i]); 99*b285192aSMauro Carvalho Chehab rc = -EFAULT; 100*b285192aSMauro Carvalho Chehab } else { 101*b285192aSMauro Carvalho Chehab rc = uv_pages; 102*b285192aSMauro Carvalho Chehab } 103*b285192aSMauro Carvalho Chehab } else { 104*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN 105*b285192aSMauro Carvalho Chehab ("failed to map y user pages, returned %d " 106*b285192aSMauro Carvalho Chehab "expecting %d\n", y_pages, y_dma.page_count); 107*b285192aSMauro Carvalho Chehab } 108*b285192aSMauro Carvalho Chehab if (y_pages >= 0) { 109*b285192aSMauro Carvalho Chehab for (i = 0; i < y_pages; i++) 110*b285192aSMauro Carvalho Chehab put_page(dma->map[i]); 111*b285192aSMauro Carvalho Chehab /* 112*b285192aSMauro Carvalho Chehab * Inherit the -EFAULT from rc's 113*b285192aSMauro Carvalho Chehab * initialization, but allow it to be 114*b285192aSMauro Carvalho Chehab * overriden by uv_pages above if it was an 115*b285192aSMauro Carvalho Chehab * actual errno. 116*b285192aSMauro Carvalho Chehab */ 117*b285192aSMauro Carvalho Chehab } else { 118*b285192aSMauro Carvalho Chehab rc = y_pages; 119*b285192aSMauro Carvalho Chehab } 120*b285192aSMauro Carvalho Chehab return rc; 121*b285192aSMauro Carvalho Chehab } 122*b285192aSMauro Carvalho Chehab 123*b285192aSMauro Carvalho Chehab dma->page_count = y_pages + uv_pages; 124*b285192aSMauro Carvalho Chehab 125*b285192aSMauro Carvalho Chehab /* Fill & map SG List */ 126*b285192aSMauro Carvalho Chehab if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { 127*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); 128*b285192aSMauro Carvalho Chehab for (i = 0; i < dma->page_count; i++) { 129*b285192aSMauro Carvalho Chehab put_page(dma->map[i]); 130*b285192aSMauro Carvalho Chehab } 131*b285192aSMauro Carvalho Chehab dma->page_count = 0; 132*b285192aSMauro Carvalho Chehab return -ENOMEM; 133*b285192aSMauro Carvalho Chehab } 134*b285192aSMauro Carvalho Chehab dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); 135*b285192aSMauro Carvalho Chehab 136*b285192aSMauro Carvalho Chehab /* Fill SG Array with new values */ 137*b285192aSMauro Carvalho Chehab ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); 138*b285192aSMauro Carvalho Chehab 139*b285192aSMauro Carvalho Chehab /* If we've offset the y plane, ensure top area is blanked */ 140*b285192aSMauro Carvalho Chehab if (f->offset_y && yi->blanking_dmaptr) { 141*b285192aSMauro Carvalho Chehab dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); 142*b285192aSMauro Carvalho Chehab dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); 143*b285192aSMauro Carvalho Chehab dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); 144*b285192aSMauro Carvalho Chehab dma->SG_length++; 145*b285192aSMauro Carvalho Chehab } 146*b285192aSMauro Carvalho Chehab 147*b285192aSMauro Carvalho Chehab /* Tag SG Array with Interrupt Bit */ 148*b285192aSMauro Carvalho Chehab dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); 149*b285192aSMauro Carvalho Chehab 150*b285192aSMauro Carvalho Chehab ivtv_udma_sync_for_device(itv); 151*b285192aSMauro Carvalho Chehab return 0; 152*b285192aSMauro Carvalho Chehab } 153*b285192aSMauro Carvalho Chehab 154*b285192aSMauro Carvalho Chehab /* We rely on a table held in the firmware - Quick check. */ 155*b285192aSMauro Carvalho Chehab int ivtv_yuv_filter_check(struct ivtv *itv) 156*b285192aSMauro Carvalho Chehab { 157*b285192aSMauro Carvalho Chehab int i, y, uv; 158*b285192aSMauro Carvalho Chehab 159*b285192aSMauro Carvalho Chehab for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { 160*b285192aSMauro Carvalho Chehab if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || 161*b285192aSMauro Carvalho Chehab (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { 162*b285192aSMauro Carvalho Chehab IVTV_WARN ("YUV filter table not found in firmware.\n"); 163*b285192aSMauro Carvalho Chehab return -1; 164*b285192aSMauro Carvalho Chehab } 165*b285192aSMauro Carvalho Chehab } 166*b285192aSMauro Carvalho Chehab return 0; 167*b285192aSMauro Carvalho Chehab } 168*b285192aSMauro Carvalho Chehab 169*b285192aSMauro Carvalho Chehab static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) 170*b285192aSMauro Carvalho Chehab { 171*b285192aSMauro Carvalho Chehab u32 i, line; 172*b285192aSMauro Carvalho Chehab 173*b285192aSMauro Carvalho Chehab /* If any filter is -1, then don't update it */ 174*b285192aSMauro Carvalho Chehab if (h_filter > -1) { 175*b285192aSMauro Carvalho Chehab if (h_filter > 4) 176*b285192aSMauro Carvalho Chehab h_filter = 4; 177*b285192aSMauro Carvalho Chehab i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); 178*b285192aSMauro Carvalho Chehab for (line = 0; line < 16; line++) { 179*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02804); 180*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x0281c); 181*b285192aSMauro Carvalho Chehab i += 4; 182*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02808); 183*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02820); 184*b285192aSMauro Carvalho Chehab i += 4; 185*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x0280c); 186*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02824); 187*b285192aSMauro Carvalho Chehab i += 4; 188*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02810); 189*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02828); 190*b285192aSMauro Carvalho Chehab i += 4; 191*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02814); 192*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x0282c); 193*b285192aSMauro Carvalho Chehab i += 8; 194*b285192aSMauro Carvalho Chehab write_reg(0, 0x02818); 195*b285192aSMauro Carvalho Chehab write_reg(0, 0x02830); 196*b285192aSMauro Carvalho Chehab } 197*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); 198*b285192aSMauro Carvalho Chehab } 199*b285192aSMauro Carvalho Chehab 200*b285192aSMauro Carvalho Chehab if (v_filter_1 > -1) { 201*b285192aSMauro Carvalho Chehab if (v_filter_1 > 4) 202*b285192aSMauro Carvalho Chehab v_filter_1 = 4; 203*b285192aSMauro Carvalho Chehab i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); 204*b285192aSMauro Carvalho Chehab for (line = 0; line < 16; line++) { 205*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02900); 206*b285192aSMauro Carvalho Chehab i += 4; 207*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02904); 208*b285192aSMauro Carvalho Chehab i += 8; 209*b285192aSMauro Carvalho Chehab write_reg(0, 0x02908); 210*b285192aSMauro Carvalho Chehab } 211*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); 212*b285192aSMauro Carvalho Chehab } 213*b285192aSMauro Carvalho Chehab 214*b285192aSMauro Carvalho Chehab if (v_filter_2 > -1) { 215*b285192aSMauro Carvalho Chehab if (v_filter_2 > 4) 216*b285192aSMauro Carvalho Chehab v_filter_2 = 4; 217*b285192aSMauro Carvalho Chehab i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); 218*b285192aSMauro Carvalho Chehab for (line = 0; line < 16; line++) { 219*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x0290c); 220*b285192aSMauro Carvalho Chehab i += 4; 221*b285192aSMauro Carvalho Chehab write_reg(read_dec(i), 0x02910); 222*b285192aSMauro Carvalho Chehab i += 8; 223*b285192aSMauro Carvalho Chehab write_reg(0, 0x02914); 224*b285192aSMauro Carvalho Chehab } 225*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); 226*b285192aSMauro Carvalho Chehab } 227*b285192aSMauro Carvalho Chehab } 228*b285192aSMauro Carvalho Chehab 229*b285192aSMauro Carvalho Chehab static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) 230*b285192aSMauro Carvalho Chehab { 231*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 232*b285192aSMauro Carvalho Chehab u32 reg_2834, reg_2838, reg_283c; 233*b285192aSMauro Carvalho Chehab u32 reg_2844, reg_2854, reg_285c; 234*b285192aSMauro Carvalho Chehab u32 reg_2864, reg_2874, reg_2890; 235*b285192aSMauro Carvalho Chehab u32 reg_2870, reg_2870_base, reg_2870_offset; 236*b285192aSMauro Carvalho Chehab int x_cutoff; 237*b285192aSMauro Carvalho Chehab int h_filter; 238*b285192aSMauro Carvalho Chehab u32 master_width; 239*b285192aSMauro Carvalho Chehab 240*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN 241*b285192aSMauro Carvalho Chehab ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", 242*b285192aSMauro Carvalho Chehab f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); 243*b285192aSMauro Carvalho Chehab 244*b285192aSMauro Carvalho Chehab /* How wide is the src image */ 245*b285192aSMauro Carvalho Chehab x_cutoff = f->src_w + f->src_x; 246*b285192aSMauro Carvalho Chehab 247*b285192aSMauro Carvalho Chehab /* Set the display width */ 248*b285192aSMauro Carvalho Chehab reg_2834 = f->dst_w; 249*b285192aSMauro Carvalho Chehab reg_2838 = reg_2834; 250*b285192aSMauro Carvalho Chehab 251*b285192aSMauro Carvalho Chehab /* Set the display position */ 252*b285192aSMauro Carvalho Chehab reg_2890 = f->dst_x; 253*b285192aSMauro Carvalho Chehab 254*b285192aSMauro Carvalho Chehab /* Index into the image horizontally */ 255*b285192aSMauro Carvalho Chehab reg_2870 = 0; 256*b285192aSMauro Carvalho Chehab 257*b285192aSMauro Carvalho Chehab /* 2870 is normally fudged to align video coords with osd coords. 258*b285192aSMauro Carvalho Chehab If running full screen, it causes an unwanted left shift 259*b285192aSMauro Carvalho Chehab Remove the fudge if we almost fill the screen. 260*b285192aSMauro Carvalho Chehab Gradually adjust the offset to avoid the video 'snapping' 261*b285192aSMauro Carvalho Chehab left/right if it gets dragged through this region. 262*b285192aSMauro Carvalho Chehab Only do this if osd is full width. */ 263*b285192aSMauro Carvalho Chehab if (f->vis_w == 720) { 264*b285192aSMauro Carvalho Chehab if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) 265*b285192aSMauro Carvalho Chehab reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; 266*b285192aSMauro Carvalho Chehab else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) 267*b285192aSMauro Carvalho Chehab reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); 268*b285192aSMauro Carvalho Chehab 269*b285192aSMauro Carvalho Chehab if (f->dst_w >= f->src_w) 270*b285192aSMauro Carvalho Chehab reg_2870 = reg_2870 << 16 | reg_2870; 271*b285192aSMauro Carvalho Chehab else 272*b285192aSMauro Carvalho Chehab reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); 273*b285192aSMauro Carvalho Chehab } 274*b285192aSMauro Carvalho Chehab 275*b285192aSMauro Carvalho Chehab if (f->dst_w < f->src_w) 276*b285192aSMauro Carvalho Chehab reg_2870 = 0x000d000e - reg_2870; 277*b285192aSMauro Carvalho Chehab else 278*b285192aSMauro Carvalho Chehab reg_2870 = 0x0012000e - reg_2870; 279*b285192aSMauro Carvalho Chehab 280*b285192aSMauro Carvalho Chehab /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ 281*b285192aSMauro Carvalho Chehab reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; 282*b285192aSMauro Carvalho Chehab 283*b285192aSMauro Carvalho Chehab if (f->dst_w >= f->src_w) { 284*b285192aSMauro Carvalho Chehab x_cutoff &= ~1; 285*b285192aSMauro Carvalho Chehab master_width = (f->src_w * 0x00200000) / (f->dst_w); 286*b285192aSMauro Carvalho Chehab if (master_width * f->dst_w != f->src_w * 0x00200000) 287*b285192aSMauro Carvalho Chehab master_width++; 288*b285192aSMauro Carvalho Chehab reg_2834 = (reg_2834 << 16) | x_cutoff; 289*b285192aSMauro Carvalho Chehab reg_2838 = (reg_2838 << 16) | x_cutoff; 290*b285192aSMauro Carvalho Chehab reg_283c = master_width >> 2; 291*b285192aSMauro Carvalho Chehab reg_2844 = master_width >> 2; 292*b285192aSMauro Carvalho Chehab reg_2854 = master_width; 293*b285192aSMauro Carvalho Chehab reg_285c = master_width >> 1; 294*b285192aSMauro Carvalho Chehab reg_2864 = master_width >> 1; 295*b285192aSMauro Carvalho Chehab 296*b285192aSMauro Carvalho Chehab /* We also need to factor in the scaling 297*b285192aSMauro Carvalho Chehab (src_w - dst_w) / (src_w / 4) */ 298*b285192aSMauro Carvalho Chehab if (f->dst_w > f->src_w) 299*b285192aSMauro Carvalho Chehab reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); 300*b285192aSMauro Carvalho Chehab else 301*b285192aSMauro Carvalho Chehab reg_2870_base = 0; 302*b285192aSMauro Carvalho Chehab 303*b285192aSMauro Carvalho Chehab reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); 304*b285192aSMauro Carvalho Chehab reg_2874 = 0; 305*b285192aSMauro Carvalho Chehab } else if (f->dst_w < f->src_w / 2) { 306*b285192aSMauro Carvalho Chehab master_width = (f->src_w * 0x00080000) / f->dst_w; 307*b285192aSMauro Carvalho Chehab if (master_width * f->dst_w != f->src_w * 0x00080000) 308*b285192aSMauro Carvalho Chehab master_width++; 309*b285192aSMauro Carvalho Chehab reg_2834 = (reg_2834 << 16) | x_cutoff; 310*b285192aSMauro Carvalho Chehab reg_2838 = (reg_2838 << 16) | x_cutoff; 311*b285192aSMauro Carvalho Chehab reg_283c = master_width >> 2; 312*b285192aSMauro Carvalho Chehab reg_2844 = master_width >> 1; 313*b285192aSMauro Carvalho Chehab reg_2854 = master_width; 314*b285192aSMauro Carvalho Chehab reg_285c = master_width >> 1; 315*b285192aSMauro Carvalho Chehab reg_2864 = master_width >> 1; 316*b285192aSMauro Carvalho Chehab reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; 317*b285192aSMauro Carvalho Chehab reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; 318*b285192aSMauro Carvalho Chehab reg_2874 = 0x00000012; 319*b285192aSMauro Carvalho Chehab } else { 320*b285192aSMauro Carvalho Chehab master_width = (f->src_w * 0x00100000) / f->dst_w; 321*b285192aSMauro Carvalho Chehab if (master_width * f->dst_w != f->src_w * 0x00100000) 322*b285192aSMauro Carvalho Chehab master_width++; 323*b285192aSMauro Carvalho Chehab reg_2834 = (reg_2834 << 16) | x_cutoff; 324*b285192aSMauro Carvalho Chehab reg_2838 = (reg_2838 << 16) | x_cutoff; 325*b285192aSMauro Carvalho Chehab reg_283c = master_width >> 2; 326*b285192aSMauro Carvalho Chehab reg_2844 = master_width >> 1; 327*b285192aSMauro Carvalho Chehab reg_2854 = master_width; 328*b285192aSMauro Carvalho Chehab reg_285c = master_width >> 1; 329*b285192aSMauro Carvalho Chehab reg_2864 = master_width >> 1; 330*b285192aSMauro Carvalho Chehab reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; 331*b285192aSMauro Carvalho Chehab reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; 332*b285192aSMauro Carvalho Chehab reg_2874 = 0x00000001; 333*b285192aSMauro Carvalho Chehab } 334*b285192aSMauro Carvalho Chehab 335*b285192aSMauro Carvalho Chehab /* Select the horizontal filter */ 336*b285192aSMauro Carvalho Chehab if (f->src_w == f->dst_w) { 337*b285192aSMauro Carvalho Chehab /* An exact size match uses filter 0 */ 338*b285192aSMauro Carvalho Chehab h_filter = 0; 339*b285192aSMauro Carvalho Chehab } else { 340*b285192aSMauro Carvalho Chehab /* Figure out which filter to use */ 341*b285192aSMauro Carvalho Chehab h_filter = ((f->src_w << 16) / f->dst_w) >> 15; 342*b285192aSMauro Carvalho Chehab h_filter = (h_filter >> 1) + (h_filter & 1); 343*b285192aSMauro Carvalho Chehab /* Only an exact size match can use filter 0 */ 344*b285192aSMauro Carvalho Chehab h_filter += !h_filter; 345*b285192aSMauro Carvalho Chehab } 346*b285192aSMauro Carvalho Chehab 347*b285192aSMauro Carvalho Chehab write_reg(reg_2834, 0x02834); 348*b285192aSMauro Carvalho Chehab write_reg(reg_2838, 0x02838); 349*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", 350*b285192aSMauro Carvalho Chehab yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); 351*b285192aSMauro Carvalho Chehab 352*b285192aSMauro Carvalho Chehab write_reg(reg_283c, 0x0283c); 353*b285192aSMauro Carvalho Chehab write_reg(reg_2844, 0x02844); 354*b285192aSMauro Carvalho Chehab 355*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", 356*b285192aSMauro Carvalho Chehab yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); 357*b285192aSMauro Carvalho Chehab 358*b285192aSMauro Carvalho Chehab write_reg(0x00080514, 0x02840); 359*b285192aSMauro Carvalho Chehab write_reg(0x00100514, 0x02848); 360*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", 361*b285192aSMauro Carvalho Chehab yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); 362*b285192aSMauro Carvalho Chehab 363*b285192aSMauro Carvalho Chehab write_reg(reg_2854, 0x02854); 364*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", 365*b285192aSMauro Carvalho Chehab yi->reg_2854, reg_2854); 366*b285192aSMauro Carvalho Chehab 367*b285192aSMauro Carvalho Chehab write_reg(reg_285c, 0x0285c); 368*b285192aSMauro Carvalho Chehab write_reg(reg_2864, 0x02864); 369*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", 370*b285192aSMauro Carvalho Chehab yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); 371*b285192aSMauro Carvalho Chehab 372*b285192aSMauro Carvalho Chehab write_reg(reg_2874, 0x02874); 373*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", 374*b285192aSMauro Carvalho Chehab yi->reg_2874, reg_2874); 375*b285192aSMauro Carvalho Chehab 376*b285192aSMauro Carvalho Chehab write_reg(reg_2870, 0x02870); 377*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", 378*b285192aSMauro Carvalho Chehab yi->reg_2870, reg_2870); 379*b285192aSMauro Carvalho Chehab 380*b285192aSMauro Carvalho Chehab write_reg(reg_2890, 0x02890); 381*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", 382*b285192aSMauro Carvalho Chehab yi->reg_2890, reg_2890); 383*b285192aSMauro Carvalho Chehab 384*b285192aSMauro Carvalho Chehab /* Only update the filter if we really need to */ 385*b285192aSMauro Carvalho Chehab if (h_filter != yi->h_filter) { 386*b285192aSMauro Carvalho Chehab ivtv_yuv_filter(itv, h_filter, -1, -1); 387*b285192aSMauro Carvalho Chehab yi->h_filter = h_filter; 388*b285192aSMauro Carvalho Chehab } 389*b285192aSMauro Carvalho Chehab } 390*b285192aSMauro Carvalho Chehab 391*b285192aSMauro Carvalho Chehab static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) 392*b285192aSMauro Carvalho Chehab { 393*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 394*b285192aSMauro Carvalho Chehab u32 master_height; 395*b285192aSMauro Carvalho Chehab u32 reg_2918, reg_291c, reg_2920, reg_2928; 396*b285192aSMauro Carvalho Chehab u32 reg_2930, reg_2934, reg_293c; 397*b285192aSMauro Carvalho Chehab u32 reg_2940, reg_2944, reg_294c; 398*b285192aSMauro Carvalho Chehab u32 reg_2950, reg_2954, reg_2958, reg_295c; 399*b285192aSMauro Carvalho Chehab u32 reg_2960, reg_2964, reg_2968, reg_296c; 400*b285192aSMauro Carvalho Chehab u32 reg_289c; 401*b285192aSMauro Carvalho Chehab u32 src_major_y, src_minor_y; 402*b285192aSMauro Carvalho Chehab u32 src_major_uv, src_minor_uv; 403*b285192aSMauro Carvalho Chehab u32 reg_2964_base, reg_2968_base; 404*b285192aSMauro Carvalho Chehab int v_filter_1, v_filter_2; 405*b285192aSMauro Carvalho Chehab 406*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN 407*b285192aSMauro Carvalho Chehab ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", 408*b285192aSMauro Carvalho Chehab f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); 409*b285192aSMauro Carvalho Chehab 410*b285192aSMauro Carvalho Chehab /* What scaling mode is being used... */ 411*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Scaling mode Y: %s\n", 412*b285192aSMauro Carvalho Chehab f->interlaced_y ? "Interlaced" : "Progressive"); 413*b285192aSMauro Carvalho Chehab 414*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Scaling mode UV: %s\n", 415*b285192aSMauro Carvalho Chehab f->interlaced_uv ? "Interlaced" : "Progressive"); 416*b285192aSMauro Carvalho Chehab 417*b285192aSMauro Carvalho Chehab /* What is the source video being treated as... */ 418*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN("Source video: %s\n", 419*b285192aSMauro Carvalho Chehab f->interlaced ? "Interlaced" : "Progressive"); 420*b285192aSMauro Carvalho Chehab 421*b285192aSMauro Carvalho Chehab /* We offset into the image using two different index methods, so split 422*b285192aSMauro Carvalho Chehab the y source coord into two parts. */ 423*b285192aSMauro Carvalho Chehab if (f->src_y < 8) { 424*b285192aSMauro Carvalho Chehab src_minor_uv = f->src_y; 425*b285192aSMauro Carvalho Chehab src_major_uv = 0; 426*b285192aSMauro Carvalho Chehab } else { 427*b285192aSMauro Carvalho Chehab src_minor_uv = 8; 428*b285192aSMauro Carvalho Chehab src_major_uv = f->src_y - 8; 429*b285192aSMauro Carvalho Chehab } 430*b285192aSMauro Carvalho Chehab 431*b285192aSMauro Carvalho Chehab src_minor_y = src_minor_uv; 432*b285192aSMauro Carvalho Chehab src_major_y = src_major_uv; 433*b285192aSMauro Carvalho Chehab 434*b285192aSMauro Carvalho Chehab if (f->offset_y) 435*b285192aSMauro Carvalho Chehab src_minor_y += 16; 436*b285192aSMauro Carvalho Chehab 437*b285192aSMauro Carvalho Chehab if (f->interlaced_y) 438*b285192aSMauro Carvalho Chehab reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); 439*b285192aSMauro Carvalho Chehab else 440*b285192aSMauro Carvalho Chehab reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); 441*b285192aSMauro Carvalho Chehab 442*b285192aSMauro Carvalho Chehab if (f->interlaced_uv) 443*b285192aSMauro Carvalho Chehab reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); 444*b285192aSMauro Carvalho Chehab else 445*b285192aSMauro Carvalho Chehab reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); 446*b285192aSMauro Carvalho Chehab 447*b285192aSMauro Carvalho Chehab reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; 448*b285192aSMauro Carvalho Chehab reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; 449*b285192aSMauro Carvalho Chehab 450*b285192aSMauro Carvalho Chehab if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { 451*b285192aSMauro Carvalho Chehab master_height = (f->src_h * 0x00400000) / f->dst_h; 452*b285192aSMauro Carvalho Chehab if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) 453*b285192aSMauro Carvalho Chehab master_height++; 454*b285192aSMauro Carvalho Chehab reg_2920 = master_height >> 2; 455*b285192aSMauro Carvalho Chehab reg_2928 = master_height >> 3; 456*b285192aSMauro Carvalho Chehab reg_2930 = master_height; 457*b285192aSMauro Carvalho Chehab reg_2940 = master_height >> 1; 458*b285192aSMauro Carvalho Chehab reg_2964_base >>= 3; 459*b285192aSMauro Carvalho Chehab reg_2968_base >>= 3; 460*b285192aSMauro Carvalho Chehab reg_296c = 0x00000000; 461*b285192aSMauro Carvalho Chehab } else if (f->dst_h >= f->src_h) { 462*b285192aSMauro Carvalho Chehab master_height = (f->src_h * 0x00400000) / f->dst_h; 463*b285192aSMauro Carvalho Chehab master_height = (master_height >> 1) + (master_height & 1); 464*b285192aSMauro Carvalho Chehab reg_2920 = master_height >> 2; 465*b285192aSMauro Carvalho Chehab reg_2928 = master_height >> 2; 466*b285192aSMauro Carvalho Chehab reg_2930 = master_height; 467*b285192aSMauro Carvalho Chehab reg_2940 = master_height >> 1; 468*b285192aSMauro Carvalho Chehab reg_296c = 0x00000000; 469*b285192aSMauro Carvalho Chehab if (f->interlaced_y) { 470*b285192aSMauro Carvalho Chehab reg_2964_base >>= 3; 471*b285192aSMauro Carvalho Chehab } else { 472*b285192aSMauro Carvalho Chehab reg_296c++; 473*b285192aSMauro Carvalho Chehab reg_2964_base >>= 2; 474*b285192aSMauro Carvalho Chehab } 475*b285192aSMauro Carvalho Chehab if (f->interlaced_uv) 476*b285192aSMauro Carvalho Chehab reg_2928 >>= 1; 477*b285192aSMauro Carvalho Chehab reg_2968_base >>= 3; 478*b285192aSMauro Carvalho Chehab } else if (f->dst_h >= f->src_h / 2) { 479*b285192aSMauro Carvalho Chehab master_height = (f->src_h * 0x00200000) / f->dst_h; 480*b285192aSMauro Carvalho Chehab master_height = (master_height >> 1) + (master_height & 1); 481*b285192aSMauro Carvalho Chehab reg_2920 = master_height >> 2; 482*b285192aSMauro Carvalho Chehab reg_2928 = master_height >> 2; 483*b285192aSMauro Carvalho Chehab reg_2930 = master_height; 484*b285192aSMauro Carvalho Chehab reg_2940 = master_height; 485*b285192aSMauro Carvalho Chehab reg_296c = 0x00000101; 486*b285192aSMauro Carvalho Chehab if (f->interlaced_y) { 487*b285192aSMauro Carvalho Chehab reg_2964_base >>= 2; 488*b285192aSMauro Carvalho Chehab } else { 489*b285192aSMauro Carvalho Chehab reg_296c++; 490*b285192aSMauro Carvalho Chehab reg_2964_base >>= 1; 491*b285192aSMauro Carvalho Chehab } 492*b285192aSMauro Carvalho Chehab if (f->interlaced_uv) 493*b285192aSMauro Carvalho Chehab reg_2928 >>= 1; 494*b285192aSMauro Carvalho Chehab reg_2968_base >>= 2; 495*b285192aSMauro Carvalho Chehab } else { 496*b285192aSMauro Carvalho Chehab master_height = (f->src_h * 0x00100000) / f->dst_h; 497*b285192aSMauro Carvalho Chehab master_height = (master_height >> 1) + (master_height & 1); 498*b285192aSMauro Carvalho Chehab reg_2920 = master_height >> 2; 499*b285192aSMauro Carvalho Chehab reg_2928 = master_height >> 2; 500*b285192aSMauro Carvalho Chehab reg_2930 = master_height; 501*b285192aSMauro Carvalho Chehab reg_2940 = master_height; 502*b285192aSMauro Carvalho Chehab reg_2964_base >>= 1; 503*b285192aSMauro Carvalho Chehab reg_2968_base >>= 2; 504*b285192aSMauro Carvalho Chehab reg_296c = 0x00000102; 505*b285192aSMauro Carvalho Chehab } 506*b285192aSMauro Carvalho Chehab 507*b285192aSMauro Carvalho Chehab /* FIXME These registers change depending on scaled / unscaled output 508*b285192aSMauro Carvalho Chehab We really need to work out what they should be */ 509*b285192aSMauro Carvalho Chehab if (f->src_h == f->dst_h) { 510*b285192aSMauro Carvalho Chehab reg_2934 = 0x00020000; 511*b285192aSMauro Carvalho Chehab reg_293c = 0x00100000; 512*b285192aSMauro Carvalho Chehab reg_2944 = 0x00040000; 513*b285192aSMauro Carvalho Chehab reg_294c = 0x000b0000; 514*b285192aSMauro Carvalho Chehab } else { 515*b285192aSMauro Carvalho Chehab reg_2934 = 0x00000FF0; 516*b285192aSMauro Carvalho Chehab reg_293c = 0x00000FF0; 517*b285192aSMauro Carvalho Chehab reg_2944 = 0x00000FF0; 518*b285192aSMauro Carvalho Chehab reg_294c = 0x00000FF0; 519*b285192aSMauro Carvalho Chehab } 520*b285192aSMauro Carvalho Chehab 521*b285192aSMauro Carvalho Chehab /* The first line to be displayed */ 522*b285192aSMauro Carvalho Chehab reg_2950 = 0x00010000 + src_major_y; 523*b285192aSMauro Carvalho Chehab if (f->interlaced_y) 524*b285192aSMauro Carvalho Chehab reg_2950 += 0x00010000; 525*b285192aSMauro Carvalho Chehab reg_2954 = reg_2950 + 1; 526*b285192aSMauro Carvalho Chehab 527*b285192aSMauro Carvalho Chehab reg_2958 = 0x00010000 + (src_major_y >> 1); 528*b285192aSMauro Carvalho Chehab if (f->interlaced_uv) 529*b285192aSMauro Carvalho Chehab reg_2958 += 0x00010000; 530*b285192aSMauro Carvalho Chehab reg_295c = reg_2958 + 1; 531*b285192aSMauro Carvalho Chehab 532*b285192aSMauro Carvalho Chehab if (yi->decode_height == 480) 533*b285192aSMauro Carvalho Chehab reg_289c = 0x011e0017; 534*b285192aSMauro Carvalho Chehab else 535*b285192aSMauro Carvalho Chehab reg_289c = 0x01500017; 536*b285192aSMauro Carvalho Chehab 537*b285192aSMauro Carvalho Chehab if (f->dst_y < 0) 538*b285192aSMauro Carvalho Chehab reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); 539*b285192aSMauro Carvalho Chehab else 540*b285192aSMauro Carvalho Chehab reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); 541*b285192aSMauro Carvalho Chehab 542*b285192aSMauro Carvalho Chehab /* How much of the source to decode. 543*b285192aSMauro Carvalho Chehab Take into account the source offset */ 544*b285192aSMauro Carvalho Chehab reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | 545*b285192aSMauro Carvalho Chehab (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); 546*b285192aSMauro Carvalho Chehab 547*b285192aSMauro Carvalho Chehab /* Calculate correct value for register 2964 */ 548*b285192aSMauro Carvalho Chehab if (f->src_h == f->dst_h) { 549*b285192aSMauro Carvalho Chehab reg_2964 = 1; 550*b285192aSMauro Carvalho Chehab } else { 551*b285192aSMauro Carvalho Chehab reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); 552*b285192aSMauro Carvalho Chehab reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); 553*b285192aSMauro Carvalho Chehab } 554*b285192aSMauro Carvalho Chehab reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); 555*b285192aSMauro Carvalho Chehab reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); 556*b285192aSMauro Carvalho Chehab 557*b285192aSMauro Carvalho Chehab /* Okay, we've wasted time working out the correct value, 558*b285192aSMauro Carvalho Chehab but if we use it, it fouls the the window alignment. 559*b285192aSMauro Carvalho Chehab Fudge it to what we want... */ 560*b285192aSMauro Carvalho Chehab reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); 561*b285192aSMauro Carvalho Chehab reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); 562*b285192aSMauro Carvalho Chehab 563*b285192aSMauro Carvalho Chehab /* Deviate further from what it should be. I find the flicker headache 564*b285192aSMauro Carvalho Chehab inducing so try to reduce it slightly. Leave 2968 as-is otherwise 565*b285192aSMauro Carvalho Chehab colours foul. */ 566*b285192aSMauro Carvalho Chehab if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) 567*b285192aSMauro Carvalho Chehab reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); 568*b285192aSMauro Carvalho Chehab 569*b285192aSMauro Carvalho Chehab if (!f->interlaced_y) 570*b285192aSMauro Carvalho Chehab reg_2964 -= 0x00010001; 571*b285192aSMauro Carvalho Chehab if (!f->interlaced_uv) 572*b285192aSMauro Carvalho Chehab reg_2968 -= 0x00010001; 573*b285192aSMauro Carvalho Chehab 574*b285192aSMauro Carvalho Chehab reg_2964 += ((reg_2964_base << 16) | reg_2964_base); 575*b285192aSMauro Carvalho Chehab reg_2968 += ((reg_2968_base << 16) | reg_2968_base); 576*b285192aSMauro Carvalho Chehab 577*b285192aSMauro Carvalho Chehab /* Select the vertical filter */ 578*b285192aSMauro Carvalho Chehab if (f->src_h == f->dst_h) { 579*b285192aSMauro Carvalho Chehab /* An exact size match uses filter 0/1 */ 580*b285192aSMauro Carvalho Chehab v_filter_1 = 0; 581*b285192aSMauro Carvalho Chehab v_filter_2 = 1; 582*b285192aSMauro Carvalho Chehab } else { 583*b285192aSMauro Carvalho Chehab /* Figure out which filter to use */ 584*b285192aSMauro Carvalho Chehab v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; 585*b285192aSMauro Carvalho Chehab v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); 586*b285192aSMauro Carvalho Chehab /* Only an exact size match can use filter 0 */ 587*b285192aSMauro Carvalho Chehab v_filter_1 += !v_filter_1; 588*b285192aSMauro Carvalho Chehab v_filter_2 = v_filter_1; 589*b285192aSMauro Carvalho Chehab } 590*b285192aSMauro Carvalho Chehab 591*b285192aSMauro Carvalho Chehab write_reg(reg_2934, 0x02934); 592*b285192aSMauro Carvalho Chehab write_reg(reg_293c, 0x0293c); 593*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", 594*b285192aSMauro Carvalho Chehab yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); 595*b285192aSMauro Carvalho Chehab write_reg(reg_2944, 0x02944); 596*b285192aSMauro Carvalho Chehab write_reg(reg_294c, 0x0294c); 597*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", 598*b285192aSMauro Carvalho Chehab yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); 599*b285192aSMauro Carvalho Chehab 600*b285192aSMauro Carvalho Chehab /* Ensure 2970 is 0 (does it ever change ?) */ 601*b285192aSMauro Carvalho Chehab /* write_reg(0,0x02970); */ 602*b285192aSMauro Carvalho Chehab /* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ 603*b285192aSMauro Carvalho Chehab 604*b285192aSMauro Carvalho Chehab write_reg(reg_2930, 0x02938); 605*b285192aSMauro Carvalho Chehab write_reg(reg_2930, 0x02930); 606*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", 607*b285192aSMauro Carvalho Chehab yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); 608*b285192aSMauro Carvalho Chehab 609*b285192aSMauro Carvalho Chehab write_reg(reg_2928, 0x02928); 610*b285192aSMauro Carvalho Chehab write_reg(reg_2928 + 0x514, 0x0292C); 611*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", 612*b285192aSMauro Carvalho Chehab yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); 613*b285192aSMauro Carvalho Chehab 614*b285192aSMauro Carvalho Chehab write_reg(reg_2920, 0x02920); 615*b285192aSMauro Carvalho Chehab write_reg(reg_2920 + 0x514, 0x02924); 616*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", 617*b285192aSMauro Carvalho Chehab yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); 618*b285192aSMauro Carvalho Chehab 619*b285192aSMauro Carvalho Chehab write_reg(reg_2918, 0x02918); 620*b285192aSMauro Carvalho Chehab write_reg(reg_291c, 0x0291C); 621*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", 622*b285192aSMauro Carvalho Chehab yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); 623*b285192aSMauro Carvalho Chehab 624*b285192aSMauro Carvalho Chehab write_reg(reg_296c, 0x0296c); 625*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", 626*b285192aSMauro Carvalho Chehab yi->reg_296c, reg_296c); 627*b285192aSMauro Carvalho Chehab 628*b285192aSMauro Carvalho Chehab write_reg(reg_2940, 0x02948); 629*b285192aSMauro Carvalho Chehab write_reg(reg_2940, 0x02940); 630*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", 631*b285192aSMauro Carvalho Chehab yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); 632*b285192aSMauro Carvalho Chehab 633*b285192aSMauro Carvalho Chehab write_reg(reg_2950, 0x02950); 634*b285192aSMauro Carvalho Chehab write_reg(reg_2954, 0x02954); 635*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", 636*b285192aSMauro Carvalho Chehab yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); 637*b285192aSMauro Carvalho Chehab 638*b285192aSMauro Carvalho Chehab write_reg(reg_2958, 0x02958); 639*b285192aSMauro Carvalho Chehab write_reg(reg_295c, 0x0295C); 640*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", 641*b285192aSMauro Carvalho Chehab yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); 642*b285192aSMauro Carvalho Chehab 643*b285192aSMauro Carvalho Chehab write_reg(reg_2960, 0x02960); 644*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", 645*b285192aSMauro Carvalho Chehab yi->reg_2960, reg_2960); 646*b285192aSMauro Carvalho Chehab 647*b285192aSMauro Carvalho Chehab write_reg(reg_2964, 0x02964); 648*b285192aSMauro Carvalho Chehab write_reg(reg_2968, 0x02968); 649*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", 650*b285192aSMauro Carvalho Chehab yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); 651*b285192aSMauro Carvalho Chehab 652*b285192aSMauro Carvalho Chehab write_reg(reg_289c, 0x0289c); 653*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", 654*b285192aSMauro Carvalho Chehab yi->reg_289c, reg_289c); 655*b285192aSMauro Carvalho Chehab 656*b285192aSMauro Carvalho Chehab /* Only update filter 1 if we really need to */ 657*b285192aSMauro Carvalho Chehab if (v_filter_1 != yi->v_filter_1) { 658*b285192aSMauro Carvalho Chehab ivtv_yuv_filter(itv, -1, v_filter_1, -1); 659*b285192aSMauro Carvalho Chehab yi->v_filter_1 = v_filter_1; 660*b285192aSMauro Carvalho Chehab } 661*b285192aSMauro Carvalho Chehab 662*b285192aSMauro Carvalho Chehab /* Only update filter 2 if we really need to */ 663*b285192aSMauro Carvalho Chehab if (v_filter_2 != yi->v_filter_2) { 664*b285192aSMauro Carvalho Chehab ivtv_yuv_filter(itv, -1, -1, v_filter_2); 665*b285192aSMauro Carvalho Chehab yi->v_filter_2 = v_filter_2; 666*b285192aSMauro Carvalho Chehab } 667*b285192aSMauro Carvalho Chehab } 668*b285192aSMauro Carvalho Chehab 669*b285192aSMauro Carvalho Chehab /* Modify the supplied coordinate information to fit the visible osd area */ 670*b285192aSMauro Carvalho Chehab static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) 671*b285192aSMauro Carvalho Chehab { 672*b285192aSMauro Carvalho Chehab struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; 673*b285192aSMauro Carvalho Chehab int osd_crop; 674*b285192aSMauro Carvalho Chehab u32 osd_scale; 675*b285192aSMauro Carvalho Chehab u32 yuv_update = 0; 676*b285192aSMauro Carvalho Chehab 677*b285192aSMauro Carvalho Chehab /* Sorry, but no negative coords for src */ 678*b285192aSMauro Carvalho Chehab if (f->src_x < 0) 679*b285192aSMauro Carvalho Chehab f->src_x = 0; 680*b285192aSMauro Carvalho Chehab if (f->src_y < 0) 681*b285192aSMauro Carvalho Chehab f->src_y = 0; 682*b285192aSMauro Carvalho Chehab 683*b285192aSMauro Carvalho Chehab /* Can only reduce width down to 1/4 original size */ 684*b285192aSMauro Carvalho Chehab if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { 685*b285192aSMauro Carvalho Chehab f->src_x += osd_crop / 2; 686*b285192aSMauro Carvalho Chehab f->src_w = (f->src_w - osd_crop) & ~3; 687*b285192aSMauro Carvalho Chehab f->dst_w = f->src_w / 4; 688*b285192aSMauro Carvalho Chehab f->dst_w += f->dst_w & 1; 689*b285192aSMauro Carvalho Chehab } 690*b285192aSMauro Carvalho Chehab 691*b285192aSMauro Carvalho Chehab /* Can only reduce height down to 1/4 original size */ 692*b285192aSMauro Carvalho Chehab if (f->src_h / f->dst_h >= 2) { 693*b285192aSMauro Carvalho Chehab /* Overflow may be because we're running progressive, 694*b285192aSMauro Carvalho Chehab so force mode switch */ 695*b285192aSMauro Carvalho Chehab f->interlaced_y = 1; 696*b285192aSMauro Carvalho Chehab /* Make sure we're still within limits for interlace */ 697*b285192aSMauro Carvalho Chehab if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { 698*b285192aSMauro Carvalho Chehab /* If we reach here we'll have to force the height. */ 699*b285192aSMauro Carvalho Chehab f->src_y += osd_crop / 2; 700*b285192aSMauro Carvalho Chehab f->src_h = (f->src_h - osd_crop) & ~3; 701*b285192aSMauro Carvalho Chehab f->dst_h = f->src_h / 4; 702*b285192aSMauro Carvalho Chehab f->dst_h += f->dst_h & 1; 703*b285192aSMauro Carvalho Chehab } 704*b285192aSMauro Carvalho Chehab } 705*b285192aSMauro Carvalho Chehab 706*b285192aSMauro Carvalho Chehab /* If there's nothing to safe to display, we may as well stop now */ 707*b285192aSMauro Carvalho Chehab if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || 708*b285192aSMauro Carvalho Chehab (int)f->src_w <= 2 || (int)f->src_h <= 2) { 709*b285192aSMauro Carvalho Chehab return IVTV_YUV_UPDATE_INVALID; 710*b285192aSMauro Carvalho Chehab } 711*b285192aSMauro Carvalho Chehab 712*b285192aSMauro Carvalho Chehab /* Ensure video remains inside OSD area */ 713*b285192aSMauro Carvalho Chehab osd_scale = (f->src_h << 16) / f->dst_h; 714*b285192aSMauro Carvalho Chehab 715*b285192aSMauro Carvalho Chehab if ((osd_crop = f->pan_y - f->dst_y) > 0) { 716*b285192aSMauro Carvalho Chehab /* Falls off the upper edge - crop */ 717*b285192aSMauro Carvalho Chehab f->src_y += (osd_scale * osd_crop) >> 16; 718*b285192aSMauro Carvalho Chehab f->src_h -= (osd_scale * osd_crop) >> 16; 719*b285192aSMauro Carvalho Chehab f->dst_h -= osd_crop; 720*b285192aSMauro Carvalho Chehab f->dst_y = 0; 721*b285192aSMauro Carvalho Chehab } else { 722*b285192aSMauro Carvalho Chehab f->dst_y -= f->pan_y; 723*b285192aSMauro Carvalho Chehab } 724*b285192aSMauro Carvalho Chehab 725*b285192aSMauro Carvalho Chehab if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { 726*b285192aSMauro Carvalho Chehab /* Falls off the lower edge - crop */ 727*b285192aSMauro Carvalho Chehab f->dst_h -= osd_crop; 728*b285192aSMauro Carvalho Chehab f->src_h -= (osd_scale * osd_crop) >> 16; 729*b285192aSMauro Carvalho Chehab } 730*b285192aSMauro Carvalho Chehab 731*b285192aSMauro Carvalho Chehab osd_scale = (f->src_w << 16) / f->dst_w; 732*b285192aSMauro Carvalho Chehab 733*b285192aSMauro Carvalho Chehab if ((osd_crop = f->pan_x - f->dst_x) > 0) { 734*b285192aSMauro Carvalho Chehab /* Fall off the left edge - crop */ 735*b285192aSMauro Carvalho Chehab f->src_x += (osd_scale * osd_crop) >> 16; 736*b285192aSMauro Carvalho Chehab f->src_w -= (osd_scale * osd_crop) >> 16; 737*b285192aSMauro Carvalho Chehab f->dst_w -= osd_crop; 738*b285192aSMauro Carvalho Chehab f->dst_x = 0; 739*b285192aSMauro Carvalho Chehab } else { 740*b285192aSMauro Carvalho Chehab f->dst_x -= f->pan_x; 741*b285192aSMauro Carvalho Chehab } 742*b285192aSMauro Carvalho Chehab 743*b285192aSMauro Carvalho Chehab if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { 744*b285192aSMauro Carvalho Chehab /* Falls off the right edge - crop */ 745*b285192aSMauro Carvalho Chehab f->dst_w -= osd_crop; 746*b285192aSMauro Carvalho Chehab f->src_w -= (osd_scale * osd_crop) >> 16; 747*b285192aSMauro Carvalho Chehab } 748*b285192aSMauro Carvalho Chehab 749*b285192aSMauro Carvalho Chehab if (itv->yuv_info.track_osd) { 750*b285192aSMauro Carvalho Chehab /* The OSD can be moved. Track to it */ 751*b285192aSMauro Carvalho Chehab f->dst_x += itv->yuv_info.osd_x_offset; 752*b285192aSMauro Carvalho Chehab f->dst_y += itv->yuv_info.osd_y_offset; 753*b285192aSMauro Carvalho Chehab } 754*b285192aSMauro Carvalho Chehab 755*b285192aSMauro Carvalho Chehab /* Width & height for both src & dst must be even. 756*b285192aSMauro Carvalho Chehab Same for coordinates. */ 757*b285192aSMauro Carvalho Chehab f->dst_w &= ~1; 758*b285192aSMauro Carvalho Chehab f->dst_x &= ~1; 759*b285192aSMauro Carvalho Chehab 760*b285192aSMauro Carvalho Chehab f->src_w += f->src_x & 1; 761*b285192aSMauro Carvalho Chehab f->src_x &= ~1; 762*b285192aSMauro Carvalho Chehab 763*b285192aSMauro Carvalho Chehab f->src_w &= ~1; 764*b285192aSMauro Carvalho Chehab f->dst_w &= ~1; 765*b285192aSMauro Carvalho Chehab 766*b285192aSMauro Carvalho Chehab f->dst_h &= ~1; 767*b285192aSMauro Carvalho Chehab f->dst_y &= ~1; 768*b285192aSMauro Carvalho Chehab 769*b285192aSMauro Carvalho Chehab f->src_h += f->src_y & 1; 770*b285192aSMauro Carvalho Chehab f->src_y &= ~1; 771*b285192aSMauro Carvalho Chehab 772*b285192aSMauro Carvalho Chehab f->src_h &= ~1; 773*b285192aSMauro Carvalho Chehab f->dst_h &= ~1; 774*b285192aSMauro Carvalho Chehab 775*b285192aSMauro Carvalho Chehab /* Due to rounding, we may have reduced the output size to <1/4 of 776*b285192aSMauro Carvalho Chehab the source. Check again, but this time just resize. Don't change 777*b285192aSMauro Carvalho Chehab source coordinates */ 778*b285192aSMauro Carvalho Chehab if (f->dst_w < f->src_w / 4) { 779*b285192aSMauro Carvalho Chehab f->src_w &= ~3; 780*b285192aSMauro Carvalho Chehab f->dst_w = f->src_w / 4; 781*b285192aSMauro Carvalho Chehab f->dst_w += f->dst_w & 1; 782*b285192aSMauro Carvalho Chehab } 783*b285192aSMauro Carvalho Chehab if (f->dst_h < f->src_h / 4) { 784*b285192aSMauro Carvalho Chehab f->src_h &= ~3; 785*b285192aSMauro Carvalho Chehab f->dst_h = f->src_h / 4; 786*b285192aSMauro Carvalho Chehab f->dst_h += f->dst_h & 1; 787*b285192aSMauro Carvalho Chehab } 788*b285192aSMauro Carvalho Chehab 789*b285192aSMauro Carvalho Chehab /* Check again. If there's nothing to safe to display, stop now */ 790*b285192aSMauro Carvalho Chehab if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || 791*b285192aSMauro Carvalho Chehab (int)f->src_w <= 2 || (int)f->src_h <= 2) { 792*b285192aSMauro Carvalho Chehab return IVTV_YUV_UPDATE_INVALID; 793*b285192aSMauro Carvalho Chehab } 794*b285192aSMauro Carvalho Chehab 795*b285192aSMauro Carvalho Chehab /* Both x offset & width are linked, so they have to be done together */ 796*b285192aSMauro Carvalho Chehab if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || 797*b285192aSMauro Carvalho Chehab (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || 798*b285192aSMauro Carvalho Chehab (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { 799*b285192aSMauro Carvalho Chehab yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; 800*b285192aSMauro Carvalho Chehab } 801*b285192aSMauro Carvalho Chehab 802*b285192aSMauro Carvalho Chehab if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || 803*b285192aSMauro Carvalho Chehab (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || 804*b285192aSMauro Carvalho Chehab (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || 805*b285192aSMauro Carvalho Chehab (of->lace_mode != f->lace_mode) || 806*b285192aSMauro Carvalho Chehab (of->interlaced_y != f->interlaced_y) || 807*b285192aSMauro Carvalho Chehab (of->interlaced_uv != f->interlaced_uv)) { 808*b285192aSMauro Carvalho Chehab yuv_update |= IVTV_YUV_UPDATE_VERTICAL; 809*b285192aSMauro Carvalho Chehab } 810*b285192aSMauro Carvalho Chehab 811*b285192aSMauro Carvalho Chehab return yuv_update; 812*b285192aSMauro Carvalho Chehab } 813*b285192aSMauro Carvalho Chehab 814*b285192aSMauro Carvalho Chehab /* Update the scaling register to the requested value */ 815*b285192aSMauro Carvalho Chehab void ivtv_yuv_work_handler(struct ivtv *itv) 816*b285192aSMauro Carvalho Chehab { 817*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 818*b285192aSMauro Carvalho Chehab struct yuv_frame_info f; 819*b285192aSMauro Carvalho Chehab int frame = yi->update_frame; 820*b285192aSMauro Carvalho Chehab u32 yuv_update; 821*b285192aSMauro Carvalho Chehab 822*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); 823*b285192aSMauro Carvalho Chehab f = yi->new_frame_info[frame]; 824*b285192aSMauro Carvalho Chehab 825*b285192aSMauro Carvalho Chehab if (yi->track_osd) { 826*b285192aSMauro Carvalho Chehab /* Snapshot the osd pan info */ 827*b285192aSMauro Carvalho Chehab f.pan_x = yi->osd_x_pan; 828*b285192aSMauro Carvalho Chehab f.pan_y = yi->osd_y_pan; 829*b285192aSMauro Carvalho Chehab f.vis_w = yi->osd_vis_w; 830*b285192aSMauro Carvalho Chehab f.vis_h = yi->osd_vis_h; 831*b285192aSMauro Carvalho Chehab } else { 832*b285192aSMauro Carvalho Chehab /* Not tracking the osd, so assume full screen */ 833*b285192aSMauro Carvalho Chehab f.pan_x = 0; 834*b285192aSMauro Carvalho Chehab f.pan_y = 0; 835*b285192aSMauro Carvalho Chehab f.vis_w = 720; 836*b285192aSMauro Carvalho Chehab f.vis_h = yi->decode_height; 837*b285192aSMauro Carvalho Chehab } 838*b285192aSMauro Carvalho Chehab 839*b285192aSMauro Carvalho Chehab /* Calculate the display window coordinates. Exit if nothing left */ 840*b285192aSMauro Carvalho Chehab if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) 841*b285192aSMauro Carvalho Chehab return; 842*b285192aSMauro Carvalho Chehab 843*b285192aSMauro Carvalho Chehab if (yuv_update & IVTV_YUV_UPDATE_INVALID) { 844*b285192aSMauro Carvalho Chehab write_reg(0x01008080, 0x2898); 845*b285192aSMauro Carvalho Chehab } else if (yuv_update) { 846*b285192aSMauro Carvalho Chehab write_reg(0x00108080, 0x2898); 847*b285192aSMauro Carvalho Chehab 848*b285192aSMauro Carvalho Chehab if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) 849*b285192aSMauro Carvalho Chehab ivtv_yuv_handle_horizontal(itv, &f); 850*b285192aSMauro Carvalho Chehab 851*b285192aSMauro Carvalho Chehab if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) 852*b285192aSMauro Carvalho Chehab ivtv_yuv_handle_vertical(itv, &f); 853*b285192aSMauro Carvalho Chehab } 854*b285192aSMauro Carvalho Chehab yi->old_frame_info = f; 855*b285192aSMauro Carvalho Chehab } 856*b285192aSMauro Carvalho Chehab 857*b285192aSMauro Carvalho Chehab static void ivtv_yuv_init(struct ivtv *itv) 858*b285192aSMauro Carvalho Chehab { 859*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 860*b285192aSMauro Carvalho Chehab 861*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("ivtv_yuv_init\n"); 862*b285192aSMauro Carvalho Chehab 863*b285192aSMauro Carvalho Chehab /* Take a snapshot of the current register settings */ 864*b285192aSMauro Carvalho Chehab yi->reg_2834 = read_reg(0x02834); 865*b285192aSMauro Carvalho Chehab yi->reg_2838 = read_reg(0x02838); 866*b285192aSMauro Carvalho Chehab yi->reg_283c = read_reg(0x0283c); 867*b285192aSMauro Carvalho Chehab yi->reg_2840 = read_reg(0x02840); 868*b285192aSMauro Carvalho Chehab yi->reg_2844 = read_reg(0x02844); 869*b285192aSMauro Carvalho Chehab yi->reg_2848 = read_reg(0x02848); 870*b285192aSMauro Carvalho Chehab yi->reg_2854 = read_reg(0x02854); 871*b285192aSMauro Carvalho Chehab yi->reg_285c = read_reg(0x0285c); 872*b285192aSMauro Carvalho Chehab yi->reg_2864 = read_reg(0x02864); 873*b285192aSMauro Carvalho Chehab yi->reg_2870 = read_reg(0x02870); 874*b285192aSMauro Carvalho Chehab yi->reg_2874 = read_reg(0x02874); 875*b285192aSMauro Carvalho Chehab yi->reg_2898 = read_reg(0x02898); 876*b285192aSMauro Carvalho Chehab yi->reg_2890 = read_reg(0x02890); 877*b285192aSMauro Carvalho Chehab 878*b285192aSMauro Carvalho Chehab yi->reg_289c = read_reg(0x0289c); 879*b285192aSMauro Carvalho Chehab yi->reg_2918 = read_reg(0x02918); 880*b285192aSMauro Carvalho Chehab yi->reg_291c = read_reg(0x0291c); 881*b285192aSMauro Carvalho Chehab yi->reg_2920 = read_reg(0x02920); 882*b285192aSMauro Carvalho Chehab yi->reg_2924 = read_reg(0x02924); 883*b285192aSMauro Carvalho Chehab yi->reg_2928 = read_reg(0x02928); 884*b285192aSMauro Carvalho Chehab yi->reg_292c = read_reg(0x0292c); 885*b285192aSMauro Carvalho Chehab yi->reg_2930 = read_reg(0x02930); 886*b285192aSMauro Carvalho Chehab yi->reg_2934 = read_reg(0x02934); 887*b285192aSMauro Carvalho Chehab yi->reg_2938 = read_reg(0x02938); 888*b285192aSMauro Carvalho Chehab yi->reg_293c = read_reg(0x0293c); 889*b285192aSMauro Carvalho Chehab yi->reg_2940 = read_reg(0x02940); 890*b285192aSMauro Carvalho Chehab yi->reg_2944 = read_reg(0x02944); 891*b285192aSMauro Carvalho Chehab yi->reg_2948 = read_reg(0x02948); 892*b285192aSMauro Carvalho Chehab yi->reg_294c = read_reg(0x0294c); 893*b285192aSMauro Carvalho Chehab yi->reg_2950 = read_reg(0x02950); 894*b285192aSMauro Carvalho Chehab yi->reg_2954 = read_reg(0x02954); 895*b285192aSMauro Carvalho Chehab yi->reg_2958 = read_reg(0x02958); 896*b285192aSMauro Carvalho Chehab yi->reg_295c = read_reg(0x0295c); 897*b285192aSMauro Carvalho Chehab yi->reg_2960 = read_reg(0x02960); 898*b285192aSMauro Carvalho Chehab yi->reg_2964 = read_reg(0x02964); 899*b285192aSMauro Carvalho Chehab yi->reg_2968 = read_reg(0x02968); 900*b285192aSMauro Carvalho Chehab yi->reg_296c = read_reg(0x0296c); 901*b285192aSMauro Carvalho Chehab yi->reg_2970 = read_reg(0x02970); 902*b285192aSMauro Carvalho Chehab 903*b285192aSMauro Carvalho Chehab yi->v_filter_1 = -1; 904*b285192aSMauro Carvalho Chehab yi->v_filter_2 = -1; 905*b285192aSMauro Carvalho Chehab yi->h_filter = -1; 906*b285192aSMauro Carvalho Chehab 907*b285192aSMauro Carvalho Chehab /* Set some valid size info */ 908*b285192aSMauro Carvalho Chehab yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF; 909*b285192aSMauro Carvalho Chehab yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; 910*b285192aSMauro Carvalho Chehab 911*b285192aSMauro Carvalho Chehab /* Bit 2 of reg 2878 indicates current decoder output format 912*b285192aSMauro Carvalho Chehab 0 : NTSC 1 : PAL */ 913*b285192aSMauro Carvalho Chehab if (read_reg(0x2878) & 4) 914*b285192aSMauro Carvalho Chehab yi->decode_height = 576; 915*b285192aSMauro Carvalho Chehab else 916*b285192aSMauro Carvalho Chehab yi->decode_height = 480; 917*b285192aSMauro Carvalho Chehab 918*b285192aSMauro Carvalho Chehab if (!itv->osd_info) { 919*b285192aSMauro Carvalho Chehab yi->osd_vis_w = 720 - yi->osd_x_offset; 920*b285192aSMauro Carvalho Chehab yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; 921*b285192aSMauro Carvalho Chehab } else { 922*b285192aSMauro Carvalho Chehab /* If no visible size set, assume full size */ 923*b285192aSMauro Carvalho Chehab if (!yi->osd_vis_w) 924*b285192aSMauro Carvalho Chehab yi->osd_vis_w = 720 - yi->osd_x_offset; 925*b285192aSMauro Carvalho Chehab 926*b285192aSMauro Carvalho Chehab if (!yi->osd_vis_h) { 927*b285192aSMauro Carvalho Chehab yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; 928*b285192aSMauro Carvalho Chehab } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { 929*b285192aSMauro Carvalho Chehab /* If output video standard has changed, requested height may 930*b285192aSMauro Carvalho Chehab not be legal */ 931*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", 932*b285192aSMauro Carvalho Chehab yi->osd_vis_h + yi->osd_y_offset, 933*b285192aSMauro Carvalho Chehab yi->decode_height); 934*b285192aSMauro Carvalho Chehab yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; 935*b285192aSMauro Carvalho Chehab } 936*b285192aSMauro Carvalho Chehab } 937*b285192aSMauro Carvalho Chehab 938*b285192aSMauro Carvalho Chehab /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ 939*b285192aSMauro Carvalho Chehab yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN); 940*b285192aSMauro Carvalho Chehab if (yi->blanking_ptr) { 941*b285192aSMauro Carvalho Chehab yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); 942*b285192aSMauro Carvalho Chehab } else { 943*b285192aSMauro Carvalho Chehab yi->blanking_dmaptr = 0; 944*b285192aSMauro Carvalho Chehab IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); 945*b285192aSMauro Carvalho Chehab } 946*b285192aSMauro Carvalho Chehab 947*b285192aSMauro Carvalho Chehab /* Enable YUV decoder output */ 948*b285192aSMauro Carvalho Chehab write_reg_sync(0x01, IVTV_REG_VDM); 949*b285192aSMauro Carvalho Chehab 950*b285192aSMauro Carvalho Chehab set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); 951*b285192aSMauro Carvalho Chehab atomic_set(&yi->next_dma_frame, 0); 952*b285192aSMauro Carvalho Chehab } 953*b285192aSMauro Carvalho Chehab 954*b285192aSMauro Carvalho Chehab /* Get next available yuv buffer on PVR350 */ 955*b285192aSMauro Carvalho Chehab static void ivtv_yuv_next_free(struct ivtv *itv) 956*b285192aSMauro Carvalho Chehab { 957*b285192aSMauro Carvalho Chehab int draw, display; 958*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 959*b285192aSMauro Carvalho Chehab 960*b285192aSMauro Carvalho Chehab if (atomic_read(&yi->next_dma_frame) == -1) 961*b285192aSMauro Carvalho Chehab ivtv_yuv_init(itv); 962*b285192aSMauro Carvalho Chehab 963*b285192aSMauro Carvalho Chehab draw = atomic_read(&yi->next_fill_frame); 964*b285192aSMauro Carvalho Chehab display = atomic_read(&yi->next_dma_frame); 965*b285192aSMauro Carvalho Chehab 966*b285192aSMauro Carvalho Chehab if (display > draw) 967*b285192aSMauro Carvalho Chehab display -= IVTV_YUV_BUFFERS; 968*b285192aSMauro Carvalho Chehab 969*b285192aSMauro Carvalho Chehab if (draw - display >= yi->max_frames_buffered) 970*b285192aSMauro Carvalho Chehab draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; 971*b285192aSMauro Carvalho Chehab else 972*b285192aSMauro Carvalho Chehab yi->new_frame_info[draw].update = 0; 973*b285192aSMauro Carvalho Chehab 974*b285192aSMauro Carvalho Chehab yi->draw_frame = draw; 975*b285192aSMauro Carvalho Chehab } 976*b285192aSMauro Carvalho Chehab 977*b285192aSMauro Carvalho Chehab /* Set up frame according to ivtv_dma_frame parameters */ 978*b285192aSMauro Carvalho Chehab static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) 979*b285192aSMauro Carvalho Chehab { 980*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 981*b285192aSMauro Carvalho Chehab u8 frame = yi->draw_frame; 982*b285192aSMauro Carvalho Chehab u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; 983*b285192aSMauro Carvalho Chehab struct yuv_frame_info *nf = &yi->new_frame_info[frame]; 984*b285192aSMauro Carvalho Chehab struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; 985*b285192aSMauro Carvalho Chehab int lace_threshold = yi->lace_threshold; 986*b285192aSMauro Carvalho Chehab 987*b285192aSMauro Carvalho Chehab /* Preserve old update flag in case we're overwriting a queued frame */ 988*b285192aSMauro Carvalho Chehab int update = nf->update; 989*b285192aSMauro Carvalho Chehab 990*b285192aSMauro Carvalho Chehab /* Take a snapshot of the yuv coordinate information */ 991*b285192aSMauro Carvalho Chehab nf->src_x = args->src.left; 992*b285192aSMauro Carvalho Chehab nf->src_y = args->src.top; 993*b285192aSMauro Carvalho Chehab nf->src_w = args->src.width; 994*b285192aSMauro Carvalho Chehab nf->src_h = args->src.height; 995*b285192aSMauro Carvalho Chehab nf->dst_x = args->dst.left; 996*b285192aSMauro Carvalho Chehab nf->dst_y = args->dst.top; 997*b285192aSMauro Carvalho Chehab nf->dst_w = args->dst.width; 998*b285192aSMauro Carvalho Chehab nf->dst_h = args->dst.height; 999*b285192aSMauro Carvalho Chehab nf->tru_x = args->dst.left; 1000*b285192aSMauro Carvalho Chehab nf->tru_w = args->src_width; 1001*b285192aSMauro Carvalho Chehab nf->tru_h = args->src_height; 1002*b285192aSMauro Carvalho Chehab 1003*b285192aSMauro Carvalho Chehab /* Are we going to offset the Y plane */ 1004*b285192aSMauro Carvalho Chehab nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; 1005*b285192aSMauro Carvalho Chehab 1006*b285192aSMauro Carvalho Chehab nf->update = 0; 1007*b285192aSMauro Carvalho Chehab nf->interlaced_y = 0; 1008*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 0; 1009*b285192aSMauro Carvalho Chehab nf->delay = 0; 1010*b285192aSMauro Carvalho Chehab nf->sync_field = 0; 1011*b285192aSMauro Carvalho Chehab nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; 1012*b285192aSMauro Carvalho Chehab 1013*b285192aSMauro Carvalho Chehab if (lace_threshold < 0) 1014*b285192aSMauro Carvalho Chehab lace_threshold = yi->decode_height - 1; 1015*b285192aSMauro Carvalho Chehab 1016*b285192aSMauro Carvalho Chehab /* Work out the lace settings */ 1017*b285192aSMauro Carvalho Chehab switch (nf->lace_mode) { 1018*b285192aSMauro Carvalho Chehab case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ 1019*b285192aSMauro Carvalho Chehab nf->interlaced = 0; 1020*b285192aSMauro Carvalho Chehab if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) 1021*b285192aSMauro Carvalho Chehab nf->interlaced_y = 0; 1022*b285192aSMauro Carvalho Chehab else 1023*b285192aSMauro Carvalho Chehab nf->interlaced_y = 1; 1024*b285192aSMauro Carvalho Chehab 1025*b285192aSMauro Carvalho Chehab if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) 1026*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 0; 1027*b285192aSMauro Carvalho Chehab else 1028*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 1; 1029*b285192aSMauro Carvalho Chehab break; 1030*b285192aSMauro Carvalho Chehab 1031*b285192aSMauro Carvalho Chehab case IVTV_YUV_MODE_AUTO: 1032*b285192aSMauro Carvalho Chehab if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { 1033*b285192aSMauro Carvalho Chehab nf->interlaced = 0; 1034*b285192aSMauro Carvalho Chehab if ((nf->tru_h < 512) || 1035*b285192aSMauro Carvalho Chehab (nf->tru_h > 576 && nf->tru_h < 1021) || 1036*b285192aSMauro Carvalho Chehab (nf->tru_w > 720 && nf->tru_h < 1021)) 1037*b285192aSMauro Carvalho Chehab nf->interlaced_y = 0; 1038*b285192aSMauro Carvalho Chehab else 1039*b285192aSMauro Carvalho Chehab nf->interlaced_y = 1; 1040*b285192aSMauro Carvalho Chehab if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) 1041*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 0; 1042*b285192aSMauro Carvalho Chehab else 1043*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 1; 1044*b285192aSMauro Carvalho Chehab } else { 1045*b285192aSMauro Carvalho Chehab nf->interlaced = 1; 1046*b285192aSMauro Carvalho Chehab nf->interlaced_y = 1; 1047*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 1; 1048*b285192aSMauro Carvalho Chehab } 1049*b285192aSMauro Carvalho Chehab break; 1050*b285192aSMauro Carvalho Chehab 1051*b285192aSMauro Carvalho Chehab case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ 1052*b285192aSMauro Carvalho Chehab default: 1053*b285192aSMauro Carvalho Chehab nf->interlaced = 1; 1054*b285192aSMauro Carvalho Chehab nf->interlaced_y = 1; 1055*b285192aSMauro Carvalho Chehab nf->interlaced_uv = 1; 1056*b285192aSMauro Carvalho Chehab break; 1057*b285192aSMauro Carvalho Chehab } 1058*b285192aSMauro Carvalho Chehab 1059*b285192aSMauro Carvalho Chehab if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { 1060*b285192aSMauro Carvalho Chehab yi->old_frame_info_args = *nf; 1061*b285192aSMauro Carvalho Chehab nf->update = 1; 1062*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); 1063*b285192aSMauro Carvalho Chehab } 1064*b285192aSMauro Carvalho Chehab 1065*b285192aSMauro Carvalho Chehab nf->update |= update; 1066*b285192aSMauro Carvalho Chehab nf->sync_field = yi->lace_sync_field; 1067*b285192aSMauro Carvalho Chehab nf->delay = nf->sync_field != of->sync_field; 1068*b285192aSMauro Carvalho Chehab } 1069*b285192aSMauro Carvalho Chehab 1070*b285192aSMauro Carvalho Chehab /* Frame is complete & ready for display */ 1071*b285192aSMauro Carvalho Chehab void ivtv_yuv_frame_complete(struct ivtv *itv) 1072*b285192aSMauro Carvalho Chehab { 1073*b285192aSMauro Carvalho Chehab atomic_set(&itv->yuv_info.next_fill_frame, 1074*b285192aSMauro Carvalho Chehab (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); 1075*b285192aSMauro Carvalho Chehab } 1076*b285192aSMauro Carvalho Chehab 1077*b285192aSMauro Carvalho Chehab static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) 1078*b285192aSMauro Carvalho Chehab { 1079*b285192aSMauro Carvalho Chehab DEFINE_WAIT(wait); 1080*b285192aSMauro Carvalho Chehab int rc = 0; 1081*b285192aSMauro Carvalho Chehab int got_sig = 0; 1082*b285192aSMauro Carvalho Chehab /* DMA the frame */ 1083*b285192aSMauro Carvalho Chehab mutex_lock(&itv->udma.lock); 1084*b285192aSMauro Carvalho Chehab 1085*b285192aSMauro Carvalho Chehab if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { 1086*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->udma.lock); 1087*b285192aSMauro Carvalho Chehab return rc; 1088*b285192aSMauro Carvalho Chehab } 1089*b285192aSMauro Carvalho Chehab 1090*b285192aSMauro Carvalho Chehab ivtv_udma_prepare(itv); 1091*b285192aSMauro Carvalho Chehab prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); 1092*b285192aSMauro Carvalho Chehab /* if no UDMA is pending and no UDMA is in progress, then the DMA 1093*b285192aSMauro Carvalho Chehab is finished */ 1094*b285192aSMauro Carvalho Chehab while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) || 1095*b285192aSMauro Carvalho Chehab test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { 1096*b285192aSMauro Carvalho Chehab /* don't interrupt if the DMA is in progress but break off 1097*b285192aSMauro Carvalho Chehab a still pending DMA. */ 1098*b285192aSMauro Carvalho Chehab got_sig = signal_pending(current); 1099*b285192aSMauro Carvalho Chehab if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) 1100*b285192aSMauro Carvalho Chehab break; 1101*b285192aSMauro Carvalho Chehab got_sig = 0; 1102*b285192aSMauro Carvalho Chehab schedule(); 1103*b285192aSMauro Carvalho Chehab } 1104*b285192aSMauro Carvalho Chehab finish_wait(&itv->dma_waitq, &wait); 1105*b285192aSMauro Carvalho Chehab 1106*b285192aSMauro Carvalho Chehab /* Unmap Last DMA Xfer */ 1107*b285192aSMauro Carvalho Chehab ivtv_udma_unmap(itv); 1108*b285192aSMauro Carvalho Chehab 1109*b285192aSMauro Carvalho Chehab if (got_sig) { 1110*b285192aSMauro Carvalho Chehab IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); 1111*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->udma.lock); 1112*b285192aSMauro Carvalho Chehab return -EINTR; 1113*b285192aSMauro Carvalho Chehab } 1114*b285192aSMauro Carvalho Chehab 1115*b285192aSMauro Carvalho Chehab ivtv_yuv_frame_complete(itv); 1116*b285192aSMauro Carvalho Chehab 1117*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->udma.lock); 1118*b285192aSMauro Carvalho Chehab return rc; 1119*b285192aSMauro Carvalho Chehab } 1120*b285192aSMauro Carvalho Chehab 1121*b285192aSMauro Carvalho Chehab /* Setup frame according to V4L2 parameters */ 1122*b285192aSMauro Carvalho Chehab void ivtv_yuv_setup_stream_frame(struct ivtv *itv) 1123*b285192aSMauro Carvalho Chehab { 1124*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 1125*b285192aSMauro Carvalho Chehab struct ivtv_dma_frame dma_args; 1126*b285192aSMauro Carvalho Chehab 1127*b285192aSMauro Carvalho Chehab ivtv_yuv_next_free(itv); 1128*b285192aSMauro Carvalho Chehab 1129*b285192aSMauro Carvalho Chehab /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ 1130*b285192aSMauro Carvalho Chehab dma_args.y_source = NULL; 1131*b285192aSMauro Carvalho Chehab dma_args.uv_source = NULL; 1132*b285192aSMauro Carvalho Chehab dma_args.src.left = 0; 1133*b285192aSMauro Carvalho Chehab dma_args.src.top = 0; 1134*b285192aSMauro Carvalho Chehab dma_args.src.width = yi->v4l2_src_w; 1135*b285192aSMauro Carvalho Chehab dma_args.src.height = yi->v4l2_src_h; 1136*b285192aSMauro Carvalho Chehab dma_args.dst = yi->main_rect; 1137*b285192aSMauro Carvalho Chehab dma_args.src_width = yi->v4l2_src_w; 1138*b285192aSMauro Carvalho Chehab dma_args.src_height = yi->v4l2_src_h; 1139*b285192aSMauro Carvalho Chehab 1140*b285192aSMauro Carvalho Chehab /* ... and use the same setup routine as ivtv_yuv_prep_frame */ 1141*b285192aSMauro Carvalho Chehab ivtv_yuv_setup_frame(itv, &dma_args); 1142*b285192aSMauro Carvalho Chehab 1143*b285192aSMauro Carvalho Chehab if (!itv->dma_data_req_offset) 1144*b285192aSMauro Carvalho Chehab itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; 1145*b285192aSMauro Carvalho Chehab } 1146*b285192aSMauro Carvalho Chehab 1147*b285192aSMauro Carvalho Chehab /* Attempt to dma a frame from a user buffer */ 1148*b285192aSMauro Carvalho Chehab int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src) 1149*b285192aSMauro Carvalho Chehab { 1150*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 1151*b285192aSMauro Carvalho Chehab struct ivtv_dma_frame dma_args; 1152*b285192aSMauro Carvalho Chehab int res; 1153*b285192aSMauro Carvalho Chehab 1154*b285192aSMauro Carvalho Chehab ivtv_yuv_setup_stream_frame(itv); 1155*b285192aSMauro Carvalho Chehab 1156*b285192aSMauro Carvalho Chehab /* We only need to supply source addresses for this */ 1157*b285192aSMauro Carvalho Chehab dma_args.y_source = src; 1158*b285192aSMauro Carvalho Chehab dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); 1159*b285192aSMauro Carvalho Chehab /* Wait for frame DMA. Note that serialize_lock is locked, 1160*b285192aSMauro Carvalho Chehab so to allow other processes to access the driver while 1161*b285192aSMauro Carvalho Chehab we are waiting unlock first and later lock again. */ 1162*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->serialize_lock); 1163*b285192aSMauro Carvalho Chehab res = ivtv_yuv_udma_frame(itv, &dma_args); 1164*b285192aSMauro Carvalho Chehab mutex_lock(&itv->serialize_lock); 1165*b285192aSMauro Carvalho Chehab return res; 1166*b285192aSMauro Carvalho Chehab } 1167*b285192aSMauro Carvalho Chehab 1168*b285192aSMauro Carvalho Chehab /* IVTV_IOC_DMA_FRAME ioctl handler */ 1169*b285192aSMauro Carvalho Chehab int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) 1170*b285192aSMauro Carvalho Chehab { 1171*b285192aSMauro Carvalho Chehab int res; 1172*b285192aSMauro Carvalho Chehab 1173*b285192aSMauro Carvalho Chehab /* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ 1174*b285192aSMauro Carvalho Chehab ivtv_yuv_next_free(itv); 1175*b285192aSMauro Carvalho Chehab ivtv_yuv_setup_frame(itv, args); 1176*b285192aSMauro Carvalho Chehab /* Wait for frame DMA. Note that serialize_lock is locked, 1177*b285192aSMauro Carvalho Chehab so to allow other processes to access the driver while 1178*b285192aSMauro Carvalho Chehab we are waiting unlock first and later lock again. */ 1179*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->serialize_lock); 1180*b285192aSMauro Carvalho Chehab res = ivtv_yuv_udma_frame(itv, args); 1181*b285192aSMauro Carvalho Chehab mutex_lock(&itv->serialize_lock); 1182*b285192aSMauro Carvalho Chehab return res; 1183*b285192aSMauro Carvalho Chehab } 1184*b285192aSMauro Carvalho Chehab 1185*b285192aSMauro Carvalho Chehab void ivtv_yuv_close(struct ivtv *itv) 1186*b285192aSMauro Carvalho Chehab { 1187*b285192aSMauro Carvalho Chehab struct yuv_playback_info *yi = &itv->yuv_info; 1188*b285192aSMauro Carvalho Chehab int h_filter, v_filter_1, v_filter_2; 1189*b285192aSMauro Carvalho Chehab 1190*b285192aSMauro Carvalho Chehab IVTV_DEBUG_YUV("ivtv_yuv_close\n"); 1191*b285192aSMauro Carvalho Chehab mutex_unlock(&itv->serialize_lock); 1192*b285192aSMauro Carvalho Chehab ivtv_waitq(&itv->vsync_waitq); 1193*b285192aSMauro Carvalho Chehab mutex_lock(&itv->serialize_lock); 1194*b285192aSMauro Carvalho Chehab 1195*b285192aSMauro Carvalho Chehab yi->running = 0; 1196*b285192aSMauro Carvalho Chehab atomic_set(&yi->next_dma_frame, -1); 1197*b285192aSMauro Carvalho Chehab atomic_set(&yi->next_fill_frame, 0); 1198*b285192aSMauro Carvalho Chehab 1199*b285192aSMauro Carvalho Chehab /* Reset registers we have changed so mpeg playback works */ 1200*b285192aSMauro Carvalho Chehab 1201*b285192aSMauro Carvalho Chehab /* If we fully restore this register, the display may remain active. 1202*b285192aSMauro Carvalho Chehab Restore, but set one bit to blank the video. Firmware will always 1203*b285192aSMauro Carvalho Chehab clear this bit when needed, so not a problem. */ 1204*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2898 | 0x01000000, 0x2898); 1205*b285192aSMauro Carvalho Chehab 1206*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2834, 0x02834); 1207*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2838, 0x02838); 1208*b285192aSMauro Carvalho Chehab write_reg(yi->reg_283c, 0x0283c); 1209*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2840, 0x02840); 1210*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2844, 0x02844); 1211*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2848, 0x02848); 1212*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2854, 0x02854); 1213*b285192aSMauro Carvalho Chehab write_reg(yi->reg_285c, 0x0285c); 1214*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2864, 0x02864); 1215*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2870, 0x02870); 1216*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2874, 0x02874); 1217*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2890, 0x02890); 1218*b285192aSMauro Carvalho Chehab write_reg(yi->reg_289c, 0x0289c); 1219*b285192aSMauro Carvalho Chehab 1220*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2918, 0x02918); 1221*b285192aSMauro Carvalho Chehab write_reg(yi->reg_291c, 0x0291c); 1222*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2920, 0x02920); 1223*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2924, 0x02924); 1224*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2928, 0x02928); 1225*b285192aSMauro Carvalho Chehab write_reg(yi->reg_292c, 0x0292c); 1226*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2930, 0x02930); 1227*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2934, 0x02934); 1228*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2938, 0x02938); 1229*b285192aSMauro Carvalho Chehab write_reg(yi->reg_293c, 0x0293c); 1230*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2940, 0x02940); 1231*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2944, 0x02944); 1232*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2948, 0x02948); 1233*b285192aSMauro Carvalho Chehab write_reg(yi->reg_294c, 0x0294c); 1234*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2950, 0x02950); 1235*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2954, 0x02954); 1236*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2958, 0x02958); 1237*b285192aSMauro Carvalho Chehab write_reg(yi->reg_295c, 0x0295c); 1238*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2960, 0x02960); 1239*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2964, 0x02964); 1240*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2968, 0x02968); 1241*b285192aSMauro Carvalho Chehab write_reg(yi->reg_296c, 0x0296c); 1242*b285192aSMauro Carvalho Chehab write_reg(yi->reg_2970, 0x02970); 1243*b285192aSMauro Carvalho Chehab 1244*b285192aSMauro Carvalho Chehab /* Prepare to restore filters */ 1245*b285192aSMauro Carvalho Chehab 1246*b285192aSMauro Carvalho Chehab /* First the horizontal filter */ 1247*b285192aSMauro Carvalho Chehab if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { 1248*b285192aSMauro Carvalho Chehab /* An exact size match uses filter 0 */ 1249*b285192aSMauro Carvalho Chehab h_filter = 0; 1250*b285192aSMauro Carvalho Chehab } else { 1251*b285192aSMauro Carvalho Chehab /* Figure out which filter to use */ 1252*b285192aSMauro Carvalho Chehab h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; 1253*b285192aSMauro Carvalho Chehab h_filter = (h_filter >> 1) + (h_filter & 1); 1254*b285192aSMauro Carvalho Chehab /* Only an exact size match can use filter 0. */ 1255*b285192aSMauro Carvalho Chehab h_filter += !h_filter; 1256*b285192aSMauro Carvalho Chehab } 1257*b285192aSMauro Carvalho Chehab 1258*b285192aSMauro Carvalho Chehab /* Now the vertical filter */ 1259*b285192aSMauro Carvalho Chehab if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { 1260*b285192aSMauro Carvalho Chehab /* An exact size match uses filter 0/1 */ 1261*b285192aSMauro Carvalho Chehab v_filter_1 = 0; 1262*b285192aSMauro Carvalho Chehab v_filter_2 = 1; 1263*b285192aSMauro Carvalho Chehab } else { 1264*b285192aSMauro Carvalho Chehab /* Figure out which filter to use */ 1265*b285192aSMauro Carvalho Chehab v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; 1266*b285192aSMauro Carvalho Chehab v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); 1267*b285192aSMauro Carvalho Chehab /* Only an exact size match can use filter 0 */ 1268*b285192aSMauro Carvalho Chehab v_filter_1 += !v_filter_1; 1269*b285192aSMauro Carvalho Chehab v_filter_2 = v_filter_1; 1270*b285192aSMauro Carvalho Chehab } 1271*b285192aSMauro Carvalho Chehab 1272*b285192aSMauro Carvalho Chehab /* Now restore the filters */ 1273*b285192aSMauro Carvalho Chehab ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); 1274*b285192aSMauro Carvalho Chehab 1275*b285192aSMauro Carvalho Chehab /* and clear a few registers */ 1276*b285192aSMauro Carvalho Chehab write_reg(0, 0x02814); 1277*b285192aSMauro Carvalho Chehab write_reg(0, 0x0282c); 1278*b285192aSMauro Carvalho Chehab write_reg(0, 0x02904); 1279*b285192aSMauro Carvalho Chehab write_reg(0, 0x02910); 1280*b285192aSMauro Carvalho Chehab 1281*b285192aSMauro Carvalho Chehab /* Release the blanking buffer */ 1282*b285192aSMauro Carvalho Chehab if (yi->blanking_ptr) { 1283*b285192aSMauro Carvalho Chehab kfree(yi->blanking_ptr); 1284*b285192aSMauro Carvalho Chehab yi->blanking_ptr = NULL; 1285*b285192aSMauro Carvalho Chehab pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); 1286*b285192aSMauro Carvalho Chehab } 1287*b285192aSMauro Carvalho Chehab 1288*b285192aSMauro Carvalho Chehab /* Invalidate the old dimension information */ 1289*b285192aSMauro Carvalho Chehab yi->old_frame_info.src_w = 0; 1290*b285192aSMauro Carvalho Chehab yi->old_frame_info.src_h = 0; 1291*b285192aSMauro Carvalho Chehab yi->old_frame_info_args.src_w = 0; 1292*b285192aSMauro Carvalho Chehab yi->old_frame_info_args.src_h = 0; 1293*b285192aSMauro Carvalho Chehab 1294*b285192aSMauro Carvalho Chehab /* All done. */ 1295*b285192aSMauro Carvalho Chehab clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); 1296*b285192aSMauro Carvalho Chehab } 1297