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