Blame view

drivers/media/video/ivtv/ivtv-yuv.c 37.5 KB
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
      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"
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
22
  #include "ivtv-udma.h"
83df8e7b0   Hans Verkuil   V4L/DVB (5405): A...
23
  #include "ivtv-yuv.h"
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
24

a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
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
612570f2c   Hans Verkuil   V4L/DVB (6091): i...
35
  };
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
36
  static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
37
  				  struct ivtv_dma_frame *args)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
38
39
40
  {
  	struct ivtv_dma_page_info y_dma;
  	struct ivtv_dma_page_info uv_dma;
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
41
42
43
  	struct yuv_playback_info *yi = &itv->yuv_info;
  	u8 frame = yi->draw_frame;
  	struct yuv_frame_info *f = &yi->new_frame_info[frame];
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
44
45
  	int i;
  	int y_pages, uv_pages;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
46
47
  	unsigned long y_buffer_offset, uv_buffer_offset;
  	int y_decode_height, uv_decode_height, y_size;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
48

33c0fcad2   Hans Verkuil   V4L/DVB (6092): i...
49
  	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
50
  	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
51
  	y_decode_height = uv_decode_height = f->src_h + f->src_y;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
52

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
53
  	if (f->offset_y)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
54
55
56
57
58
59
60
61
62
63
64
65
  		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) {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
66
67
68
69
  		IVTV_DEBUG_WARN
  		    ("prep_user_dma: SG_length %d page_count %d still full?
  ",
  		     dma->SG_length, dma->page_count);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
70
71
72
73
74
75
76
77
78
  		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);
7fd4b41f0   Paul Cassella   [media] ivtv: yuv...
79
80
81
82
83
84
  	uv_pages = 0; /* silence gcc. value is set and consumed only if: */
  	if (y_pages == y_dma.page_count) {
  		uv_pages = get_user_pages(current, current->mm,
  					  uv_dma.uaddr, uv_dma.page_count, 0, 1,
  					  &dma->map[y_pages], NULL);
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
85
  	up_read(&current->mm->mmap_sem);
7fd4b41f0   Paul Cassella   [media] ivtv: yuv...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  	if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
  		int rc = -EFAULT;
  
  		if (y_pages == y_dma.page_count) {
  			IVTV_DEBUG_WARN
  				("failed to map uv user pages, returned %d "
  				 "expecting %d
  ", uv_pages, uv_dma.page_count);
  
  			if (uv_pages >= 0) {
  				for (i = 0; i < uv_pages; i++)
  					put_page(dma->map[y_pages + i]);
  				rc = -EFAULT;
  			} else {
  				rc = uv_pages;
  			}
  		} else {
  			IVTV_DEBUG_WARN
  				("failed to map y user pages, returned %d "
  				 "expecting %d
  ", y_pages, y_dma.page_count);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
107
  		}
7fd4b41f0   Paul Cassella   [media] ivtv: yuv...
108
109
110
111
112
113
114
115
116
117
118
119
120
  		if (y_pages >= 0) {
  			for (i = 0; i < y_pages; i++)
  				put_page(dma->map[i]);
  			/*
  			 * Inherit the -EFAULT from rc's
  			 * initialization, but allow it to be
  			 * overriden by uv_pages above if it was an
  			 * actual errno.
  			 */
  		} else {
  			rc = y_pages;
  		}
  		return rc;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
121
  	}
7fd4b41f0   Paul Cassella   [media] ivtv: yuv...
122
  	dma->page_count = y_pages + uv_pages;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
123
  	/* Fill & map SG List */
8beb058f1   Hans Verkuil   V4L/DVB (6060): i...
124
  	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
0989fd2c8   Hans Verkuil   V4L/DVB (6058): i...
125
126
127
128
129
130
131
132
  		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers
  ");
  		for (i = 0; i < dma->page_count; i++) {
  			put_page(dma->map[i]);
  		}
  		dma->page_count = 0;
  		return -ENOMEM;
  	}
8ac05ae31   Hans Verkuil   V4L/DVB (10488): ...
133
  	dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
134
135
  
  	/* Fill SG Array with new values */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
136
  	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
137
138
  
  	/* If we've offset the y plane, ensure top area is blanked */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
139
  	if (f->offset_y && yi->blanking_dmaptr) {
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
140
  		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
141
  		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
142
143
  		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
  		dma->SG_length++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
144
145
146
147
148
149
150
151
152
153
154
155
  	}
  
  	/* 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)
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
156
  	int i, y, uv;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
157

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
158
159
160
  	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)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
161
162
163
164
165
166
167
168
169
170
  			IVTV_WARN ("YUV filter table not found in firmware.
  ");
  			return -1;
  		}
  	}
  	return 0;
  }
  
  static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
171
  	u32 i, line;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
172
173
174
  
  	/* If any filter is -1, then don't update it */
  	if (h_filter > -1) {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
194
195
  			write_reg(0, 0x02818);
  			write_reg(0, 0x02830);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
196
  		}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
197
198
  		IVTV_DEBUG_YUV("h_filter -> %d
  ", h_filter);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
199
200
201
  	}
  
  	if (v_filter_1 > -1) {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
202
203
204
205
206
207
208
209
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
210
  			write_reg(0, 0x02908);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
211
  		}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
212
213
  		IVTV_DEBUG_YUV("v_filter_1 -> %d
  ", v_filter_1);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
214
215
216
  	}
  
  	if (v_filter_2 > -1) {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
217
218
219
220
221
222
223
224
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
225
  			write_reg(0, 0x02914);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
226
  		}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
227
228
  		IVTV_DEBUG_YUV("v_filter_2 -> %d
  ", v_filter_2);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
229
230
  	}
  }
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
231
  static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
