V4L/DVB (6715): ivtv: Remove unnecessary register update
[linux-2.6/verdex.git] / drivers / media / video / ivtv / ivtv-yuv.c
bloba23108fae4fdb7e27a4999a9c84b0d401d369835
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 /* YUV buffer offsets */
26 const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
27 0x001a8600,
28 0x00240400,
29 0x002d8200,
30 0x00370000,
31 0x00029000,
32 0x000C0E00,
33 0x006B0400,
34 0x00748200
37 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
38 struct ivtv_dma_frame *args)
40 struct ivtv_dma_page_info y_dma;
41 struct ivtv_dma_page_info uv_dma;
43 int i;
44 int y_pages, uv_pages;
45 u8 frame = itv->yuv_info.draw_frame;
46 unsigned long y_buffer_offset, uv_buffer_offset;
47 int y_decode_height, uv_decode_height, y_size;
49 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
50 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
52 y_decode_height = uv_decode_height = args->src.height + args->src.top;
54 if (y_decode_height < 512-16)
55 y_buffer_offset += 720 * 16;
57 if (y_decode_height & 15)
58 y_decode_height = (y_decode_height + 16) & ~15;
60 if (uv_decode_height & 31)
61 uv_decode_height = (uv_decode_height + 32) & ~31;
63 y_size = 720 * y_decode_height;
65 /* Still in USE */
66 if (dma->SG_length || dma->page_count) {
67 IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
68 dma->SG_length, dma->page_count);
69 return -EBUSY;
72 ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
73 ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
75 /* Get user pages for DMA Xfer */
76 down_read(&current->mm->mmap_sem);
77 y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
78 uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
79 up_read(&current->mm->mmap_sem);
81 dma->page_count = y_dma.page_count + uv_dma.page_count;
83 if (y_pages + uv_pages != dma->page_count) {
84 IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
85 y_pages + uv_pages, dma->page_count);
87 for (i = 0; i < dma->page_count; i++) {
88 put_page(dma->map[i]);
90 dma->page_count = 0;
91 return -EINVAL;
94 /* Fill & map SG List */
95 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
96 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
97 for (i = 0; i < dma->page_count; i++) {
98 put_page(dma->map[i]);
100 dma->page_count = 0;
101 return -ENOMEM;
103 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
105 /* Fill SG Array with new values */
106 ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
108 /* If we've offset the y plane, ensure top area is blanked */
109 if (args->src.height + args->src.top < 512-16) {
110 if (itv->yuv_info.blanking_dmaptr) {
111 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
112 dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
113 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
114 dma->SG_length++;
118 /* Tag SG Array with Interrupt Bit */
119 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
121 ivtv_udma_sync_for_device(itv);
122 return 0;
125 /* We rely on a table held in the firmware - Quick check. */
126 int ivtv_yuv_filter_check(struct ivtv *itv)
128 int i, offset_y, offset_uv;
130 for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
131 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
132 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
133 IVTV_WARN ("YUV filter table not found in firmware.\n");
134 return -1;
137 return 0;
140 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
142 int filter_index, filter_line;
144 /* If any filter is -1, then don't update it */
145 if (h_filter > -1) {
146 if (h_filter > 4) h_filter = 4;
147 filter_index = h_filter * 384;
148 filter_line = 0;
149 while (filter_line < 16) {
150 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
151 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
152 filter_index += 4;
153 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
154 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
155 filter_index += 4;
156 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
157 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
158 filter_index += 4;
159 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
160 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
161 filter_index += 4;
162 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
163 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
164 filter_index += 8;
165 write_reg(0, 0x02818);
166 write_reg(0, 0x02830);
167 filter_line ++;
169 IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
172 if (v_filter_1 > -1) {
173 if (v_filter_1 > 4) v_filter_1 = 4;
174 filter_index = v_filter_1 * 192;
175 filter_line = 0;
176 while (filter_line < 16) {
177 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
178 filter_index += 4;
179 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
180 filter_index += 8;
181 write_reg(0, 0x02908);
182 filter_line ++;
184 IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
187 if (v_filter_2 > -1) {
188 if (v_filter_2 > 4) v_filter_2 = 4;
189 filter_index = v_filter_2 * 192;
190 filter_line = 0;
191 while (filter_line < 16) {
192 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
193 filter_index += 4;
194 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
195 filter_index += 8;
196 write_reg(0, 0x02914);
197 filter_line ++;
199 IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
203 static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
205 u32 reg_2834, reg_2838, reg_283c;
206 u32 reg_2844, reg_2854, reg_285c;
207 u32 reg_2864, reg_2874, reg_2890;
208 u32 reg_2870, reg_2870_base, reg_2870_offset;
209 int x_cutoff;
210 int h_filter;
211 u32 master_width;
213 IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
214 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
216 /* How wide is the src image */
217 x_cutoff = window->src_w + window->src_x;
219 /* Set the display width */
220 reg_2834 = window->dst_w;
221 reg_2838 = reg_2834;
223 /* Set the display position */
224 reg_2890 = window->dst_x;
226 /* Index into the image horizontally */
227 reg_2870 = 0;
229 /* 2870 is normally fudged to align video coords with osd coords.
230 If running full screen, it causes an unwanted left shift
231 Remove the fudge if we almost fill the screen.
232 Gradually adjust the offset to avoid the video 'snapping'
233 left/right if it gets dragged through this region.
234 Only do this if osd is full width. */
235 if (window->vis_w == 720) {
236 if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
237 reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
239 else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
240 reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
243 if (window->dst_w >= window->src_w)
244 reg_2870 = reg_2870 << 16 | reg_2870;
245 else
246 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
249 if (window->dst_w < window->src_w)
250 reg_2870 = 0x000d000e - reg_2870;
251 else
252 reg_2870 = 0x0012000e - reg_2870;
254 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
255 reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
257 if (window->dst_w >= window->src_w) {
258 x_cutoff &= ~1;
259 master_width = (window->src_w * 0x00200000) / (window->dst_w);
260 if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
261 reg_2834 = (reg_2834 << 16) | x_cutoff;
262 reg_2838 = (reg_2838 << 16) | x_cutoff;
263 reg_283c = master_width >> 2;
264 reg_2844 = master_width >> 2;
265 reg_2854 = master_width;
266 reg_285c = master_width >> 1;
267 reg_2864 = master_width >> 1;
269 /* We also need to factor in the scaling
270 (src_w - dst_w) / (src_w / 4) */
271 if (window->dst_w > window->src_w)
272 reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
273 else
274 reg_2870_base = 0;
276 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
277 reg_2874 = 0;
279 else if (window->dst_w < window->src_w / 2) {
280 master_width = (window->src_w * 0x00080000) / window->dst_w;
281 if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
282 reg_2834 = (reg_2834 << 16) | x_cutoff;
283 reg_2838 = (reg_2838 << 16) | x_cutoff;
284 reg_283c = master_width >> 2;
285 reg_2844 = master_width >> 1;
286 reg_2854 = master_width;
287 reg_285c = master_width >> 1;
288 reg_2864 = master_width >> 1;
289 reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
290 reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
291 reg_2874 = 0x00000012;
293 else {
294 master_width = (window->src_w * 0x00100000) / window->dst_w;
295 if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
296 reg_2834 = (reg_2834 << 16) | x_cutoff;
297 reg_2838 = (reg_2838 << 16) | x_cutoff;
298 reg_283c = master_width >> 2;
299 reg_2844 = master_width >> 1;
300 reg_2854 = master_width;
301 reg_285c = master_width >> 1;
302 reg_2864 = master_width >> 1;
303 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
304 reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
305 reg_2874 = 0x00000001;
308 /* Select the horizontal filter */
309 if (window->src_w == window->dst_w) {
310 /* An exact size match uses filter 0 */
311 h_filter = 0;
313 else {
314 /* Figure out which filter to use */
315 h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
316 h_filter = (h_filter >> 1) + (h_filter & 1);
317 /* Only an exact size match can use filter 0 */
318 if (h_filter == 0) h_filter = 1;
321 write_reg(reg_2834, 0x02834);
322 write_reg(reg_2838, 0x02838);
323 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);
325 write_reg(reg_283c, 0x0283c);
326 write_reg(reg_2844, 0x02844);
328 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);
330 write_reg(0x00080514, 0x02840);
331 write_reg(0x00100514, 0x02848);
332 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
334 write_reg(reg_2854, 0x02854);
335 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
337 write_reg(reg_285c, 0x0285c);
338 write_reg(reg_2864, 0x02864);
339 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);
341 write_reg(reg_2874, 0x02874);
342 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
344 write_reg(reg_2870, 0x02870);
345 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
347 write_reg( reg_2890,0x02890);
348 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
350 /* Only update the filter if we really need to */
351 if (h_filter != itv->yuv_info.h_filter) {
352 ivtv_yuv_filter (itv,h_filter,-1,-1);
353 itv->yuv_info.h_filter = h_filter;
357 static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
359 u32 master_height;
360 u32 reg_2918, reg_291c, reg_2920, reg_2928;
361 u32 reg_2930, reg_2934, reg_293c;
362 u32 reg_2940, reg_2944, reg_294c;
363 u32 reg_2950, reg_2954, reg_2958, reg_295c;
364 u32 reg_2960, reg_2964, reg_2968, reg_296c;
365 u32 reg_289c;
366 u32 src_y_major_y, src_y_minor_y;
367 u32 src_y_major_uv, src_y_minor_uv;
368 u32 reg_2964_base, reg_2968_base;
369 int v_filter_1, v_filter_2;
371 IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
372 window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
374 /* What scaling mode is being used... */
375 if (window->interlaced_y) {
376 IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
378 else {
379 IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
382 if (window->interlaced_uv) {
383 IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
385 else {
386 IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
389 /* What is the source video being treated as... */
390 if (itv->yuv_info.frame_interlaced) {
391 IVTV_DEBUG_WARN("Source video: Interlaced\n");
393 else {
394 IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
397 /* We offset into the image using two different index methods, so split
398 the y source coord into two parts. */
399 if (window->src_y < 8) {
400 src_y_minor_uv = window->src_y;
401 src_y_major_uv = 0;
403 else {
404 src_y_minor_uv = 8;
405 src_y_major_uv = window->src_y - 8;
408 src_y_minor_y = src_y_minor_uv;
409 src_y_major_y = src_y_major_uv;
411 if (window->offset_y) src_y_minor_y += 16;
413 if (window->interlaced_y)
414 reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
415 else
416 reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
418 if (window->interlaced_uv)
419 reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
420 else
421 reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
423 reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
424 reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
426 if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
427 master_height = (window->src_h * 0x00400000) / window->dst_h;
428 if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
429 reg_2920 = master_height >> 2;
430 reg_2928 = master_height >> 3;
431 reg_2930 = master_height;
432 reg_2940 = master_height >> 1;
433 reg_2964_base >>= 3;
434 reg_2968_base >>= 3;
435 reg_296c = 0x00000000;
437 else if (window->dst_h >= window->src_h) {
438 master_height = (window->src_h * 0x00400000) / window->dst_h;
439 master_height = (master_height >> 1) + (master_height & 1);
440 reg_2920 = master_height >> 2;
441 reg_2928 = master_height >> 2;
442 reg_2930 = master_height;
443 reg_2940 = master_height >> 1;
444 reg_296c = 0x00000000;
445 if (window->interlaced_y) {
446 reg_2964_base >>= 3;
448 else {
449 reg_296c ++;
450 reg_2964_base >>= 2;
452 if (window->interlaced_uv) reg_2928 >>= 1;
453 reg_2968_base >>= 3;
455 else if (window->dst_h >= window->src_h / 2) {
456 master_height = (window->src_h * 0x00200000) / window->dst_h;
457 master_height = (master_height >> 1) + (master_height & 1);
458 reg_2920 = master_height >> 2;
459 reg_2928 = master_height >> 2;
460 reg_2930 = master_height;
461 reg_2940 = master_height;
462 reg_296c = 0x00000101;
463 if (window->interlaced_y) {
464 reg_2964_base >>= 2;
466 else {
467 reg_296c ++;
468 reg_2964_base >>= 1;
470 if (window->interlaced_uv) reg_2928 >>= 1;
471 reg_2968_base >>= 2;
473 else {
474 master_height = (window->src_h * 0x00100000) / window->dst_h;
475 master_height = (master_height >> 1) + (master_height & 1);
476 reg_2920 = master_height >> 2;
477 reg_2928 = master_height >> 2;
478 reg_2930 = master_height;
479 reg_2940 = master_height;
480 reg_2964_base >>= 1;
481 reg_2968_base >>= 2;
482 reg_296c = 0x00000102;
485 /* FIXME These registers change depending on scaled / unscaled output
486 We really need to work out what they should be */
487 if (window->src_h == window->dst_h){
488 reg_2934 = 0x00020000;
489 reg_293c = 0x00100000;
490 reg_2944 = 0x00040000;
491 reg_294c = 0x000b0000;
493 else {
494 reg_2934 = 0x00000FF0;
495 reg_293c = 0x00000FF0;
496 reg_2944 = 0x00000FF0;
497 reg_294c = 0x00000FF0;
500 /* The first line to be displayed */
501 reg_2950 = 0x00010000 + src_y_major_y;
502 if (window->interlaced_y) reg_2950 += 0x00010000;
503 reg_2954 = reg_2950 + 1;
505 reg_2958 = 0x00010000 + (src_y_major_y >> 1);
506 if (window->interlaced_uv) reg_2958 += 0x00010000;
507 reg_295c = reg_2958 + 1;
509 if (itv->yuv_info.decode_height == 480)
510 reg_289c = 0x011e0017;
511 else
512 reg_289c = 0x01500017;
514 if (window->dst_y < 0)
515 reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
516 else
517 reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
519 /* How much of the source to decode.
520 Take into account the source offset */
521 reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
522 ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
524 /* Calculate correct value for register 2964 */
525 if (window->src_h == window->dst_h)
526 reg_2964 = 1;
527 else {
528 reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
529 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
531 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
532 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
534 /* Okay, we've wasted time working out the correct value,
535 but if we use it, it fouls the the window alignment.
536 Fudge it to what we want... */
537 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
538 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
540 /* Deviate further from what it should be. I find the flicker headache
541 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
542 colours foul. */
543 if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
544 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
546 if (!window->interlaced_y) reg_2964 -= 0x00010001;
547 if (!window->interlaced_uv) reg_2968 -= 0x00010001;
549 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
550 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
552 /* Select the vertical filter */
553 if (window->src_h == window->dst_h) {
554 /* An exact size match uses filter 0/1 */
555 v_filter_1 = 0;
556 v_filter_2 = 1;
558 else {
559 /* Figure out which filter to use */
560 v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
561 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
562 /* Only an exact size match can use filter 0 */
563 if (v_filter_1 == 0) v_filter_1 = 1;
564 v_filter_2 = v_filter_1;
567 write_reg(reg_2934, 0x02934);
568 write_reg(reg_293c, 0x0293c);
569 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);
570 write_reg(reg_2944, 0x02944);
571 write_reg(reg_294c, 0x0294c);
572 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);
574 /* Ensure 2970 is 0 (does it ever change ?) */
575 /* write_reg(0,0x02970); */
576 /* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
578 write_reg(reg_2930, 0x02938);
579 write_reg(reg_2930, 0x02930);
580 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);
582 write_reg(reg_2928, 0x02928);
583 write_reg(reg_2928+0x514, 0x0292C);
584 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);
586 write_reg(reg_2920, 0x02920);
587 write_reg(reg_2920+0x514, 0x02924);
588 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);
590 write_reg (reg_2918,0x02918);
591 write_reg (reg_291c,0x0291C);
592 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);
594 write_reg(reg_296c, 0x0296c);
595 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
597 write_reg(reg_2940, 0x02948);
598 write_reg(reg_2940, 0x02940);
599 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);
601 write_reg(reg_2950, 0x02950);
602 write_reg(reg_2954, 0x02954);
603 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);
605 write_reg(reg_2958, 0x02958);
606 write_reg(reg_295c, 0x0295C);
607 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);
609 write_reg(reg_2960, 0x02960);
610 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
612 write_reg(reg_2964, 0x02964);
613 write_reg(reg_2968, 0x02968);
614 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);
616 write_reg( reg_289c,0x0289c);
617 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
619 /* Only update filter 1 if we really need to */
620 if (v_filter_1 != itv->yuv_info.v_filter_1) {
621 ivtv_yuv_filter (itv,-1,v_filter_1,-1);
622 itv->yuv_info.v_filter_1 = v_filter_1;
625 /* Only update filter 2 if we really need to */
626 if (v_filter_2 != itv->yuv_info.v_filter_2) {
627 ivtv_yuv_filter (itv,-1,-1,v_filter_2);
628 itv->yuv_info.v_filter_2 = v_filter_2;
633 /* Modify the supplied coordinate information to fit the visible osd area */
634 static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
636 int osd_crop, lace_threshold;
637 u32 osd_scale;
638 u32 yuv_update = 0;
640 lace_threshold = itv->yuv_info.lace_threshold;
641 if (lace_threshold < 0)
642 lace_threshold = itv->yuv_info.decode_height - 1;
644 /* Work out the lace settings */
645 switch (itv->yuv_info.lace_mode) {
646 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
647 itv->yuv_info.frame_interlaced = 0;
648 if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
649 window->interlaced_y = 0;
650 else
651 window->interlaced_y = 1;
653 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
654 window->interlaced_uv = 0;
655 else
656 window->interlaced_uv = 1;
657 break;
659 case IVTV_YUV_MODE_AUTO:
660 if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
661 itv->yuv_info.frame_interlaced = 0;
662 if ((window->tru_h < 512) ||
663 (window->tru_h > 576 && window->tru_h < 1021) ||
664 (window->tru_w > 720 && window->tru_h < 1021))
665 window->interlaced_y = 0;
666 else
667 window->interlaced_y = 1;
669 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
670 window->interlaced_uv = 0;
671 else
672 window->interlaced_uv = 1;
674 else {
675 itv->yuv_info.frame_interlaced = 1;
676 window->interlaced_y = 1;
677 window->interlaced_uv = 1;
679 break;
681 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
682 default:
683 itv->yuv_info.frame_interlaced = 1;
684 window->interlaced_y = 1;
685 window->interlaced_uv = 1;
686 break;
689 /* Sorry, but no negative coords for src */
690 if (window->src_x < 0) window->src_x = 0;
691 if (window->src_y < 0) window->src_y = 0;
693 /* Can only reduce width down to 1/4 original size */
694 if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
695 window->src_x += osd_crop / 2;
696 window->src_w = (window->src_w - osd_crop) & ~3;
697 window->dst_w = window->src_w / 4;
698 window->dst_w += window->dst_w & 1;
701 /* Can only reduce height down to 1/4 original size */
702 if (window->src_h / window->dst_h >= 2) {
703 /* Overflow may be because we're running progressive, so force mode switch */
704 window->interlaced_y = 1;
705 /* Make sure we're still within limits for interlace */
706 if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
707 /* If we reach here we'll have to force the height. */
708 window->src_y += osd_crop / 2;
709 window->src_h = (window->src_h - osd_crop) & ~3;
710 window->dst_h = window->src_h / 4;
711 window->dst_h += window->dst_h & 1;
715 /* If there's nothing to safe to display, we may as well stop now */
716 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
717 return IVTV_YUV_UPDATE_INVALID;
720 /* Ensure video remains inside OSD area */
721 osd_scale = (window->src_h << 16) / window->dst_h;
723 if ((osd_crop = window->pan_y - window->dst_y) > 0) {
724 /* Falls off the upper edge - crop */
725 window->src_y += (osd_scale * osd_crop) >> 16;
726 window->src_h -= (osd_scale * osd_crop) >> 16;
727 window->dst_h -= osd_crop;
728 window->dst_y = 0;
730 else {
731 window->dst_y -= window->pan_y;
734 if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
735 /* Falls off the lower edge - crop */
736 window->dst_h -= osd_crop;
737 window->src_h -= (osd_scale * osd_crop) >> 16;
740 osd_scale = (window->src_w << 16) / window->dst_w;
742 if ((osd_crop = window->pan_x - window->dst_x) > 0) {
743 /* Fall off the left edge - crop */
744 window->src_x += (osd_scale * osd_crop) >> 16;
745 window->src_w -= (osd_scale * osd_crop) >> 16;
746 window->dst_w -= osd_crop;
747 window->dst_x = 0;
749 else {
750 window->dst_x -= window->pan_x;
753 if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
754 /* Falls off the right edge - crop */
755 window->dst_w -= osd_crop;
756 window->src_w -= (osd_scale * osd_crop) >> 16;
759 /* The OSD can be moved. Track to it */
760 window->dst_x += itv->yuv_info.osd_x_offset;
761 window->dst_y += itv->yuv_info.osd_y_offset;
763 /* Width & height for both src & dst must be even.
764 Same for coordinates. */
765 window->dst_w &= ~1;
766 window->dst_x &= ~1;
768 window->src_w += window->src_x & 1;
769 window->src_x &= ~1;
771 window->src_w &= ~1;
772 window->dst_w &= ~1;
774 window->dst_h &= ~1;
775 window->dst_y &= ~1;
777 window->src_h += window->src_y & 1;
778 window->src_y &= ~1;
780 window->src_h &= ~1;
781 window->dst_h &= ~1;
783 /* Due to rounding, we may have reduced the output size to <1/4 of the source
784 Check again, but this time just resize. Don't change source coordinates */
785 if (window->dst_w < window->src_w / 4) {
786 window->src_w &= ~3;
787 window->dst_w = window->src_w / 4;
788 window->dst_w += window->dst_w & 1;
790 if (window->dst_h < window->src_h / 4) {
791 window->src_h &= ~3;
792 window->dst_h = window->src_h / 4;
793 window->dst_h += window->dst_h & 1;
796 /* Check again. If there's nothing to safe to display, stop now */
797 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
798 return IVTV_YUV_UPDATE_INVALID;
801 /* Both x offset & width are linked, so they have to be done together */
802 if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
803 (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
804 (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
805 (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
806 (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
807 (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
808 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
811 if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
812 (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
813 (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
814 (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
815 (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
816 (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
817 (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
818 (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
819 (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
820 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
823 return yuv_update;
826 /* Update the scaling register to the requested value */
827 void ivtv_yuv_work_handler (struct ivtv *itv)
829 struct yuv_frame_info window;
830 u32 yuv_update;
832 int frame = itv->yuv_info.update_frame;
834 /* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
835 memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
837 /* Update the osd pan info */
838 window.pan_x = itv->yuv_info.osd_x_pan;
839 window.pan_y = itv->yuv_info.osd_y_pan;
840 window.vis_w = itv->yuv_info.osd_vis_w;
841 window.vis_h = itv->yuv_info.osd_vis_h;
843 /* Calculate the display window coordinates. Exit if nothing left */
844 if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
845 return;
847 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
848 write_reg(0x01008080, 0x2898);
849 } else if (yuv_update) {
850 write_reg(0x00108080, 0x2898);
852 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
853 ivtv_yuv_handle_horizontal(itv, &window);
855 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
856 ivtv_yuv_handle_vertical(itv, &window);
859 memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
862 static void ivtv_yuv_init (struct ivtv *itv)
864 struct yuv_playback_info *yi = &itv->yuv_info;
866 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
868 /* Take a snapshot of the current register settings */
869 yi->reg_2834 = read_reg(0x02834);
870 yi->reg_2838 = read_reg(0x02838);
871 yi->reg_283c = read_reg(0x0283c);
872 yi->reg_2840 = read_reg(0x02840);
873 yi->reg_2844 = read_reg(0x02844);
874 yi->reg_2848 = read_reg(0x02848);
875 yi->reg_2854 = read_reg(0x02854);
876 yi->reg_285c = read_reg(0x0285c);
877 yi->reg_2864 = read_reg(0x02864);
878 yi->reg_2870 = read_reg(0x02870);
879 yi->reg_2874 = read_reg(0x02874);
880 yi->reg_2898 = read_reg(0x02898);
881 yi->reg_2890 = read_reg(0x02890);
883 yi->reg_289c = read_reg(0x0289c);
884 yi->reg_2918 = read_reg(0x02918);
885 yi->reg_291c = read_reg(0x0291c);
886 yi->reg_2920 = read_reg(0x02920);
887 yi->reg_2924 = read_reg(0x02924);
888 yi->reg_2928 = read_reg(0x02928);
889 yi->reg_292c = read_reg(0x0292c);
890 yi->reg_2930 = read_reg(0x02930);
891 yi->reg_2934 = read_reg(0x02934);
892 yi->reg_2938 = read_reg(0x02938);
893 yi->reg_293c = read_reg(0x0293c);
894 yi->reg_2940 = read_reg(0x02940);
895 yi->reg_2944 = read_reg(0x02944);
896 yi->reg_2948 = read_reg(0x02948);
897 yi->reg_294c = read_reg(0x0294c);
898 yi->reg_2950 = read_reg(0x02950);
899 yi->reg_2954 = read_reg(0x02954);
900 yi->reg_2958 = read_reg(0x02958);
901 yi->reg_295c = read_reg(0x0295c);
902 yi->reg_2960 = read_reg(0x02960);
903 yi->reg_2964 = read_reg(0x02964);
904 yi->reg_2968 = read_reg(0x02968);
905 yi->reg_296c = read_reg(0x0296c);
906 yi->reg_2970 = read_reg(0x02970);
908 yi->v_filter_1 = -1;
909 yi->v_filter_2 = -1;
910 yi->h_filter = -1;
912 /* Set some valid size info */
913 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
914 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
916 /* Bit 2 of reg 2878 indicates current decoder output format
917 0 : NTSC 1 : PAL */
918 if (read_reg(0x2878) & 4)
919 yi->decode_height = 576;
920 else
921 yi->decode_height = 480;
923 if (!itv->osd_info) {
924 yi->osd_vis_w = 720 - yi->osd_x_offset;
925 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
926 } else {
927 /* If no visible size set, assume full size */
928 if (!yi->osd_vis_w)
929 yi->osd_vis_w = 720 - yi->osd_x_offset;
931 if (!yi->osd_vis_h)
932 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
933 else {
934 /* If output video standard has changed, requested height may
935 not be legal */
936 if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
937 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
938 yi->osd_vis_h + yi->osd_y_offset,
939 yi->decode_height);
940 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
945 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
946 yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
947 if (yi->blanking_ptr)
948 yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
949 else {
950 yi->blanking_dmaptr = 0;
951 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
954 /* Enable YUV decoder output */
955 write_reg_sync(0x01, IVTV_REG_VDM);
957 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
958 atomic_set(&yi->next_dma_frame, 0);
961 /* Get next available yuv buffer on PVR350 */
962 void ivtv_yuv_next_free(struct ivtv *itv)
964 int draw, display;
965 struct yuv_playback_info *yi = &itv->yuv_info;
967 if (atomic_read(&yi->next_dma_frame) == -1)
968 ivtv_yuv_init(itv);
970 draw = atomic_read(&yi->next_fill_frame);
971 display = atomic_read(&yi->next_dma_frame);
973 if (display > draw)
974 display -= IVTV_YUV_BUFFERS;
976 if (draw - display >= yi->max_frames_buffered)
977 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
978 else
979 yi->new_frame_info[draw].update = 0;
981 yi->draw_frame = draw;
984 /* Set up frame according to ivtv_dma_frame parameters */
985 void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
987 struct yuv_playback_info *yi = &itv->yuv_info;
988 u8 frame = yi->draw_frame;
990 /* Preserve old update flag in case we're overwriting a queued frame */
991 int register_update = yi->new_frame_info[frame].update;
993 /* Take a snapshot of the yuv coordinate information */
994 yi->new_frame_info[frame].src_x = args->src.left;
995 yi->new_frame_info[frame].src_y = args->src.top;
996 yi->new_frame_info[frame].src_w = args->src.width;
997 yi->new_frame_info[frame].src_h = args->src.height;
998 yi->new_frame_info[frame].dst_x = args->dst.left;
999 yi->new_frame_info[frame].dst_y = args->dst.top;
1000 yi->new_frame_info[frame].dst_w = args->dst.width;
1001 yi->new_frame_info[frame].dst_h = args->dst.height;
1002 yi->new_frame_info[frame].tru_x = args->dst.left;
1003 yi->new_frame_info[frame].tru_w = args->src_width;
1004 yi->new_frame_info[frame].tru_h = args->src_height;
1006 /* Snapshot field order */
1007 yi->sync_field[frame] = yi->lace_sync_field;
1009 /* Are we going to offset the Y plane */
1010 if (args->src.height + args->src.top < 512-16)
1011 yi->new_frame_info[frame].offset_y = 1;
1012 else
1013 yi->new_frame_info[frame].offset_y = 0;
1015 /* Snapshot the osd pan info */
1016 yi->new_frame_info[frame].pan_x = yi->osd_x_pan;
1017 yi->new_frame_info[frame].pan_y = yi->osd_y_pan;
1018 yi->new_frame_info[frame].vis_w = yi->osd_vis_w;
1019 yi->new_frame_info[frame].vis_h = yi->osd_vis_h;
1021 yi->new_frame_info[frame].update = 0;
1022 yi->new_frame_info[frame].interlaced_y = 0;
1023 yi->new_frame_info[frame].interlaced_uv = 0;
1024 yi->new_frame_info[frame].lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
1026 if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame],
1027 sizeof(yi->new_frame_info[frame]))) {
1028 yi->old_frame_info_args = yi->new_frame_info[frame];
1029 yi->new_frame_info[frame].update = 1;
1030 /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
1033 yi->new_frame_info[frame].update |= register_update;
1035 /* Should this frame be delayed ? */
1036 if (yi->sync_field[frame] !=
1037 yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS])
1038 yi->field_delay[frame] = 1;
1039 else
1040 yi->field_delay[frame] = 0;
1043 /* Frame is complete & ready for display */
1044 void ivtv_yuv_frame_complete(struct ivtv *itv)
1046 atomic_set(&itv->yuv_info.next_fill_frame,
1047 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1050 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1052 DEFINE_WAIT(wait);
1053 int rc = 0;
1054 int got_sig = 0;
1056 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1058 ivtv_yuv_next_free(itv);
1059 ivtv_yuv_setup_frame(itv, args);
1061 /* DMA the frame */
1062 mutex_lock(&itv->udma.lock);
1064 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1065 mutex_unlock(&itv->udma.lock);
1066 return rc;
1069 ivtv_udma_prepare(itv);
1070 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1071 /* if no UDMA is pending and no UDMA is in progress, then the DMA
1072 is finished */
1073 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1074 /* don't interrupt if the DMA is in progress but break off
1075 a still pending DMA. */
1076 got_sig = signal_pending(current);
1077 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1078 break;
1079 got_sig = 0;
1080 schedule();
1082 finish_wait(&itv->dma_waitq, &wait);
1084 /* Unmap Last DMA Xfer */
1085 ivtv_udma_unmap(itv);
1087 if (got_sig) {
1088 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1089 mutex_unlock(&itv->udma.lock);
1090 return -EINTR;
1093 ivtv_yuv_frame_complete(itv);
1095 mutex_unlock(&itv->udma.lock);
1096 return rc;
1099 void ivtv_yuv_close(struct ivtv *itv)
1101 int h_filter, v_filter_1, v_filter_2;
1103 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1104 ivtv_waitq(&itv->vsync_waitq);
1106 atomic_set(&itv->yuv_info.next_dma_frame, -1);
1107 atomic_set(&itv->yuv_info.next_fill_frame, 0);
1109 /* Reset registers we have changed so mpeg playback works */
1111 /* If we fully restore this register, the display may remain active.
1112 Restore, but set one bit to blank the video. Firmware will always
1113 clear this bit when needed, so not a problem. */
1114 write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1116 write_reg(itv->yuv_info.reg_2834, 0x02834);
1117 write_reg(itv->yuv_info.reg_2838, 0x02838);
1118 write_reg(itv->yuv_info.reg_283c, 0x0283c);
1119 write_reg(itv->yuv_info.reg_2840, 0x02840);
1120 write_reg(itv->yuv_info.reg_2844, 0x02844);
1121 write_reg(itv->yuv_info.reg_2848, 0x02848);
1122 write_reg(itv->yuv_info.reg_2854, 0x02854);
1123 write_reg(itv->yuv_info.reg_285c, 0x0285c);
1124 write_reg(itv->yuv_info.reg_2864, 0x02864);
1125 write_reg(itv->yuv_info.reg_2870, 0x02870);
1126 write_reg(itv->yuv_info.reg_2874, 0x02874);
1127 write_reg(itv->yuv_info.reg_2890, 0x02890);
1128 write_reg(itv->yuv_info.reg_289c, 0x0289c);
1130 write_reg(itv->yuv_info.reg_2918, 0x02918);
1131 write_reg(itv->yuv_info.reg_291c, 0x0291c);
1132 write_reg(itv->yuv_info.reg_2920, 0x02920);
1133 write_reg(itv->yuv_info.reg_2924, 0x02924);
1134 write_reg(itv->yuv_info.reg_2928, 0x02928);
1135 write_reg(itv->yuv_info.reg_292c, 0x0292c);
1136 write_reg(itv->yuv_info.reg_2930, 0x02930);
1137 write_reg(itv->yuv_info.reg_2934, 0x02934);
1138 write_reg(itv->yuv_info.reg_2938, 0x02938);
1139 write_reg(itv->yuv_info.reg_293c, 0x0293c);
1140 write_reg(itv->yuv_info.reg_2940, 0x02940);
1141 write_reg(itv->yuv_info.reg_2944, 0x02944);
1142 write_reg(itv->yuv_info.reg_2948, 0x02948);
1143 write_reg(itv->yuv_info.reg_294c, 0x0294c);
1144 write_reg(itv->yuv_info.reg_2950, 0x02950);
1145 write_reg(itv->yuv_info.reg_2954, 0x02954);
1146 write_reg(itv->yuv_info.reg_2958, 0x02958);
1147 write_reg(itv->yuv_info.reg_295c, 0x0295c);
1148 write_reg(itv->yuv_info.reg_2960, 0x02960);
1149 write_reg(itv->yuv_info.reg_2964, 0x02964);
1150 write_reg(itv->yuv_info.reg_2968, 0x02968);
1151 write_reg(itv->yuv_info.reg_296c, 0x0296c);
1152 write_reg(itv->yuv_info.reg_2970, 0x02970);
1154 /* Prepare to restore filters */
1156 /* First the horizontal filter */
1157 if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1158 /* An exact size match uses filter 0 */
1159 h_filter = 0;
1161 else {
1162 /* Figure out which filter to use */
1163 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1164 h_filter = (h_filter >> 1) + (h_filter & 1);
1165 /* Only an exact size match can use filter 0. */
1166 if (h_filter < 1) h_filter = 1;
1169 /* Now the vertical filter */
1170 if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1171 /* An exact size match uses filter 0/1 */
1172 v_filter_1 = 0;
1173 v_filter_2 = 1;
1175 else {
1176 /* Figure out which filter to use */
1177 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1178 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1179 /* Only an exact size match can use filter 0 */
1180 if (v_filter_1 == 0) v_filter_1 = 1;
1181 v_filter_2 = v_filter_1;
1184 /* Now restore the filters */
1185 ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1187 /* and clear a few registers */
1188 write_reg(0, 0x02814);
1189 write_reg(0, 0x0282c);
1190 write_reg(0, 0x02904);
1191 write_reg(0, 0x02910);
1193 /* Release the blanking buffer */
1194 if (itv->yuv_info.blanking_ptr) {
1195 kfree (itv->yuv_info.blanking_ptr);
1196 itv->yuv_info.blanking_ptr = NULL;
1197 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1200 /* Invalidate the old dimension information */
1201 itv->yuv_info.old_frame_info.src_w = 0;
1202 itv->yuv_info.old_frame_info.src_h = 0;
1203 itv->yuv_info.old_frame_info_args.src_w = 0;
1204 itv->yuv_info.old_frame_info_args.src_h = 0;
1206 /* All done. */
1207 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);