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