ivtv-yuv.c 36.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
    yuv support

    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "ivtv-driver.h"
#include "ivtv-udma.h"
23
#include "ivtv-yuv.h"
24

25 26 27 28 29 30 31 32 33 34
/* YUV buffer offsets */
const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
	0x001a8600,
	0x00240400,
	0x002d8200,
	0x00370000,
	0x00029000,
	0x000C0E00,
	0x006B0400,
	0x00748200
35 36
};

37
static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
38
				  struct ivtv_dma_frame *args)
39 40 41
{
	struct ivtv_dma_page_info y_dma;
	struct ivtv_dma_page_info uv_dma;
42 43 44
	struct yuv_playback_info *yi = &itv->yuv_info;
	u8 frame = yi->draw_frame;
	struct yuv_frame_info *f = &yi->new_frame_info[frame];
45 46 47 48 49
	int i;
	int y_pages, uv_pages;
	unsigned long y_buffer_offset, uv_buffer_offset;
	int y_decode_height, uv_decode_height, y_size;

50
	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
51 52
	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;

53
	y_decode_height = uv_decode_height = f->src_h + f->src_y;
54

55
	if (f->offset_y)
56 57 58 59 60 61 62 63 64 65 66 67
		y_buffer_offset += 720 * 16;

	if (y_decode_height & 15)
		y_decode_height = (y_decode_height + 16) & ~15;

	if (uv_decode_height & 31)
		uv_decode_height = (uv_decode_height + 32) & ~31;

	y_size = 720 * y_decode_height;

	/* Still in USE */
	if (dma->SG_length || dma->page_count) {
68 69 70
		IVTV_DEBUG_WARN
		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
		     dma->SG_length, dma->page_count);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
		return -EBUSY;
	}

	ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
	ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);

	/* Get user pages for DMA Xfer */
	down_read(&current->mm->mmap_sem);
	y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
	uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
	up_read(&current->mm->mmap_sem);

	dma->page_count = y_dma.page_count + uv_dma.page_count;

	if (y_pages + uv_pages != dma->page_count) {
86 87 88
		IVTV_DEBUG_WARN
		    ("failed to map user pages, returned %d instead of %d\n",
		     y_pages + uv_pages, dma->page_count);
89 90 91 92 93 94 95 96 97

		for (i = 0; i < dma->page_count; i++) {
			put_page(dma->map[i]);
		}
		dma->page_count = 0;
		return -EINVAL;
	}

	/* Fill & map SG List */
98
	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
99 100 101 102 103 104 105
		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
		for (i = 0; i < dma->page_count; i++) {
			put_page(dma->map[i]);
		}
		dma->page_count = 0;
		return -ENOMEM;
	}
106 107 108
	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);

	/* Fill SG Array with new values */
109
	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
110 111

	/* If we've offset the y plane, ensure top area is blanked */
112
	if (f->offset_y && yi->blanking_dmaptr) {
113
		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
114
		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
115 116
		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
		dma->SG_length++;
117 118 119 120 121 122 123 124 125 126 127 128
	}

	/* Tag SG Array with Interrupt Bit */
	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);

	ivtv_udma_sync_for_device(itv);
	return 0;
}

/* We rely on a table held in the firmware - Quick check. */
int ivtv_yuv_filter_check(struct ivtv *itv)
{
129
	int i, y, uv;
130

131 132 133
	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
134 135 136 137 138 139 140 141 142
			IVTV_WARN ("YUV filter table not found in firmware.\n");
			return -1;
		}
	}
	return 0;
}

static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
{
143
	u32 i, line;
144 145 146

	/* If any filter is -1, then don't update it */
	if (h_filter > -1) {
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
		if (h_filter > 4)
			h_filter = 4;
		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
		for (line = 0; line < 16; line++) {
			write_reg(read_dec(i), 0x02804);
			write_reg(read_dec(i), 0x0281c);
			i += 4;
			write_reg(read_dec(i), 0x02808);
			write_reg(read_dec(i), 0x02820);
			i += 4;
			write_reg(read_dec(i), 0x0280c);
			write_reg(read_dec(i), 0x02824);
			i += 4;
			write_reg(read_dec(i), 0x02810);
			write_reg(read_dec(i), 0x02828);
			i += 4;
			write_reg(read_dec(i), 0x02814);
			write_reg(read_dec(i), 0x0282c);
			i += 8;
166 167 168
			write_reg(0, 0x02818);
			write_reg(0, 0x02830);
		}
169
		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
170 171 172
	}

	if (v_filter_1 > -1) {
173 174 175 176 177 178 179 180
		if (v_filter_1 > 4)
			v_filter_1 = 4;
		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
		for (line = 0; line < 16; line++) {
			write_reg(read_dec(i), 0x02900);
			i += 4;
			write_reg(read_dec(i), 0x02904);
			i += 8;
181 182
			write_reg(0, 0x02908);
		}
183
		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
184 185 186
	}

	if (v_filter_2 > -1) {
187 188 189 190 191 192 193 194
		if (v_filter_2 > 4)
			v_filter_2 = 4;
		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
		for (line = 0; line < 16; line++) {
			write_reg(read_dec(i), 0x0290c);
			i += 4;
			write_reg(read_dec(i), 0x02910);
			i += 8;
195 196
			write_reg(0, 0x02914);
		}
197
		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
198 199 200
	}
}

