Merge git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / media / video / ivtv / ivtv-yuv.c
CommitLineData
1a0adaf3
HV
1/*
2 yuv support
3
4 Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "ivtv-driver.h"
1a0adaf3 22#include "ivtv-udma.h"
83df8e7b 23#include "ivtv-yuv.h"
1a0adaf3 24
a3e5f5e2
IA
25/* YUV buffer offsets */
26const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
27 0x001a8600,
28 0x00240400,
29 0x002d8200,
30 0x00370000,
31 0x00029000,
32 0x000C0E00,
33 0x006B0400,
34 0x00748200
612570f2
HV
35};
36
1a0adaf3 37static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
2b057e8d 38 struct ivtv_dma_frame *args)
1a0adaf3
HV
39{
40 struct ivtv_dma_page_info y_dma;
41 struct ivtv_dma_page_info uv_dma;
3b5c1c8e
IA
42 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];
1a0adaf3
HV
45 int i;
46 int y_pages, uv_pages;
1a0adaf3
HV
47 unsigned long y_buffer_offset, uv_buffer_offset;
48 int y_decode_height, uv_decode_height, y_size;
1a0adaf3 49
33c0fcad 50 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
1a0adaf3
HV
51 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
52
2b057e8d 53 y_decode_height = uv_decode_height = f->src_h + f->src_y;
1a0adaf3 54
3b5c1c8e 55 if (f->offset_y)
1a0adaf3
HV
56 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) {
2b057e8d
IA
68 IVTV_DEBUG_WARN
69 ("prep_user_dma: SG_length %d page_count %d still full?\n",
70 dma->SG_length, dma->page_count);
1a0adaf3
HV
71 return -EBUSY;
72 }
73
74 ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
75 ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
76
77 /* Get user pages for DMA Xfer */
78 down_read(&current->mm->mmap_sem);
79 y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
7fd4b41f
PC
80 uv_pages = 0; /* silence gcc. value is set and consumed only if: */
81 if (y_pages == y_dma.page_count) {
82 uv_pages = get_user_pages(current, current->mm,
83 uv_dma.uaddr, uv_dma.page_count, 0, 1,
84 &dma->map[y_pages], NULL);
85 }
1a0adaf3
HV
86 up_read(&current->mm->mmap_sem);
87
7fd4b41f
PC
88 if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
89 int rc = -EFAULT;
90
91 if (y_pages == y_dma.page_count) {
92 IVTV_DEBUG_WARN
93 ("failed to map uv user pages, returned %d "
94 "expecting %d\n", uv_pages, uv_dma.page_count);
95
96 if (uv_pages >= 0) {
97 for (i = 0; i < uv_pages; i++)
98 put_page(dma->map[y_pages + i]);
99 rc = -EFAULT;
100 } else {
101 rc = uv_pages;
102 }
103 } else {
104 IVTV_DEBUG_WARN
105 ("failed to map y user pages, returned %d "
106 "expecting %d\n", y_pages, y_dma.page_count);
1a0adaf3 107 }
7fd4b41f
PC
108 if (y_pages >= 0) {
109 for (i = 0; i < y_pages; i++)
110 put_page(dma->map[i]);
111 /*
112 * Inherit the -EFAULT from rc's
113 * initialization, but allow it to be
114 * overriden by uv_pages above if it was an
115 * actual errno.
116 */
117 } else {
118 rc = y_pages;
119 }
120 return rc;
1a0adaf3
HV
121 }
122
7fd4b41f
PC
123 dma->page_count = y_pages + uv_pages;
124
1a0adaf3 125 /* Fill & map SG List */
8beb058f 126 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
0989fd2c
HV
127 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
128 for (i = 0; i < dma->page_count; i++) {
129 put_page(dma->map[i]);
130 }
131 dma->page_count = 0;
132 return -ENOMEM;
133 }
8ac05ae3 134 dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
1a0adaf3
HV
135
136 /* Fill SG Array with new values */
2b057e8d 137 ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
1a0adaf3
HV
138
139 /* If we've offset the y plane, ensure top area is blanked */
2b057e8d 140 if (f->offset_y && yi->blanking_dmaptr) {
3b5c1c8e 141 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
2b057e8d 142 dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
3b5c1c8e
IA
143 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
144 dma->SG_length++;
1a0adaf3
HV
145 }
146
147 /* Tag SG Array with Interrupt Bit */
148 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
149
150 ivtv_udma_sync_for_device(itv);
151 return 0;
152}
153
154/* We rely on a table held in the firmware - Quick check. */
155int ivtv_yuv_filter_check(struct ivtv *itv)
156{
2b057e8d 157 int i, y, uv;
1a0adaf3 158
2b057e8d
IA
159 for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
160 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
161 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
1a0adaf3
HV
162 IVTV_WARN ("YUV filter table not found in firmware.\n");
163 return -1;
164 }
165 }
166 return 0;
167}
168
169static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
170{
2b057e8d 171 u32 i, line;
1a0adaf3
HV
172
173 /* If any filter is -1, then don't update it */
174 if (h_filter > -1) {
2b057e8d
IA
175 if (h_filter > 4)
176 h_filter = 4;
177 i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
178 for (line = 0; line < 16; line++) {
179 write_reg(read_dec(i), 0x02804);
180 write_reg(read_dec(i), 0x0281c);
181 i += 4;
182 write_reg(read_dec(i), 0x02808);
183 write_reg(read_dec(i), 0x02820);
184 i += 4;
185 write_reg(read_dec(i), 0x0280c);
186 write_reg(read_dec(i), 0x02824);
187 i += 4;
188 write_reg(read_dec(i), 0x02810);
189 write_reg(read_dec(i), 0x02828);
190 i += 4;
191 write_reg(read_dec(i), 0x02814);
192 write_reg(read_dec(i), 0x0282c);
193 i += 8;
1a0adaf3
HV
194 write_reg(0, 0x02818);
195 write_reg(0, 0x02830);
1a0adaf3 196 }
2b057e8d 197 IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
1a0adaf3
HV
198 }
199
200 if (v_filter_1 > -1) {
2b057e8d
IA
201 if (v_filter_1 > 4)
202 v_filter_1 = 4;
203 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
204 for (line = 0; line < 16; line++) {
205 write_reg(read_dec(i), 0x02900);
206 i += 4;
207 write_reg(read_dec(i), 0x02904);
208 i += 8;
1a0adaf3 209 write_reg(0, 0x02908);
1a0adaf3 210 }
2b057e8d 211 IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
1a0adaf3
HV
212 }
213
214 if (v_filter_2 > -1) {
2b057e8d
IA
215 if (v_filter_2 > 4)
216 v_filter_2 = 4;
217 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
218 for (line = 0; line < 16; line++) {
219 write_reg(read_dec(i), 0x0290c);
220 i += 4;
221 write_reg(read_dec(i), 0x02910);
222 i += 8;
1a0adaf3 223 write_reg(0, 0x02914);
1a0adaf3 224 }
2b057e8d 225 IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
1a0adaf3
HV
226 }
227}
228
2b057e8d 229static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf3 230{
2b057e8d 231 struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf3
HV
232 u32 reg_2834, reg_2838, reg_283c;
233 u32 reg_2844, reg_2854, reg_285c;
234 u32 reg_2864, reg_2874, reg_2890;
235 u32 reg_2870, reg_2870_base, reg_2870_offset;
236 int x_cutoff;
237 int h_filter;
238 u32 master_width;
239
2b057e8d
IA
240 IVTV_DEBUG_WARN
241 ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
242 f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
1a0adaf3
HV
243
244 /* How wide is the src image */
2b057e8d 245 x_cutoff = f->src_w + f->src_x;
1a0adaf3
HV
246
247 /* Set the display width */
2b057e8d 248 reg_2834 = f->dst_w;
1a0adaf3
HV
249 reg_2838 = reg_2834;
250
251 /* Set the display position */
2b057e8d 252 reg_2890 = f->dst_x;
1a0adaf3
HV
253
254 /* Index into the image horizontally */
255 reg_2870 = 0;
256
257 /* 2870 is normally fudged to align video coords with osd coords.
258 If running full screen, it causes an unwanted left shift
259 Remove the fudge if we almost fill the screen.
260 Gradually adjust the offset to avoid the video 'snapping'
261 left/right if it gets dragged through this region.
262 Only do this if osd is full width. */
2b057e8d
IA
263 if (f->vis_w == 720) {
264 if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
265 reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
266 else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
267 reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
1a0adaf3 268
2b057e8d 269 if (f->dst_w >= f->src_w)
1a0adaf3
HV
270 reg_2870 = reg_2870 << 16 | reg_2870;
271 else
272 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
273 }
274
2b057e8d 275 if (f->dst_w < f->src_w)
1a0adaf3
HV
276 reg_2870 = 0x000d000e - reg_2870;
277 else
278 reg_2870 = 0x0012000e - reg_2870;
279
280 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
2b057e8d 281 reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
1a0adaf3 282
2b057e8d 283 if (f->dst_w >= f->src_w) {
1a0adaf3 284 x_cutoff &= ~1;
2b057e8d
IA
285 master_width = (f->src_w * 0x00200000) / (f->dst_w);
286 if (master_width * f->dst_w != f->src_w * 0x00200000)
287 master_width++;
1a0adaf3
HV
288 reg_2834 = (reg_2834 << 16) | x_cutoff;
289 reg_2838 = (reg_2838 << 16) | x_cutoff;
290 reg_283c = master_width >> 2;
291 reg_2844 = master_width >> 2;
292 reg_2854 = master_width;
293 reg_285c = master_width >> 1;
294 reg_2864 = master_width >> 1;
295
296 /* We also need to factor in the scaling
297 (src_w - dst_w) / (src_w / 4) */
2b057e8d
IA
298 if (f->dst_w > f->src_w)
299 reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
1a0adaf3
HV
300 else
301 reg_2870_base = 0;
302
303 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
304 reg_2874 = 0;
2b057e8d
IA
305 } else if (f->dst_w < f->src_w / 2) {
306 master_width = (f->src_w * 0x00080000) / f->dst_w;
307 if (master_width * f->dst_w != f->src_w * 0x00080000)
308 master_width++;
1a0adaf3
HV
309 reg_2834 = (reg_2834 << 16) | x_cutoff;
310 reg_2838 = (reg_2838 << 16) | x_cutoff;
311 reg_283c = master_width >> 2;
312 reg_2844 = master_width >> 1;
313 reg_2854 = master_width;
314 reg_285c = master_width >> 1;
315 reg_2864 = master_width >> 1;
2b057e8d
IA
316 reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
317 reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
1a0adaf3 318 reg_2874 = 0x00000012;
2b057e8d
IA
319 } else {
320 master_width = (f->src_w * 0x00100000) / f->dst_w;
321 if (master_width * f->dst_w != f->src_w * 0x00100000)
322 master_width++;
1a0adaf3
HV
323 reg_2834 = (reg_2834 << 16) | x_cutoff;
324 reg_2838 = (reg_2838 << 16) | x_cutoff;
325 reg_283c = master_width >> 2;
326 reg_2844 = master_width >> 1;
327 reg_2854 = master_width;
328 reg_285c = master_width >> 1;
329 reg_2864 = master_width >> 1;
2b057e8d
IA
330 reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
331 reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
1a0adaf3
HV
332 reg_2874 = 0x00000001;
333 }
334
335 /* Select the horizontal filter */
2b057e8d 336 if (f->src_w == f->dst_w) {
1a0adaf3
HV
337 /* An exact size match uses filter 0 */
338 h_filter = 0;
2b057e8d 339 } else {
1a0adaf3 340 /* Figure out which filter to use */
2b057e8d 341 h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
1a0adaf3
HV
342 h_filter = (h_filter >> 1) + (h_filter & 1);
343 /* Only an exact size match can use filter 0 */
2b057e8d 344 h_filter += !h_filter;
1a0adaf3
HV
345 }
346
347 write_reg(reg_2834, 0x02834);
348 write_reg(reg_2838, 0x02838);
2b057e8d
IA
349 IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
350 yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
1a0adaf3
HV
351
352 write_reg(reg_283c, 0x0283c);
353 write_reg(reg_2844, 0x02844);
354
2b057e8d
IA
355 IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
356 yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
1a0adaf3
HV
357
358 write_reg(0x00080514, 0x02840);
359 write_reg(0x00100514, 0x02848);
2b057e8d
IA
360 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
361 yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
1a0adaf3
HV
362
363 write_reg(reg_2854, 0x02854);
2b057e8d
IA
364 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
365 yi->reg_2854, reg_2854);
1a0adaf3
HV
366
367 write_reg(reg_285c, 0x0285c);
368 write_reg(reg_2864, 0x02864);
2b057e8d
IA
369 IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
370 yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
1a0adaf3
HV
371
372 write_reg(reg_2874, 0x02874);
2b057e8d
IA
373 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
374 yi->reg_2874, reg_2874);
1a0adaf3
HV
375
376 write_reg(reg_2870, 0x02870);
2b057e8d
IA
377 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
378 yi->reg_2870, reg_2870);
1a0adaf3 379
2b057e8d
IA
380 write_reg(reg_2890, 0x02890);
381 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
382 yi->reg_2890, reg_2890);
1a0adaf3
HV
383
384 /* Only update the filter if we really need to */
2b057e8d
IA
385 if (h_filter != yi->h_filter) {
386 ivtv_yuv_filter(itv, h_filter, -1, -1);
387 yi->h_filter = h_filter;
1a0adaf3
HV
388 }
389}
390
2b057e8d 391static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf3 392{
2b057e8d 393 struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf3
HV
394 u32 master_height;
395 u32 reg_2918, reg_291c, reg_2920, reg_2928;
396 u32 reg_2930, reg_2934, reg_293c;
397 u32 reg_2940, reg_2944, reg_294c;
398 u32 reg_2950, reg_2954, reg_2958, reg_295c;
399 u32 reg_2960, reg_2964, reg_2968, reg_296c;
400 u32 reg_289c;
2b057e8d
IA
401 u32 src_major_y, src_minor_y;
402 u32 src_major_uv, src_minor_uv;
1a0adaf3
HV
403 u32 reg_2964_base, reg_2968_base;
404 int v_filter_1, v_filter_2;
405
2b057e8d
IA
406 IVTV_DEBUG_WARN
407 ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
408 f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
1a0adaf3
HV
409
410 /* What scaling mode is being used... */
2b057e8d
IA
411 IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
412 f->interlaced_y ? "Interlaced" : "Progressive");
1a0adaf3 413
2b057e8d
IA
414 IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
415 f->interlaced_uv ? "Interlaced" : "Progressive");
1a0adaf3
HV
416
417 /* What is the source video being treated as... */
2b057e8d
IA
418 IVTV_DEBUG_WARN("Source video: %s\n",
419 f->interlaced ? "Interlaced" : "Progressive");
1a0adaf3
HV
420
421 /* We offset into the image using two different index methods, so split
422 the y source coord into two parts. */
2b057e8d
IA
423 if (f->src_y < 8) {
424 src_minor_uv = f->src_y;
425 src_major_uv = 0;
426 } else {
427 src_minor_uv = 8;
428 src_major_uv = f->src_y - 8;
1a0adaf3
HV
429 }
430
2b057e8d
IA
431 src_minor_y = src_minor_uv;
432 src_major_y = src_major_uv;
1a0adaf3 433
2b057e8d
IA
434 if (f->offset_y)
435 src_minor_y += 16;
1a0adaf3 436
2b057e8d
IA
437 if (f->interlaced_y)
438 reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
1a0adaf3 439 else
2b057e8d 440 reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
1a0adaf3 441
2b057e8d
IA
442 if (f->interlaced_uv)
443 reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
1a0adaf3 444 else
2b057e8d 445 reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
1a0adaf3 446
2b057e8d
IA
447 reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
448 reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
1a0adaf3 449
2b057e8d
IA
450 if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
451 master_height = (f->src_h * 0x00400000) / f->dst_h;
452 if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
453 master_height++;
1a0adaf3
HV
454 reg_2920 = master_height >> 2;
455 reg_2928 = master_height >> 3;
456 reg_2930 = master_height;
457 reg_2940 = master_height >> 1;
458 reg_2964_base >>= 3;
459 reg_2968_base >>= 3;
460 reg_296c = 0x00000000;
2b057e8d
IA
461 } else if (f->dst_h >= f->src_h) {
462 master_height = (f->src_h * 0x00400000) / f->dst_h;
1a0adaf3
HV
463 master_height = (master_height >> 1) + (master_height & 1);
464 reg_2920 = master_height >> 2;
465 reg_2928 = master_height >> 2;
466 reg_2930 = master_height;
467 reg_2940 = master_height >> 1;
468 reg_296c = 0x00000000;
2b057e8d 469 if (f->interlaced_y) {
1a0adaf3 470 reg_2964_base >>= 3;
2b057e8d
IA
471 } else {
472 reg_296c++;
1a0adaf3
HV
473 reg_2964_base >>= 2;
474 }
2b057e8d
IA
475 if (f->interlaced_uv)
476 reg_2928 >>= 1;
1a0adaf3 477 reg_2968_base >>= 3;
2b057e8d
IA
478 } else if (f->dst_h >= f->src_h / 2) {
479 master_height = (f->src_h * 0x00200000) / f->dst_h;
1a0adaf3
HV
480 master_height = (master_height >> 1) + (master_height & 1);
481 reg_2920 = master_height >> 2;
482 reg_2928 = master_height >> 2;
483 reg_2930 = master_height;
484 reg_2940 = master_height;
485 reg_296c = 0x00000101;
2b057e8d 486 if (f->interlaced_y) {
1a0adaf3 487 reg_2964_base >>= 2;
2b057e8d
IA
488 } else {
489 reg_296c++;
1a0adaf3
HV
490 reg_2964_base >>= 1;
491 }
2b057e8d
IA
492 if (f->interlaced_uv)
493 reg_2928 >>= 1;
1a0adaf3 494 reg_2968_base >>= 2;
2b057e8d
IA
495 } else {
496 master_height = (f->src_h * 0x00100000) / f->dst_h;
1a0adaf3
HV
497 master_height = (master_height >> 1) + (master_height & 1);
498 reg_2920 = master_height >> 2;
499 reg_2928 = master_height >> 2;
500 reg_2930 = master_height;
501 reg_2940 = master_height;
502 reg_2964_base >>= 1;
503 reg_2968_base >>= 2;
504 reg_296c = 0x00000102;
505 }
506
507 /* FIXME These registers change depending on scaled / unscaled output
508 We really need to work out what they should be */
2b057e8d 509 if (f->src_h == f->dst_h) {
1a0adaf3
HV
510 reg_2934 = 0x00020000;
511 reg_293c = 0x00100000;
512 reg_2944 = 0x00040000;
513 reg_294c = 0x000b0000;
2b057e8d 514 } else {
1a0adaf3
HV
515 reg_2934 = 0x00000FF0;
516 reg_293c = 0x00000FF0;
517 reg_2944 = 0x00000FF0;
518 reg_294c = 0x00000FF0;
519 }
520
521 /* The first line to be displayed */
2b057e8d
IA
522 reg_2950 = 0x00010000 + src_major_y;
523 if (f->interlaced_y)
524 reg_2950 += 0x00010000;
1a0adaf3
HV
525 reg_2954 = reg_2950 + 1;
526
2b057e8d
IA
527 reg_2958 = 0x00010000 + (src_major_y >> 1);
528 if (f->interlaced_uv)
529 reg_2958 += 0x00010000;
1a0adaf3
HV
530 reg_295c = reg_2958 + 1;
531
2b057e8d 532 if (yi->decode_height == 480)
1a0adaf3
HV
533 reg_289c = 0x011e0017;
534 else
535 reg_289c = 0x01500017;
536
2b057e8d
IA
537 if (f->dst_y < 0)
538 reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
1a0adaf3 539 else
2b057e8d 540 reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
1a0adaf3
HV
541
542 /* How much of the source to decode.
543 Take into account the source offset */
2b057e8d
IA
544 reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
545 (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
1a0adaf3
HV
546
547 /* Calculate correct value for register 2964 */
2b057e8d 548 if (f->src_h == f->dst_h) {
1a0adaf3 549 reg_2964 = 1;
2b057e8d
IA
550 } else {
551 reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
1a0adaf3
HV
552 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
553 }
554 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
555 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
556
557 /* Okay, we've wasted time working out the correct value,
558 but if we use it, it fouls the the window alignment.
559 Fudge it to what we want... */
560 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
561 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
562
563 /* Deviate further from what it should be. I find the flicker headache
564 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
565 colours foul. */
2b057e8d
IA
566 if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
567 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
1a0adaf3 568
2b057e8d
IA
569 if (!f->interlaced_y)
570 reg_2964 -= 0x00010001;
571 if (!f->interlaced_uv)
572 reg_2968 -= 0x00010001;
1a0adaf3
HV
573
574 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
575 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
576
577 /* Select the vertical filter */
2b057e8d 578 if (f->src_h == f->dst_h) {
1a0adaf3
HV
579 /* An exact size match uses filter 0/1 */
580 v_filter_1 = 0;
581 v_filter_2 = 1;
2b057e8d 582 } else {
1a0adaf3 583 /* Figure out which filter to use */
2b057e8d 584 v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
1a0adaf3
HV
585 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
586 /* Only an exact size match can use filter 0 */
2b057e8d 587 v_filter_1 += !v_filter_1;
1a0adaf3
HV
588 v_filter_2 = v_filter_1;
589 }
590
591 write_reg(reg_2934, 0x02934);
592 write_reg(reg_293c, 0x0293c);
2b057e8d
IA
593 IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
594 yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
1a0adaf3
HV
595 write_reg(reg_2944, 0x02944);
596 write_reg(reg_294c, 0x0294c);
2b057e8d
IA
597 IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
598 yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
1a0adaf3
HV
599
600 /* Ensure 2970 is 0 (does it ever change ?) */
601/* write_reg(0,0x02970); */
2b057e8d 602/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
1a0adaf3
HV
603
604 write_reg(reg_2930, 0x02938);
605 write_reg(reg_2930, 0x02930);
2b057e8d
IA
606 IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
607 yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
1a0adaf3
HV
608
609 write_reg(reg_2928, 0x02928);
2b057e8d
IA
610 write_reg(reg_2928 + 0x514, 0x0292C);
611 IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
612 yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
1a0adaf3
HV
613
614 write_reg(reg_2920, 0x02920);
2b057e8d
IA
615 write_reg(reg_2920 + 0x514, 0x02924);
616 IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
617 yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
1a0adaf3 618
2b057e8d
IA
619 write_reg(reg_2918, 0x02918);
620 write_reg(reg_291c, 0x0291C);
621 IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
622 yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
1a0adaf3
HV
623
624 write_reg(reg_296c, 0x0296c);
2b057e8d
IA
625 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
626 yi->reg_296c, reg_296c);
1a0adaf3
HV
627
628 write_reg(reg_2940, 0x02948);
629 write_reg(reg_2940, 0x02940);
2b057e8d
IA
630 IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
631 yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
1a0adaf3
HV
632
633 write_reg(reg_2950, 0x02950);
634 write_reg(reg_2954, 0x02954);
2b057e8d
IA
635 IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
636 yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
1a0adaf3
HV
637
638 write_reg(reg_2958, 0x02958);
639 write_reg(reg_295c, 0x0295C);
2b057e8d
IA
640 IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
641 yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
1a0adaf3
HV
642
643 write_reg(reg_2960, 0x02960);
2b057e8d
IA
644 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
645 yi->reg_2960, reg_2960);
1a0adaf3
HV
646
647 write_reg(reg_2964, 0x02964);
648 write_reg(reg_2968, 0x02968);
2b057e8d
IA
649 IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
650 yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
1a0adaf3 651
2b057e8d
IA
652 write_reg(reg_289c, 0x0289c);
653 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
654 yi->reg_289c, reg_289c);
1a0adaf3
HV
655
656 /* Only update filter 1 if we really need to */
2b057e8d
IA
657 if (v_filter_1 != yi->v_filter_1) {
658 ivtv_yuv_filter(itv, -1, v_filter_1, -1);
659 yi->v_filter_1 = v_filter_1;
1a0adaf3
HV
660 }
661
662 /* Only update filter 2 if we really need to */
2b057e8d
IA
663 if (v_filter_2 != yi->v_filter_2) {
664 ivtv_yuv_filter(itv, -1, -1, v_filter_2);
665 yi->v_filter_2 = v_filter_2;
1a0adaf3 666 }
1a0adaf3
HV
667}
668
669/* Modify the supplied coordinate information to fit the visible osd area */
3b5c1c8e 670static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf3 671{
3b5c1c8e
IA
672 struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
673 int osd_crop;
1a0adaf3
HV
674 u32 osd_scale;
675 u32 yuv_update = 0;
676
1a0adaf3 677 /* Sorry, but no negative coords for src */
3b5c1c8e
IA
678 if (f->src_x < 0)
679 f->src_x = 0;
680 if (f->src_y < 0)
681 f->src_y = 0;
1a0adaf3
HV
682
683 /* Can only reduce width down to 1/4 original size */
3b5c1c8e
IA
684 if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
685 f->src_x += osd_crop / 2;
686 f->src_w = (f->src_w - osd_crop) & ~3;
687 f->dst_w = f->src_w / 4;
688 f->dst_w += f->dst_w & 1;
1a0adaf3
HV
689 }
690
691 /* Can only reduce height down to 1/4 original size */
3b5c1c8e
IA
692 if (f->src_h / f->dst_h >= 2) {
693 /* Overflow may be because we're running progressive,
694 so force mode switch */
695 f->interlaced_y = 1;
1a0adaf3 696 /* Make sure we're still within limits for interlace */
3b5c1c8e 697 if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
1a0adaf3 698 /* If we reach here we'll have to force the height. */
3b5c1c8e
IA
699 f->src_y += osd_crop / 2;
700 f->src_h = (f->src_h - osd_crop) & ~3;
701 f->dst_h = f->src_h / 4;
702 f->dst_h += f->dst_h & 1;
1a0adaf3
HV
703 }
704 }
705
706 /* If there's nothing to safe to display, we may as well stop now */
3b5c1c8e 707 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
2b057e8d 708 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0bfeb04a 709 return IVTV_YUV_UPDATE_INVALID;
1a0adaf3
HV
710 }
711
712 /* Ensure video remains inside OSD area */
3b5c1c8e 713 osd_scale = (f->src_h << 16) / f->dst_h;
1a0adaf3 714
3b5c1c8e 715 if ((osd_crop = f->pan_y - f->dst_y) > 0) {
1a0adaf3 716 /* Falls off the upper edge - crop */
3b5c1c8e
IA
717 f->src_y += (osd_scale * osd_crop) >> 16;
718 f->src_h -= (osd_scale * osd_crop) >> 16;
719 f->dst_h -= osd_crop;
720 f->dst_y = 0;
721 } else {
722 f->dst_y -= f->pan_y;
1a0adaf3
HV
723 }
724
3b5c1c8e 725 if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
1a0adaf3 726 /* Falls off the lower edge - crop */
3b5c1c8e
IA
727 f->dst_h -= osd_crop;
728 f->src_h -= (osd_scale * osd_crop) >> 16;
1a0adaf3
HV
729 }
730
3b5c1c8e 731 osd_scale = (f->src_w << 16) / f->dst_w;
1a0adaf3 732
3b5c1c8e 733 if ((osd_crop = f->pan_x - f->dst_x) > 0) {
1a0adaf3 734 /* Fall off the left edge - crop */
3b5c1c8e
IA
735 f->src_x += (osd_scale * osd_crop) >> 16;
736 f->src_w -= (osd_scale * osd_crop) >> 16;
737 f->dst_w -= osd_crop;
738 f->dst_x = 0;
739 } else {
740 f->dst_x -= f->pan_x;
1a0adaf3
HV
741 }
742
3b5c1c8e 743 if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
1a0adaf3 744 /* Falls off the right edge - crop */
3b5c1c8e
IA
745 f->dst_w -= osd_crop;
746 f->src_w -= (osd_scale * osd_crop) >> 16;
1a0adaf3
HV
747 }
748
88ab075a
IA
749 if (itv->yuv_info.track_osd) {
750 /* The OSD can be moved. Track to it */
751 f->dst_x += itv->yuv_info.osd_x_offset;
752 f->dst_y += itv->yuv_info.osd_y_offset;
753 }
1a0adaf3
HV
754
755 /* Width & height for both src & dst must be even.
756 Same for coordinates. */
3b5c1c8e
IA
757 f->dst_w &= ~1;
758 f->dst_x &= ~1;
1a0adaf3 759
3b5c1c8e
IA
760 f->src_w += f->src_x & 1;
761 f->src_x &= ~1;
1a0adaf3 762
3b5c1c8e
IA
763 f->src_w &= ~1;
764 f->dst_w &= ~1;
1a0adaf3 765
3b5c1c8e
IA
766 f->dst_h &= ~1;
767 f->dst_y &= ~1;
1a0adaf3 768
3b5c1c8e
IA
769 f->src_h += f->src_y & 1;
770 f->src_y &= ~1;
1a0adaf3 771
3b5c1c8e
IA
772 f->src_h &= ~1;
773 f->dst_h &= ~1;
1a0adaf3 774
3b5c1c8e
IA
775 /* Due to rounding, we may have reduced the output size to <1/4 of
776 the source. Check again, but this time just resize. Don't change
777 source coordinates */
778 if (f->dst_w < f->src_w / 4) {
779 f->src_w &= ~3;
780 f->dst_w = f->src_w / 4;
781 f->dst_w += f->dst_w & 1;
1a0adaf3 782 }
3b5c1c8e
IA
783 if (f->dst_h < f->src_h / 4) {
784 f->src_h &= ~3;
785 f->dst_h = f->src_h / 4;
786 f->dst_h += f->dst_h & 1;
1a0adaf3
HV
787 }
788
789 /* Check again. If there's nothing to safe to display, stop now */
3b5c1c8e 790 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
2b057e8d 791 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0bfeb04a 792 return IVTV_YUV_UPDATE_INVALID;
1a0adaf3
HV
793 }
794
795 /* Both x offset & width are linked, so they have to be done together */
3b5c1c8e 796 if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
2b057e8d
IA
797 (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
798 (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
1a0adaf3
HV
799 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
800 }
801
3b5c1c8e 802 if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
2b057e8d
IA
803 (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
804 (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
805 (of->lace_mode != f->lace_mode) ||
806 (of->interlaced_y != f->interlaced_y) ||
807 (of->interlaced_uv != f->interlaced_uv)) {
1a0adaf3
HV
808 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
809 }
810
811 return yuv_update;
812}
813
814/* Update the scaling register to the requested value */
2b057e8d 815void ivtv_yuv_work_handler(struct ivtv *itv)
1a0adaf3 816{
3b5c1c8e
IA
817 struct yuv_playback_info *yi = &itv->yuv_info;
818 struct yuv_frame_info f;
819 int frame = yi->update_frame;
1a0adaf3
HV
820 u32 yuv_update;
821
2b057e8d 822 IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
3b5c1c8e 823 f = yi->new_frame_info[frame];
1a0adaf3 824
88ab075a
IA
825 if (yi->track_osd) {
826 /* Snapshot the osd pan info */
827 f.pan_x = yi->osd_x_pan;
828 f.pan_y = yi->osd_y_pan;
829 f.vis_w = yi->osd_vis_w;
830 f.vis_h = yi->osd_vis_h;
831 } else {
832 /* Not tracking the osd, so assume full screen */
833 f.pan_x = 0;
834 f.pan_y = 0;
835 f.vis_w = 720;
836 f.vis_h = yi->decode_height;
837 }
1a0adaf3
HV
838
839 /* Calculate the display window coordinates. Exit if nothing left */
2b057e8d 840 if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
1a0adaf3
HV
841 return;
842
0bfeb04a
IA
843 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
844 write_reg(0x01008080, 0x2898);
845 } else if (yuv_update) {
846 write_reg(0x00108080, 0x2898);
1a0adaf3 847
0bfeb04a 848 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
3b5c1c8e 849 ivtv_yuv_handle_horizontal(itv, &f);
0bfeb04a
IA
850
851 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
3b5c1c8e 852 ivtv_yuv_handle_vertical(itv, &f);
0bfeb04a 853 }
3b5c1c8e 854 yi->old_frame_info = f;
1a0adaf3
HV
855}
856
2b057e8d 857static void ivtv_yuv_init(struct ivtv *itv)
1a0adaf3 858{
195b1252
IA
859 struct yuv_playback_info *yi = &itv->yuv_info;
860
1a0adaf3
HV
861 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
862
863 /* Take a snapshot of the current register settings */
195b1252
IA
864 yi->reg_2834 = read_reg(0x02834);
865 yi->reg_2838 = read_reg(0x02838);
866 yi->reg_283c = read_reg(0x0283c);
867 yi->reg_2840 = read_reg(0x02840);
868 yi->reg_2844 = read_reg(0x02844);
869 yi->reg_2848 = read_reg(0x02848);
870 yi->reg_2854 = read_reg(0x02854);
871 yi->reg_285c = read_reg(0x0285c);
872 yi->reg_2864 = read_reg(0x02864);
873 yi->reg_2870 = read_reg(0x02870);
874 yi->reg_2874 = read_reg(0x02874);
875 yi->reg_2898 = read_reg(0x02898);
876 yi->reg_2890 = read_reg(0x02890);
877
878 yi->reg_289c = read_reg(0x0289c);
879 yi->reg_2918 = read_reg(0x02918);
880 yi->reg_291c = read_reg(0x0291c);
881 yi->reg_2920 = read_reg(0x02920);
882 yi->reg_2924 = read_reg(0x02924);
883 yi->reg_2928 = read_reg(0x02928);
884 yi->reg_292c = read_reg(0x0292c);
885 yi->reg_2930 = read_reg(0x02930);
886 yi->reg_2934 = read_reg(0x02934);
887 yi->reg_2938 = read_reg(0x02938);
888 yi->reg_293c = read_reg(0x0293c);
889 yi->reg_2940 = read_reg(0x02940);
890 yi->reg_2944 = read_reg(0x02944);
891 yi->reg_2948 = read_reg(0x02948);
892 yi->reg_294c = read_reg(0x0294c);
893 yi->reg_2950 = read_reg(0x02950);
894 yi->reg_2954 = read_reg(0x02954);
895 yi->reg_2958 = read_reg(0x02958);
896 yi->reg_295c = read_reg(0x0295c);
897 yi->reg_2960 = read_reg(0x02960);
898 yi->reg_2964 = read_reg(0x02964);
899 yi->reg_2968 = read_reg(0x02968);
900 yi->reg_296c = read_reg(0x0296c);
901 yi->reg_2970 = read_reg(0x02970);
902
903 yi->v_filter_1 = -1;
904 yi->v_filter_2 = -1;
905 yi->h_filter = -1;
1a0adaf3
HV
906
907 /* Set some valid size info */
195b1252
IA
908 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
909 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
1a0adaf3
HV
910
911 /* Bit 2 of reg 2878 indicates current decoder output format
912 0 : NTSC 1 : PAL */
913 if (read_reg(0x2878) & 4)
195b1252 914 yi->decode_height = 576;
1a0adaf3 915 else
195b1252 916 yi->decode_height = 480;
b4b38bd6 917
195b1252
IA
918 if (!itv->osd_info) {
919 yi->osd_vis_w = 720 - yi->osd_x_offset;
920 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
b4b38bd6 921 } else {
195b1252
IA
922 /* If no visible size set, assume full size */
923 if (!yi->osd_vis_w)
924 yi->osd_vis_w = 720 - yi->osd_x_offset;
925
2b057e8d 926 if (!yi->osd_vis_h) {
195b1252 927 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
2b057e8d 928 } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
195b1252 929 /* If output video standard has changed, requested height may
2b057e8d
IA
930 not be legal */
931 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
932 yi->osd_vis_h + yi->osd_y_offset,
933 yi->decode_height);
934 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
b4b38bd6
IA
935 }
936 }
1a0adaf3
HV
937
938 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
3f98387e 939 yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
2b057e8d 940 if (yi->blanking_ptr) {
8ac05ae3 941 yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
2b057e8d 942 } else {
195b1252
IA
943 yi->blanking_dmaptr = 0;
944 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
1a0adaf3
HV
945 }
946
1a0adaf3
HV
947 /* Enable YUV decoder output */
948 write_reg_sync(0x01, IVTV_REG_VDM);
949
950 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
195b1252 951 atomic_set(&yi->next_dma_frame, 0);
1a0adaf3
HV
952}
953
a3e5f5e2 954/* Get next available yuv buffer on PVR350 */
5eedc466 955static void ivtv_yuv_next_free(struct ivtv *itv)
1a0adaf3 956{
a3e5f5e2
IA
957 int draw, display;
958 struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf3 959
a3e5f5e2
IA
960 if (atomic_read(&yi->next_dma_frame) == -1)
961 ivtv_yuv_init(itv);
1a0adaf3 962
a3e5f5e2
IA
963 draw = atomic_read(&yi->next_fill_frame);
964 display = atomic_read(&yi->next_dma_frame);
1a0adaf3 965
a3e5f5e2
IA
966 if (display > draw)
967 display -= IVTV_YUV_BUFFERS;
1a0adaf3 968
a3e5f5e2
IA
969 if (draw - display >= yi->max_frames_buffered)
970 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
971 else
972 yi->new_frame_info[draw].update = 0;
973
974 yi->draw_frame = draw;
975}
976
977/* Set up frame according to ivtv_dma_frame parameters */
5eedc466 978static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
a3e5f5e2
IA
979{
980 struct yuv_playback_info *yi = &itv->yuv_info;
981 u8 frame = yi->draw_frame;
3b5c1c8e
IA
982 u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
983 struct yuv_frame_info *nf = &yi->new_frame_info[frame];
984 struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
985 int lace_threshold = yi->lace_threshold;
a3e5f5e2
IA
986
987 /* Preserve old update flag in case we're overwriting a queued frame */
3b5c1c8e 988 int update = nf->update;
1a0adaf3
HV
989
990 /* Take a snapshot of the yuv coordinate information */
3b5c1c8e
IA
991 nf->src_x = args->src.left;
992 nf->src_y = args->src.top;
993 nf->src_w = args->src.width;
994 nf->src_h = args->src.height;
995 nf->dst_x = args->dst.left;
996 nf->dst_y = args->dst.top;
997 nf->dst_w = args->dst.width;
998 nf->dst_h = args->dst.height;
999 nf->tru_x = args->dst.left;
1000 nf->tru_w = args->src_width;
1001 nf->tru_h = args->src_height;
bfd7beac 1002
1a0adaf3 1003 /* Are we going to offset the Y plane */
3b5c1c8e 1004 nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
1a0adaf3 1005
3b5c1c8e
IA
1006 nf->update = 0;
1007 nf->interlaced_y = 0;
1008 nf->interlaced_uv = 0;
1009 nf->delay = 0;
1010 nf->sync_field = 0;
1011 nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
1012
1013 if (lace_threshold < 0)
1014 lace_threshold = yi->decode_height - 1;
1015
1016 /* Work out the lace settings */
1017 switch (nf->lace_mode) {
1018 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
1019 nf->interlaced = 0;
1020 if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
1021 nf->interlaced_y = 0;
1022 else
1023 nf->interlaced_y = 1;
1024
1025 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1026 nf->interlaced_uv = 0;
1027 else
1028 nf->interlaced_uv = 1;
1029 break;
1030
1031 case IVTV_YUV_MODE_AUTO:
1032 if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
1033 nf->interlaced = 0;
1034 if ((nf->tru_h < 512) ||
2b057e8d
IA
1035 (nf->tru_h > 576 && nf->tru_h < 1021) ||
1036 (nf->tru_w > 720 && nf->tru_h < 1021))
3b5c1c8e
IA
1037 nf->interlaced_y = 0;
1038 else
1039 nf->interlaced_y = 1;
1040 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1041 nf->interlaced_uv = 0;
1042 else
1043 nf->interlaced_uv = 1;
1044 } else {
1045 nf->interlaced = 1;
1046 nf->interlaced_y = 1;
1047 nf->interlaced_uv = 1;
1048 }
1049 break;
1050
1051 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1052 default:
1053 nf->interlaced = 1;
1054 nf->interlaced_y = 1;
1055 nf->interlaced_uv = 1;
1056 break;
1a0adaf3
HV
1057 }
1058
3b5c1c8e
IA
1059 if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1060 yi->old_frame_info_args = *nf;
1061 nf->update = 1;
2b057e8d 1062 IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
3b5c1c8e 1063 }
943e8910 1064
3b5c1c8e
IA
1065 nf->update |= update;
1066 nf->sync_field = yi->lace_sync_field;
1067 nf->delay = nf->sync_field != of->sync_field;
a3e5f5e2
IA
1068}
1069
1070/* Frame is complete & ready for display */
1071void ivtv_yuv_frame_complete(struct ivtv *itv)
1072{
1073 atomic_set(&itv->yuv_info.next_fill_frame,
1074 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1075}
1076
5eedc466 1077static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
a3e5f5e2
IA
1078{
1079 DEFINE_WAIT(wait);
1080 int rc = 0;
1081 int got_sig = 0;
1a0adaf3
HV
1082 /* DMA the frame */
1083 mutex_lock(&itv->udma.lock);
1084
1085 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1086 mutex_unlock(&itv->udma.lock);
1087 return rc;
1088 }
1089
1090 ivtv_udma_prepare(itv);
1091 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1092 /* if no UDMA is pending and no UDMA is in progress, then the DMA
2b057e8d 1093 is finished */
ec105a42
HV
1094 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
1095 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
1a0adaf3 1096 /* don't interrupt if the DMA is in progress but break off
2b057e8d 1097 a still pending DMA. */
1a0adaf3
HV
1098 got_sig = signal_pending(current);
1099 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1100 break;
1101 got_sig = 0;
1102 schedule();
1103 }
1104 finish_wait(&itv->dma_waitq, &wait);
1105
1106 /* Unmap Last DMA Xfer */
1107 ivtv_udma_unmap(itv);
1108
1109 if (got_sig) {
1110 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1111 mutex_unlock(&itv->udma.lock);
1112 return -EINTR;
1113 }
1114
a3e5f5e2 1115 ivtv_yuv_frame_complete(itv);
1a0adaf3
HV
1116
1117 mutex_unlock(&itv->udma.lock);
1118 return rc;
1119}
1120
77aded6b
IA
1121/* Setup frame according to V4L2 parameters */
1122void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1123{
1124 struct yuv_playback_info *yi = &itv->yuv_info;
1125 struct ivtv_dma_frame dma_args;
1126
1127 ivtv_yuv_next_free(itv);
1128
1129 /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
a6a3a17b
HH
1130 dma_args.y_source = NULL;
1131 dma_args.uv_source = NULL;
77aded6b
IA
1132 dma_args.src.left = 0;
1133 dma_args.src.top = 0;
1134 dma_args.src.width = yi->v4l2_src_w;
1135 dma_args.src.height = yi->v4l2_src_h;
1136 dma_args.dst = yi->main_rect;
1137 dma_args.src_width = yi->v4l2_src_w;
1138 dma_args.src_height = yi->v4l2_src_h;
1139
1140 /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1141 ivtv_yuv_setup_frame(itv, &dma_args);
1142
1143 if (!itv->dma_data_req_offset)
1144 itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1145}
1146
1147/* Attempt to dma a frame from a user buffer */
b0510f8d 1148int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
77aded6b
IA
1149{
1150 struct yuv_playback_info *yi = &itv->yuv_info;
1151 struct ivtv_dma_frame dma_args;
1152
1153 ivtv_yuv_setup_stream_frame(itv);
1154
1155 /* We only need to supply source addresses for this */
1156 dma_args.y_source = src;
1157 dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
1158 return ivtv_yuv_udma_frame(itv, &dma_args);
1159}
1160
1161/* IVTV_IOC_DMA_FRAME ioctl handler */
1162int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1163{
2b057e8d 1164/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
77aded6b
IA
1165
1166 ivtv_yuv_next_free(itv);
1167 ivtv_yuv_setup_frame(itv, args);
1168 return ivtv_yuv_udma_frame(itv, args);
1169}
1170
1a0adaf3
HV
1171void ivtv_yuv_close(struct ivtv *itv)
1172{
2b057e8d 1173 struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf3
HV
1174 int h_filter, v_filter_1, v_filter_2;
1175
1176 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1177 ivtv_waitq(&itv->vsync_waitq);
1178
2bd7ac55 1179 yi->running = 0;
2b057e8d
IA
1180 atomic_set(&yi->next_dma_frame, -1);
1181 atomic_set(&yi->next_fill_frame, 0);
1a0adaf3
HV
1182
1183 /* Reset registers we have changed so mpeg playback works */
1184
1185 /* If we fully restore this register, the display may remain active.
1186 Restore, but set one bit to blank the video. Firmware will always
1187 clear this bit when needed, so not a problem. */
2b057e8d
IA
1188 write_reg(yi->reg_2898 | 0x01000000, 0x2898);
1189
1190 write_reg(yi->reg_2834, 0x02834);
1191 write_reg(yi->reg_2838, 0x02838);
1192 write_reg(yi->reg_283c, 0x0283c);
1193 write_reg(yi->reg_2840, 0x02840);
1194 write_reg(yi->reg_2844, 0x02844);
1195 write_reg(yi->reg_2848, 0x02848);
1196 write_reg(yi->reg_2854, 0x02854);
1197 write_reg(yi->reg_285c, 0x0285c);
1198 write_reg(yi->reg_2864, 0x02864);
1199 write_reg(yi->reg_2870, 0x02870);
1200 write_reg(yi->reg_2874, 0x02874);
1201 write_reg(yi->reg_2890, 0x02890);
1202 write_reg(yi->reg_289c, 0x0289c);
1203
1204 write_reg(yi->reg_2918, 0x02918);
1205 write_reg(yi->reg_291c, 0x0291c);
1206 write_reg(yi->reg_2920, 0x02920);
1207 write_reg(yi->reg_2924, 0x02924);
1208 write_reg(yi->reg_2928, 0x02928);
1209 write_reg(yi->reg_292c, 0x0292c);
1210 write_reg(yi->reg_2930, 0x02930);
1211 write_reg(yi->reg_2934, 0x02934);
1212 write_reg(yi->reg_2938, 0x02938);
1213 write_reg(yi->reg_293c, 0x0293c);
1214 write_reg(yi->reg_2940, 0x02940);
1215 write_reg(yi->reg_2944, 0x02944);
1216 write_reg(yi->reg_2948, 0x02948);
1217 write_reg(yi->reg_294c, 0x0294c);
1218 write_reg(yi->reg_2950, 0x02950);
1219 write_reg(yi->reg_2954, 0x02954);
1220 write_reg(yi->reg_2958, 0x02958);
1221 write_reg(yi->reg_295c, 0x0295c);
1222 write_reg(yi->reg_2960, 0x02960);
1223 write_reg(yi->reg_2964, 0x02964);
1224 write_reg(yi->reg_2968, 0x02968);
1225 write_reg(yi->reg_296c, 0x0296c);
1226 write_reg(yi->reg_2970, 0x02970);
1a0adaf3
HV
1227
1228 /* Prepare to restore filters */
1229
1230 /* First the horizontal filter */
2b057e8d 1231 if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
1a0adaf3
HV
1232 /* An exact size match uses filter 0 */
1233 h_filter = 0;
2b057e8d 1234 } else {
1a0adaf3 1235 /* Figure out which filter to use */
2b057e8d 1236 h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
1a0adaf3
HV
1237 h_filter = (h_filter >> 1) + (h_filter & 1);
1238 /* Only an exact size match can use filter 0. */
2b057e8d 1239 h_filter += !h_filter;
1a0adaf3
HV
1240 }
1241
1242 /* Now the vertical filter */
2b057e8d 1243 if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
1a0adaf3
HV
1244 /* An exact size match uses filter 0/1 */
1245 v_filter_1 = 0;
1246 v_filter_2 = 1;
2b057e8d 1247 } else {
1a0adaf3 1248 /* Figure out which filter to use */
2b057e8d 1249 v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
1a0adaf3
HV
1250 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1251 /* Only an exact size match can use filter 0 */
2b057e8d 1252 v_filter_1 += !v_filter_1;
1a0adaf3
HV
1253 v_filter_2 = v_filter_1;
1254 }
1255
1256 /* Now restore the filters */
2b057e8d 1257 ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
1a0adaf3
HV
1258
1259 /* and clear a few registers */
1260 write_reg(0, 0x02814);
1261 write_reg(0, 0x0282c);
1262 write_reg(0, 0x02904);
1263 write_reg(0, 0x02910);
1264
1265 /* Release the blanking buffer */
2b057e8d
IA
1266 if (yi->blanking_ptr) {
1267 kfree(yi->blanking_ptr);
1268 yi->blanking_ptr = NULL;
8ac05ae3 1269 pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1a0adaf3
HV
1270 }
1271
1272 /* Invalidate the old dimension information */
2b057e8d
IA
1273 yi->old_frame_info.src_w = 0;
1274 yi->old_frame_info.src_h = 0;
1275 yi->old_frame_info_args.src_w = 0;
1276 yi->old_frame_info_args.src_h = 0;
1a0adaf3
HV
1277
1278 /* All done. */
1279 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1280}