232
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
233
  	struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
234
235
236
237
238
239
240
  	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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
241
242
243
244
  	IVTV_DEBUG_WARN
  	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d
  ",
  	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
245
246
  
  	/* How wide is the src image */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
247
  	x_cutoff = f->src_w + f->src_x;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
248
249
  
  	/* Set the display width */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
250
  	reg_2834 = f->dst_w;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
251
252
253
  	reg_2838 = reg_2834;
  
  	/* Set the display position */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
254
  	reg_2890 = f->dst_x;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
255
256
257
258
259
260
261
262
263
264
  
  	/* 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. */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
265
266
267
268
269
  	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);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
270

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
271
  		if (f->dst_w >= f->src_w)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
272
273
274
275
  			reg_2870 = reg_2870 << 16 | reg_2870;
  		else
  			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
  	}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
276
  	if (f->dst_w < f->src_w)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
277
278
279
280
281
  		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) */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
282
  	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
283

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
284
  	if (f->dst_w >= f->src_w) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
285
  		x_cutoff &= ~1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
286
287
288
  		master_width = (f->src_w * 0x00200000) / (f->dst_w);
  		if (master_width * f->dst_w != f->src_w * 0x00200000)
  			master_width++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
289
290
291
292
293
294
295
296
297
298
  		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) */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
299
300
  		if (f->dst_w > f->src_w)
  			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
301
302
303
304
305
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
306
307
308
309
  	} 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++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
310
311
312
313
314
315
316
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
317
318
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
319
  		reg_2874 = 0x00000012;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
320
321
322
323
  	} else {
  		master_width = (f->src_w * 0x00100000) / f->dst_w;
  		if (master_width * f->dst_w != f->src_w * 0x00100000)
  			master_width++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
324
325
326
327
328
329
330
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
331
332
  		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
  		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
333
334
335
336
  		reg_2874 = 0x00000001;
  	}
  
  	/* Select the horizontal filter */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
337
  	if (f->src_w == f->dst_w) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
338
339
  		/* An exact size match uses filter 0 */
  		h_filter = 0;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
