blob: 15e9bd2486d0ad517cdded9bbdf5f39592cab75a [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"
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030022#include "ivtv-udma.h"
Hans Verkuil83df8e72007-03-10 06:54:58 -030023#include "ivtv-yuv.h"
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030024
Ian Armstronga3e5f5e2007-10-20 14:52:55 -030025/* 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
Hans Verkuil612570f2007-08-23 05:42:59 -030035};
36
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030037static 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;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -030045 u8 frame = itv->yuv_info.draw_frame;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030046 unsigned long y_buffer_offset, uv_buffer_offset;
47 int y_decode_height, uv_decode_height, y_size;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030048
Hans Verkuil33c0fca2007-08-23 06:32:46 -030049 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030050 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 */
Hans Verkuil8beb0582007-08-19 17:56:41 -030095 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
Hans Verkuil0989fd22007-08-19 12:25:39 -030096 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 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300103 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);
Hans Verkuil33c0fca2007-08-23 06:32:46 -0300113 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300114 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
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300631}
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{
Ian Armstrong9e0df402007-03-16 07:44:42 -0300636 int osd_crop, lace_threshold;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300637 u32 osd_scale;
638 u32 yuv_update = 0;
639
Ian Armstrong9e0df402007-03-16 07:44:42 -0300640 lace_threshold = itv->yuv_info.lace_threshold;
641 if (lace_threshold < 0)
642 lace_threshold = itv->yuv_info.decode_height - 1;
643
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300644 /* 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:
Ian Armstrong9e0df402007-03-16 07:44:42 -0300660 if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300661 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) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300717 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300718 }
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) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300798 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300799 }
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) ||
Ian Armstrongbfd7bea2007-08-03 10:01:39 -0300817 (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300818 (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 */
Hans Verkuil1e13f9e2007-03-10 06:52:02 -0300827void ivtv_yuv_work_handler (struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300828{
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300829 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
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300847 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
848 write_reg(0x01008080, 0x2898);
849 } else if (yuv_update) {
850 write_reg(0x00108080, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300851
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300852 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 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300858
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{
Ian Armstrong195b1252007-10-14 13:12:28 -0300864 struct yuv_playback_info *yi = &itv->yuv_info;
865
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300866 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
867
868 /* Take a snapshot of the current register settings */
Ian Armstrong195b1252007-10-14 13:12:28 -0300869 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);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300882
Ian Armstrong195b1252007-10-14 13:12:28 -0300883 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);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300907
Ian Armstrong195b1252007-10-14 13:12:28 -0300908 yi->v_filter_1 = -1;
909 yi->v_filter_2 = -1;
910 yi->h_filter = -1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300911
912 /* Set some valid size info */
Ian Armstrong195b1252007-10-14 13:12:28 -0300913 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
914 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300915
916 /* Bit 2 of reg 2878 indicates current decoder output format
917 0 : NTSC 1 : PAL */
918 if (read_reg(0x2878) & 4)
Ian Armstrong195b1252007-10-14 13:12:28 -0300919 yi->decode_height = 576;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300920 else
Ian Armstrong195b1252007-10-14 13:12:28 -0300921 yi->decode_height = 480;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300922
Ian Armstrong195b1252007-10-14 13:12:28 -0300923 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;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300926 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300927 /* 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 }
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300942 }
943 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300944
945 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
Ian Armstrong195b1252007-10-14 13:12:28 -0300946 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);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300949 else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300950 yi->blanking_dmaptr = 0;
951 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300952 }
953
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300954 /* Enable YUV decoder output */
955 write_reg_sync(0x01, IVTV_REG_VDM);
956
957 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
Ian Armstrong195b1252007-10-14 13:12:28 -0300958 atomic_set(&yi->next_dma_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300959}
960
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300961/* Get next available yuv buffer on PVR350 */
962void ivtv_yuv_next_free(struct ivtv *itv)
963{
964 int draw, display;
965 struct yuv_playback_info *yi = &itv->yuv_info;
966
967 if (atomic_read(&yi->next_dma_frame) == -1)
968 ivtv_yuv_init(itv);
969
970 draw = atomic_read(&yi->next_fill_frame);
971 display = atomic_read(&yi->next_dma_frame);
972
973 if (display > draw)
974 display -= IVTV_YUV_BUFFERS;
975
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;
992
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;
1005
1006 /* Snapshot field order */
1007 yi->sync_field[frame] = yi->lace_sync_field;
1008
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;
1014
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;
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); */
1031 }
1032
1033 yi->new_frame_info[frame].update |= register_update;
1034
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;
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
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001050int 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;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001055
1056 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1057
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001058 ivtv_yuv_next_free(itv);
1059 ivtv_yuv_setup_frame(itv, args);
Ian Armstrongbfd7bea2007-08-03 10:01:39 -03001060
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001061 /* 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
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001093 ivtv_yuv_frame_complete(itv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001094
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