V4L/DVB (6346): ivtvfb: YUV output size fix when ivtvfb is not loaded
[linux-2.6/linux-2.6-openrd.git] / drivers / media / video / ivtv / ivtv-yuv.c
blob9091c4837bbca23bcb0f65ad0135537406b68bea
1 /*
2 yuv support
4 Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk>
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.
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.
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
21 #include "ivtv-driver.h"
22 #include "ivtv-udma.h"
23 #include "ivtv-yuv.h"
25 const u32 yuv_offset[4] = {
26 IVTV_YUV_BUFFER_OFFSET,
27 IVTV_YUV_BUFFER_OFFSET_1,
28 IVTV_YUV_BUFFER_OFFSET_2,
29 IVTV_YUV_BUFFER_OFFSET_3
32 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
33 struct ivtv_dma_frame *args)
35 struct ivtv_dma_page_info y_dma;
36 struct ivtv_dma_page_info uv_dma;
38 int i;
39 int y_pages, uv_pages;
41 unsigned long y_buffer_offset, uv_buffer_offset;
42 int y_decode_height, uv_decode_height, y_size;
43 int frame = atomic_read(&itv->yuv_info.next_fill_frame);
45 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
46 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
48 y_decode_height = uv_decode_height = args->src.height + args->src.top;
50 if (y_decode_height < 512-16)
51 y_buffer_offset += 720 * 16;
53 if (y_decode_height & 15)
54 y_decode_height = (y_decode_height + 16) & ~15;
56 if (uv_decode_height & 31)
57 uv_decode_height = (uv_decode_height + 32) & ~31;
59 y_size = 720 * y_decode_height;
61 /* Still in USE */
62 if (dma->SG_length || dma->page_count) {
63 IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
64 dma->SG_length, dma->page_count);
65 return -EBUSY;
68 ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
69 ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
71 /* Get user pages for DMA Xfer */
72 down_read(&current->mm->mmap_sem);
73 y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
74 uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
75 up_read(&current->mm->mmap_sem);
77 dma->page_count = y_dma.page_count + uv_dma.page_count;
79 if (y_pages + uv_pages != dma->page_count) {
80 IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
81 y_pages + uv_pages, dma->page_count);
83 for (i = 0; i < dma->page_count; i++) {
84 put_page(dma->map[i]);
86 dma->page_count = 0;
87 return -EINVAL;
90 /* Fill & map SG List */
91 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
92 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
93 for (i = 0; i < dma->page_count; i++) {
94 put_page(dma->map[i]);
96 dma->page_count = 0;
97 return -ENOMEM;
99 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
101 /* Fill SG Array with new values */
102 ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
104 /* If we've offset the y plane, ensure top area is blanked */
105 if (args->src.height + args->src.top < 512-16) {
106 if (itv->yuv_info.blanking_dmaptr) {
107 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
108 dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
109 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
110 dma->SG_length++;
114 /* Tag SG Array with Interrupt Bit */
115 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
117 ivtv_udma_sync_for_device(itv);
118 return 0;
121 /* We rely on a table held in the firmware - Quick check. */
122 int ivtv_yuv_filter_check(struct ivtv *itv)
124 int i, offset_y, offset_uv;
126 for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
127 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
128 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
129 IVTV_WARN ("YUV filter table not found in firmware.\n");
130 return -1;
133 return 0;
136 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
138 int filter_index, filter_line;
140 /* If any filter is -1, then don't update it */
141 if (h_filter > -1) {
142 if (h_filter > 4) h_filter = 4;
143 filter_index = h_filter * 384;
144 filter_line = 0;
145 while (filter_line < 16) {
146 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
147 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
148 filter_index += 4;
149 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
150 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
151 filter_index += 4;
152 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
153 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
154 filter_index += 4;
155 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
156 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
157 filter_index += 4;
158 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
159 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
160 filter_index += 8;
161 write_reg(0, 0x02818);
162 write_reg(0, 0x02830);
163 filter_line ++;
165 IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
168 if (v_filter_1 > -1) {
169 if (v_filter_1 > 4) v_filter_1 = 4;
170 filter_index = v_filter_1 * 192;
171 filter_line = 0;
172 while (filter_line < 16) {
173 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
174 filter_index += 4;
175 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
176 filter_index += 8;
177 write_reg(0, 0x02908);
178 filter_line ++;
180 IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
183 if (v_filter_2 > -1) {
184 if (v_filter_2 > 4) v_filter_2 = 4;
185 filter_index = v_filter_2 * 192;
186 filter_line = 0;
187 while (filter_line < 16) {
188 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
189 filter_index += 4;
190 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
191 filter_index += 8;
192 write_reg(0, 0x02914);
193 filter_line ++;
195 IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
199 static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
201 u32 reg_2834, reg_2838, reg_283c;
202 u32 reg_2844, reg_2854, reg_285c;
203 u32 reg_2864, reg_2874, reg_2890;
204 u32 reg_2870, reg_2870_base, reg_2870_offset;
205 int x_cutoff;
206 int h_filter;
207 u32 master_width;
209 IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
210 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
212 /* How wide is the src image */
213 x_cutoff = window->src_w + window->src_x;
215 /* Set the display width */
216 reg_2834 = window->dst_w;
217 reg_2838 = reg_2834;
219 /* Set the display position */
220 reg_2890 = window->dst_x;
222 /* Index into the image horizontally */
223 reg_2870 = 0;
225 /* 2870 is normally fudged to align video coords with osd coords.
226 If running full screen, it causes an unwanted left shift
227 Remove the fudge if we almost fill the screen.
228 Gradually adjust the offset to avoid the video 'snapping'
229 left/right if it gets dragged through this region.
230 Only do this if osd is full width. */
231 if (window->vis_w == 720) {
232 if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
233 reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
235 else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
236 reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
239 if (window->dst_w >= window->src_w)
240 reg_2870 = reg_2870 << 16 | reg_2870;
241 else
242 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
245 if (window->dst_w < window->src_w)
246 reg_2870 = 0x000d000e - reg_2870;
247 else
248 reg_2870 = 0x0012000e - reg_2870;
250 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
251 reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
253 if (window->dst_w >= window->src_w) {
254 x_cutoff &= ~1;
255 master_width = (window->src_w * 0x00200000) / (window->dst_w);
256 if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
257 reg_2834 = (reg_2834 << 16) | x_cutoff;
258 reg_2838 = (reg_2838 << 16) | x_cutoff;
259 reg_283c = master_width >> 2;
260 reg_2844 = master_width >> 2;
261 reg_2854 = master_width;
262 reg_285c = master_width >> 1;
263 reg_2864 = master_width >> 1;
265 /* We also need to factor in the scaling
266 (src_w - dst_w) / (src_w / 4) */
267 if (window->dst_w > window->src_w)
268 reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
269 else
270 reg_2870_base = 0;
272 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
273 reg_2874 = 0;
275 else if (window->dst_w < window->src_w / 2) {
276 master_width = (window->src_w * 0x00080000) / window->dst_w;
277 if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
278 reg_2834 = (reg_2834 << 16) | x_cutoff;
279 reg_2838 = (reg_2838 << 16) | x_cutoff;
280 reg_283c = master_width >> 2;
281 reg_2844 = master_width >> 1;
282 reg_2854 = master_width;
283 reg_285c = master_width >> 1;
284 reg_2864 = master_width >> 1;
285 reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
286 reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
287 reg_2874 = 0x00000012;
289 else {
290 master_width = (window->src_w * 0x00100000) / window->dst_w;
291 if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
292 reg_2834 = (reg_2834 << 16) | x_cutoff;
293 reg_2838 = (reg_2838 << 16) | x_cutoff;
294 reg_283c = master_width >> 2;
295 reg_2844 = master_width >> 1;
296 reg_2854 = master_width;
297 reg_285c = master_width >> 1;
298 reg_2864 = master_width >> 1;
299 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
300 reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
301 reg_2874 = 0x00000001;
304 /* Select the horizontal filter */
305 if (window->src_w == window->dst_w) {
306 /* An exact size match uses filter 0 */
307 h_filter = 0;
309 else {
310 /* Figure out which filter to use */
311 h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
312 h_filter = (h_filter >> 1) + (h_filter & 1);
313 /* Only an exact size match can use filter 0 */
314 if (h_filter == 0) h_filter = 1;
317 write_reg(reg_2834, 0x02834);
318 write_reg(reg_2838, 0x02838);
319 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);
321 write_reg(reg_283c, 0x0283c);
322 write_reg(reg_2844, 0x02844);
324 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);
326 write_reg(0x00080514, 0x02840);
327 write_reg(0x00100514, 0x02848);
328 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
330 write_reg(reg_2854, 0x02854);
331 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
333 write_reg(reg_285c, 0x0285c);
334 write_reg(reg_2864, 0x02864);
335 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);
337 write_reg(reg_2874, 0x02874);
338 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
340 write_reg(reg_2870, 0x02870);
341 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
343 write_reg( reg_2890,0x02890);
344 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
346 /* Only update the filter if we really need to */
347 if (h_filter != itv->yuv_info.h_filter) {
348 ivtv_yuv_filter (itv,h_filter,-1,-1);
349 itv->yuv_info.h_filter = h_filter;
353 static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
355 u32 master_height;
356 u32 reg_2918, reg_291c, reg_2920, reg_2928;
357 u32 reg_2930, reg_2934, reg_293c;
358 u32 reg_2940, reg_2944, reg_294c;
359 u32 reg_2950, reg_2954, reg_2958, reg_295c;
360 u32 reg_2960, reg_2964, reg_2968, reg_296c;
361 u32 reg_289c;
362 u32 src_y_major_y, src_y_minor_y;
363 u32 src_y_major_uv, src_y_minor_uv;
364 u32 reg_2964_base, reg_2968_base;
365 int v_filter_1, v_filter_2;
367 IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
368 window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
370 /* What scaling mode is being used... */
371 if (window->interlaced_y) {
372 IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
374 else {
375 IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
378 if (window->interlaced_uv) {
379 IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
381 else {
382 IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
385 /* What is the source video being treated as... */
386 if (itv->yuv_info.frame_interlaced) {
387 IVTV_DEBUG_WARN("Source video: Interlaced\n");
389 else {
390 IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
393 /* We offset into the image using two different index methods, so split
394 the y source coord into two parts. */
395 if (window->src_y < 8) {
396 src_y_minor_uv = window->src_y;
397 src_y_major_uv = 0;
399 else {
400 src_y_minor_uv = 8;
401 src_y_major_uv = window->src_y - 8;
404 src_y_minor_y = src_y_minor_uv;
405 src_y_major_y = src_y_major_uv;
407 if (window->offset_y) src_y_minor_y += 16;
409 if (window->interlaced_y)
410 reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
411 else
412 reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
414 if (window->interlaced_uv)
415 reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
416 else
417 reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
419 reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
420 reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
422 if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
423 master_height = (window->src_h * 0x00400000) / window->dst_h;
424 if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
425 reg_2920 = master_height >> 2;
426 reg_2928 = master_height >> 3;
427 reg_2930 = master_height;
428 reg_2940 = master_height >> 1;
429 reg_2964_base >>= 3;
430 reg_2968_base >>= 3;
431 reg_296c = 0x00000000;
433 else if (window->dst_h >= window->src_h) {
434 master_height = (window->src_h * 0x00400000) / window->dst_h;
435 master_height = (master_height >> 1) + (master_height & 1);
436 reg_2920 = master_height >> 2;
437 reg_2928 = master_height >> 2;
438 reg_2930 = master_height;
439 reg_2940 = master_height >> 1;
440 reg_296c = 0x00000000;
441 if (window->interlaced_y) {
442 reg_2964_base >>= 3;
444 else {
445 reg_296c ++;
446 reg_2964_base >>= 2;
448 if (window->interlaced_uv) reg_2928 >>= 1;
449 reg_2968_base >>= 3;
451 else if (window->dst_h >= window->src_h / 2) {
452 master_height = (window->src_h * 0x00200000) / window->dst_h;
453 master_height = (master_height >> 1) + (master_height & 1);
454 reg_2920 = master_height >> 2;
455 reg_2928 = master_height >> 2;
456 reg_2930 = master_height;
457 reg_2940 = master_height;
458 reg_296c = 0x00000101;
459 if (window->interlaced_y) {
460 reg_2964_base >>= 2;
462 else {
463 reg_296c ++;
464 reg_2964_base >>= 1;
466 if (window->interlaced_uv) reg_2928 >>= 1;
467 reg_2968_base >>= 2;
469 else {
470 master_height = (window->src_h * 0x00100000) / window->dst_h;
471 master_height = (master_height >> 1) + (master_height & 1);
472 reg_2920 = master_height >> 2;
473 reg_2928 = master_height >> 2;
474 reg_2930 = master_height;
475 reg_2940 = master_height;
476 reg_2964_base >>= 1;
477 reg_2968_base >>= 2;
478 reg_296c = 0x00000102;
481 /* FIXME These registers change depending on scaled / unscaled output
482 We really need to work out what they should be */
483 if (window->src_h == window->dst_h){
484 reg_2934 = 0x00020000;
485 reg_293c = 0x00100000;
486 reg_2944 = 0x00040000;
487 reg_294c = 0x000b0000;
489 else {
490 reg_2934 = 0x00000FF0;
491 reg_293c = 0x00000FF0;
492 reg_2944 = 0x00000FF0;
493 reg_294c = 0x00000FF0;
496 /* The first line to be displayed */
497 reg_2950 = 0x00010000 + src_y_major_y;
498 if (window->interlaced_y) reg_2950 += 0x00010000;
499 reg_2954 = reg_2950 + 1;
501 reg_2958 = 0x00010000 + (src_y_major_y >> 1);
502 if (window->interlaced_uv) reg_2958 += 0x00010000;
503 reg_295c = reg_2958 + 1;
505 if (itv->yuv_info.decode_height == 480)
506 reg_289c = 0x011e0017;
507 else
508 reg_289c = 0x01500017;
510 if (window->dst_y < 0)
511 reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
512 else
513 reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
515 /* How much of the source to decode.
516 Take into account the source offset */
517 reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
518 ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
520 /* Calculate correct value for register 2964 */
521 if (window->src_h == window->dst_h)
522 reg_2964 = 1;
523 else {
524 reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
525 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
527 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
528 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
530 /* Okay, we've wasted time working out the correct value,
531 but if we use it, it fouls the the window alignment.
532 Fudge it to what we want... */
533 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
534 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
536 /* Deviate further from what it should be. I find the flicker headache
537 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
538 colours foul. */
539 if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
540 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
542 if (!window->interlaced_y) reg_2964 -= 0x00010001;
543 if (!window->interlaced_uv) reg_2968 -= 0x00010001;
545 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
546 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
548 /* Select the vertical filter */
549 if (window->src_h == window->dst_h) {
550 /* An exact size match uses filter 0/1 */
551 v_filter_1 = 0;
552 v_filter_2 = 1;
554 else {
555 /* Figure out which filter to use */
556 v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
557 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
558 /* Only an exact size match can use filter 0 */
559 if (v_filter_1 == 0) v_filter_1 = 1;
560 v_filter_2 = v_filter_1;
563 write_reg(reg_2934, 0x02934);
564 write_reg(reg_293c, 0x0293c);
565 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);
566 write_reg(reg_2944, 0x02944);
567 write_reg(reg_294c, 0x0294c);
568 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);
570 /* Ensure 2970 is 0 (does it ever change ?) */
571 /* write_reg(0,0x02970); */
572 /* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
574 write_reg(reg_2930, 0x02938);
575 write_reg(reg_2930, 0x02930);
576 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);
578 write_reg(reg_2928, 0x02928);
579 write_reg(reg_2928+0x514, 0x0292C);
580 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);
582 write_reg(reg_2920, 0x02920);
583 write_reg(reg_2920+0x514, 0x02924);
584 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);
586 write_reg (reg_2918,0x02918);
587 write_reg (reg_291c,0x0291C);
588 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);
590 write_reg(reg_296c, 0x0296c);
591 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
593 write_reg(reg_2940, 0x02948);
594 write_reg(reg_2940, 0x02940);
595 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);
597 write_reg(reg_2950, 0x02950);
598 write_reg(reg_2954, 0x02954);
599 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);
601 write_reg(reg_2958, 0x02958);
602 write_reg(reg_295c, 0x0295C);
603 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);
605 write_reg(reg_2960, 0x02960);
606 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
608 write_reg(reg_2964, 0x02964);
609 write_reg(reg_2968, 0x02968);
610 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);
612 write_reg( reg_289c,0x0289c);
613 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
615 /* Only update filter 1 if we really need to */
616 if (v_filter_1 != itv->yuv_info.v_filter_1) {
617 ivtv_yuv_filter (itv,-1,v_filter_1,-1);
618 itv->yuv_info.v_filter_1 = v_filter_1;
621 /* Only update filter 2 if we really need to */
622 if (v_filter_2 != itv->yuv_info.v_filter_2) {
623 ivtv_yuv_filter (itv,-1,-1,v_filter_2);
624 itv->yuv_info.v_filter_2 = v_filter_2;
629 /* Modify the supplied coordinate information to fit the visible osd area */
630 static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
632 int osd_crop, lace_threshold;
633 u32 osd_scale;
634 u32 yuv_update = 0;
636 lace_threshold = itv->yuv_info.lace_threshold;
637 if (lace_threshold < 0)
638 lace_threshold = itv->yuv_info.decode_height - 1;
640 /* Work out the lace settings */
641 switch (itv->yuv_info.lace_mode) {
642 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
643 itv->yuv_info.frame_interlaced = 0;
644 if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
645 window->interlaced_y = 0;
646 else
647 window->interlaced_y = 1;
649 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
650 window->interlaced_uv = 0;
651 else
652 window->interlaced_uv = 1;
653 break;
655 case IVTV_YUV_MODE_AUTO:
656 if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
657 itv->yuv_info.frame_interlaced = 0;
658 if ((window->tru_h < 512) ||
659 (window->tru_h > 576 && window->tru_h < 1021) ||
660 (window->tru_w > 720 && window->tru_h < 1021))
661 window->interlaced_y = 0;
662 else
663 window->interlaced_y = 1;
665 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
666 window->interlaced_uv = 0;
667 else
668 window->interlaced_uv = 1;
670 else {
671 itv->yuv_info.frame_interlaced = 1;
672 window->interlaced_y = 1;
673 window->interlaced_uv = 1;
675 break;
677 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
678 default:
679 itv->yuv_info.frame_interlaced = 1;
680 window->interlaced_y = 1;
681 window->interlaced_uv = 1;
682 break;
685 /* Sorry, but no negative coords for src */
686 if (window->src_x < 0) window->src_x = 0;
687 if (window->src_y < 0) window->src_y = 0;
689 /* Can only reduce width down to 1/4 original size */
690 if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
691 window->src_x += osd_crop / 2;
692 window->src_w = (window->src_w - osd_crop) & ~3;
693 window->dst_w = window->src_w / 4;
694 window->dst_w += window->dst_w & 1;
697 /* Can only reduce height down to 1/4 original size */
698 if (window->src_h / window->dst_h >= 2) {
699 /* Overflow may be because we're running progressive, so force mode switch */
700 window->interlaced_y = 1;
701 /* Make sure we're still within limits for interlace */
702 if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
703 /* If we reach here we'll have to force the height. */
704 window->src_y += osd_crop / 2;
705 window->src_h = (window->src_h - osd_crop) & ~3;
706 window->dst_h = window->src_h / 4;
707 window->dst_h += window->dst_h & 1;
711 /* If there's nothing to safe to display, we may as well stop now */
712 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
713 return IVTV_YUV_UPDATE_INVALID;
716 /* Ensure video remains inside OSD area */
717 osd_scale = (window->src_h << 16) / window->dst_h;
719 if ((osd_crop = window->pan_y - window->dst_y) > 0) {
720 /* Falls off the upper edge - crop */
721 window->src_y += (osd_scale * osd_crop) >> 16;
722 window->src_h -= (osd_scale * osd_crop) >> 16;
723 window->dst_h -= osd_crop;
724 window->dst_y = 0;
726 else {
727 window->dst_y -= window->pan_y;
730 if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
731 /* Falls off the lower edge - crop */
732 window->dst_h -= osd_crop;
733 window->src_h -= (osd_scale * osd_crop) >> 16;
736 osd_scale = (window->src_w << 16) / window->dst_w;
738 if ((osd_crop = window->pan_x - window->dst_x) > 0) {
739 /* Fall off the left edge - crop */
740 window->src_x += (osd_scale * osd_crop) >> 16;
741 window->src_w -= (osd_scale * osd_crop) >> 16;
742 window->dst_w -= osd_crop;
743 window->dst_x = 0;
745 else {
746 window->dst_x -= window->pan_x;
749 if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
750 /* Falls off the right edge - crop */
751 window->dst_w -= osd_crop;
752 window->src_w -= (osd_scale * osd_crop) >> 16;
755 /* The OSD can be moved. Track to it */
756 window->dst_x += itv->yuv_info.osd_x_offset;
757 window->dst_y += itv->yuv_info.osd_y_offset;
759 /* Width & height for both src & dst must be even.
760 Same for coordinates. */
761 window->dst_w &= ~1;
762 window->dst_x &= ~1;
764 window->src_w += window->src_x & 1;
765 window->src_x &= ~1;
767 window->src_w &= ~1;
768 window->dst_w &= ~1;
770 window->dst_h &= ~1;
771 window->dst_y &= ~1;
773 window->src_h += window->src_y & 1;
774 window->src_y &= ~1;
776 window->src_h &= ~1;
777 window->dst_h &= ~1;
779 /* Due to rounding, we may have reduced the output size to <1/4 of the source
780 Check again, but this time just resize. Don't change source coordinates */
781 if (window->dst_w < window->src_w / 4) {
782 window->src_w &= ~3;
783 window->dst_w = window->src_w / 4;
784 window->dst_w += window->dst_w & 1;
786 if (window->dst_h < window->src_h / 4) {
787 window->src_h &= ~3;
788 window->dst_h = window->src_h / 4;
789 window->dst_h += window->dst_h & 1;
792 /* Check again. If there's nothing to safe to display, stop now */
793 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
794 return IVTV_YUV_UPDATE_INVALID;
797 /* Both x offset & width are linked, so they have to be done together */
798 if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
799 (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
800 (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
801 (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
802 (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
803 (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
804 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
807 if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
808 (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
809 (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
810 (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
811 (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
812 (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
813 (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
814 (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
815 (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
816 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
819 return yuv_update;
822 /* Update the scaling register to the requested value */
823 void ivtv_yuv_work_handler (struct ivtv *itv)
825 struct yuv_frame_info window;
826 u32 yuv_update;
828 int frame = itv->yuv_info.update_frame;
830 /* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
831 memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
833 /* Update the osd pan info */
834 window.pan_x = itv->yuv_info.osd_x_pan;
835 window.pan_y = itv->yuv_info.osd_y_pan;
836 window.vis_w = itv->yuv_info.osd_vis_w;
837 window.vis_h = itv->yuv_info.osd_vis_h;
839 /* Calculate the display window coordinates. Exit if nothing left */
840 if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
841 return;
843 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
844 write_reg(0x01008080, 0x2898);
845 } else if (yuv_update) {
846 write_reg(0x00108080, 0x2898);
848 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
849 ivtv_yuv_handle_horizontal(itv, &window);
851 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
852 ivtv_yuv_handle_vertical(itv, &window);
855 memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
858 static void ivtv_yuv_init (struct ivtv *itv)
860 struct yuv_playback_info *yi = &itv->yuv_info;
862 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
864 /* Take a snapshot of the current register settings */
865 yi->reg_2834 = read_reg(0x02834);
866 yi->reg_2838 = read_reg(0x02838);
867 yi->reg_283c = read_reg(0x0283c);
868 yi->reg_2840 = read_reg(0x02840);
869 yi->reg_2844 = read_reg(0x02844);
870 yi->reg_2848 = read_reg(0x02848);
871 yi->reg_2854 = read_reg(0x02854);
872 yi->reg_285c = read_reg(0x0285c);
873 yi->reg_2864 = read_reg(0x02864);
874 yi->reg_2870 = read_reg(0x02870);
875 yi->reg_2874 = read_reg(0x02874);
876 yi->reg_2898 = read_reg(0x02898);
877 yi->reg_2890 = read_reg(0x02890);
879 yi->reg_289c = read_reg(0x0289c);
880 yi->reg_2918 = read_reg(0x02918);
881 yi->reg_291c = read_reg(0x0291c);
882 yi->reg_2920 = read_reg(0x02920);
883 yi->reg_2924 = read_reg(0x02924);
884 yi->reg_2928 = read_reg(0x02928);
885 yi->reg_292c = read_reg(0x0292c);
886 yi->reg_2930 = read_reg(0x02930);
887 yi->reg_2934 = read_reg(0x02934);
888 yi->reg_2938 = read_reg(0x02938);
889 yi->reg_293c = read_reg(0x0293c);
890 yi->reg_2940 = read_reg(0x02940);
891 yi->reg_2944 = read_reg(0x02944);
892 yi->reg_2948 = read_reg(0x02948);
893 yi->reg_294c = read_reg(0x0294c);
894 yi->reg_2950 = read_reg(0x02950);
895 yi->reg_2954 = read_reg(0x02954);
896 yi->reg_2958 = read_reg(0x02958);
897 yi->reg_295c = read_reg(0x0295c);
898 yi->reg_2960 = read_reg(0x02960);
899 yi->reg_2964 = read_reg(0x02964);
900 yi->reg_2968 = read_reg(0x02968);
901 yi->reg_296c = read_reg(0x0296c);
902 yi->reg_2970 = read_reg(0x02970);
904 yi->v_filter_1 = -1;
905 yi->v_filter_2 = -1;
906 yi->h_filter = -1;
908 /* Set some valid size info */
909 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
910 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
912 /* Bit 2 of reg 2878 indicates current decoder output format
913 0 : NTSC 1 : PAL */
914 if (read_reg(0x2878) & 4)
915 yi->decode_height = 576;
916 else
917 yi->decode_height = 480;
919 if (!itv->osd_info) {
920 yi->osd_vis_w = 720 - yi->osd_x_offset;
921 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
922 } else {
923 /* If no visible size set, assume full size */
924 if (!yi->osd_vis_w)
925 yi->osd_vis_w = 720 - yi->osd_x_offset;
927 if (!yi->osd_vis_h)
928 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
929 else {
930 /* If output video standard has changed, requested height may
931 not be legal */
932 if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
933 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
934 yi->osd_vis_h + yi->osd_y_offset,
935 yi->decode_height);
936 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
941 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
942 yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
943 if (yi->blanking_ptr)
944 yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
945 else {
946 yi->blanking_dmaptr = 0;
947 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
950 /* Enable YUV decoder output */
951 write_reg_sync(0x01, IVTV_REG_VDM);
953 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
954 atomic_set(&yi->next_dma_frame, 0);
957 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
959 DEFINE_WAIT(wait);
960 int rc = 0;
961 int got_sig = 0;
962 int frame, next_fill_frame, last_fill_frame;
963 int register_update = 0;
965 IVTV_DEBUG_INFO("yuv_prep_frame\n");
967 if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
969 frame = atomic_read(&itv->yuv_info.next_fill_frame);
970 next_fill_frame = (frame + 1) & 0x3;
971 last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
973 if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
974 /* Buffers are full - Overwrite the last frame */
975 next_fill_frame = frame;
976 frame = (frame - 1) & 3;
977 register_update = itv->yuv_info.new_frame_info[frame].update;
980 /* Take a snapshot of the yuv coordinate information */
981 itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
982 itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
983 itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
984 itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
985 itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
986 itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
987 itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
988 itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
989 itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
990 itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
991 itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
993 /* Snapshot field order */
994 itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
996 /* Are we going to offset the Y plane */
997 if (args->src.height + args->src.top < 512-16)
998 itv->yuv_info.new_frame_info[frame].offset_y = 1;
999 else
1000 itv->yuv_info.new_frame_info[frame].offset_y = 0;
1002 /* Snapshot the osd pan info */
1003 itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
1004 itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
1005 itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
1006 itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
1008 itv->yuv_info.new_frame_info[frame].update = 0;
1009 itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
1010 itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
1011 itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
1013 if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
1014 sizeof (itv->yuv_info.new_frame_info[frame]))) {
1015 memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
1016 itv->yuv_info.new_frame_info[frame].update = 1;
1017 /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
1020 itv->yuv_info.new_frame_info[frame].update |= register_update;
1022 /* Should this frame be delayed ? */
1023 if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
1024 itv->yuv_info.field_delay[frame] = 1;
1025 else
1026 itv->yuv_info.field_delay[frame] = 0;
1028 /* DMA the frame */
1029 mutex_lock(&itv->udma.lock);
1031 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1032 mutex_unlock(&itv->udma.lock);
1033 return rc;
1036 ivtv_udma_prepare(itv);
1037 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1038 /* if no UDMA is pending and no UDMA is in progress, then the DMA
1039 is finished */
1040 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1041 /* don't interrupt if the DMA is in progress but break off
1042 a still pending DMA. */
1043 got_sig = signal_pending(current);
1044 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1045 break;
1046 got_sig = 0;
1047 schedule();
1049 finish_wait(&itv->dma_waitq, &wait);
1051 /* Unmap Last DMA Xfer */
1052 ivtv_udma_unmap(itv);
1054 if (got_sig) {
1055 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1056 mutex_unlock(&itv->udma.lock);
1057 return -EINTR;
1060 atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
1062 mutex_unlock(&itv->udma.lock);
1063 return rc;
1066 void ivtv_yuv_close(struct ivtv *itv)
1068 int h_filter, v_filter_1, v_filter_2;
1070 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1071 ivtv_waitq(&itv->vsync_waitq);
1073 atomic_set(&itv->yuv_info.next_dma_frame, -1);
1074 atomic_set(&itv->yuv_info.next_fill_frame, 0);
1076 /* Reset registers we have changed so mpeg playback works */
1078 /* If we fully restore this register, the display may remain active.
1079 Restore, but set one bit to blank the video. Firmware will always
1080 clear this bit when needed, so not a problem. */
1081 write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1083 write_reg(itv->yuv_info.reg_2834, 0x02834);
1084 write_reg(itv->yuv_info.reg_2838, 0x02838);
1085 write_reg(itv->yuv_info.reg_283c, 0x0283c);
1086 write_reg(itv->yuv_info.reg_2840, 0x02840);
1087 write_reg(itv->yuv_info.reg_2844, 0x02844);
1088 write_reg(itv->yuv_info.reg_2848, 0x02848);
1089 write_reg(itv->yuv_info.reg_2854, 0x02854);
1090 write_reg(itv->yuv_info.reg_285c, 0x0285c);
1091 write_reg(itv->yuv_info.reg_2864, 0x02864);
1092 write_reg(itv->yuv_info.reg_2870, 0x02870);
1093 write_reg(itv->yuv_info.reg_2874, 0x02874);
1094 write_reg(itv->yuv_info.reg_2890, 0x02890);
1095 write_reg(itv->yuv_info.reg_289c, 0x0289c);
1097 write_reg(itv->yuv_info.reg_2918, 0x02918);
1098 write_reg(itv->yuv_info.reg_291c, 0x0291c);
1099 write_reg(itv->yuv_info.reg_2920, 0x02920);
1100 write_reg(itv->yuv_info.reg_2924, 0x02924);
1101 write_reg(itv->yuv_info.reg_2928, 0x02928);
1102 write_reg(itv->yuv_info.reg_292c, 0x0292c);
1103 write_reg(itv->yuv_info.reg_2930, 0x02930);
1104 write_reg(itv->yuv_info.reg_2934, 0x02934);
1105 write_reg(itv->yuv_info.reg_2938, 0x02938);
1106 write_reg(itv->yuv_info.reg_293c, 0x0293c);
1107 write_reg(itv->yuv_info.reg_2940, 0x02940);
1108 write_reg(itv->yuv_info.reg_2944, 0x02944);
1109 write_reg(itv->yuv_info.reg_2948, 0x02948);
1110 write_reg(itv->yuv_info.reg_294c, 0x0294c);
1111 write_reg(itv->yuv_info.reg_2950, 0x02950);
1112 write_reg(itv->yuv_info.reg_2954, 0x02954);
1113 write_reg(itv->yuv_info.reg_2958, 0x02958);
1114 write_reg(itv->yuv_info.reg_295c, 0x0295c);
1115 write_reg(itv->yuv_info.reg_2960, 0x02960);
1116 write_reg(itv->yuv_info.reg_2964, 0x02964);
1117 write_reg(itv->yuv_info.reg_2968, 0x02968);
1118 write_reg(itv->yuv_info.reg_296c, 0x0296c);
1119 write_reg(itv->yuv_info.reg_2970, 0x02970);
1121 /* Prepare to restore filters */
1123 /* First the horizontal filter */
1124 if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1125 /* An exact size match uses filter 0 */
1126 h_filter = 0;
1128 else {
1129 /* Figure out which filter to use */
1130 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1131 h_filter = (h_filter >> 1) + (h_filter & 1);
1132 /* Only an exact size match can use filter 0. */
1133 if (h_filter < 1) h_filter = 1;
1136 /* Now the vertical filter */
1137 if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1138 /* An exact size match uses filter 0/1 */
1139 v_filter_1 = 0;
1140 v_filter_2 = 1;
1142 else {
1143 /* Figure out which filter to use */
1144 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1145 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1146 /* Only an exact size match can use filter 0 */
1147 if (v_filter_1 == 0) v_filter_1 = 1;
1148 v_filter_2 = v_filter_1;
1151 /* Now restore the filters */
1152 ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1154 /* and clear a few registers */
1155 write_reg(0, 0x02814);
1156 write_reg(0, 0x0282c);
1157 write_reg(0, 0x02904);
1158 write_reg(0, 0x02910);
1160 /* Release the blanking buffer */
1161 if (itv->yuv_info.blanking_ptr) {
1162 kfree (itv->yuv_info.blanking_ptr);
1163 itv->yuv_info.blanking_ptr = NULL;
1164 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1167 /* Invalidate the old dimension information */
1168 itv->yuv_info.old_frame_info.src_w = 0;
1169 itv->yuv_info.old_frame_info.src_h = 0;
1170 itv->yuv_info.old_frame_info_args.src_w = 0;
1171 itv->yuv_info.old_frame_info_args.src_h = 0;
1173 /* All done. */
1174 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);