340
  	} else {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
341
  		/* Figure out which filter to use */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
342
  		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
343
344
  		h_filter = (h_filter >> 1) + (h_filter & 1);
  		/* Only an exact size match can use filter 0 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
345
  		h_filter += !h_filter;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
346
347
348
349
  	}
  
  	write_reg(reg_2834, 0x02834);
  	write_reg(reg_2838, 0x02838);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
350
351
352
  	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x
  ",
  		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
353
354
355
  
  	write_reg(reg_283c, 0x0283c);
  	write_reg(reg_2844, 0x02844);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
356
357
358
  	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x
  ",
  		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
359
360
361
  
  	write_reg(0x00080514, 0x02840);
  	write_reg(0x00100514, 0x02848);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
362
363
364
  	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x
  ",
  		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
365
366
  
  	write_reg(reg_2854, 0x02854);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
367
368
369
  	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x 
  ",
  		       yi->reg_2854, reg_2854);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
370
371
372
  
  	write_reg(reg_285c, 0x0285c);
  	write_reg(reg_2864, 0x02864);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
373
374
375
  	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x
  ",
  		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
376
377
  
  	write_reg(reg_2874, 0x02874);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
378
379
380
  	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x
  ",
  		       yi->reg_2874, reg_2874);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
381
382
  
  	write_reg(reg_2870, 0x02870);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
383
384
385
  	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x
  ",
  		       yi->reg_2870, reg_2870);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
386

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
387
388
389
390
  	write_reg(reg_2890, 0x02890);
  	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x
  ",
  		       yi->reg_2890, reg_2890);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
391
392
  
  	/* Only update the filter if we really need to */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
393
394
395
  	if (h_filter != yi->h_filter) {
  		ivtv_yuv_filter(itv, h_filter, -1, -1);
  		yi->h_filter = h_filter;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
396
397
  	}
  }
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
398
  static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
399
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
400
  	struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
401
402
403
404
405
406
407
  	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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
408
409
  	u32 src_major_y, src_minor_y;
  	u32 src_major_uv, src_minor_uv;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
410
411
  	u32 reg_2964_base, reg_2968_base;
  	int v_filter_1, v_filter_2;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
412
413
414
415
  	IVTV_DEBUG_WARN
  	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d
  ",
  	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
416
417
  
  	/* What scaling mode is being used... */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
418
419
420
  	IVTV_DEBUG_YUV("Scaling mode Y: %s
  ",
  		       f->interlaced_y ? "Interlaced" : "Progressive");
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
421

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
422
423
424
  	IVTV_DEBUG_YUV("Scaling mode UV: %s
  ",
  		       f->interlaced_uv ? "Interlaced" : "Progressive");
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
425
426
  
  	/* What is the source video being treated as... */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
427
428
429
  	IVTV_DEBUG_WARN("Source video: %s
  ",
  			f->interlaced ? "Interlaced" : "Progressive");
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
430
431
432
  
  	/* We offset into the image using two different index methods, so split
  	   the y source coord into two parts. */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
433
434
435
436
437
438
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
439
  	}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
440
441
  	src_minor_y = src_minor_uv;
  	src_major_y = src_major_uv;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
442

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
443
444
  	if (f->offset_y)
  		src_minor_y += 16;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
445

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
446
447
  	if (f->interlaced_y)
  		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
448
  	else
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
449
  		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
450

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
451
452
  	if (f->interlaced_uv)
  		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
453
  	else
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
454
  		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
455

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
456
457
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
458

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
459
460
461
462
  	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++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
463
464
465
466
467
468
469
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
470
471
  	} else if (f->dst_h >= f->src_h) {
  		master_height = (f->src_h * 0x00400000) / f->dst_h;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
472
473
474
475
476
477
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
478
  		if (f->interlaced_y) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
479
  			reg_2964_base >>= 3;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
480
481
  		} else {
  			reg_296c++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
482
483
  			reg_2964_base >>= 2;
  		}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
484
485
  		if (f->interlaced_uv)
  			reg_2928 >>= 1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
486
  		reg_2968_base >>= 3;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
