]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/media/video/ivtv/ivtv-yuv.c
V4L/DVB (6713): ivtv: ivtv_yuv_prep_frame breakup and yuv hardware buffer changes
[net-next-2.6.git] / drivers / media / video / ivtv / ivtv-yuv.c
CommitLineData
1a0adaf3
HV
1/*
2 yuv support
3
4 Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "ivtv-driver.h"
1a0adaf3 22#include "ivtv-udma.h"
83df8e7b 23#include "ivtv-yuv.h"
1a0adaf3 24
a3e5f5e2
IA
25/* YUV buffer offsets */
26const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
27 0x001a8600,
28 0x00240400,
29 0x002d8200,
30 0x00370000,
31 0x00029000,
32 0x000C0E00,
33 0x006B0400,
34 0x00748200
612570f2
HV
35};
36
1a0adaf3
HV
37static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
38 struct ivtv_dma_frame *args)
39{
40 struct ivtv_dma_page_info y_dma;
41 struct ivtv_dma_page_info uv_dma;
42
43 int i;
44 int y_pages, uv_pages;
a3e5f5e2 45 u8 frame = itv->yuv_info.draw_frame;
1a0adaf3
HV
46 unsigned long y_buffer_offset, uv_buffer_offset;
47 int y_decode_height, uv_decode_height, y_size;
1a0adaf3 48
33c0fcad 49 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
1a0adaf3
HV
50 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
51
52 y_decode_height = uv_decode_height = args->src.height + args->src.top;
53
54 if (y_decode_height < 512-16)
55 y_buffer_offset += 720 * 16;
56
57 if (y_decode_height & 15)
58 y_decode_height = (y_decode_height + 16) & ~15;
59
60 if (uv_decode_height & 31)
61 uv_decode_height = (uv_decode_height + 32) & ~31;
62
63 y_size = 720 * y_decode_height;
64
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;
70 }
71
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);
74
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);
80
81 dma->page_count = y_dma.page_count + uv_dma.page_count;
82
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);
86
87 for (i = 0; i < dma->page_count; i++) {
88 put_page(dma->map[i]);
89 }
90 dma->page_count = 0;
91 return -EINVAL;
92 }
93
94 /* Fill & map SG List */
8beb058f 95 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
0989fd2c
HV
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]);
99 }
100 dma->page_count = 0;
101 return -ENOMEM;
102 }
1a0adaf3
HV
103 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
104
105 /* Fill SG Array with new values */
106 ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
107
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);
33c0fcad 113 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
1a0adaf3
HV
114 dma->SG_length++;
115 }
116 }
117
118 /* Tag SG Array with Interrupt Bit */
119 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
120
121 ivtv_udma_sync_for_device(itv);
122 return 0;
123}
124
125/* We rely on a table held in the firmware - Quick check. */
126int ivtv_yuv_filter_check(struct ivtv *itv)
127{
128 int i, offset_y, offset_uv;
129
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;
135 }
136 }
137 return 0;
138}
139
140static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
141{
142 int filter_index, filter_line;
143
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 ++;
168 }
169 IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
170 }
171
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 ++;
183 }
184 IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
185 }
186
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 ++;
198 }
199 IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
200 }
201}
202
203static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
204{
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;
212
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);
215
216 /* How wide is the src image */
217 x_cutoff = window->src_w + window->src_x;
218
219 /* Set the display width */
220 reg_2834 = window->dst_w;
221 reg_2838 = reg_2834;
222
223 /* Set the display position */
224 reg_2890 = window->dst_x;
225
226 /* Index into the image horizontally */
227 reg_2870 = 0;
228
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;
238 }
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);
241 }
242
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);
247 }
248
249 if (window->dst_w < window->src_w)
250 reg_2870 = 0x000d000e - reg_2870;
251 else
252 reg_2870 = 0x0012000e - reg_2870;
253
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;
256
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;
268
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;
275
276 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
277 reg_2874 = 0;
278 }
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;
292 }
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;
306 }
307
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;
312 }
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;
319 }
320
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);
324
325 write_reg(reg_283c, 0x0283c);
326 write_reg(reg_2844, 0x02844);
327
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);
329
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);
333
334 write_reg(reg_2854, 0x02854);
335 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
336
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);
340
341 write_reg(reg_2874, 0x02874);
342 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
343
344 write_reg(reg_2870, 0x02870);
345 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
346
347 write_reg( reg_2890,0x02890);
348 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
349
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;
354 }
355}
356
357static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
358{
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;
370
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);
373
374 /* What scaling mode is being used... */
375 if (window->interlaced_y) {
376 IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
377 }
378 else {
379 IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
380 }
381
382 if (window->interlaced_uv) {
383 IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
384 }
385 else {
386 IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
387 }
388
389 /* What is the source video being treated as... */
390 if (itv->yuv_info.frame_interlaced) {
391 IVTV_DEBUG_WARN("Source video: Interlaced\n");
392 }
393 else {
394 IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
395 }
396
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;
402 }
403 else {
404 src_y_minor_uv = 8;
405 src_y_major_uv = window->src_y - 8;
406 }
407
408 src_y_minor_y = src_y_minor_uv;
409 src_y_major_y = src_y_major_uv;
410
411 if (window->offset_y) src_y_minor_y += 16;
412
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);
417
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);
422
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;
425
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;
436 }
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;
447 }
448 else {
449 reg_296c ++;
450 reg_2964_base >>= 2;
451 }
452 if (window->interlaced_uv) reg_2928 >>= 1;
453 reg_2968_base >>= 3;
454 }
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;
465 }
466 else {
467 reg_296c ++;
468 reg_2964_base >>= 1;
469 }
470 if (window->interlaced_uv) reg_2928 >>= 1;
471 reg_2968_base >>= 2;
472 }
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;
483 }
484
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;
492 }
493 else {
494 reg_2934 = 0x00000FF0;
495 reg_293c = 0x00000FF0;
496 reg_2944 = 0x00000FF0;
497 reg_294c = 0x00000FF0;
498 }
499
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;
504
505 reg_2958 = 0x00010000 + (src_y_major_y >> 1);
506 if (window->interlaced_uv) reg_2958 += 0x00010000;
507 reg_295c = reg_2958 + 1;
508
509 if (itv->yuv_info.decode_height == 480)
510 reg_289c = 0x011e0017;
511 else
512 reg_289c = 0x01500017;
513
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);
518
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);
523
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);
530 }
531 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
532 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
533
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));
539
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);
545
546 if (!window->interlaced_y) reg_2964 -= 0x00010001;
547 if (!window->interlaced_uv) reg_2968 -= 0x00010001;
548
549 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
550 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
551
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;
557 }
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;
565 }
566
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);
573
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); */
577
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);
581
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);
585
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);
589
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);
593
594 write_reg(reg_296c, 0x0296c);
595 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
596
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);
600
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);
604
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);
608
609 write_reg(reg_2960, 0x02960);
610 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
611
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);
615
616 write_reg( reg_289c,0x0289c);
617 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
618
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;
623 }
624
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;
629 }
630
1a0adaf3
HV
631}
632
633/* Modify the supplied coordinate information to fit the visible osd area */
634static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
635{
9e0df402 636 int osd_crop, lace_threshold;
1a0adaf3
HV
637 u32 osd_scale;
638 u32 yuv_update = 0;
639
9e0df402
IA
640 lace_threshold = itv->yuv_info.lace_threshold;
641 if (lace_threshold < 0)
642 lace_threshold = itv->yuv_info.decode_height - 1;
643
1a0adaf3
HV
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;
652
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;
658
659 case IVTV_YUV_MODE_AUTO:
9e0df402 660 if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
1a0adaf3
HV
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;
668
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;
673 }
674 else {
675 itv->yuv_info.frame_interlaced = 1;
676 window->interlaced_y = 1;
677 window->interlaced_uv = 1;
678 }
679 break;
680
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;
687 }
688
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;
692
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;
699 }
700
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;
712 }
713 }
714
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) {
0bfeb04a 717 return IVTV_YUV_UPDATE_INVALID;
1a0adaf3
HV
718 }
719
720 /* Ensure video remains inside OSD area */
721 osd_scale = (window->src_h << 16) / window->dst_h;
722
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;
729 }
730 else {
731 window->dst_y -= window->pan_y;
732 }
733
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;
738 }
739
740 osd_scale = (window->src_w << 16) / window->dst_w;
741
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;
748 }
749 else {
750 window->dst_x -= window->pan_x;
751 }
752
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;
757 }
758
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;
762
763 /* Width & height for both src & dst must be even.
764 Same for coordinates. */
765 window->dst_w &= ~1;
766 window->dst_x &= ~1;
767
768 window->src_w += window->src_x & 1;
769 window->src_x &= ~1;
770
771 window->src_w &= ~1;
772 window->dst_w &= ~1;
773
774 window->dst_h &= ~1;
775 window->dst_y &= ~1;
776
777 window->src_h += window->src_y & 1;
778 window->src_y &= ~1;
779
780 window->src_h &= ~1;
781 window->dst_h &= ~1;
782
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;
789 }
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;
794 }
795
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) {
0bfeb04a 798 return IVTV_YUV_UPDATE_INVALID;
1a0adaf3
HV
799 }
800
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;
809 }
810
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) ||
bfd7beac 817 (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
1a0adaf3
HV
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;
821 }
822
823 return yuv_update;
824}
825
826/* Update the scaling register to the requested value */
1e13f9e3 827void ivtv_yuv_work_handler (struct ivtv *itv)
1a0adaf3 828{
1a0adaf3
HV
829 struct yuv_frame_info window;
830 u32 yuv_update;
831
832 int frame = itv->yuv_info.update_frame;
833
834/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
835 memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
836
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;
842
843 /* Calculate the display window coordinates. Exit if nothing left */
844 if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
845 return;
846
0bfeb04a
IA
847 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
848 write_reg(0x01008080, 0x2898);
849 } else if (yuv_update) {
850 write_reg(0x00108080, 0x2898);
1a0adaf3 851
0bfeb04a
IA
852 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
853 ivtv_yuv_handle_horizontal(itv, &window);
854
855 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
856 ivtv_yuv_handle_vertical(itv, &window);
857 }
1a0adaf3
HV
858
859 memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
860}
861
862static void ivtv_yuv_init (struct ivtv *itv)
863{
195b1252
IA
864 struct yuv_playback_info *yi = &itv->yuv_info;
865
1a0adaf3
HV
866 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
867
868 /* Take a snapshot of the current register settings */
195b1252
IA
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);
882
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);
907
908 yi->v_filter_1 = -1;
909 yi->v_filter_2 = -1;
910 yi->h_filter = -1;
1a0adaf3
HV
911
912 /* Set some valid size info */
195b1252
IA
913 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
914 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
1a0adaf3
HV
915
916 /* Bit 2 of reg 2878 indicates current decoder output format
917 0 : NTSC 1 : PAL */
918 if (read_reg(0x2878) & 4)
195b1252 919 yi->decode_height = 576;
1a0adaf3 920 else
195b1252 921 yi->decode_height = 480;
b4b38bd6 922
195b1252
IA
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;
b4b38bd6 926 } else {
195b1252
IA
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;
930
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;
941 }
b4b38bd6
IA
942 }
943 }
1a0adaf3
HV
944
945 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
195b1252
IA
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);
1a0adaf3 949 else {
195b1252
IA
950 yi->blanking_dmaptr = 0;
951 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
1a0adaf3
HV
952 }
953
1a0adaf3
HV
954 /* Enable YUV decoder output */
955 write_reg_sync(0x01, IVTV_REG_VDM);
956
957 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
195b1252 958 atomic_set(&yi->next_dma_frame, 0);
1a0adaf3
HV
959}
960
a3e5f5e2
IA
961/* Get next available yuv buffer on PVR350 */
962void ivtv_yuv_next_free(struct ivtv *itv)
1a0adaf3 963{
a3e5f5e2
IA
964 int draw, display;
965 struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf3 966
a3e5f5e2
IA
967 if (atomic_read(&yi->next_dma_frame) == -1)
968 ivtv_yuv_init(itv);
1a0adaf3 969
a3e5f5e2
IA
970 draw = atomic_read(&yi->next_fill_frame);
971 display = atomic_read(&yi->next_dma_frame);
1a0adaf3 972
a3e5f5e2
IA
973 if (display > draw)
974 display -= IVTV_YUV_BUFFERS;
1a0adaf3 975
a3e5f5e2
IA
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;
980
981 yi->draw_frame = draw;
982}
983
984/* Set up frame according to ivtv_dma_frame parameters */
985void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
986{
987 struct yuv_playback_info *yi = &itv->yuv_info;
988 u8 frame = yi->draw_frame;
989
990 /* Preserve old update flag in case we're overwriting a queued frame */
991 int register_update = yi->new_frame_info[frame].update;
1a0adaf3
HV
992
993 /* Take a snapshot of the yuv coordinate information */
a3e5f5e2
IA
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;
1a0adaf3 1005
bfd7beac 1006 /* Snapshot field order */
a3e5f5e2 1007 yi->sync_field[frame] = yi->lace_sync_field;
bfd7beac 1008
1a0adaf3
HV
1009 /* Are we going to offset the Y plane */
1010 if (args->src.height + args->src.top < 512-16)
a3e5f5e2 1011 yi->new_frame_info[frame].offset_y = 1;
1a0adaf3 1012 else
a3e5f5e2 1013 yi->new_frame_info[frame].offset_y = 0;
1a0adaf3
HV
1014
1015 /* Snapshot the osd pan info */
a3e5f5e2
IA
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;
1020
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;
1025
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); */
1a0adaf3
HV
1031 }
1032
a3e5f5e2 1033 yi->new_frame_info[frame].update |= register_update;
943e8910 1034
bfd7beac 1035 /* Should this frame be delayed ? */
a3e5f5e2
IA
1036 if (yi->sync_field[frame] !=
1037 yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS])
1038 yi->field_delay[frame] = 1;
bfd7beac 1039 else
a3e5f5e2
IA
1040 yi->field_delay[frame] = 0;
1041}
1042
1043/* Frame is complete & ready for display */
1044void ivtv_yuv_frame_complete(struct ivtv *itv)
1045{
1046 atomic_set(&itv->yuv_info.next_fill_frame,
1047 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1048}
1049
1050int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1051{
1052 DEFINE_WAIT(wait);
1053 int rc = 0;
1054 int got_sig = 0;
1055
1056 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1057
1058 ivtv_yuv_next_free(itv);
1059 ivtv_yuv_setup_frame(itv, args);
bfd7beac 1060
1a0adaf3
HV
1061 /* DMA the frame */
1062 mutex_lock(&itv->udma.lock);
1063
1064 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1065 mutex_unlock(&itv->udma.lock);
1066 return rc;
1067 }
1068
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();
1081 }
1082 finish_wait(&itv->dma_waitq, &wait);
1083
1084 /* Unmap Last DMA Xfer */
1085 ivtv_udma_unmap(itv);
1086
1087 if (got_sig) {
1088 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1089 mutex_unlock(&itv->udma.lock);
1090 return -EINTR;
1091 }
1092
a3e5f5e2 1093 ivtv_yuv_frame_complete(itv);
1a0adaf3
HV
1094
1095 mutex_unlock(&itv->udma.lock);
1096 return rc;
1097}
1098
1099void ivtv_yuv_close(struct ivtv *itv)
1100{
1101 int h_filter, v_filter_1, v_filter_2;
1102
1103 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1104 ivtv_waitq(&itv->vsync_waitq);
1105
1106 atomic_set(&itv->yuv_info.next_dma_frame, -1);
1107 atomic_set(&itv->yuv_info.next_fill_frame, 0);
1108
1109 /* Reset registers we have changed so mpeg playback works */
1110
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);
1115
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);
1129
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);
1153
1154 /* Prepare to restore filters */
1155
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;
1160 }
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;
1167 }
1168
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;
1174 }
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;
1182 }
1183
1184 /* Now restore the filters */
1185 ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1186
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);
1192
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);
1198 }
1199
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;
1205
1206 /* All done. */
1207 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1208}
1209