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