201
static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
202
{
203
	struct yuv_playback_info *yi = &itv->yuv_info;
204 205 206 207 208 209 210 211
	u32 reg_2834, reg_2838, reg_283c;
	u32 reg_2844, reg_2854, reg_285c;
	u32 reg_2864, reg_2874, reg_2890;
	u32 reg_2870, reg_2870_base, reg_2870_offset;
	int x_cutoff;
	int h_filter;
	u32 master_width;

212 213 214
	IVTV_DEBUG_WARN
	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
215 216

	/* How wide is the src image */
217
	x_cutoff = f->src_w + f->src_x;
218 219

	/* Set the display width */
220
	reg_2834 = f->dst_w;
221 222 223
	reg_2838 = reg_2834;

	/* Set the display position */
224
	reg_2890 = f->dst_x;
225 226 227 228 229 230 231 232 233 234

	/* Index into the image horizontally */
	reg_2870 = 0;

	/* 2870 is normally fudged to align video coords with osd coords.
	   If running full screen, it causes an unwanted left shift
	   Remove the fudge if we almost fill the screen.
	   Gradually adjust the offset to avoid the video 'snapping'
	   left/right if it gets dragged through this region.
	   Only do this if osd is full width. */
235 236 237 238 239
	if (f->vis_w == 720) {
		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
240

241
		if (f->dst_w >= f->src_w)
242 243 244 245 246
			reg_2870 = reg_2870 << 16 | reg_2870;
		else
			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
	}

247
	if (f->dst_w < f->src_w)
248 249 250 251 252
		reg_2870 = 0x000d000e - reg_2870;
	else
		reg_2870 = 0x0012000e - reg_2870;

	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
253
	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
254

255
	if (f->dst_w >= f->src_w) {
256
		x_cutoff &= ~1;
257 258 259
		master_width = (f->src_w * 0x00200000) / (f->dst_w);
		if (master_width * f->dst_w != f->src_w * 0x00200000)
			master_width++;
260 261 262 263 264 265 266 267 268 269
		reg_2834 = (reg_2834 << 16) | x_cutoff;
		reg_2838 = (reg_2838 << 16) | x_cutoff;
		reg_283c = master_width >> 2;
		reg_2844 = master_width >> 2;
		reg_2854 = master_width;
		reg_285c = master_width >> 1;
		reg_2864 = master_width >> 1;

		/* We also need to factor in the scaling
		   (src_w - dst_w) / (src_w / 4) */
270 271
		if (f->dst_w > f->src_w)
			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
272 273 274 275 276
		else
			reg_2870_base = 0;

		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
		reg_2874 = 0;
277 278 279 280
	} else if (f->dst_w < f->src_w / 2) {
		master_width = (f->src_w * 0x00080000) / f->dst_w;
		if (master_width * f->dst_w != f->src_w * 0x00080000)
			master_width++;
281 282 283 284 285 286 287
		reg_2834 = (reg_2834 << 16) | x_cutoff;
		reg_2838 = (reg_2838 << 16) | x_cutoff;
		reg_283c = master_width >> 2;
		reg_2844 = master_width >> 1;
		reg_2854 = master_width;
		reg_285c = master_width >> 1;
		reg_2864 = master_width >> 1;
288 289
		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
290
		reg_2874 = 0x00000012;
291 292 293 294
	} else {
		master_width = (f->src_w * 0x00100000) / f->dst_w;
		if (master_width * f->dst_w != f->src_w * 0x00100000)
			master_width++;
295 296 297 298 299 300 301
		reg_2834 = (reg_2834 << 16) | x_cutoff;
		reg_2838 = (reg_2838 << 16) | x_cutoff;
		reg_283c = master_width >> 2;
		reg_2844 = master_width >> 1;
		reg_2854 = master_width;
		reg_285c = master_width >> 1;
		reg_2864 = master_width >> 1;
302 303
		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
304 305 306 307
		reg_2874 = 0x00000001;
	}

	/* Select the horizontal filter */
308
	if (f->src_w == f->dst_w) {
309 310
		/* An exact size match uses filter 0 */
		h_filter = 0;
311
	} else {
312
		/* Figure out which filter to use */
313
		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
314 315
		h_filter = (h_filter >> 1) + (h_filter & 1);
		/* Only an exact size match can use filter 0 */
316
		h_filter += !h_filter;
317 318 319 320
	}

	write_reg(reg_2834, 0x02834);
	write_reg(reg_2838, 0x02838);
321 322
	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
323 324 325 326

	write_reg(reg_283c, 0x0283c);
	write_reg(reg_2844, 0x02844);

327 328
	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
329 330 331

	write_reg(0x00080514, 0x02840);
	write_reg(0x00100514, 0x02848);
332 333
	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
334 335

	write_reg(reg_2854, 0x02854);
336 337
	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
		       yi->reg_2854, reg_2854);