487
488
  	} else if (f->dst_h >= f->src_h / 2) {
  		master_height = (f->src_h * 0x00200000) / f->dst_h;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
489
490
491
492
493
494
  		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;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
495
  		if (f->interlaced_y) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
496
  			reg_2964_base >>= 2;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
497
498
  		} else {
  			reg_296c++;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
499
500
  			reg_2964_base >>= 1;
  		}
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
501
502
  		if (f->interlaced_uv)
  			reg_2928 >>= 1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
503
  		reg_2968_base >>= 2;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
504
505
  	} else {
  		master_height = (f->src_h * 0x00100000) / f->dst_h;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
506
507
508
509
510
511
512
513
514
515
516
517
  		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 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
518
  	if (f->src_h == f->dst_h) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
519
520
521
522
  		reg_2934 = 0x00020000;
  		reg_293c = 0x00100000;
  		reg_2944 = 0x00040000;
  		reg_294c = 0x000b0000;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
523
  	} else {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
524
525
526
527
528
529
530
  		reg_2934 = 0x00000FF0;
  		reg_293c = 0x00000FF0;
  		reg_2944 = 0x00000FF0;
  		reg_294c = 0x00000FF0;
  	}
  
  	/* The first line to be displayed */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
531
532
533
  	reg_2950 = 0x00010000 + src_major_y;
  	if (f->interlaced_y)
  		reg_2950 += 0x00010000;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
534
  	reg_2954 = reg_2950 + 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
535
536
537
  	reg_2958 = 0x00010000 + (src_major_y >> 1);
  	if (f->interlaced_uv)
  		reg_2958 += 0x00010000;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
538
  	reg_295c = reg_2958 + 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
539
  	if (yi->decode_height == 480)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
540
541
542
  		reg_289c = 0x011e0017;
  	else
  		reg_289c = 0x01500017;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
543
544
  	if (f->dst_y < 0)
  		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
545
  	else
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
546
  		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
547
548
549
  
  	/* How much of the source to decode.
  	   Take into account the source offset */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
550
551
  	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
  		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
552
553
  
  	/* Calculate correct value for register 2964 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
554
  	if (f->src_h == f->dst_h) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
555
  		reg_2964 = 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
556
557
  	} else {
  		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  		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. */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
572
573
  	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
  		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
574

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
575
576
577
578
  	if (!f->interlaced_y)
  		reg_2964 -= 0x00010001;
  	if (!f->interlaced_uv)
  		reg_2968 -= 0x00010001;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
579
580
581
582
583
  
  	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
  	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
  
  	/* Select the vertical filter */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
584
  	if (f->src_h == f->dst_h) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
585
586
587
  		/* An exact size match uses filter 0/1 */
  		v_filter_1 = 0;
  		v_filter_2 = 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
588
  	} else {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
589
  		/* Figure out which filter to use */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
590
  		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
591
592
  		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
  		/* Only an exact size match can use filter 0 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
593
  		v_filter_1 += !v_filter_1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
594
595
596
597
598
  		v_filter_2 = v_filter_1;
  	}
  
  	write_reg(reg_2934, 0x02934);
  	write_reg(reg_293c, 0x0293c);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
599
600
601
  	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x
  ",
  		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
602
603
  	write_reg(reg_2944, 0x02944);
  	write_reg(reg_294c, 0x0294c);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
604
605
606
  	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x
  ",
  		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
607
608
609
  
  	/* Ensure 2970 is 0 (does it ever change ?) */
  /*	write_reg(0,0x02970); */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
610
611
  /*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x
  ", yi->reg_2970, 0); */
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
612
613
614
  
  	write_reg(reg_2930, 0x02938);
  	write_reg(reg_2930, 0x02930);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
615
616
617
  	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x
  ",
  		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
618
619
  
  	write_reg(reg_2928, 0x02928);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
620
621
622
623
  	write_reg(reg_2928 + 0x514, 0x0292C);
  	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x
  ",
  		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
624
625
  
  	write_reg(reg_2920, 0x02920);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
626
627
628
629
  	write_reg(reg_2920 + 0x514, 0x02924);
  	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x
  ",
  		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
630

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
631
632
633
634
635
  	write_reg(reg_2918, 0x02918);
  	write_reg(reg_291c, 0x0291C);
  	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x
  ",
  		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
636
637
  
  	write_reg(reg_296c, 0x0296c);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
638
639
640
  	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x
  ",
  		       yi->reg_296c, reg_296c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
641
642
643
  
  	write_reg(reg_2940, 0x02948);
  	write_reg(reg_2940, 0x02940);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
644
645
646
  	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x
  ",
  		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
647
648
649
  
  	write_reg(reg_2950, 0x02950);
  	write_reg(reg_2954, 0x02954);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
650
651
652
  	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x
  ",
  		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
653
654
655
  
  	write_reg(reg_2958, 0x02958);
  	write_reg(reg_295c, 0x0295C);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
656
657
658
  	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x
  ",
  		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
659
660
  
  	write_reg(reg_2960, 0x02960);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
661
662
663
  	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x 
  ",
  		       yi->reg_2960, reg_2960);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
