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