338 339 340

	write_reg(reg_285c, 0x0285c);
	write_reg(reg_2864, 0x02864);
341 342
	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
343 344

	write_reg(reg_2874, 0x02874);
345 346
	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
		       yi->reg_2874, reg_2874);
347 348

	write_reg(reg_2870, 0x02870);
349 350
	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
		       yi->reg_2870, reg_2870);
351

352 353 354
	write_reg(reg_2890, 0x02890);
	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
		       yi->reg_2890, reg_2890);
355 356

	/* Only update the filter if we really need to */
357 358 359
	if (h_filter != yi->h_filter) {
		ivtv_yuv_filter(itv, h_filter, -1, -1);
		yi->h_filter = h_filter;
360 361 362
	}
}

363
static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
364
{
365
	struct yuv_playback_info *yi = &itv->yuv_info;
366 367 368 369 370 371 372
	u32 master_height;
	u32 reg_2918, reg_291c, reg_2920, reg_2928;
	u32 reg_2930, reg_2934, reg_293c;
	u32 reg_2940, reg_2944, reg_294c;
	u32 reg_2950, reg_2954, reg_2958, reg_295c;
	u32 reg_2960, reg_2964, reg_2968, reg_296c;
	u32 reg_289c;
373 374
	u32 src_major_y, src_minor_y;
	u32 src_major_uv, src_minor_uv;
375 376 377
	u32 reg_2964_base, reg_2968_base;
	int v_filter_1, v_filter_2;

378 379 380
	IVTV_DEBUG_WARN
	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
381 382

	/* What scaling mode is being used... */
383 384
	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
		       f->interlaced_y ? "Interlaced" : "Progressive");
385

386 387
	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
		       f->interlaced_uv ? "Interlaced" : "Progressive");
388 389

	/* What is the source video being treated as... */
390 391
	IVTV_DEBUG_WARN("Source video: %s\n",
			f->interlaced ? "Interlaced" : "Progressive");
392 393 394

	/* We offset into the image using two different index methods, so split
	   the y source coord into two parts. */
395 396 397 398 399 400
	if (f->src_y < 8) {
		src_minor_uv = f->src_y;
		src_major_uv = 0;
	} else {
		src_minor_uv = 8;
		src_major_uv = f->src_y - 8;
401 402
	}

403 404
	src_minor_y = src_minor_uv;
	src_major_y = src_major_uv;
405

406 407
	if (f->offset_y)
		src_minor_y += 16;
408

409 410
	if (f->interlaced_y)
		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
411
	else
412
		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
413

414 415
	if (f->interlaced_uv)
		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
416
	else
417
		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
418

419 420
	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
421

422 423 424 425
	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
		master_height = (f->src_h * 0x00400000) / f->dst_h;
		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
			master_height++;
426 427 428 429 430 431 432
		reg_2920 = master_height >> 2;
		reg_2928 = master_height >> 3;
		reg_2930 = master_height;
		reg_2940 = master_height >> 1;
		reg_2964_base >>= 3;
		reg_2968_base >>= 3;
		reg_296c = 0x00000000;
433 434
	} else if (f->dst_h >= f->src_h) {
		master_height = (f->src_h * 0x00400000) / f->dst_h;
435 436 437 438 439 440
		master_height = (master_height >> 1) + (master_height & 1);
		reg_2920 = master_height >> 2;
		reg_2928 = master_height >> 2;
		reg_2930 = master_height;
		reg_2940 = master_height >> 1;
		reg_296c = 0x00000000;
441
		if (f->interlaced_y) {
442
			reg_2964_base >>= 3;
443 444
		} else {
			reg_296c++;
445 446
			reg_2964_base >>= 2;
		}
447 448
		if (f->interlaced_uv)
			reg_2928 >>= 1;
449
		reg_2968_base >>= 3;
450 451
	} else if (f->dst_h >= f->src_h / 2) {
		master_height = (f->src_h * 0x00200000) / f->dst_h;
452 453 454 455 456 457
		master_height = (master_height >> 1) + (master_height & 1);
		reg_2920 = master_height >> 2;
		reg_2928 = master_height >> 2;
		reg_2930 = master_height;
		reg_2940 = master_height;
		reg_296c = 0x00000101;
458
		if (f->interlaced_y) {
459
			reg_2964_base >>= 2;
460 461
		} else {
			reg_296c++;
462 463
			reg_2964_base >>= 1;
		}
464 465
		if (f->interlaced_uv)
			reg_2928 >>= 1;
466
		reg_2968_base >>= 2;
467 468
	} else {
		master_height = (f->src_h * 0x00100000) / f->dst_h;
469 470 471 472 473 474 475 476 477 478 479 480
		master_height = (master_height >> 1) + (master_height & 1);
		reg_2920 = master_height >> 2;
		reg_2928 = master_height >> 2;
		reg_2930 = master_height;
		reg_2940 = master_height;
		reg_2964_base >>= 1;
		reg_2968_base >>= 2;
		reg_296c = 0x00000102;
	}

	/* FIXME These registers change depending on scaled / unscaled output
	   We really need to work out what they should be */