664
665
666
  
  	write_reg(reg_2964, 0x02964);
  	write_reg(reg_2968, 0x02968);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
667
668
669
  	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x
  ",
  		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
670

2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
671
672
673
674
  	write_reg(reg_289c, 0x0289c);
  	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x
  ",
  		       yi->reg_289c, reg_289c);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
675
676
  
  	/* Only update filter 1 if we really need to */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
677
678
679
  	if (v_filter_1 != yi->v_filter_1) {
  		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
  		yi->v_filter_1 = v_filter_1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
680
681
682
  	}
  
  	/* Only update filter 2 if we really need to */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
683
684
685
  	if (v_filter_2 != yi->v_filter_2) {
  		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
  		yi->v_filter_2 = v_filter_2;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
686
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
687
688
689
  }
  
  /* Modify the supplied coordinate information to fit the visible osd area */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
690
  static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
691
  {
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
692
693
  	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
  	int osd_crop;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
694
695
  	u32 osd_scale;
  	u32 yuv_update = 0;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
696
  	/* Sorry, but no negative coords for src */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
697
698
699
700
  	if (f->src_x < 0)
  		f->src_x = 0;
  	if (f->src_y < 0)
  		f->src_y = 0;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
701
702
  
  	/* Can only reduce width down to 1/4 original size */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
703
704
705
706
707
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
708
709
710
  	}
  
  	/* Can only reduce height down to 1/4 original size */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
711
712
713
714
  	if (f->src_h / f->dst_h >= 2) {
  		/* Overflow may be because we're running progressive,
  		   so force mode switch */
  		f->interlaced_y = 1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
715
  		/* Make sure we're still within limits for interlace */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
716
  		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
717
  			/* If we reach here we'll have to force the height. */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
718
719
720
721
  			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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
722
723
724
725
  		}
  	}
  
  	/* If there's nothing to safe to display, we may as well stop now */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
726
  	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
727
  	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
728
  		return IVTV_YUV_UPDATE_INVALID;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
729
730
731
  	}
  
  	/* Ensure video remains inside OSD area */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
732
  	osd_scale = (f->src_h << 16) / f->dst_h;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
733

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
734
  	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
735
  		/* Falls off the upper edge - crop */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
736
737
738
739
740
741
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
742
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
743
  	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
744
  		/* Falls off the lower edge - crop */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
745
746
  		f->dst_h -= osd_crop;
  		f->src_h -= (osd_scale * osd_crop) >> 16;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
747
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
748
  	osd_scale = (f->src_w << 16) / f->dst_w;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
749

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
750
  	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
751
  		/* Fall off the left edge - crop */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
752
753
754
755
756
757
  		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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
758
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
759
  	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
760
  		/* Falls off the right edge - crop */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
761
762
  		f->dst_w -= osd_crop;
  		f->src_w -= (osd_scale * osd_crop) >> 16;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
763
  	}
88ab075ae   Ian Armstrong   V4L/DVB (7243): i...
764
765
766
767
768
  	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;
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
769
770
771
  
  	/* Width & height for both src & dst must be even.
  	   Same for coordinates. */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
