blob: 5c94d3282c820ad9d30479b763a28dca22f20569 [file] [log] [blame]
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001/*
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"
Hans Verkuil83df8e72007-03-10 06:54:58 -030025#include "ivtv-yuv.h"
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030026
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(&current->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(&current->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 /* FIXME These registers change depending on scaled / unscaled output
470 We really need to work out what they should be */
471 if (window->src_h == window->dst_h){
472 reg_2934 = 0x00020000;
473 reg_293c = 0x00100000;
474 reg_2944 = 0x00040000;
475 reg_294c = 0x000b0000;
476 }
477 else {
478 reg_2934 = 0x00000FF0;
479 reg_293c = 0x00000FF0;
480 reg_2944 = 0x00000FF0;
481 reg_294c = 0x00000FF0;
482 }
483
484 /* The first line to be displayed */
485 reg_2950 = 0x00010000 + src_y_major_y;
486 if (window->interlaced_y) reg_2950 += 0x00010000;
487 reg_2954 = reg_2950 + 1;
488
489 reg_2958 = 0x00010000 + (src_y_major_y >> 1);
490 if (window->interlaced_uv) reg_2958 += 0x00010000;
491 reg_295c = reg_2958 + 1;
492
493 if (itv->yuv_info.decode_height == 480)
494 reg_289c = 0x011e0017;
495 else
496 reg_289c = 0x01500017;
497
498 if (window->dst_y < 0)
499 reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
500 else
501 reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
502
503 /* How much of the source to decode.
504 Take into account the source offset */
505 reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
506 ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
507
508 /* Calculate correct value for register 2964 */
509 if (window->src_h == window->dst_h)
510 reg_2964 = 1;
511 else {
512 reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
513 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
514 }
515 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
516 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
517
518 /* Okay, we've wasted time working out the correct value,
519 but if we use it, it fouls the the window alignment.
520 Fudge it to what we want... */
521 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
522 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
523
524 /* Deviate further from what it should be. I find the flicker headache
525 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
526 colours foul. */
527 if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
528 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
529
530 if (!window->interlaced_y) reg_2964 -= 0x00010001;
531 if (!window->interlaced_uv) reg_2968 -= 0x00010001;
532
533 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
534 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
535
536 /* Select the vertical filter */
537 if (window->src_h == window->dst_h) {
538 /* An exact size match uses filter 0/1 */
539 v_filter_1 = 0;
540 v_filter_2 = 1;
541 }
542 else {
543 /* Figure out which filter to use */
544 v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
545 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
546 /* Only an exact size match can use filter 0 */
547 if (v_filter_1 == 0) v_filter_1 = 1;
548 v_filter_2 = v_filter_1;
549 }
550
551 write_reg(reg_2934, 0x02934);
552 write_reg(reg_293c, 0x0293c);
553 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);
554 write_reg(reg_2944, 0x02944);
555 write_reg(reg_294c, 0x0294c);
556 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);
557
558 /* Ensure 2970 is 0 (does it ever change ?) */
559/* write_reg(0,0x02970); */
560/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
561
562 write_reg(reg_2930, 0x02938);
563 write_reg(reg_2930, 0x02930);
564 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);
565
566 write_reg(reg_2928, 0x02928);
567 write_reg(reg_2928+0x514, 0x0292C);
568 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);
569
570 write_reg(reg_2920, 0x02920);
571 write_reg(reg_2920+0x514, 0x02924);
572 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);
573
574 write_reg (reg_2918,0x02918);
575 write_reg (reg_291c,0x0291C);
576 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);
577
578 write_reg(reg_296c, 0x0296c);
579 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
580
581 write_reg(reg_2940, 0x02948);
582 write_reg(reg_2940, 0x02940);
583 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);
584
585 write_reg(reg_2950, 0x02950);
586 write_reg(reg_2954, 0x02954);
587 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);
588
589 write_reg(reg_2958, 0x02958);
590 write_reg(reg_295c, 0x0295C);
591 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);
592
593 write_reg(reg_2960, 0x02960);
594 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
595
596 write_reg(reg_2964, 0x02964);
597 write_reg(reg_2968, 0x02968);
598 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);
599
600 write_reg( reg_289c,0x0289c);
601 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
602
603 /* Only update filter 1 if we really need to */
604 if (v_filter_1 != itv->yuv_info.v_filter_1) {
605 ivtv_yuv_filter (itv,-1,v_filter_1,-1);
606 itv->yuv_info.v_filter_1 = v_filter_1;
607 }
608
609 /* Only update filter 2 if we really need to */
610 if (v_filter_2 != itv->yuv_info.v_filter_2) {
611 ivtv_yuv_filter (itv,-1,-1,v_filter_2);
612 itv->yuv_info.v_filter_2 = v_filter_2;
613 }
614
615 itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300616}
617
618/* Modify the supplied coordinate information to fit the visible osd area */
619static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
620{
Ian Armstrong9e0df402007-03-16 07:44:42 -0300621 int osd_crop, lace_threshold;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300622 u32 osd_scale;
623 u32 yuv_update = 0;
624
Ian Armstrong9e0df402007-03-16 07:44:42 -0300625 lace_threshold = itv->yuv_info.lace_threshold;
626 if (lace_threshold < 0)
627 lace_threshold = itv->yuv_info.decode_height - 1;
628
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300629 /* Work out the lace settings */
630 switch (itv->yuv_info.lace_mode) {
631 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
632 itv->yuv_info.frame_interlaced = 0;
633 if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
634 window->interlaced_y = 0;
635 else
636 window->interlaced_y = 1;
637
638 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
639 window->interlaced_uv = 0;
640 else
641 window->interlaced_uv = 1;
642 break;
643
644 case IVTV_YUV_MODE_AUTO:
Ian Armstrong9e0df402007-03-16 07:44:42 -0300645 if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300646 itv->yuv_info.frame_interlaced = 0;
647 if ((window->tru_h < 512) ||
648 (window->tru_h > 576 && window->tru_h < 1021) ||
649 (window->tru_w > 720 && window->tru_h < 1021))
650 window->interlaced_y = 0;
651 else
652 window->interlaced_y = 1;
653
654 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
655 window->interlaced_uv = 0;
656 else
657 window->interlaced_uv = 1;
658 }
659 else {
660 itv->yuv_info.frame_interlaced = 1;
661 window->interlaced_y = 1;
662 window->interlaced_uv = 1;
663 }
664 break;
665
666 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
667 default:
668 itv->yuv_info.frame_interlaced = 1;
669 window->interlaced_y = 1;
670 window->interlaced_uv = 1;
671 break;
672 }
673
674 /* Sorry, but no negative coords for src */
675 if (window->src_x < 0) window->src_x = 0;
676 if (window->src_y < 0) window->src_y = 0;
677
678 /* Can only reduce width down to 1/4 original size */
679 if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
680 window->src_x += osd_crop / 2;
681 window->src_w = (window->src_w - osd_crop) & ~3;
682 window->dst_w = window->src_w / 4;
683 window->dst_w += window->dst_w & 1;
684 }
685
686 /* Can only reduce height down to 1/4 original size */
687 if (window->src_h / window->dst_h >= 2) {
688 /* Overflow may be because we're running progressive, so force mode switch */
689 window->interlaced_y = 1;
690 /* Make sure we're still within limits for interlace */
691 if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
692 /* If we reach here we'll have to force the height. */
693 window->src_y += osd_crop / 2;
694 window->src_h = (window->src_h - osd_crop) & ~3;
695 window->dst_h = window->src_h / 4;
696 window->dst_h += window->dst_h & 1;
697 }
698 }
699
700 /* If there's nothing to safe to display, we may as well stop now */
701 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
702 return 0;
703 }
704
705 /* Ensure video remains inside OSD area */
706 osd_scale = (window->src_h << 16) / window->dst_h;
707
708 if ((osd_crop = window->pan_y - window->dst_y) > 0) {
709 /* Falls off the upper edge - crop */
710 window->src_y += (osd_scale * osd_crop) >> 16;
711 window->src_h -= (osd_scale * osd_crop) >> 16;
712 window->dst_h -= osd_crop;
713 window->dst_y = 0;
714 }
715 else {
716 window->dst_y -= window->pan_y;
717 }
718
719 if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
720 /* Falls off the lower edge - crop */
721 window->dst_h -= osd_crop;
722 window->src_h -= (osd_scale * osd_crop) >> 16;
723 }
724
725 osd_scale = (window->src_w << 16) / window->dst_w;
726
727 if ((osd_crop = window->pan_x - window->dst_x) > 0) {
728 /* Fall off the left edge - crop */
729 window->src_x += (osd_scale * osd_crop) >> 16;
730 window->src_w -= (osd_scale * osd_crop) >> 16;
731 window->dst_w -= osd_crop;
732 window->dst_x = 0;
733 }
734 else {
735 window->dst_x -= window->pan_x;
736 }
737
738 if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
739 /* Falls off the right edge - crop */
740 window->dst_w -= osd_crop;
741 window->src_w -= (osd_scale * osd_crop) >> 16;
742 }
743
744 /* The OSD can be moved. Track to it */
745 window->dst_x += itv->yuv_info.osd_x_offset;
746 window->dst_y += itv->yuv_info.osd_y_offset;
747
748 /* Width & height for both src & dst must be even.
749 Same for coordinates. */
750 window->dst_w &= ~1;
751 window->dst_x &= ~1;
752
753 window->src_w += window->src_x & 1;
754 window->src_x &= ~1;
755
756 window->src_w &= ~1;
757 window->dst_w &= ~1;
758
759 window->dst_h &= ~1;
760 window->dst_y &= ~1;
761
762 window->src_h += window->src_y & 1;
763 window->src_y &= ~1;
764
765 window->src_h &= ~1;
766 window->dst_h &= ~1;
767
768 /* Due to rounding, we may have reduced the output size to <1/4 of the source
769 Check again, but this time just resize. Don't change source coordinates */
770 if (window->dst_w < window->src_w / 4) {
771 window->src_w &= ~3;
772 window->dst_w = window->src_w / 4;
773 window->dst_w += window->dst_w & 1;
774 }
775 if (window->dst_h < window->src_h / 4) {
776 window->src_h &= ~3;
777 window->dst_h = window->src_h / 4;
778 window->dst_h += window->dst_h & 1;
779 }
780
781 /* Check again. If there's nothing to safe to display, stop now */
782 if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
783 return 0;
784 }
785
786 /* Both x offset & width are linked, so they have to be done together */
787 if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
788 (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
789 (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
790 (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
791 (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
792 (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
793 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
794 }
795
796 if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
797 (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
798 (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
799 (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
800 (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
801 (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
802 (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
803 (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
804 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
805 }
806
807 return yuv_update;
808}
809
810/* Update the scaling register to the requested value */
Hans Verkuil1e13f9e2007-03-10 06:52:02 -0300811void ivtv_yuv_work_handler (struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300812{
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300813 struct yuv_frame_info window;
814 u32 yuv_update;
815
816 int frame = itv->yuv_info.update_frame;
817
818/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
819 memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
820
821 /* Update the osd pan info */
822 window.pan_x = itv->yuv_info.osd_x_pan;
823 window.pan_y = itv->yuv_info.osd_y_pan;
824 window.vis_w = itv->yuv_info.osd_vis_w;
825 window.vis_h = itv->yuv_info.osd_vis_h;
826
827 /* Calculate the display window coordinates. Exit if nothing left */
828 if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
829 return;
830
831 /* Update horizontal settings */
832 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
833 ivtv_yuv_handle_horizontal(itv, &window);
834
835 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
836 ivtv_yuv_handle_vertical(itv, &window);
837
838 memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
839}
840
841static void ivtv_yuv_init (struct ivtv *itv)
842{
843 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
844
845 /* Take a snapshot of the current register settings */
846 itv->yuv_info.reg_2834 = read_reg(0x02834);
847 itv->yuv_info.reg_2838 = read_reg(0x02838);
848 itv->yuv_info.reg_283c = read_reg(0x0283c);
849 itv->yuv_info.reg_2840 = read_reg(0x02840);
850 itv->yuv_info.reg_2844 = read_reg(0x02844);
851 itv->yuv_info.reg_2848 = read_reg(0x02848);
852 itv->yuv_info.reg_2854 = read_reg(0x02854);
853 itv->yuv_info.reg_285c = read_reg(0x0285c);
854 itv->yuv_info.reg_2864 = read_reg(0x02864);
855 itv->yuv_info.reg_2870 = read_reg(0x02870);
856 itv->yuv_info.reg_2874 = read_reg(0x02874);
857 itv->yuv_info.reg_2898 = read_reg(0x02898);
858 itv->yuv_info.reg_2890 = read_reg(0x02890);
859
860 itv->yuv_info.reg_289c = read_reg(0x0289c);
861 itv->yuv_info.reg_2918 = read_reg(0x02918);
862 itv->yuv_info.reg_291c = read_reg(0x0291c);
863 itv->yuv_info.reg_2920 = read_reg(0x02920);
864 itv->yuv_info.reg_2924 = read_reg(0x02924);
865 itv->yuv_info.reg_2928 = read_reg(0x02928);
866 itv->yuv_info.reg_292c = read_reg(0x0292c);
867 itv->yuv_info.reg_2930 = read_reg(0x02930);
868 itv->yuv_info.reg_2934 = read_reg(0x02934);
869 itv->yuv_info.reg_2938 = read_reg(0x02938);
870 itv->yuv_info.reg_293c = read_reg(0x0293c);
871 itv->yuv_info.reg_2940 = read_reg(0x02940);
872 itv->yuv_info.reg_2944 = read_reg(0x02944);
873 itv->yuv_info.reg_2948 = read_reg(0x02948);
874 itv->yuv_info.reg_294c = read_reg(0x0294c);
875 itv->yuv_info.reg_2950 = read_reg(0x02950);
876 itv->yuv_info.reg_2954 = read_reg(0x02954);
877 itv->yuv_info.reg_2958 = read_reg(0x02958);
878 itv->yuv_info.reg_295c = read_reg(0x0295c);
879 itv->yuv_info.reg_2960 = read_reg(0x02960);
880 itv->yuv_info.reg_2964 = read_reg(0x02964);
881 itv->yuv_info.reg_2968 = read_reg(0x02968);
882 itv->yuv_info.reg_296c = read_reg(0x0296c);
883 itv->yuv_info.reg_2970 = read_reg(0x02970);
884
885 itv->yuv_info.v_filter_1 = -1;
886 itv->yuv_info.v_filter_2 = -1;
887 itv->yuv_info.h_filter = -1;
888
889 /* Set some valid size info */
890 itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
891 itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
892
893 /* Bit 2 of reg 2878 indicates current decoder output format
894 0 : NTSC 1 : PAL */
895 if (read_reg(0x2878) & 4)
896 itv->yuv_info.decode_height = 576;
897 else
898 itv->yuv_info.decode_height = 480;
899
900 /* If no visible size set, assume full size */
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300901 if (!itv->yuv_info.osd_vis_w)
902 itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
903
904 if (!itv->yuv_info.osd_vis_h) {
905 itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
906 } else {
907 /* If output video standard has changed, requested height may
908 not be legal */
909 if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
910 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
911 itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
912 itv->yuv_info.decode_height);
913 itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
914 }
915 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300916
917 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
918 itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
919 if (itv->yuv_info.blanking_ptr) {
920 itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
921 }
922 else {
923 itv->yuv_info.blanking_dmaptr = 0;
924 IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
925 }
926
927 IVTV_DEBUG_WARN("Enable video output\n");
928 write_reg_sync(0x00108080, 0x2898);
929
930 /* Enable YUV decoder output */
931 write_reg_sync(0x01, IVTV_REG_VDM);
932
933 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
934 atomic_set(&itv->yuv_info.next_dma_frame,0);
935}
936
937int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
938{
939 DEFINE_WAIT(wait);
940 int rc = 0;
941 int got_sig = 0;
942 int frame, next_fill_frame, last_fill_frame;
Ian Armstrong943e8912007-08-03 09:58:29 -0300943 int register_update = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300944
945 IVTV_DEBUG_INFO("yuv_prep_frame\n");
946
947 if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
948
949 frame = atomic_read(&itv->yuv_info.next_fill_frame);
950 next_fill_frame = (frame + 1) & 0x3;
951 last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
952
953 if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
954 /* Buffers are full - Overwrite the last frame */
955 next_fill_frame = frame;
956 frame = (frame - 1) & 3;
Ian Armstrong943e8912007-08-03 09:58:29 -0300957 register_update = itv->yuv_info.new_frame_info[frame].update;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300958 }
959
960 /* Take a snapshot of the yuv coordinate information */
961 itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
962 itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
963 itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
964 itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
965 itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
966 itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
967 itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
968 itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
969 itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
970 itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
971 itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
972
973 /* Are we going to offset the Y plane */
974 if (args->src.height + args->src.top < 512-16)
975 itv->yuv_info.new_frame_info[frame].offset_y = 1;
976 else
977 itv->yuv_info.new_frame_info[frame].offset_y = 0;
978
979 /* Snapshot the osd pan info */
980 itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
981 itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
982 itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
983 itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
984
985 itv->yuv_info.new_frame_info[frame].update = 0;
986 itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
987 itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
988
989 if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
990 sizeof (itv->yuv_info.new_frame_info[frame]))) {
991 memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
992 itv->yuv_info.new_frame_info[frame].update = 1;
993/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
994 }
995
Ian Armstrong943e8912007-08-03 09:58:29 -0300996 itv->yuv_info.new_frame_info[frame].update |= register_update;
997
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300998 /* DMA the frame */
999 mutex_lock(&itv->udma.lock);
1000
1001 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1002 mutex_unlock(&itv->udma.lock);
1003 return rc;
1004 }
1005
1006 ivtv_udma_prepare(itv);
1007 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1008 /* if no UDMA is pending and no UDMA is in progress, then the DMA
1009 is finished */
1010 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1011 /* don't interrupt if the DMA is in progress but break off
1012 a still pending DMA. */
1013 got_sig = signal_pending(current);
1014 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1015 break;
1016 got_sig = 0;
1017 schedule();
1018 }
1019 finish_wait(&itv->dma_waitq, &wait);
1020
1021 /* Unmap Last DMA Xfer */
1022 ivtv_udma_unmap(itv);
1023
1024 if (got_sig) {
1025 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1026 mutex_unlock(&itv->udma.lock);
1027 return -EINTR;
1028 }
1029
1030 atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
1031
1032 mutex_unlock(&itv->udma.lock);
1033 return rc;
1034}
1035
1036void ivtv_yuv_close(struct ivtv *itv)
1037{
1038 int h_filter, v_filter_1, v_filter_2;
1039
1040 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1041 ivtv_waitq(&itv->vsync_waitq);
1042
1043 atomic_set(&itv->yuv_info.next_dma_frame, -1);
1044 atomic_set(&itv->yuv_info.next_fill_frame, 0);
1045
1046 /* Reset registers we have changed so mpeg playback works */
1047
1048 /* If we fully restore this register, the display may remain active.
1049 Restore, but set one bit to blank the video. Firmware will always
1050 clear this bit when needed, so not a problem. */
1051 write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1052
1053 write_reg(itv->yuv_info.reg_2834, 0x02834);
1054 write_reg(itv->yuv_info.reg_2838, 0x02838);
1055 write_reg(itv->yuv_info.reg_283c, 0x0283c);
1056 write_reg(itv->yuv_info.reg_2840, 0x02840);
1057 write_reg(itv->yuv_info.reg_2844, 0x02844);
1058 write_reg(itv->yuv_info.reg_2848, 0x02848);
1059 write_reg(itv->yuv_info.reg_2854, 0x02854);
1060 write_reg(itv->yuv_info.reg_285c, 0x0285c);
1061 write_reg(itv->yuv_info.reg_2864, 0x02864);
1062 write_reg(itv->yuv_info.reg_2870, 0x02870);
1063 write_reg(itv->yuv_info.reg_2874, 0x02874);
1064 write_reg(itv->yuv_info.reg_2890, 0x02890);
1065 write_reg(itv->yuv_info.reg_289c, 0x0289c);
1066
1067 write_reg(itv->yuv_info.reg_2918, 0x02918);
1068 write_reg(itv->yuv_info.reg_291c, 0x0291c);
1069 write_reg(itv->yuv_info.reg_2920, 0x02920);
1070 write_reg(itv->yuv_info.reg_2924, 0x02924);
1071 write_reg(itv->yuv_info.reg_2928, 0x02928);
1072 write_reg(itv->yuv_info.reg_292c, 0x0292c);
1073 write_reg(itv->yuv_info.reg_2930, 0x02930);
1074 write_reg(itv->yuv_info.reg_2934, 0x02934);
1075 write_reg(itv->yuv_info.reg_2938, 0x02938);
1076 write_reg(itv->yuv_info.reg_293c, 0x0293c);
1077 write_reg(itv->yuv_info.reg_2940, 0x02940);
1078 write_reg(itv->yuv_info.reg_2944, 0x02944);
1079 write_reg(itv->yuv_info.reg_2948, 0x02948);
1080 write_reg(itv->yuv_info.reg_294c, 0x0294c);
1081 write_reg(itv->yuv_info.reg_2950, 0x02950);
1082 write_reg(itv->yuv_info.reg_2954, 0x02954);
1083 write_reg(itv->yuv_info.reg_2958, 0x02958);
1084 write_reg(itv->yuv_info.reg_295c, 0x0295c);
1085 write_reg(itv->yuv_info.reg_2960, 0x02960);
1086 write_reg(itv->yuv_info.reg_2964, 0x02964);
1087 write_reg(itv->yuv_info.reg_2968, 0x02968);
1088 write_reg(itv->yuv_info.reg_296c, 0x0296c);
1089 write_reg(itv->yuv_info.reg_2970, 0x02970);
1090
1091 /* Prepare to restore filters */
1092
1093 /* First the horizontal filter */
1094 if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1095 /* An exact size match uses filter 0 */
1096 h_filter = 0;
1097 }
1098 else {
1099 /* Figure out which filter to use */
1100 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1101 h_filter = (h_filter >> 1) + (h_filter & 1);
1102 /* Only an exact size match can use filter 0. */
1103 if (h_filter < 1) h_filter = 1;
1104 }
1105
1106 /* Now the vertical filter */
1107 if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1108 /* An exact size match uses filter 0/1 */
1109 v_filter_1 = 0;
1110 v_filter_2 = 1;
1111 }
1112 else {
1113 /* Figure out which filter to use */
1114 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1115 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1116 /* Only an exact size match can use filter 0 */
1117 if (v_filter_1 == 0) v_filter_1 = 1;
1118 v_filter_2 = v_filter_1;
1119 }
1120
1121 /* Now restore the filters */
1122 ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1123
1124 /* and clear a few registers */
1125 write_reg(0, 0x02814);
1126 write_reg(0, 0x0282c);
1127 write_reg(0, 0x02904);
1128 write_reg(0, 0x02910);
1129
1130 /* Release the blanking buffer */
1131 if (itv->yuv_info.blanking_ptr) {
1132 kfree (itv->yuv_info.blanking_ptr);
1133 itv->yuv_info.blanking_ptr = NULL;
1134 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1135 }
1136
1137 /* Invalidate the old dimension information */
1138 itv->yuv_info.old_frame_info.src_w = 0;
1139 itv->yuv_info.old_frame_info.src_h = 0;
1140 itv->yuv_info.old_frame_info_args.src_w = 0;
1141 itv->yuv_info.old_frame_info_args.src_h = 0;
1142
1143 /* All done. */
1144 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1145}
1146