481
	if (f->src_h == f->dst_h) {
482 483 484 485
		reg_2934 = 0x00020000;
		reg_293c = 0x00100000;
		reg_2944 = 0x00040000;
		reg_294c = 0x000b0000;
486
	} else {
487 488 489 490 491 492 493
		reg_2934 = 0x00000FF0;
		reg_293c = 0x00000FF0;
		reg_2944 = 0x00000FF0;
		reg_294c = 0x00000FF0;
	}

	/* The first line to be displayed */
494 495 496
	reg_2950 = 0x00010000 + src_major_y;
	if (f->interlaced_y)
		reg_2950 += 0x00010000;
497 498
	reg_2954 = reg_2950 + 1;

499 500 501
	reg_2958 = 0x00010000 + (src_major_y >> 1);
	if (f->interlaced_uv)
		reg_2958 += 0x00010000;
502 503
	reg_295c = reg_2958 + 1;

504
	if (yi->decode_height == 480)
505 506 507 508
		reg_289c = 0x011e0017;
	else
		reg_289c = 0x01500017;

509 510
	if (f->dst_y < 0)
		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
511
	else
512
		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
513 514 515

	/* How much of the source to decode.
	   Take into account the source offset */
516 517
	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
518 519

	/* Calculate correct value for register 2964 */
520
	if (f->src_h == f->dst_h) {
521
		reg_2964 = 1;
522 523
	} else {
		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
524 525 526 527 528 529 530 531 532 533 534 535 536 537
		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
	}
	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
	reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);

	/* Okay, we've wasted time working out the correct value,
	   but if we use it, it fouls the the window alignment.
	   Fudge it to what we want... */
	reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
	reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));

	/* Deviate further from what it should be. I find the flicker headache
	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
	   colours foul. */
538 539
	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
540

541 542 543 544
	if (!f->interlaced_y)
		reg_2964 -= 0x00010001;
	if (!f->interlaced_uv)
		reg_2968 -= 0x00010001;
545 546 547 548 549

	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);

	/* Select the vertical filter */
550
	if (f->src_h == f->dst_h) {
551 552 553
		/* An exact size match uses filter 0/1 */
		v_filter_1 = 0;
		v_filter_2 = 1;
554
	} else {
555
		/* Figure out which filter to use */
556
		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
557 558
		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
		/* Only an exact size match can use filter 0 */
559
		v_filter_1 += !v_filter_1;
560 561 562 563 564
		v_filter_2 = v_filter_1;
	}

	write_reg(reg_2934, 0x02934);
	write_reg(reg_293c, 0x0293c);
565 566
	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
567 568
	write_reg(reg_2944, 0x02944);
	write_reg(reg_294c, 0x0294c);
569 570
	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
571 572 573

	/* Ensure 2970 is 0 (does it ever change ?) */
/*	write_reg(0,0x02970); */
574
/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
575 576 577

	write_reg(reg_2930, 0x02938);
	write_reg(reg_2930, 0x02930);
578 579
	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
580 581

	write_reg(reg_2928, 0x02928);
582 583 584
	write_reg(reg_2928 + 0x514, 0x0292C);
	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
585 586

	write_reg(reg_2920, 0x02920);
587 588 589
	write_reg(reg_2920 + 0x514, 0x02924);
	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
590

591 592 593 594
	write_reg(reg_2918, 0x02918);
	write_reg(reg_291c, 0x0291C);
	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
595 596

	write_reg(reg_296c, 0x0296c);
597 598
	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
		       yi->reg_296c, reg_296c);
599 600 601

	write_reg(reg_2940, 0x02948);
	write_reg(reg_2940, 0x02940);
602 603
	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
604 605 606

	write_reg(reg_2950, 0x02950);
	write_reg(reg_2954, 0x02954);
607 608
	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
609 610 611

	write_reg(reg_2958, 0x02958);
	write_reg(reg_295c, 0x0295C);
612 613
	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
614 615

	write_reg(reg_2960, 0x02960);
616 617
	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
		       yi->reg_2960, reg_2960);
618 619 620

	write_reg(reg_2964, 0x02964);
	write_reg(reg_2968, 0x02968);
621 622
	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
623

624 625 626
	write_reg(reg_289c, 0x0289c);
	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
		       yi->reg_289c, reg_289c);
627 628

	/* Only update filter 1 if we really need to */
629 630 631
	if (v_filter_1 != yi->v_filter_1) {
		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
		yi->v_filter_1 = v_filter_1;
632 633 634
	}

	/* Only update filter 2 if we really need to */
635 636 637
	if (v_filter_2 != yi->v_filter_2) {
		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
		yi->v_filter_2 = v_filter_2;
638 639 640 641
	}
}

/* Modify the supplied coordinate information to fit the visible osd area */
642
static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
643
{
644 645
	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
	int osd_crop;
646 647 648 649
	u32 osd_scale;
	u32 yuv_update = 0;

	/* Sorry, but no negative coords for src */
650 651 652 653
	if (f->src_x < 0)
		f->src_x = 0;
	if (f->src_y < 0)
		f->src_y = 0;
654 655

	/* Can only reduce width down to 1/4 original size */
656 657 658 659 660
	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
		f->src_x += osd_crop / 2;
		f->src_w = (f->src_w - osd_crop) & ~3;
		f->dst_w = f->src_w / 4;
		f->dst_w += f->dst_w & 1;
661 662 663
	}

	/* Can only reduce height down to 1/4 original size */