772
773
  	f->dst_w &= ~1;
  	f->dst_x &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
774

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
775
776
  	f->src_w += f->src_x & 1;
  	f->src_x &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
777

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
778
779
  	f->src_w &= ~1;
  	f->dst_w &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
780

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
781
782
  	f->dst_h &= ~1;
  	f->dst_y &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
783

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
784
785
  	f->src_h += f->src_y & 1;
  	f->src_y &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
786

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
787
788
  	f->src_h &= ~1;
  	f->dst_h &= ~1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
789

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
790
791
792
793
794
795
796
  	/* 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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
797
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
798
799
800
801
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
802
803
804
  	}
  
  	/* Check again. If there's nothing to safe to display, stop now */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
805
  	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
806
  	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
807
  		return IVTV_YUV_UPDATE_INVALID;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
808
809
810
  	}
  
  	/* Both x offset & width are linked, so they have to be done together */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
811
  	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
812
813
  	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
  	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
814
815
  		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
816
  	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
817
818
819
820
821
  	    (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)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
822
823
824
825
826
827
828
  		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
  	}
  
  	return yuv_update;
  }
  
  /* Update the scaling register to the requested value */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
829
  void ivtv_yuv_work_handler(struct ivtv *itv)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
830
  {
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
831
832
833
  	struct yuv_playback_info *yi = &itv->yuv_info;
  	struct yuv_frame_info f;
  	int frame = yi->update_frame;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
834
  	u32 yuv_update;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
835
836
  	IVTV_DEBUG_YUV("Update yuv registers for frame %d
  ", frame);
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
837
  	f = yi->new_frame_info[frame];
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
838

88ab075ae   Ian Armstrong   V4L/DVB (7243): i...
839
840
841
842
843
844
845
846
847
848
849
850
851
  	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;
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
852
853
  
  	/* Calculate the display window coordinates. Exit if nothing left */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
854
  	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
855
  		return;
0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
856
857
858
859
  	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
  		write_reg(0x01008080, 0x2898);
  	} else if (yuv_update) {
  		write_reg(0x00108080, 0x2898);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
860

0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
861
  		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
862
  			ivtv_yuv_handle_horizontal(itv, &f);
0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
863
864
  
  		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
865
  			ivtv_yuv_handle_vertical(itv, &f);
0bfeb04a9   Ian Armstrong   V4L/DVB (6345): i...
866
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
867
  	yi->old_frame_info = f;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
868
  }
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
869
  static void ivtv_yuv_init(struct ivtv *itv)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
870
  {
195b12525   Ian Armstrong   V4L/DVB (6346): i...
871
  	struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
872
873
874
875
  	IVTV_DEBUG_YUV("ivtv_yuv_init
  ");
  
  	/* Take a snapshot of the current register settings */
195b12525   Ian Armstrong   V4L/DVB (6346): i...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
918
919
  
  	/* Set some valid size info */
195b12525   Ian Armstrong   V4L/DVB (6346): i...
920
921
  	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
  	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
922
923
924
925
  
  	/* Bit 2 of reg 2878 indicates current decoder output format
  	   0 : NTSC    1 : PAL */
  	if (read_reg(0x2878) & 4)
195b12525   Ian Armstrong   V4L/DVB (6346): i...
926
  		yi->decode_height = 576;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
927
  	else
195b12525   Ian Armstrong   V4L/DVB (6346): i...
928
  		yi->decode_height = 480;
b4b38bd63   Ian Armstrong   V4L/DVB (5970): i...
929

195b12525   Ian Armstrong   V4L/DVB (6346): i...
930
931
932
  	if (!itv->osd_info) {
  		yi->osd_vis_w = 720 - yi->osd_x_offset;
  		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
b4b38bd63   Ian Armstrong   V4L/DVB (5970): i...
933
  	} else {
195b12525   Ian Armstrong   V4L/DVB (6346): i...
934
935
936
  		/* If no visible size set, assume full size */
  		if (!yi->osd_vis_w)
  			yi->osd_vis_w = 720 - yi->osd_x_offset;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
937
  		if (!yi->osd_vis_h) {
195b12525   Ian Armstrong   V4L/DVB (6346): i...
938
  			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
939
  		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
195b12525   Ian Armstrong   V4L/DVB (6346): i...
940
  			/* If output video standard has changed, requested height may
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
941
942
943
944
945
946
  			   not be legal */
  			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)
  ",
  					yi->osd_vis_h + yi->osd_y_offset,
  					yi->decode_height);
  			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
b4b38bd63   Ian Armstrong   V4L/DVB (5970): i...
947
948
  		}
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
949
950
  
  	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
3f98387ef   Hans Verkuil   V4L/DVB (7854): c...
951
  	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
952
  	if (yi->blanking_ptr) {
8ac05ae31   Hans Verkuil   V4L/DVB (10488): ...
953
  		yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
954
  	} else {
195b12525   Ian Armstrong   V4L/DVB (6346): i...
955
956
957
  		yi->blanking_dmaptr = 0;
  		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer
  ");
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
958
  	}
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
959
960
961
962
  	/* Enable YUV decoder output */
  	write_reg_sync(0x01, IVTV_REG_VDM);
  
  	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
195b12525   Ian Armstrong   V4L/DVB (6346): i...
963
  	atomic_set(&yi->next_dma_frame, 0);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
964
  }
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
965
  /* Get next available yuv buffer on PVR350 */
5eedc4667   Adrian Bunk   V4L/DVB (7105): i...
966
  static void ivtv_yuv_next_free(struct ivtv *itv)
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
967
  {
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
968
969
  	int draw, display;
  	struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
970

a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
971
972
  	if (atomic_read(&yi->next_dma_frame) == -1)
  		ivtv_yuv_init(itv);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
973

a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
974
975
  	draw = atomic_read(&yi->next_fill_frame);
  	display = atomic_read(&yi->next_dma_frame);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
976

a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
977
978
  	if (display > draw)
  		display -= IVTV_YUV_BUFFERS;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
979

a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
980
981
982
983
984
985
986
987
988
  	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 */
5eedc4667   Adrian Bunk   V4L/DVB (7105): i...
989
  static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
990
991
992
  {
  	struct yuv_playback_info *yi = &itv->yuv_info;
  	u8 frame = yi->draw_frame;
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
993
994
995
996
  	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;
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
997
998
  
  	/* Preserve old update flag in case we're overwriting a queued frame */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
999
  	int update = nf->update;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1000
1001
  
  	/* Take a snapshot of the yuv coordinate information */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  	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;
bfd7beacf   Ian Armstrong   V4L/DVB (5973): i...
1013

1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1014
  	/* Are we going to offset the Y plane */
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1015
  	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1016

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  	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) ||
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1046
1047
  			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
  			    (nf->tru_w > 720 && nf->tru_h < 1021))
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
  				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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1068
  	}
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1069
1070
1071
  	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
  		yi->old_frame_info_args = *nf;
  		nf->update = 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1072
