blob: cd42db9b5a155e562b47b7b2eb04e4e4dc1fb880 [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;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -030042 struct yuv_playback_info *yi = &itv->yuv_info;
43 u8 frame = yi->draw_frame;
44 struct yuv_frame_info *f = &yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030045 int i;
46 int y_pages, uv_pages;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030047 unsigned long y_buffer_offset, uv_buffer_offset;
48 int y_decode_height, uv_decode_height, y_size;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030049
Hans Verkuil33c0fca2007-08-23 06:32:46 -030050 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030051 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
52
Ian Armstrong3b5c1c82007-10-22 14:24:26 -030053 y_decode_height = uv_decode_height = f->src_h + f->src_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030054
Ian Armstrong3b5c1c82007-10-22 14:24:26 -030055 if (f->offset_y)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030056 y_buffer_offset += 720 * 16;
57
58 if (y_decode_height & 15)
59 y_decode_height = (y_decode_height + 16) & ~15;
60
61 if (uv_decode_height & 31)
62 uv_decode_height = (uv_decode_height + 32) & ~31;
63
64 y_size = 720 * y_decode_height;
65
66 /* Still in USE */
67 if (dma->SG_length || dma->page_count) {
68 IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
69 dma->SG_length, dma->page_count);
70 return -EBUSY;
71 }
72
73 ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
74 ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
75
76 /* Get user pages for DMA Xfer */
77 down_read(&current->mm->mmap_sem);
78 y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
79 uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
80 up_read(&current->mm->mmap_sem);
81
82 dma->page_count = y_dma.page_count + uv_dma.page_count;
83
84 if (y_pages + uv_pages != dma->page_count) {
85 IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
86 y_pages + uv_pages, dma->page_count);
87
88 for (i = 0; i < dma->page_count; i++) {
89 put_page(dma->map[i]);
90 }
91 dma->page_count = 0;
92 return -EINVAL;
93 }
94
95 /* Fill & map SG List */
Hans Verkuil8beb0582007-08-19 17:56:41 -030096 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 -030097 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
98 for (i = 0; i < dma->page_count; i++) {
99 put_page(dma->map[i]);
100 }
101 dma->page_count = 0;
102 return -ENOMEM;
103 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300104 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
105
106 /* Fill SG Array with new values */
107 ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
108
109 /* If we've offset the y plane, ensure top area is blanked */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300110 if (f->offset_y && itv->yuv_info.blanking_dmaptr) {
111 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
112 dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
113 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
114 dma->SG_length++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300115 }
116
117 /* Tag SG Array with Interrupt Bit */
118 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
119
120 ivtv_udma_sync_for_device(itv);
121 return 0;
122}
123
124/* We rely on a table held in the firmware - Quick check. */
125int ivtv_yuv_filter_check(struct ivtv *itv)
126{
127 int i, offset_y, offset_uv;
128
129 for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
130 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
131 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
132 IVTV_WARN ("YUV filter table not found in firmware.\n");
133 return -1;
134 }
135 }
136 return 0;
137}
138
139static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
140{
141 int filter_index, filter_line;
142
143 /* If any filter is -1, then don't update it */
144 if (h_filter > -1) {
145 if (h_filter > 4) h_filter = 4;
146 filter_index = h_filter * 384;
147 filter_line = 0;
148 while (filter_line < 16) {
149 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
150 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
151 filter_index += 4;
152 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
153 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
154 filter_index += 4;
155 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
156 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
157 filter_index += 4;
158 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
159 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
160 filter_index += 4;
161 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
162 write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
163 filter_index += 8;
164 write_reg(0, 0x02818);
165 write_reg(0, 0x02830);
166 filter_line ++;
167 }
168 IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
169 }
170
171 if (v_filter_1 > -1) {
172 if (v_filter_1 > 4) v_filter_1 = 4;
173 filter_index = v_filter_1 * 192;
174 filter_line = 0;
175 while (filter_line < 16) {
176 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
177 filter_index += 4;
178 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
179 filter_index += 8;
180 write_reg(0, 0x02908);
181 filter_line ++;
182 }
183 IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
184 }
185
186 if (v_filter_2 > -1) {
187 if (v_filter_2 > 4) v_filter_2 = 4;
188 filter_index = v_filter_2 * 192;
189 filter_line = 0;
190 while (filter_line < 16) {
191 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
192 filter_index += 4;
193 write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
194 filter_index += 8;
195 write_reg(0, 0x02914);
196 filter_line ++;
197 }
198 IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
199 }
200}
201
202static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
203{
204 u32 reg_2834, reg_2838, reg_283c;
205 u32 reg_2844, reg_2854, reg_285c;
206 u32 reg_2864, reg_2874, reg_2890;
207 u32 reg_2870, reg_2870_base, reg_2870_offset;
208 int x_cutoff;
209 int h_filter;
210 u32 master_width;
211
212 IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
213 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
214
215 /* How wide is the src image */
216 x_cutoff = window->src_w + window->src_x;
217
218 /* Set the display width */
219 reg_2834 = window->dst_w;
220 reg_2838 = reg_2834;
221
222 /* Set the display position */
223 reg_2890 = window->dst_x;
224
225 /* Index into the image horizontally */
226 reg_2870 = 0;
227
228 /* 2870 is normally fudged to align video coords with osd coords.
229 If running full screen, it causes an unwanted left shift
230 Remove the fudge if we almost fill the screen.
231 Gradually adjust the offset to avoid the video 'snapping'
232 left/right if it gets dragged through this region.
233 Only do this if osd is full width. */
234 if (window->vis_w == 720) {
235 if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
236 reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
237 }
238 else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
239 reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
240 }
241
242 if (window->dst_w >= window->src_w)
243 reg_2870 = reg_2870 << 16 | reg_2870;
244 else
245 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
246 }
247
248 if (window->dst_w < window->src_w)
249 reg_2870 = 0x000d000e - reg_2870;
250 else
251 reg_2870 = 0x0012000e - reg_2870;
252
253 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
254 reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
255
256 if (window->dst_w >= window->src_w) {
257 x_cutoff &= ~1;
258 master_width = (window->src_w * 0x00200000) / (window->dst_w);
259 if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
260 reg_2834 = (reg_2834 << 16) | x_cutoff;
261 reg_2838 = (reg_2838 << 16) | x_cutoff;
262 reg_283c = master_width >> 2;
263 reg_2844 = master_width >> 2;
264 reg_2854 = master_width;
265 reg_285c = master_width >> 1;
266 reg_2864 = master_width >> 1;
267
268 /* We also need to factor in the scaling
269 (src_w - dst_w) / (src_w / 4) */
270 if (window->dst_w > window->src_w)
271 reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
272 else
273 reg_2870_base = 0;
274
275 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
276 reg_2874 = 0;
277 }
278 else if (window->dst_w < window->src_w / 2) {
279 master_width = (window->src_w * 0x00080000) / window->dst_w;
280 if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
281 reg_2834 = (reg_2834 << 16) | x_cutoff;
282 reg_2838 = (reg_2838 << 16) | x_cutoff;
283 reg_283c = master_width >> 2;
284 reg_2844 = master_width >> 1;
285 reg_2854 = master_width;
286 reg_285c = master_width >> 1;
287 reg_2864 = master_width >> 1;
288 reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
289 reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
290 reg_2874 = 0x00000012;
291 }
292 else {
293 master_width = (window->src_w * 0x00100000) / window->dst_w;
294 if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
295 reg_2834 = (reg_2834 << 16) | x_cutoff;
296 reg_2838 = (reg_2838 << 16) | x_cutoff;
297 reg_283c = master_width >> 2;
298 reg_2844 = master_width >> 1;
299 reg_2854 = master_width;
300 reg_285c = master_width >> 1;
301 reg_2864 = master_width >> 1;
302 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
303 reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
304 reg_2874 = 0x00000001;
305 }
306
307 /* Select the horizontal filter */
308 if (window->src_w == window->dst_w) {
309 /* An exact size match uses filter 0 */
310 h_filter = 0;
311 }
312 else {
313 /* Figure out which filter to use */
314 h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
315 h_filter = (h_filter >> 1) + (h_filter & 1);
316 /* Only an exact size match can use filter 0 */
317 if (h_filter == 0) h_filter = 1;
318 }
319
320 write_reg(reg_2834, 0x02834);
321 write_reg(reg_2838, 0x02838);
322 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);
323
324 write_reg(reg_283c, 0x0283c);
325 write_reg(reg_2844, 0x02844);
326
327 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);
328
329 write_reg(0x00080514, 0x02840);
330 write_reg(0x00100514, 0x02848);
331 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
332
333 write_reg(reg_2854, 0x02854);
334 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
335
336 write_reg(reg_285c, 0x0285c);
337 write_reg(reg_2864, 0x02864);
338 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);
339
340 write_reg(reg_2874, 0x02874);
341 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
342
343 write_reg(reg_2870, 0x02870);
344 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
345
346 write_reg( reg_2890,0x02890);
347 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
348
349 /* Only update the filter if we really need to */
350 if (h_filter != itv->yuv_info.h_filter) {
351 ivtv_yuv_filter (itv,h_filter,-1,-1);
352 itv->yuv_info.h_filter = h_filter;
353 }
354}
355
356static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
357{
358 u32 master_height;
359 u32 reg_2918, reg_291c, reg_2920, reg_2928;
360 u32 reg_2930, reg_2934, reg_293c;
361 u32 reg_2940, reg_2944, reg_294c;
362 u32 reg_2950, reg_2954, reg_2958, reg_295c;
363 u32 reg_2960, reg_2964, reg_2968, reg_296c;
364 u32 reg_289c;
365 u32 src_y_major_y, src_y_minor_y;
366 u32 src_y_major_uv, src_y_minor_uv;
367 u32 reg_2964_base, reg_2968_base;
368 int v_filter_1, v_filter_2;
369
370 IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
371 window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
372
373 /* What scaling mode is being used... */
374 if (window->interlaced_y) {
375 IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
376 }
377 else {
378 IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
379 }
380
381 if (window->interlaced_uv) {
382 IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
383 }
384 else {
385 IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
386 }
387
388 /* What is the source video being treated as... */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300389 if (window->interlaced) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300390 IVTV_DEBUG_WARN("Source video: Interlaced\n");
391 }
392 else {
393 IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
394 }
395
396 /* We offset into the image using two different index methods, so split
397 the y source coord into two parts. */
398 if (window->src_y < 8) {
399 src_y_minor_uv = window->src_y;
400 src_y_major_uv = 0;
401 }
402 else {
403 src_y_minor_uv = 8;
404 src_y_major_uv = window->src_y - 8;
405 }
406
407 src_y_minor_y = src_y_minor_uv;
408 src_y_major_y = src_y_major_uv;
409
410 if (window->offset_y) src_y_minor_y += 16;
411
412 if (window->interlaced_y)
413 reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
414 else
415 reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
416
417 if (window->interlaced_uv)
418 reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
419 else
420 reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
421
422 reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
423 reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
424
425 if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
426 master_height = (window->src_h * 0x00400000) / window->dst_h;
427 if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
428 reg_2920 = master_height >> 2;
429 reg_2928 = master_height >> 3;
430 reg_2930 = master_height;
431 reg_2940 = master_height >> 1;
432 reg_2964_base >>= 3;
433 reg_2968_base >>= 3;
434 reg_296c = 0x00000000;
435 }
436 else if (window->dst_h >= window->src_h) {
437 master_height = (window->src_h * 0x00400000) / window->dst_h;
438 master_height = (master_height >> 1) + (master_height & 1);
439 reg_2920 = master_height >> 2;
440 reg_2928 = master_height >> 2;
441 reg_2930 = master_height;
442 reg_2940 = master_height >> 1;
443 reg_296c = 0x00000000;
444 if (window->interlaced_y) {
445 reg_2964_base >>= 3;
446 }
447 else {
448 reg_296c ++;
449 reg_2964_base >>= 2;
450 }
451 if (window->interlaced_uv) reg_2928 >>= 1;
452 reg_2968_base >>= 3;
453 }
454 else if (window->dst_h >= window->src_h / 2) {
455 master_height = (window->src_h * 0x00200000) / window->dst_h;
456 master_height = (master_height >> 1) + (master_height & 1);
457 reg_2920 = master_height >> 2;
458 reg_2928 = master_height >> 2;
459 reg_2930 = master_height;
460 reg_2940 = master_height;
461 reg_296c = 0x00000101;
462 if (window->interlaced_y) {
463 reg_2964_base >>= 2;
464 }
465 else {
466 reg_296c ++;
467 reg_2964_base >>= 1;
468 }
469 if (window->interlaced_uv) reg_2928 >>= 1;
470 reg_2968_base >>= 2;
471 }
472 else {
473 master_height = (window->src_h * 0x00100000) / window->dst_h;
474 master_height = (master_height >> 1) + (master_height & 1);
475 reg_2920 = master_height >> 2;
476 reg_2928 = master_height >> 2;
477 reg_2930 = master_height;
478 reg_2940 = master_height;
479 reg_2964_base >>= 1;
480 reg_2968_base >>= 2;
481 reg_296c = 0x00000102;
482 }
483
484 /* FIXME These registers change depending on scaled / unscaled output
485 We really need to work out what they should be */
486 if (window->src_h == window->dst_h){
487 reg_2934 = 0x00020000;
488 reg_293c = 0x00100000;
489 reg_2944 = 0x00040000;
490 reg_294c = 0x000b0000;
491 }
492 else {
493 reg_2934 = 0x00000FF0;
494 reg_293c = 0x00000FF0;
495 reg_2944 = 0x00000FF0;
496 reg_294c = 0x00000FF0;
497 }
498
499 /* The first line to be displayed */
500 reg_2950 = 0x00010000 + src_y_major_y;
501 if (window->interlaced_y) reg_2950 += 0x00010000;
502 reg_2954 = reg_2950 + 1;
503
504 reg_2958 = 0x00010000 + (src_y_major_y >> 1);
505 if (window->interlaced_uv) reg_2958 += 0x00010000;
506 reg_295c = reg_2958 + 1;
507
508 if (itv->yuv_info.decode_height == 480)
509 reg_289c = 0x011e0017;
510 else
511 reg_289c = 0x01500017;
512
513 if (window->dst_y < 0)
514 reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
515 else
516 reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
517
518 /* How much of the source to decode.
519 Take into account the source offset */
520 reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
521 ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
522
523 /* Calculate correct value for register 2964 */
524 if (window->src_h == window->dst_h)
525 reg_2964 = 1;
526 else {
527 reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
528 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
529 }
530 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
531 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
532
533 /* Okay, we've wasted time working out the correct value,
534 but if we use it, it fouls the the window alignment.
535 Fudge it to what we want... */
536 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
537 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
538
539 /* Deviate further from what it should be. I find the flicker headache
540 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
541 colours foul. */
542 if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
543 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
544
545 if (!window->interlaced_y) reg_2964 -= 0x00010001;
546 if (!window->interlaced_uv) reg_2968 -= 0x00010001;
547
548 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
549 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
550
551 /* Select the vertical filter */
552 if (window->src_h == window->dst_h) {
553 /* An exact size match uses filter 0/1 */
554 v_filter_1 = 0;
555 v_filter_2 = 1;
556 }
557 else {
558 /* Figure out which filter to use */
559 v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
560 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
561 /* Only an exact size match can use filter 0 */
562 if (v_filter_1 == 0) v_filter_1 = 1;
563 v_filter_2 = v_filter_1;
564 }
565
566 write_reg(reg_2934, 0x02934);
567 write_reg(reg_293c, 0x0293c);
568 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);
569 write_reg(reg_2944, 0x02944);
570 write_reg(reg_294c, 0x0294c);
571 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);
572
573 /* Ensure 2970 is 0 (does it ever change ?) */
574/* write_reg(0,0x02970); */
575/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
576
577 write_reg(reg_2930, 0x02938);
578 write_reg(reg_2930, 0x02930);
579 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);
580
581 write_reg(reg_2928, 0x02928);
582 write_reg(reg_2928+0x514, 0x0292C);
583 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);
584
585 write_reg(reg_2920, 0x02920);
586 write_reg(reg_2920+0x514, 0x02924);
587 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);
588
589 write_reg (reg_2918,0x02918);
590 write_reg (reg_291c,0x0291C);
591 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);
592
593 write_reg(reg_296c, 0x0296c);
594 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
595
596 write_reg(reg_2940, 0x02948);
597 write_reg(reg_2940, 0x02940);
598 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);
599
600 write_reg(reg_2950, 0x02950);
601 write_reg(reg_2954, 0x02954);
602 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);
603
604 write_reg(reg_2958, 0x02958);
605 write_reg(reg_295c, 0x0295C);
606 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);
607
608 write_reg(reg_2960, 0x02960);
609 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
610
611 write_reg(reg_2964, 0x02964);
612 write_reg(reg_2968, 0x02968);
613 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);
614
615 write_reg( reg_289c,0x0289c);
616 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
617
618 /* Only update filter 1 if we really need to */
619 if (v_filter_1 != itv->yuv_info.v_filter_1) {
620 ivtv_yuv_filter (itv,-1,v_filter_1,-1);
621 itv->yuv_info.v_filter_1 = v_filter_1;
622 }
623
624 /* Only update filter 2 if we really need to */
625 if (v_filter_2 != itv->yuv_info.v_filter_2) {
626 ivtv_yuv_filter (itv,-1,-1,v_filter_2);
627 itv->yuv_info.v_filter_2 = v_filter_2;
628 }
629
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300630}
631
632/* Modify the supplied coordinate information to fit the visible osd area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300633static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300634{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300635 struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
636 int osd_crop;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300637 u32 osd_scale;
638 u32 yuv_update = 0;
639
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300640 /* Sorry, but no negative coords for src */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300641 if (f->src_x < 0)
642 f->src_x = 0;
643 if (f->src_y < 0)
644 f->src_y = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300645
646 /* Can only reduce width down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300647 if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
648 f->src_x += osd_crop / 2;
649 f->src_w = (f->src_w - osd_crop) & ~3;
650 f->dst_w = f->src_w / 4;
651 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300652 }
653
654 /* Can only reduce height down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300655 if (f->src_h / f->dst_h >= 2) {
656 /* Overflow may be because we're running progressive,
657 so force mode switch */
658 f->interlaced_y = 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300659 /* Make sure we're still within limits for interlace */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300660 if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300661 /* If we reach here we'll have to force the height. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300662 f->src_y += osd_crop / 2;
663 f->src_h = (f->src_h - osd_crop) & ~3;
664 f->dst_h = f->src_h / 4;
665 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300666 }
667 }
668
669 /* If there's nothing to safe to display, we may as well stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300670 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
671 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300672 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300673 }
674
675 /* Ensure video remains inside OSD area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300676 osd_scale = (f->src_h << 16) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300677
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300678 if ((osd_crop = f->pan_y - f->dst_y) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300679 /* Falls off the upper edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300680 f->src_y += (osd_scale * osd_crop) >> 16;
681 f->src_h -= (osd_scale * osd_crop) >> 16;
682 f->dst_h -= osd_crop;
683 f->dst_y = 0;
684 } else {
685 f->dst_y -= f->pan_y;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300686 }
687
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300688 if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300689 /* Falls off the lower edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300690 f->dst_h -= osd_crop;
691 f->src_h -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300692 }
693
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300694 osd_scale = (f->src_w << 16) / f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300695
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300696 if ((osd_crop = f->pan_x - f->dst_x) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300697 /* Fall off the left edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300698 f->src_x += (osd_scale * osd_crop) >> 16;
699 f->src_w -= (osd_scale * osd_crop) >> 16;
700 f->dst_w -= osd_crop;
701 f->dst_x = 0;
702 } else {
703 f->dst_x -= f->pan_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300704 }
705
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300706 if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300707 /* Falls off the right edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300708 f->dst_w -= osd_crop;
709 f->src_w -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300710 }
711
712 /* The OSD can be moved. Track to it */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300713 f->dst_x += itv->yuv_info.osd_x_offset;
714 f->dst_y += itv->yuv_info.osd_y_offset;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300715
716 /* Width & height for both src & dst must be even.
717 Same for coordinates. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300718 f->dst_w &= ~1;
719 f->dst_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300720
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300721 f->src_w += f->src_x & 1;
722 f->src_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300723
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300724 f->src_w &= ~1;
725 f->dst_w &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300726
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300727 f->dst_h &= ~1;
728 f->dst_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300729
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300730 f->src_h += f->src_y & 1;
731 f->src_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300732
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300733 f->src_h &= ~1;
734 f->dst_h &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300735
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300736 /* Due to rounding, we may have reduced the output size to <1/4 of
737 the source. Check again, but this time just resize. Don't change
738 source coordinates */
739 if (f->dst_w < f->src_w / 4) {
740 f->src_w &= ~3;
741 f->dst_w = f->src_w / 4;
742 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300743 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300744 if (f->dst_h < f->src_h / 4) {
745 f->src_h &= ~3;
746 f->dst_h = f->src_h / 4;
747 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300748 }
749
750 /* Check again. If there's nothing to safe to display, stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300751 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
752 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300753 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300754 }
755
756 /* Both x offset & width are linked, so they have to be done together */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300757 if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
758 (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
759 (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300760 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
761 }
762
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300763 if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
764 (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
765 (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
766 (of->lace_mode != f->lace_mode) ||
767 (of->interlaced_y != f->interlaced_y) ||
768 (of->interlaced_uv != f->interlaced_uv)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300769 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
770 }
771
772 return yuv_update;
773}
774
775/* Update the scaling register to the requested value */
Hans Verkuil1e13f9e2007-03-10 06:52:02 -0300776void ivtv_yuv_work_handler (struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300777{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300778 struct yuv_playback_info *yi = &itv->yuv_info;
779 struct yuv_frame_info f;
780 int frame = yi->update_frame;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300781 u32 yuv_update;
782
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300783/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300784 f = yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300785
786 /* Update the osd pan info */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300787 f.pan_x = itv->yuv_info.osd_x_pan;
788 f.pan_y = itv->yuv_info.osd_y_pan;
789 f.vis_w = itv->yuv_info.osd_vis_w;
790 f.vis_h = itv->yuv_info.osd_vis_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300791
792 /* Calculate the display window coordinates. Exit if nothing left */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300793 if (!(yuv_update = ivtv_yuv_window_setup (itv, &f)))
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300794 return;
795
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300796 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
797 write_reg(0x01008080, 0x2898);
798 } else if (yuv_update) {
799 write_reg(0x00108080, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300800
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300801 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300802 ivtv_yuv_handle_horizontal(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300803
804 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300805 ivtv_yuv_handle_vertical(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300806 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300807 yi->old_frame_info = f;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300808}
809
810static void ivtv_yuv_init (struct ivtv *itv)
811{
Ian Armstrong195b1252007-10-14 13:12:28 -0300812 struct yuv_playback_info *yi = &itv->yuv_info;
813
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300814 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
815
816 /* Take a snapshot of the current register settings */
Ian Armstrong195b1252007-10-14 13:12:28 -0300817 yi->reg_2834 = read_reg(0x02834);
818 yi->reg_2838 = read_reg(0x02838);
819 yi->reg_283c = read_reg(0x0283c);
820 yi->reg_2840 = read_reg(0x02840);
821 yi->reg_2844 = read_reg(0x02844);
822 yi->reg_2848 = read_reg(0x02848);
823 yi->reg_2854 = read_reg(0x02854);
824 yi->reg_285c = read_reg(0x0285c);
825 yi->reg_2864 = read_reg(0x02864);
826 yi->reg_2870 = read_reg(0x02870);
827 yi->reg_2874 = read_reg(0x02874);
828 yi->reg_2898 = read_reg(0x02898);
829 yi->reg_2890 = read_reg(0x02890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300830
Ian Armstrong195b1252007-10-14 13:12:28 -0300831 yi->reg_289c = read_reg(0x0289c);
832 yi->reg_2918 = read_reg(0x02918);
833 yi->reg_291c = read_reg(0x0291c);
834 yi->reg_2920 = read_reg(0x02920);
835 yi->reg_2924 = read_reg(0x02924);
836 yi->reg_2928 = read_reg(0x02928);
837 yi->reg_292c = read_reg(0x0292c);
838 yi->reg_2930 = read_reg(0x02930);
839 yi->reg_2934 = read_reg(0x02934);
840 yi->reg_2938 = read_reg(0x02938);
841 yi->reg_293c = read_reg(0x0293c);
842 yi->reg_2940 = read_reg(0x02940);
843 yi->reg_2944 = read_reg(0x02944);
844 yi->reg_2948 = read_reg(0x02948);
845 yi->reg_294c = read_reg(0x0294c);
846 yi->reg_2950 = read_reg(0x02950);
847 yi->reg_2954 = read_reg(0x02954);
848 yi->reg_2958 = read_reg(0x02958);
849 yi->reg_295c = read_reg(0x0295c);
850 yi->reg_2960 = read_reg(0x02960);
851 yi->reg_2964 = read_reg(0x02964);
852 yi->reg_2968 = read_reg(0x02968);
853 yi->reg_296c = read_reg(0x0296c);
854 yi->reg_2970 = read_reg(0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300855
Ian Armstrong195b1252007-10-14 13:12:28 -0300856 yi->v_filter_1 = -1;
857 yi->v_filter_2 = -1;
858 yi->h_filter = -1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300859
860 /* Set some valid size info */
Ian Armstrong195b1252007-10-14 13:12:28 -0300861 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
862 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300863
864 /* Bit 2 of reg 2878 indicates current decoder output format
865 0 : NTSC 1 : PAL */
866 if (read_reg(0x2878) & 4)
Ian Armstrong195b1252007-10-14 13:12:28 -0300867 yi->decode_height = 576;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300868 else
Ian Armstrong195b1252007-10-14 13:12:28 -0300869 yi->decode_height = 480;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300870
Ian Armstrong195b1252007-10-14 13:12:28 -0300871 if (!itv->osd_info) {
872 yi->osd_vis_w = 720 - yi->osd_x_offset;
873 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300874 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300875 /* If no visible size set, assume full size */
876 if (!yi->osd_vis_w)
877 yi->osd_vis_w = 720 - yi->osd_x_offset;
878
879 if (!yi->osd_vis_h)
880 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
881 else {
882 /* If output video standard has changed, requested height may
883 not be legal */
884 if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
885 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
886 yi->osd_vis_h + yi->osd_y_offset,
887 yi->decode_height);
888 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
889 }
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300890 }
891 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300892
893 /* 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 -0300894 yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
895 if (yi->blanking_ptr)
896 yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300897 else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300898 yi->blanking_dmaptr = 0;
899 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300900 }
901
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300902 /* Enable YUV decoder output */
903 write_reg_sync(0x01, IVTV_REG_VDM);
904
905 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
Ian Armstrong195b1252007-10-14 13:12:28 -0300906 atomic_set(&yi->next_dma_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300907}
908
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300909/* Get next available yuv buffer on PVR350 */
910void ivtv_yuv_next_free(struct ivtv *itv)
911{
912 int draw, display;
913 struct yuv_playback_info *yi = &itv->yuv_info;
914
915 if (atomic_read(&yi->next_dma_frame) == -1)
916 ivtv_yuv_init(itv);
917
918 draw = atomic_read(&yi->next_fill_frame);
919 display = atomic_read(&yi->next_dma_frame);
920
921 if (display > draw)
922 display -= IVTV_YUV_BUFFERS;
923
924 if (draw - display >= yi->max_frames_buffered)
925 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
926 else
927 yi->new_frame_info[draw].update = 0;
928
929 yi->draw_frame = draw;
930}
931
932/* Set up frame according to ivtv_dma_frame parameters */
933void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
934{
935 struct yuv_playback_info *yi = &itv->yuv_info;
936 u8 frame = yi->draw_frame;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300937 u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
938 struct yuv_frame_info *nf = &yi->new_frame_info[frame];
939 struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
940 int lace_threshold = yi->lace_threshold;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300941
942 /* Preserve old update flag in case we're overwriting a queued frame */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300943 int update = nf->update;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300944
945 /* Take a snapshot of the yuv coordinate information */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300946 nf->src_x = args->src.left;
947 nf->src_y = args->src.top;
948 nf->src_w = args->src.width;
949 nf->src_h = args->src.height;
950 nf->dst_x = args->dst.left;
951 nf->dst_y = args->dst.top;
952 nf->dst_w = args->dst.width;
953 nf->dst_h = args->dst.height;
954 nf->tru_x = args->dst.left;
955 nf->tru_w = args->src_width;
956 nf->tru_h = args->src_height;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300957
958 /* Are we going to offset the Y plane */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300959 nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300960
961 /* Snapshot the osd pan info */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300962 nf->pan_x = yi->osd_x_pan;
963 nf->pan_y = yi->osd_y_pan;
964 nf->vis_w = yi->osd_vis_w;
965 nf->vis_h = yi->osd_vis_h;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300966
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300967 nf->update = 0;
968 nf->interlaced_y = 0;
969 nf->interlaced_uv = 0;
970 nf->delay = 0;
971 nf->sync_field = 0;
972 nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300973
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300974 if (lace_threshold < 0)
975 lace_threshold = yi->decode_height - 1;
976
977 /* Work out the lace settings */
978 switch (nf->lace_mode) {
979 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
980 nf->interlaced = 0;
981 if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
982 nf->interlaced_y = 0;
983 else
984 nf->interlaced_y = 1;
985
986 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
987 nf->interlaced_uv = 0;
988 else
989 nf->interlaced_uv = 1;
990 break;
991
992 case IVTV_YUV_MODE_AUTO:
993 if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
994 nf->interlaced = 0;
995 if ((nf->tru_h < 512) ||
996 (nf->tru_h > 576 && nf->tru_h < 1021) ||
997 (nf->tru_w > 720 && nf->tru_h < 1021))
998 nf->interlaced_y = 0;
999 else
1000 nf->interlaced_y = 1;
1001 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1002 nf->interlaced_uv = 0;
1003 else
1004 nf->interlaced_uv = 1;
1005 } else {
1006 nf->interlaced = 1;
1007 nf->interlaced_y = 1;
1008 nf->interlaced_uv = 1;
1009 }
1010 break;
1011
1012 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1013 default:
1014 nf->interlaced = 1;
1015 nf->interlaced_y = 1;
1016 nf->interlaced_uv = 1;
1017 break;
1018 }
1019
1020 if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1021 yi->old_frame_info_args = *nf;
1022 nf->update = 1;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001023/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
1024 }
1025
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001026 nf->update |= update;
1027 nf->sync_field = yi->lace_sync_field;
1028 nf->delay = nf->sync_field != of->sync_field;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001029}
1030
1031/* Frame is complete & ready for display */
1032void ivtv_yuv_frame_complete(struct ivtv *itv)
1033{
1034 atomic_set(&itv->yuv_info.next_fill_frame,
1035 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1036}
1037
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001038int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1039{
1040 DEFINE_WAIT(wait);
1041 int rc = 0;
1042 int got_sig = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001043
1044 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1045
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001046 ivtv_yuv_next_free(itv);
1047 ivtv_yuv_setup_frame(itv, args);
Ian Armstrongbfd7bea2007-08-03 10:01:39 -03001048
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001049 /* DMA the frame */
1050 mutex_lock(&itv->udma.lock);
1051
1052 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1053 mutex_unlock(&itv->udma.lock);
1054 return rc;
1055 }
1056
1057 ivtv_udma_prepare(itv);
1058 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1059 /* if no UDMA is pending and no UDMA is in progress, then the DMA
1060 is finished */
1061 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1062 /* don't interrupt if the DMA is in progress but break off
1063 a still pending DMA. */
1064 got_sig = signal_pending(current);
1065 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1066 break;
1067 got_sig = 0;
1068 schedule();
1069 }
1070 finish_wait(&itv->dma_waitq, &wait);
1071
1072 /* Unmap Last DMA Xfer */
1073 ivtv_udma_unmap(itv);
1074
1075 if (got_sig) {
1076 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1077 mutex_unlock(&itv->udma.lock);
1078 return -EINTR;
1079 }
1080
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001081 ivtv_yuv_frame_complete(itv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001082
1083 mutex_unlock(&itv->udma.lock);
1084 return rc;
1085}
1086
1087void ivtv_yuv_close(struct ivtv *itv)
1088{
1089 int h_filter, v_filter_1, v_filter_2;
1090
1091 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1092 ivtv_waitq(&itv->vsync_waitq);
1093
1094 atomic_set(&itv->yuv_info.next_dma_frame, -1);
1095 atomic_set(&itv->yuv_info.next_fill_frame, 0);
1096
1097 /* Reset registers we have changed so mpeg playback works */
1098
1099 /* If we fully restore this register, the display may remain active.
1100 Restore, but set one bit to blank the video. Firmware will always
1101 clear this bit when needed, so not a problem. */
1102 write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1103
1104 write_reg(itv->yuv_info.reg_2834, 0x02834);
1105 write_reg(itv->yuv_info.reg_2838, 0x02838);
1106 write_reg(itv->yuv_info.reg_283c, 0x0283c);
1107 write_reg(itv->yuv_info.reg_2840, 0x02840);
1108 write_reg(itv->yuv_info.reg_2844, 0x02844);
1109 write_reg(itv->yuv_info.reg_2848, 0x02848);
1110 write_reg(itv->yuv_info.reg_2854, 0x02854);
1111 write_reg(itv->yuv_info.reg_285c, 0x0285c);
1112 write_reg(itv->yuv_info.reg_2864, 0x02864);
1113 write_reg(itv->yuv_info.reg_2870, 0x02870);
1114 write_reg(itv->yuv_info.reg_2874, 0x02874);
1115 write_reg(itv->yuv_info.reg_2890, 0x02890);
1116 write_reg(itv->yuv_info.reg_289c, 0x0289c);
1117
1118 write_reg(itv->yuv_info.reg_2918, 0x02918);
1119 write_reg(itv->yuv_info.reg_291c, 0x0291c);
1120 write_reg(itv->yuv_info.reg_2920, 0x02920);
1121 write_reg(itv->yuv_info.reg_2924, 0x02924);
1122 write_reg(itv->yuv_info.reg_2928, 0x02928);
1123 write_reg(itv->yuv_info.reg_292c, 0x0292c);
1124 write_reg(itv->yuv_info.reg_2930, 0x02930);
1125 write_reg(itv->yuv_info.reg_2934, 0x02934);
1126 write_reg(itv->yuv_info.reg_2938, 0x02938);
1127 write_reg(itv->yuv_info.reg_293c, 0x0293c);
1128 write_reg(itv->yuv_info.reg_2940, 0x02940);
1129 write_reg(itv->yuv_info.reg_2944, 0x02944);
1130 write_reg(itv->yuv_info.reg_2948, 0x02948);
1131 write_reg(itv->yuv_info.reg_294c, 0x0294c);
1132 write_reg(itv->yuv_info.reg_2950, 0x02950);
1133 write_reg(itv->yuv_info.reg_2954, 0x02954);
1134 write_reg(itv->yuv_info.reg_2958, 0x02958);
1135 write_reg(itv->yuv_info.reg_295c, 0x0295c);
1136 write_reg(itv->yuv_info.reg_2960, 0x02960);
1137 write_reg(itv->yuv_info.reg_2964, 0x02964);
1138 write_reg(itv->yuv_info.reg_2968, 0x02968);
1139 write_reg(itv->yuv_info.reg_296c, 0x0296c);
1140 write_reg(itv->yuv_info.reg_2970, 0x02970);
1141
1142 /* Prepare to restore filters */
1143
1144 /* First the horizontal filter */
1145 if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1146 /* An exact size match uses filter 0 */
1147 h_filter = 0;
1148 }
1149 else {
1150 /* Figure out which filter to use */
1151 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1152 h_filter = (h_filter >> 1) + (h_filter & 1);
1153 /* Only an exact size match can use filter 0. */
1154 if (h_filter < 1) h_filter = 1;
1155 }
1156
1157 /* Now the vertical filter */
1158 if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1159 /* An exact size match uses filter 0/1 */
1160 v_filter_1 = 0;
1161 v_filter_2 = 1;
1162 }
1163 else {
1164 /* Figure out which filter to use */
1165 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1166 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1167 /* Only an exact size match can use filter 0 */
1168 if (v_filter_1 == 0) v_filter_1 = 1;
1169 v_filter_2 = v_filter_1;
1170 }
1171
1172 /* Now restore the filters */
1173 ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1174
1175 /* and clear a few registers */
1176 write_reg(0, 0x02814);
1177 write_reg(0, 0x0282c);
1178 write_reg(0, 0x02904);
1179 write_reg(0, 0x02910);
1180
1181 /* Release the blanking buffer */
1182 if (itv->yuv_info.blanking_ptr) {
1183 kfree (itv->yuv_info.blanking_ptr);
1184 itv->yuv_info.blanking_ptr = NULL;
1185 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1186 }
1187
1188 /* Invalidate the old dimension information */
1189 itv->yuv_info.old_frame_info.src_w = 0;
1190 itv->yuv_info.old_frame_info.src_h = 0;
1191 itv->yuv_info.old_frame_info_args.src_w = 0;
1192 itv->yuv_info.old_frame_info_args.src_h = 0;
1193
1194 /* All done. */
1195 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1196}
1197