664 665 666 667
	if (f->src_h / f->dst_h >= 2) {
		/* Overflow may be because we're running progressive,
		   so force mode switch */
		f->interlaced_y = 1;
668
		/* Make sure we're still within limits for interlace */
669
		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
670
			/* If we reach here we'll have to force the height. */
671 672 673 674
			f->src_y += osd_crop / 2;
			f->src_h = (f->src_h - osd_crop) & ~3;
			f->dst_h = f->src_h / 4;
			f->dst_h += f->dst_h & 1;
675 676 677 678
		}
	}

	/* If there's nothing to safe to display, we may as well stop now */
679
	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
680
	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
681
		return IVTV_YUV_UPDATE_INVALID;
682 683 684
	}

	/* Ensure video remains inside OSD area */
685
	osd_scale = (f->src_h << 16) / f->dst_h;
686

687
	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
688
		/* Falls off the upper edge - crop */
689 690 691 692 693 694
		f->src_y += (osd_scale * osd_crop) >> 16;
		f->src_h -= (osd_scale * osd_crop) >> 16;
		f->dst_h -= osd_crop;
		f->dst_y = 0;
	} else {
		f->dst_y -= f->pan_y;
695 696
	}

697
	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
698
		/* Falls off the lower edge - crop */
699 700
		f->dst_h -= osd_crop;
		f->src_h -= (osd_scale * osd_crop) >> 16;
701 702
	}

703
	osd_scale = (f->src_w << 16) / f->dst_w;
704

705
	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
706
		/* Fall off the left edge - crop */
707 708 709 710 711 712
		f->src_x += (osd_scale * osd_crop) >> 16;
		f->src_w -= (osd_scale * osd_crop) >> 16;
		f->dst_w -= osd_crop;
		f->dst_x = 0;
	} else {
		f->dst_x -= f->pan_x;
713 714
	}

715
	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
716
		/* Falls off the right edge - crop */
717 718
		f->dst_w -= osd_crop;
		f->src_w -= (osd_scale * osd_crop) >> 16;
719 720
	}

721 722 723 724 725
	if (itv->yuv_info.track_osd) {
		/* The OSD can be moved. Track to it */
		f->dst_x += itv->yuv_info.osd_x_offset;
		f->dst_y += itv->yuv_info.osd_y_offset;
	}
726 727 728

	/* Width & height for both src & dst must be even.
	   Same for coordinates. */
729 730
	f->dst_w &= ~1;
	f->dst_x &= ~1;
731

732 733
	f->src_w += f->src_x & 1;
	f->src_x &= ~1;
734

735 736
	f->src_w &= ~1;
	f->dst_w &= ~1;
737

738 739
	f->dst_h &= ~1;
	f->dst_y &= ~1;
740

741 742
	f->src_h += f->src_y & 1;
	f->src_y &= ~1;
743

744 745
	f->src_h &= ~1;
	f->dst_h &= ~1;
746

747 748 749 750 751 752 753
	/* Due to rounding, we may have reduced the output size to <1/4 of
	   the source. Check again, but this time just resize. Don't change
	   source coordinates */
	if (f->dst_w < f->src_w / 4) {
		f->src_w &= ~3;
		f->dst_w = f->src_w / 4;
		f->dst_w += f->dst_w & 1;
754
	}
755 756 757 758
	if (f->dst_h < f->src_h / 4) {
		f->src_h &= ~3;
		f->dst_h = f->src_h / 4;
		f->dst_h += f->dst_h & 1;
759 760 761
	}

	/* Check again. If there's nothing to safe to display, stop now */
762
	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
763
	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
764
		return IVTV_YUV_UPDATE_INVALID;
765 766 767
	}

	/* Both x offset & width are linked, so they have to be done together */
768
	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
769 770
	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
771 772 773
		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
	}

774
	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
775 776 777 778 779
	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
	    (of->lace_mode != f->lace_mode) ||
	    (of->interlaced_y != f->interlaced_y) ||
	    (of->interlaced_uv != f->interlaced_uv)) {
780 781 782 783 784 785 786
		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
	}

	return yuv_update;
}

/* Update the scaling register to the requested value */
787
void ivtv_yuv_work_handler(struct ivtv *itv)
788
{
789 790 791
	struct yuv_playback_info *yi = &itv->yuv_info;
	struct yuv_frame_info f;
	int frame = yi->update_frame;
792 793
	u32 yuv_update;

794
	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
795
	f = yi->new_frame_info[frame];
796

797 798 799 800 801 802 803 804 805 806 807 808 809
	if (yi->track_osd) {
		/* Snapshot the osd pan info */
		f.pan_x = yi->osd_x_pan;
		f.pan_y = yi->osd_y_pan;
		f.vis_w = yi->osd_vis_w;
		f.vis_h = yi->osd_vis_h;
	} else {
		/* Not tracking the osd, so assume full screen */
		f.pan_x = 0;
		f.pan_y = 0;
		f.vis_w = 720;
		f.vis_h = yi->decode_height;
	}
810 811

	/* Calculate the display window coordinates. Exit if nothing left */
812
	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
813 814
		return;

815 816 817 818
	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
		write_reg(0x01008080, 0x2898);
	} else if (yuv_update) {
		write_reg(0x00108080, 0x2898);
819

820
		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
821
			ivtv_yuv_handle_horizontal(itv, &f);
822 823

		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
824
			ivtv_yuv_handle_vertical(itv, &f);
825
	}