1073
  		IVTV_DEBUG_YUV("Requesting reg update for frame %d
  ", frame);
3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1074
  	}
943e8910d   Ian Armstrong   V4L/DVB (5972): i...
1075

3b5c1c8e7   Ian Armstrong   V4L/DVB (6716): i...
1076
1077
1078
  	nf->update |= update;
  	nf->sync_field = yi->lace_sync_field;
  	nf->delay = nf->sync_field != of->sync_field;
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
1079
1080
1081
1082
1083
1084
1085
1086
  }
  
  /* 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);
  }
5eedc4667   Adrian Bunk   V4L/DVB (7105): i...
1087
  static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
1088
1089
1090
1091
  {
  	DEFINE_WAIT(wait);
  	int rc = 0;
  	int got_sig = 0;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  	/* 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
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1103
  	   is finished */
ec105a42a   Hans Verkuil   V4L/DVB (11674): ...
1104
1105
  	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
  	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1106
  		/* don't interrupt if the DMA is in progress but break off
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1107
  		   a still pending DMA. */
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  		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
  ");
  		mutex_unlock(&itv->udma.lock);
  		return -EINTR;
  	}
a3e5f5e2d   Ian Armstrong   V4L/DVB (6713): i...
1125
  	ivtv_yuv_frame_complete(itv);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1126