826
	yi->old_frame_info = f;
827 828
}

829
static void ivtv_yuv_init(struct ivtv *itv)
830
{
831 832
	struct yuv_playback_info *yi = &itv->yuv_info;

833 834 835
	IVTV_DEBUG_YUV("ivtv_yuv_init\n");

	/* Take a snapshot of the current register settings */
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
	yi->reg_2834 = read_reg(0x02834);
	yi->reg_2838 = read_reg(0x02838);
	yi->reg_283c = read_reg(0x0283c);
	yi->reg_2840 = read_reg(0x02840);
	yi->reg_2844 = read_reg(0x02844);
	yi->reg_2848 = read_reg(0x02848);
	yi->reg_2854 = read_reg(0x02854);
	yi->reg_285c = read_reg(0x0285c);
	yi->reg_2864 = read_reg(0x02864);
	yi->reg_2870 = read_reg(0x02870);
	yi->reg_2874 = read_reg(0x02874);
	yi->reg_2898 = read_reg(0x02898);
	yi->reg_2890 = read_reg(0x02890);

	yi->reg_289c = read_reg(0x0289c);
	yi->reg_2918 = read_reg(0x02918);
	yi->reg_291c = read_reg(0x0291c);
	yi->reg_2920 = read_reg(0x02920);
	yi->reg_2924 = read_reg(0x02924);
	yi->reg_2928 = read_reg(0x02928);
	yi->reg_292c = read_reg(0x0292c);
	yi->reg_2930 = read_reg(0x02930);
	yi->reg_2934 = read_reg(0x02934);
	yi->reg_2938 = read_reg(0x02938);
	yi->reg_293c = read_reg(0x0293c);
	yi->reg_2940 = read_reg(0x02940);
	yi->reg_2944 = read_reg(0x02944);
	yi->reg_2948 = read_reg(0x02948);
	yi->reg_294c = read_reg(0x0294c);
	yi->reg_2950 = read_reg(0x02950);
	yi->reg_2954 = read_reg(0x02954);
	yi->reg_2958 = read_reg(0x02958);
	yi->reg_295c = read_reg(0x0295c);
	yi->reg_2960 = read_reg(0x02960);
	yi->reg_2964 = read_reg(0x02964);
	yi->reg_2968 = read_reg(0x02968);
	yi->reg_296c = read_reg(0x0296c);
	yi->reg_2970 = read_reg(0x02970);

	yi->v_filter_1 = -1;
	yi->v_filter_2 = -1;
	yi->h_filter = -1;
878 879

	/* Set some valid size info */
880 881
	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
882 883 884 885

	/* Bit 2 of reg 2878 indicates current decoder output format
	   0 : NTSC    1 : PAL */
	if (read_reg(0x2878) & 4)
886
		yi->decode_height = 576;
887
	else
888
		yi->decode_height = 480;
889

890 891 892
	if (!itv->osd_info) {
		yi->osd_vis_w = 720 - yi->osd_x_offset;
		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
893
	} else {
894 895 896 897
		/* If no visible size set, assume full size */
		if (!yi->osd_vis_w)
			yi->osd_vis_w = 720 - yi->osd_x_offset;

898
		if (!yi->osd_vis_h) {
899
			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
900
		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
901
			/* If output video standard has changed, requested height may
902 903 904 905 906
			   not be legal */
			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
					yi->osd_vis_h + yi->osd_y_offset,
					yi->decode_height);
			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
907 908
		}
	}
909 910

	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
911
	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
912
	if (yi->blanking_ptr) {
913
		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
914
	} else {
915 916
		yi->blanking_dmaptr = 0;
		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
917 918 919 920 921 922
	}

	/* Enable YUV decoder output */
	write_reg_sync(0x01, IVTV_REG_VDM);

	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
923
	atomic_set(&yi->next_dma_frame, 0);
924 925
}

926
/* Get next available yuv buffer on PVR350 */
927
static void ivtv_yuv_next_free(struct ivtv *itv)
928
{
929 930
	int draw, display;
	struct yuv_playback_info *yi = &itv->yuv_info;
931

932 933
	if (atomic_read(&yi->next_dma_frame) == -1)
		ivtv_yuv_init(itv);
934

935 936
	draw = atomic_read(&yi->next_fill_frame);
	display = atomic_read(&yi->next_dma_frame);
937

938 939
	if (display > draw)
		display -= IVTV_YUV_BUFFERS;
940

941 942 943 944 945 946 947 948 949
	if (draw - display >= yi->max_frames_buffered)
		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
	else
		yi->new_frame_info[draw].update = 0;

	yi->draw_frame = draw;
}