1127
1128
1129
  
  	mutex_unlock(&itv->udma.lock);
  	return rc;
  }
77aded6ba   Ian Armstrong   V4L/DVB (6717): i...
1130
1131
1132
1133
1134
1135
1136
1137
1138
  /* 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... */
a6a3a17b7   Harvey Harrison   media: fix intege...
1139
1140
  	dma_args.y_source = NULL;
  	dma_args.uv_source = NULL;
77aded6ba   Ian Armstrong   V4L/DVB (6717): i...
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  	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 */
b0510f8dc   Al Viro   V4L/DVB (7963): i...
1157
  int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
77aded6ba   Ian Armstrong   V4L/DVB (6717): i...
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  {
  	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)
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1173
1174
  /*	IVTV_DEBUG_INFO("yuv_prep_frame
  "); */
77aded6ba   Ian Armstrong   V4L/DVB (6717): i...
1175
1176
1177
1178
1179
  
  	ivtv_yuv_next_free(itv);
  	ivtv_yuv_setup_frame(itv, args);
  	return ivtv_yuv_udma_frame(itv, args);
  }
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1180
1181
  void ivtv_yuv_close(struct ivtv *itv)
  {
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1182
  	struct yuv_playback_info *yi = &itv->yuv_info;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1183
1184
1185
1186
1187
  	int h_filter, v_filter_1, v_filter_2;
  
  	IVTV_DEBUG_YUV("ivtv_yuv_close
  ");
  	ivtv_waitq(&itv->vsync_waitq);
2bd7ac55c   Ian Armstrong   V4L/DVB (9166): i...
1188
  	yi->running = 0;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1189
1190
  	atomic_set(&yi->next_dma_frame, -1);
  	atomic_set(&yi->next_fill_frame, 0);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1191
1192
1193
1194
1195
1196
  
  	/* 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. */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  	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);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1236
1237
1238
1239
  
  	/* Prepare to restore filters */
  
  	/* First the horizontal filter */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1240
  	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1241
1242
  		/* An exact size match uses filter 0 */
  		h_filter = 0;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1243
  	} else {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1244
  		/* Figure out which filter to use */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1245
  		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1246
1247
  		h_filter = (h_filter >> 1) + (h_filter & 1);
  		/* Only an exact size match can use filter 0. */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1248
  		h_filter += !h_filter;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1249
1250
1251
  	}
  
  	/* Now the vertical filter */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1252
  	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1253
1254
1255
  		/* An exact size match uses filter 0/1 */
  		v_filter_1 = 0;
  		v_filter_2 = 1;
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1256
  	} else {
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1257
  		/* Figure out which filter to use */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1258
  		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1259
1260
  		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
  		/* Only an exact size match can use filter 0 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1261
  		v_filter_1 += !v_filter_1;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1262
1263
1264
1265
  		v_filter_2 = v_filter_1;
  	}
  
  	/* Now restore the filters */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1266
  	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1267
1268
1269
1270
1271
1272
1273
1274
  
  	/* 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 */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1275
1276
1277
  	if (yi->blanking_ptr) {
  		kfree(yi->blanking_ptr);
  		yi->blanking_ptr = NULL;
8ac05ae31   Hans Verkuil   V4L/DVB (10488): ...
1278
  		pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1279
1280
1281
  	}
  
  	/* Invalidate the old dimension information */
2b057e8dc   Ian Armstrong   V4L/DVB (6719): i...
1282
1283
1284
1285
  	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;
1a0adaf37   Hans Verkuil   V4L/DVB (5345): i...
1286
1287
1288
1289
  
  	/* All done. */
  	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
  }