/* Set up frame according to ivtv_dma_frame parameters */
950
static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
951 952 953
{
	struct yuv_playback_info *yi = &itv->yuv_info;
	u8 frame = yi->draw_frame;
954 955 956 957
	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
	int lace_threshold = yi->lace_threshold;
958 959

	/* Preserve old update flag in case we're overwriting a queued frame */
960
	int update = nf->update;
961 962

	/* Take a snapshot of the yuv coordinate information */
963 964 965 966 967 968 969 970 971 972 973
	nf->src_x = args->src.left;
	nf->src_y = args->src.top;
	nf->src_w = args->src.width;
	nf->src_h = args->src.height;
	nf->dst_x = args->dst.left;
	nf->dst_y = args->dst.top;
	nf->dst_w = args->dst.width;
	nf->dst_h = args->dst.height;
	nf->tru_x = args->dst.left;
	nf->tru_w = args->src_width;
	nf->tru_h = args->src_height;
974

975
	/* Are we going to offset the Y plane */
976
	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
977

978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
	nf->update = 0;
	nf->interlaced_y = 0;
	nf->interlaced_uv = 0;
	nf->delay = 0;
	nf->sync_field = 0;
	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;

	if (lace_threshold < 0)
		lace_threshold = yi->decode_height - 1;

	/* Work out the lace settings */
	switch (nf->lace_mode) {
	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
		nf->interlaced = 0;
		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
			nf->interlaced_y = 0;
		else
			nf->interlaced_y = 1;

		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
			nf->interlaced_uv = 0;
		else
			nf->interlaced_uv = 1;
		break;

	case IVTV_YUV_MODE_AUTO:
		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
			nf->interlaced = 0;
			if ((nf->tru_h < 512) ||
1007 1008
			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
			    (nf->tru_w > 720 && nf->tru_h < 1021))
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
				nf->interlaced_y = 0;
			else
				nf->interlaced_y = 1;
			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
				nf->interlaced_uv = 0;
			else
				nf->interlaced_uv = 1;
		} else {
			nf->interlaced = 1;
			nf->interlaced_y = 1;
			nf->interlaced_uv = 1;
		}
		break;

	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
	default:
		nf->interlaced = 1;
		nf->interlaced_y = 1;
		nf->interlaced_uv = 1;
		break;
1029 1030
	}

1031 1032 1033
	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
		yi->old_frame_info_args = *nf;
		nf->update = 1;
1034
		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
1035
	}
1036

1037 1038 1039
	nf->update |= update;
	nf->sync_field = yi->lace_sync_field;
	nf->delay = nf->sync_field != of->sync_field;
1040 1041 1042 1043 1044 1045 1046 1047 1048
}

/* Frame is complete & ready for display */
void ivtv_yuv_frame_complete(struct ivtv *itv)
{
	atomic_set(&itv->yuv_info.next_fill_frame,
			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
}

1049
static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1050 1051 1052 1053
{
	DEFINE_WAIT(wait);
	int rc = 0;
	int got_sig = 0;
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
	/* DMA the frame */
	mutex_lock(&itv->udma.lock);

	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
		mutex_unlock(&itv->udma.lock);
		return rc;
	}

	ivtv_udma_prepare(itv);
	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
	/* if no UDMA is pending and no UDMA is in progress, then the DMA
1065
	   is finished */
1066 1067
	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
		/* don't interrupt if the DMA is in progress but break off
1068
		   a still pending DMA. */
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
		got_sig = signal_pending(current);
		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
			break;
		got_sig = 0;
		schedule();
	}
	finish_wait(&itv->dma_waitq, &wait);

	/* Unmap Last DMA Xfer */
	ivtv_udma_unmap(itv);

	if (got_sig) {
		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
		mutex_unlock(&itv->udma.lock);
		return -EINTR;
	}

1086
	ivtv_yuv_frame_complete(itv);
1087 1088 1089 1090 1091

	mutex_unlock(&itv->udma.lock);
	return rc;
}

1092 1093 1094 1095 1096 1097 1098 1099 1100
/* Setup frame according to V4L2 parameters */
void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
{
	struct yuv_playback_info *yi = &itv->yuv_info;
	struct ivtv_dma_frame dma_args;

	ivtv_yuv_next_free(itv);

	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
1101 1102
	dma_args.y_source = NULL;
	dma_args.uv_source = NULL;
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
	dma_args.src.left = 0;
	dma_args.src.top = 0;
	dma_args.src.width = yi->v4l2_src_w;
	dma_args.src.height = yi->v4l2_src_h;
	dma_args.dst = yi->main_rect;
	dma_args.src_width = yi->v4l2_src_w;
	dma_args.src_height = yi->v4l2_src_h;

	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
	ivtv_yuv_setup_frame(itv, &dma_args);

	if (!itv->dma_data_req_offset)
		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
}

/* Attempt to dma a frame from a user buffer */
int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
{
	struct yuv_playback_info *yi = &itv->yuv_info;
	struct ivtv_dma_frame dma_args;

	ivtv_yuv_setup_stream_frame(itv);

	/* We only need to supply source addresses for this */
	dma_args.y_source = src;
	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
	return ivtv_yuv_udma_frame(itv, &dma_args);
}

/* IVTV_IOC_DMA_FRAME ioctl handler */
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
1135
/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
1136 1137 1138 1139 1140 1141

	ivtv_yuv_next_free(itv);
	ivtv_yuv_setup_frame(itv, args);
	return ivtv_yuv_udma_frame(itv, args);
}

1142 1143
void ivtv_yuv_close(struct ivtv *itv)
{
1144
	struct yuv_playback_info *yi = &itv->yuv_info;
1145 1146 1147 1148 1149
	int h_filter, v_filter_1, v_filter_2;

	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
	ivtv_waitq(&itv->vsync_waitq);

1150 1151
	atomic_set(&yi->next_dma_frame, -1);
	atomic_set(&yi->next_fill_frame, 0);
1152 1153 1154 1155 1156 1157

	/* Reset registers we have changed so mpeg playback works */

	/* If we fully restore this register, the display may remain active.
	   Restore, but set one bit to blank the video. Firmware will always
	   clear this bit when needed, so not a problem. */
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
	write_reg(yi->reg_2898 | 0x01000000, 0x2898);

	write_reg(yi->reg_2834, 0x02834);
	write_reg(yi->reg_2838, 0x02838);
	write_reg(yi->reg_283c, 0x0283c);
	write_reg(yi->reg_2840, 0x02840);
	write_reg(yi->reg_2844, 0x02844);
	write_reg(yi->reg_2848, 0x02848);
	write_reg(yi->reg_2854, 0x02854);
	write_reg(yi->reg_285c, 0x0285c);
	write_reg(yi->reg_2864, 0x02864);
	write_reg(yi->reg_2870, 0x02870);
	write_reg(yi->reg_2874, 0x02874);
	write_reg(yi->reg_2890, 0x02890);
	write_reg(yi->reg_289c, 0x0289c);

	write_reg(yi->reg_2918, 0x02918);
	write_reg(yi->reg_291c, 0x0291c);
	write_reg(yi->reg_2920, 0x02920);
	write_reg(yi->reg_2924, 0x02924);
	write_reg(yi->reg_2928, 0x02928);
	write_reg(yi->reg_292c, 0x0292c);
	write_reg(yi->reg_2930, 0x02930);
	write_reg(yi->reg_2934, 0x02934);
	write_reg(yi->reg_2938, 0x02938);
	write_reg(yi->reg_293c, 0x0293c);
	write_reg(yi->reg_2940, 0x02940);
	write_reg(yi->reg_2944, 0x02944);
	write_reg(yi->reg_2948, 0x02948);
	write_reg(yi->reg_294c, 0x0294c);
	write_reg(yi->reg_2950, 0x02950);
	write_reg(yi->reg_2954, 0x02954);
	write_reg(yi->reg_2958, 0x02958);
	write_reg(yi->reg_295c, 0x0295c);
	write_reg(yi->reg_2960, 0x02960);
	write_reg(yi->reg_2964, 0x02964);
	write_reg(yi->reg_2968, 0x02968);
	write_reg(yi->reg_296c, 0x0296c);
	write_reg(yi->reg_2970, 0x02970);
1197 1198 1199 1200

	/* Prepare to restore filters */

	/* First the horizontal filter */
1201
	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
1202 1203
		/* An exact size match uses filter 0 */
		h_filter = 0;
1204
	} else {
1205
		/* Figure out which filter to use */
1206
		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
1207 1208
		h_filter = (h_filter >> 1) + (h_filter & 1);
		/* Only an exact size match can use filter 0. */
1209
		h_filter += !h_filter;
1210 1211 1212
	}

	/* Now the vertical filter */
1213
	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
1214 1215 1216
		/* An exact size match uses filter 0/1 */
		v_filter_1 = 0;
		v_filter_2 = 1;
1217
	} else {
1218
		/* Figure out which filter to use */
1219
		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
1220 1221
		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
		/* Only an exact size match can use filter 0 */
1222
		v_filter_1 += !v_filter_1;
1223 1224 1225 1226
		v_filter_2 = v_filter_1;
	}

	/* Now restore the filters */
1227
	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
1228 1229 1230 1231 1232 1233 1234 1235

	/* and clear a few registers */
	write_reg(0, 0x02814);
	write_reg(0, 0x0282c);
	write_reg(0, 0x02904);
	write_reg(0, 0x02910);

	/* Release the blanking buffer */
1236 1237 1238 1239
	if (yi->blanking_ptr) {
		kfree(yi->blanking_ptr);
		yi->blanking_ptr = NULL;
		pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1240 1241 1242
	}

	/* Invalidate the old dimension information */
1243 1244 1245 1246
	yi->old_frame_info.src_w = 0;
	yi->old_frame_info.src_h = 0;
	yi->old_frame_info_args.src_w = 0;
	yi->old_frame_info_args.src_h = 0;
1247 1248 1249 1250

	/* All done. */
	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
}