blob: ee91107376c75440ca56f6620924724a2267c5ab [file] [log] [blame]
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001/*
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"
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030022#include "ivtv-udma.h"
Hans Verkuil83df8e72007-03-10 06:54:58 -030023#include "ivtv-yuv.h"
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030024
Ian Armstronga3e5f5e2007-10-20 14:52:55 -030025/* YUV buffer offsets */
26const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
27 0x001a8600,
28 0x00240400,
29 0x002d8200,
30 0x00370000,
31 0x00029000,
32 0x000C0E00,
33 0x006B0400,
34 0x00748200
Hans Verkuil612570f2007-08-23 05:42:59 -030035};
36
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030037static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
Ian Armstrong2b057e82007-11-13 19:15:25 -030038 struct ivtv_dma_frame *args)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030039{
40 struct ivtv_dma_page_info y_dma;
41 struct ivtv_dma_page_info uv_dma;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -030042 struct yuv_playback_info *yi = &itv->yuv_info;
43 u8 frame = yi->draw_frame;
44 struct yuv_frame_info *f = &yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030045 int i;
46 int y_pages, uv_pages;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030047 unsigned long y_buffer_offset, uv_buffer_offset;
48 int y_decode_height, uv_decode_height, y_size;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030049
Hans Verkuil33c0fca2007-08-23 06:32:46 -030050 y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030051 uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
52
Ian Armstrong2b057e82007-11-13 19:15:25 -030053 y_decode_height = uv_decode_height = f->src_h + f->src_y;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030054
Ian Armstrong3b5c1c82007-10-22 14:24:26 -030055 if (f->offset_y)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030056 y_buffer_offset += 720 * 16;
57
58 if (y_decode_height & 15)
59 y_decode_height = (y_decode_height + 16) & ~15;
60
61 if (uv_decode_height & 31)
62 uv_decode_height = (uv_decode_height + 32) & ~31;
63
64 y_size = 720 * y_decode_height;
65
66 /* Still in USE */
67 if (dma->SG_length || dma->page_count) {
Ian Armstrong2b057e82007-11-13 19:15:25 -030068 IVTV_DEBUG_WARN
69 ("prep_user_dma: SG_length %d page_count %d still full?\n",
70 dma->SG_length, dma->page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030071 return -EBUSY;
72 }
73
74 ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
75 ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
76
77 /* Get user pages for DMA Xfer */
78 down_read(&current->mm->mmap_sem);
79 y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
80 uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
81 up_read(&current->mm->mmap_sem);
82
83 dma->page_count = y_dma.page_count + uv_dma.page_count;
84
85 if (y_pages + uv_pages != dma->page_count) {
Ian Armstrong2b057e82007-11-13 19:15:25 -030086 IVTV_DEBUG_WARN
87 ("failed to map user pages, returned %d instead of %d\n",
88 y_pages + uv_pages, dma->page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030089
90 for (i = 0; i < dma->page_count; i++) {
91 put_page(dma->map[i]);
92 }
93 dma->page_count = 0;
94 return -EINVAL;
95 }
96
97 /* Fill & map SG List */
Hans Verkuil8beb0582007-08-19 17:56:41 -030098 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
Hans Verkuil0989fd22007-08-19 12:25:39 -030099 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
100 for (i = 0; i < dma->page_count; i++) {
101 put_page(dma->map[i]);
102 }
103 dma->page_count = 0;
104 return -ENOMEM;
105 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300106 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
107
108 /* Fill SG Array with new values */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300109 ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300110
111 /* If we've offset the y plane, ensure top area is blanked */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300112 if (f->offset_y && yi->blanking_dmaptr) {
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300113 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300114 dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300115 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
116 dma->SG_length++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300117 }
118
119 /* Tag SG Array with Interrupt Bit */
120 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
121
122 ivtv_udma_sync_for_device(itv);
123 return 0;
124}
125
126/* We rely on a table held in the firmware - Quick check. */
127int ivtv_yuv_filter_check(struct ivtv *itv)
128{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300129 int i, y, uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300130
Ian Armstrong2b057e82007-11-13 19:15:25 -0300131 for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
132 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
133 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300134 IVTV_WARN ("YUV filter table not found in firmware.\n");
135 return -1;
136 }
137 }
138 return 0;
139}
140
141static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
142{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300143 u32 i, line;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300144
145 /* If any filter is -1, then don't update it */
146 if (h_filter > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300147 if (h_filter > 4)
148 h_filter = 4;
149 i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
150 for (line = 0; line < 16; line++) {
151 write_reg(read_dec(i), 0x02804);
152 write_reg(read_dec(i), 0x0281c);
153 i += 4;
154 write_reg(read_dec(i), 0x02808);
155 write_reg(read_dec(i), 0x02820);
156 i += 4;
157 write_reg(read_dec(i), 0x0280c);
158 write_reg(read_dec(i), 0x02824);
159 i += 4;
160 write_reg(read_dec(i), 0x02810);
161 write_reg(read_dec(i), 0x02828);
162 i += 4;
163 write_reg(read_dec(i), 0x02814);
164 write_reg(read_dec(i), 0x0282c);
165 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300166 write_reg(0, 0x02818);
167 write_reg(0, 0x02830);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300168 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300169 IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300170 }
171
172 if (v_filter_1 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300173 if (v_filter_1 > 4)
174 v_filter_1 = 4;
175 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
176 for (line = 0; line < 16; line++) {
177 write_reg(read_dec(i), 0x02900);
178 i += 4;
179 write_reg(read_dec(i), 0x02904);
180 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300181 write_reg(0, 0x02908);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300182 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300183 IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300184 }
185
186 if (v_filter_2 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300187 if (v_filter_2 > 4)
188 v_filter_2 = 4;
189 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
190 for (line = 0; line < 16; line++) {
191 write_reg(read_dec(i), 0x0290c);
192 i += 4;
193 write_reg(read_dec(i), 0x02910);
194 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300195 write_reg(0, 0x02914);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300196 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300197 IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300198 }
199}
200
Ian Armstrong2b057e82007-11-13 19:15:25 -0300201static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300202{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300203 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300204 u32 reg_2834, reg_2838, reg_283c;
205 u32 reg_2844, reg_2854, reg_285c;
206 u32 reg_2864, reg_2874, reg_2890;
207 u32 reg_2870, reg_2870_base, reg_2870_offset;
208 int x_cutoff;
209 int h_filter;
210 u32 master_width;
211
Ian Armstrong2b057e82007-11-13 19:15:25 -0300212 IVTV_DEBUG_WARN
213 ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
214 f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300215
216 /* How wide is the src image */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300217 x_cutoff = f->src_w + f->src_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300218
219 /* Set the display width */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300220 reg_2834 = f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300221 reg_2838 = reg_2834;
222
223 /* Set the display position */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300224 reg_2890 = f->dst_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300225
226 /* Index into the image horizontally */
227 reg_2870 = 0;
228
229 /* 2870 is normally fudged to align video coords with osd coords.
230 If running full screen, it causes an unwanted left shift
231 Remove the fudge if we almost fill the screen.
232 Gradually adjust the offset to avoid the video 'snapping'
233 left/right if it gets dragged through this region.
234 Only do this if osd is full width. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300235 if (f->vis_w == 720) {
236 if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
237 reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
238 else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
239 reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300240
Ian Armstrong2b057e82007-11-13 19:15:25 -0300241 if (f->dst_w >= f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300242 reg_2870 = reg_2870 << 16 | reg_2870;
243 else
244 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
245 }
246
Ian Armstrong2b057e82007-11-13 19:15:25 -0300247 if (f->dst_w < f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300248 reg_2870 = 0x000d000e - reg_2870;
249 else
250 reg_2870 = 0x0012000e - reg_2870;
251
252 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300253 reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300254
Ian Armstrong2b057e82007-11-13 19:15:25 -0300255 if (f->dst_w >= f->src_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300256 x_cutoff &= ~1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300257 master_width = (f->src_w * 0x00200000) / (f->dst_w);
258 if (master_width * f->dst_w != f->src_w * 0x00200000)
259 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300260 reg_2834 = (reg_2834 << 16) | x_cutoff;
261 reg_2838 = (reg_2838 << 16) | x_cutoff;
262 reg_283c = master_width >> 2;
263 reg_2844 = master_width >> 2;
264 reg_2854 = master_width;
265 reg_285c = master_width >> 1;
266 reg_2864 = master_width >> 1;
267
268 /* We also need to factor in the scaling
269 (src_w - dst_w) / (src_w / 4) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300270 if (f->dst_w > f->src_w)
271 reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300272 else
273 reg_2870_base = 0;
274
275 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
276 reg_2874 = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300277 } else if (f->dst_w < f->src_w / 2) {
278 master_width = (f->src_w * 0x00080000) / f->dst_w;
279 if (master_width * f->dst_w != f->src_w * 0x00080000)
280 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300281 reg_2834 = (reg_2834 << 16) | x_cutoff;
282 reg_2838 = (reg_2838 << 16) | x_cutoff;
283 reg_283c = master_width >> 2;
284 reg_2844 = master_width >> 1;
285 reg_2854 = master_width;
286 reg_285c = master_width >> 1;
287 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300288 reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
289 reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300290 reg_2874 = 0x00000012;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300291 } else {
292 master_width = (f->src_w * 0x00100000) / f->dst_w;
293 if (master_width * f->dst_w != f->src_w * 0x00100000)
294 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300295 reg_2834 = (reg_2834 << 16) | x_cutoff;
296 reg_2838 = (reg_2838 << 16) | x_cutoff;
297 reg_283c = master_width >> 2;
298 reg_2844 = master_width >> 1;
299 reg_2854 = master_width;
300 reg_285c = master_width >> 1;
301 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300302 reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
303 reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300304 reg_2874 = 0x00000001;
305 }
306
307 /* Select the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300308 if (f->src_w == f->dst_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300309 /* An exact size match uses filter 0 */
310 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300311 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300312 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300313 h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300314 h_filter = (h_filter >> 1) + (h_filter & 1);
315 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300316 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300317 }
318
319 write_reg(reg_2834, 0x02834);
320 write_reg(reg_2838, 0x02838);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300321 IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
322 yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300323
324 write_reg(reg_283c, 0x0283c);
325 write_reg(reg_2844, 0x02844);
326
Ian Armstrong2b057e82007-11-13 19:15:25 -0300327 IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
328 yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300329
330 write_reg(0x00080514, 0x02840);
331 write_reg(0x00100514, 0x02848);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300332 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
333 yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300334
335 write_reg(reg_2854, 0x02854);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300336 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
337 yi->reg_2854, reg_2854);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300338
339 write_reg(reg_285c, 0x0285c);
340 write_reg(reg_2864, 0x02864);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300341 IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
342 yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300343
344 write_reg(reg_2874, 0x02874);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300345 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
346 yi->reg_2874, reg_2874);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300347
348 write_reg(reg_2870, 0x02870);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300349 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
350 yi->reg_2870, reg_2870);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300351
Ian Armstrong2b057e82007-11-13 19:15:25 -0300352 write_reg(reg_2890, 0x02890);
353 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
354 yi->reg_2890, reg_2890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300355
356 /* Only update the filter if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300357 if (h_filter != yi->h_filter) {
358 ivtv_yuv_filter(itv, h_filter, -1, -1);
359 yi->h_filter = h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300360 }
361}
362
Ian Armstrong2b057e82007-11-13 19:15:25 -0300363static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300364{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300365 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300366 u32 master_height;
367 u32 reg_2918, reg_291c, reg_2920, reg_2928;
368 u32 reg_2930, reg_2934, reg_293c;
369 u32 reg_2940, reg_2944, reg_294c;
370 u32 reg_2950, reg_2954, reg_2958, reg_295c;
371 u32 reg_2960, reg_2964, reg_2968, reg_296c;
372 u32 reg_289c;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300373 u32 src_major_y, src_minor_y;
374 u32 src_major_uv, src_minor_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300375 u32 reg_2964_base, reg_2968_base;
376 int v_filter_1, v_filter_2;
377
Ian Armstrong2b057e82007-11-13 19:15:25 -0300378 IVTV_DEBUG_WARN
379 ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
380 f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300381
382 /* What scaling mode is being used... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300383 IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
384 f->interlaced_y ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300385
Ian Armstrong2b057e82007-11-13 19:15:25 -0300386 IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
387 f->interlaced_uv ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300388
389 /* What is the source video being treated as... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300390 IVTV_DEBUG_WARN("Source video: %s\n",
391 f->interlaced ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300392
393 /* We offset into the image using two different index methods, so split
394 the y source coord into two parts. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300395 if (f->src_y < 8) {
396 src_minor_uv = f->src_y;
397 src_major_uv = 0;
398 } else {
399 src_minor_uv = 8;
400 src_major_uv = f->src_y - 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300401 }
402
Ian Armstrong2b057e82007-11-13 19:15:25 -0300403 src_minor_y = src_minor_uv;
404 src_major_y = src_major_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300405
Ian Armstrong2b057e82007-11-13 19:15:25 -0300406 if (f->offset_y)
407 src_minor_y += 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300408
Ian Armstrong2b057e82007-11-13 19:15:25 -0300409 if (f->interlaced_y)
410 reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300411 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300412 reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300413
Ian Armstrong2b057e82007-11-13 19:15:25 -0300414 if (f->interlaced_uv)
415 reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300416 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300417 reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300418
Ian Armstrong2b057e82007-11-13 19:15:25 -0300419 reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
420 reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300421
Ian Armstrong2b057e82007-11-13 19:15:25 -0300422 if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
423 master_height = (f->src_h * 0x00400000) / f->dst_h;
424 if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
425 master_height++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300426 reg_2920 = master_height >> 2;
427 reg_2928 = master_height >> 3;
428 reg_2930 = master_height;
429 reg_2940 = master_height >> 1;
430 reg_2964_base >>= 3;
431 reg_2968_base >>= 3;
432 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300433 } else if (f->dst_h >= f->src_h) {
434 master_height = (f->src_h * 0x00400000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300435 master_height = (master_height >> 1) + (master_height & 1);
436 reg_2920 = master_height >> 2;
437 reg_2928 = master_height >> 2;
438 reg_2930 = master_height;
439 reg_2940 = master_height >> 1;
440 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300441 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300442 reg_2964_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300443 } else {
444 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300445 reg_2964_base >>= 2;
446 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300447 if (f->interlaced_uv)
448 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300449 reg_2968_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300450 } else if (f->dst_h >= f->src_h / 2) {
451 master_height = (f->src_h * 0x00200000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300452 master_height = (master_height >> 1) + (master_height & 1);
453 reg_2920 = master_height >> 2;
454 reg_2928 = master_height >> 2;
455 reg_2930 = master_height;
456 reg_2940 = master_height;
457 reg_296c = 0x00000101;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300458 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300459 reg_2964_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300460 } else {
461 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300462 reg_2964_base >>= 1;
463 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300464 if (f->interlaced_uv)
465 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300466 reg_2968_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300467 } else {
468 master_height = (f->src_h * 0x00100000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300469 master_height = (master_height >> 1) + (master_height & 1);
470 reg_2920 = master_height >> 2;
471 reg_2928 = master_height >> 2;
472 reg_2930 = master_height;
473 reg_2940 = master_height;
474 reg_2964_base >>= 1;
475 reg_2968_base >>= 2;
476 reg_296c = 0x00000102;
477 }
478
479 /* FIXME These registers change depending on scaled / unscaled output
480 We really need to work out what they should be */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300481 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300482 reg_2934 = 0x00020000;
483 reg_293c = 0x00100000;
484 reg_2944 = 0x00040000;
485 reg_294c = 0x000b0000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300486 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300487 reg_2934 = 0x00000FF0;
488 reg_293c = 0x00000FF0;
489 reg_2944 = 0x00000FF0;
490 reg_294c = 0x00000FF0;
491 }
492
493 /* The first line to be displayed */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300494 reg_2950 = 0x00010000 + src_major_y;
495 if (f->interlaced_y)
496 reg_2950 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300497 reg_2954 = reg_2950 + 1;
498
Ian Armstrong2b057e82007-11-13 19:15:25 -0300499 reg_2958 = 0x00010000 + (src_major_y >> 1);
500 if (f->interlaced_uv)
501 reg_2958 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300502 reg_295c = reg_2958 + 1;
503
Ian Armstrong2b057e82007-11-13 19:15:25 -0300504 if (yi->decode_height == 480)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300505 reg_289c = 0x011e0017;
506 else
507 reg_289c = 0x01500017;
508
Ian Armstrong2b057e82007-11-13 19:15:25 -0300509 if (f->dst_y < 0)
510 reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300511 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300512 reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300513
514 /* How much of the source to decode.
515 Take into account the source offset */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300516 reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
517 (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300518
519 /* Calculate correct value for register 2964 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300520 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300521 reg_2964 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300522 } else {
523 reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300524 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
525 }
526 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
527 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
528
529 /* Okay, we've wasted time working out the correct value,
530 but if we use it, it fouls the the window alignment.
531 Fudge it to what we want... */
532 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
533 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
534
535 /* Deviate further from what it should be. I find the flicker headache
536 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
537 colours foul. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300538 if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
539 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300540
Ian Armstrong2b057e82007-11-13 19:15:25 -0300541 if (!f->interlaced_y)
542 reg_2964 -= 0x00010001;
543 if (!f->interlaced_uv)
544 reg_2968 -= 0x00010001;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300545
546 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
547 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
548
549 /* Select the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300550 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300551 /* An exact size match uses filter 0/1 */
552 v_filter_1 = 0;
553 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300554 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300555 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300556 v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300557 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
558 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300559 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300560 v_filter_2 = v_filter_1;
561 }
562
563 write_reg(reg_2934, 0x02934);
564 write_reg(reg_293c, 0x0293c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300565 IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
566 yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300567 write_reg(reg_2944, 0x02944);
568 write_reg(reg_294c, 0x0294c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300569 IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
570 yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300571
572 /* Ensure 2970 is 0 (does it ever change ?) */
573/* write_reg(0,0x02970); */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300574/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300575
576 write_reg(reg_2930, 0x02938);
577 write_reg(reg_2930, 0x02930);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300578 IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
579 yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300580
581 write_reg(reg_2928, 0x02928);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300582 write_reg(reg_2928 + 0x514, 0x0292C);
583 IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
584 yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300585
586 write_reg(reg_2920, 0x02920);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300587 write_reg(reg_2920 + 0x514, 0x02924);
588 IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
589 yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300590
Ian Armstrong2b057e82007-11-13 19:15:25 -0300591 write_reg(reg_2918, 0x02918);
592 write_reg(reg_291c, 0x0291C);
593 IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
594 yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300595
596 write_reg(reg_296c, 0x0296c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300597 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
598 yi->reg_296c, reg_296c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300599
600 write_reg(reg_2940, 0x02948);
601 write_reg(reg_2940, 0x02940);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300602 IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
603 yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300604
605 write_reg(reg_2950, 0x02950);
606 write_reg(reg_2954, 0x02954);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300607 IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
608 yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300609
610 write_reg(reg_2958, 0x02958);
611 write_reg(reg_295c, 0x0295C);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300612 IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
613 yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300614
615 write_reg(reg_2960, 0x02960);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300616 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
617 yi->reg_2960, reg_2960);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300618
619 write_reg(reg_2964, 0x02964);
620 write_reg(reg_2968, 0x02968);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300621 IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
622 yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300623
Ian Armstrong2b057e82007-11-13 19:15:25 -0300624 write_reg(reg_289c, 0x0289c);
625 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
626 yi->reg_289c, reg_289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300627
628 /* Only update filter 1 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300629 if (v_filter_1 != yi->v_filter_1) {
630 ivtv_yuv_filter(itv, -1, v_filter_1, -1);
631 yi->v_filter_1 = v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300632 }
633
634 /* Only update filter 2 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300635 if (v_filter_2 != yi->v_filter_2) {
636 ivtv_yuv_filter(itv, -1, -1, v_filter_2);
637 yi->v_filter_2 = v_filter_2;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300638 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300639}
640
641/* Modify the supplied coordinate information to fit the visible osd area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300642static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300643{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300644 struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
645 int osd_crop;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300646 u32 osd_scale;
647 u32 yuv_update = 0;
648
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300649 /* Sorry, but no negative coords for src */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300650 if (f->src_x < 0)
651 f->src_x = 0;
652 if (f->src_y < 0)
653 f->src_y = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300654
655 /* Can only reduce width down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300656 if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
657 f->src_x += osd_crop / 2;
658 f->src_w = (f->src_w - osd_crop) & ~3;
659 f->dst_w = f->src_w / 4;
660 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300661 }
662
663 /* Can only reduce height down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300664 if (f->src_h / f->dst_h >= 2) {
665 /* Overflow may be because we're running progressive,
666 so force mode switch */
667 f->interlaced_y = 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300668 /* Make sure we're still within limits for interlace */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300669 if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300670 /* If we reach here we'll have to force the height. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300671 f->src_y += osd_crop / 2;
672 f->src_h = (f->src_h - osd_crop) & ~3;
673 f->dst_h = f->src_h / 4;
674 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300675 }
676 }
677
678 /* If there's nothing to safe to display, we may as well stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300679 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300680 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300681 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300682 }
683
684 /* Ensure video remains inside OSD area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300685 osd_scale = (f->src_h << 16) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300686
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300687 if ((osd_crop = f->pan_y - f->dst_y) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300688 /* Falls off the upper edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300689 f->src_y += (osd_scale * osd_crop) >> 16;
690 f->src_h -= (osd_scale * osd_crop) >> 16;
691 f->dst_h -= osd_crop;
692 f->dst_y = 0;
693 } else {
694 f->dst_y -= f->pan_y;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300695 }
696
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300697 if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300698 /* Falls off the lower edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300699 f->dst_h -= osd_crop;
700 f->src_h -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300701 }
702
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300703 osd_scale = (f->src_w << 16) / f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300704
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300705 if ((osd_crop = f->pan_x - f->dst_x) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300706 /* Fall off the left edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300707 f->src_x += (osd_scale * osd_crop) >> 16;
708 f->src_w -= (osd_scale * osd_crop) >> 16;
709 f->dst_w -= osd_crop;
710 f->dst_x = 0;
711 } else {
712 f->dst_x -= f->pan_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300713 }
714
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300715 if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300716 /* Falls off the right edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300717 f->dst_w -= osd_crop;
718 f->src_w -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300719 }
720
Ian Armstrong88ab0752008-04-22 14:42:14 -0300721 if (itv->yuv_info.track_osd) {
722 /* The OSD can be moved. Track to it */
723 f->dst_x += itv->yuv_info.osd_x_offset;
724 f->dst_y += itv->yuv_info.osd_y_offset;
725 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300726
727 /* Width & height for both src & dst must be even.
728 Same for coordinates. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300729 f->dst_w &= ~1;
730 f->dst_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300731
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300732 f->src_w += f->src_x & 1;
733 f->src_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300734
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300735 f->src_w &= ~1;
736 f->dst_w &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300737
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300738 f->dst_h &= ~1;
739 f->dst_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300740
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300741 f->src_h += f->src_y & 1;
742 f->src_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300743
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300744 f->src_h &= ~1;
745 f->dst_h &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300746
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300747 /* Due to rounding, we may have reduced the output size to <1/4 of
748 the source. Check again, but this time just resize. Don't change
749 source coordinates */
750 if (f->dst_w < f->src_w / 4) {
751 f->src_w &= ~3;
752 f->dst_w = f->src_w / 4;
753 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300754 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300755 if (f->dst_h < f->src_h / 4) {
756 f->src_h &= ~3;
757 f->dst_h = f->src_h / 4;
758 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300759 }
760
761 /* Check again. If there's nothing to safe to display, stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300762 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300763 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300764 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300765 }
766
767 /* Both x offset & width are linked, so they have to be done together */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300768 if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300769 (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
770 (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300771 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
772 }
773
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300774 if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300775 (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
776 (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
777 (of->lace_mode != f->lace_mode) ||
778 (of->interlaced_y != f->interlaced_y) ||
779 (of->interlaced_uv != f->interlaced_uv)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300780 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
781 }
782
783 return yuv_update;
784}
785
786/* Update the scaling register to the requested value */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300787void ivtv_yuv_work_handler(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300788{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300789 struct yuv_playback_info *yi = &itv->yuv_info;
790 struct yuv_frame_info f;
791 int frame = yi->update_frame;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300792 u32 yuv_update;
793
Ian Armstrong2b057e82007-11-13 19:15:25 -0300794 IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300795 f = yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300796
Ian Armstrong88ab0752008-04-22 14:42:14 -0300797 if (yi->track_osd) {
798 /* Snapshot the osd pan info */
799 f.pan_x = yi->osd_x_pan;
800 f.pan_y = yi->osd_y_pan;
801 f.vis_w = yi->osd_vis_w;
802 f.vis_h = yi->osd_vis_h;
803 } else {
804 /* Not tracking the osd, so assume full screen */
805 f.pan_x = 0;
806 f.pan_y = 0;
807 f.vis_w = 720;
808 f.vis_h = yi->decode_height;
809 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300810
811 /* Calculate the display window coordinates. Exit if nothing left */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300812 if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300813 return;
814
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300815 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
816 write_reg(0x01008080, 0x2898);
817 } else if (yuv_update) {
818 write_reg(0x00108080, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300819
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300820 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300821 ivtv_yuv_handle_horizontal(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300822
823 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300824 ivtv_yuv_handle_vertical(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300825 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300826 yi->old_frame_info = f;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300827}
828
Ian Armstrong2b057e82007-11-13 19:15:25 -0300829static void ivtv_yuv_init(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300830{
Ian Armstrong195b1252007-10-14 13:12:28 -0300831 struct yuv_playback_info *yi = &itv->yuv_info;
832
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300833 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
834
835 /* Take a snapshot of the current register settings */
Ian Armstrong195b1252007-10-14 13:12:28 -0300836 yi->reg_2834 = read_reg(0x02834);
837 yi->reg_2838 = read_reg(0x02838);
838 yi->reg_283c = read_reg(0x0283c);
839 yi->reg_2840 = read_reg(0x02840);
840 yi->reg_2844 = read_reg(0x02844);
841 yi->reg_2848 = read_reg(0x02848);
842 yi->reg_2854 = read_reg(0x02854);
843 yi->reg_285c = read_reg(0x0285c);
844 yi->reg_2864 = read_reg(0x02864);
845 yi->reg_2870 = read_reg(0x02870);
846 yi->reg_2874 = read_reg(0x02874);
847 yi->reg_2898 = read_reg(0x02898);
848 yi->reg_2890 = read_reg(0x02890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300849
Ian Armstrong195b1252007-10-14 13:12:28 -0300850 yi->reg_289c = read_reg(0x0289c);
851 yi->reg_2918 = read_reg(0x02918);
852 yi->reg_291c = read_reg(0x0291c);
853 yi->reg_2920 = read_reg(0x02920);
854 yi->reg_2924 = read_reg(0x02924);
855 yi->reg_2928 = read_reg(0x02928);
856 yi->reg_292c = read_reg(0x0292c);
857 yi->reg_2930 = read_reg(0x02930);
858 yi->reg_2934 = read_reg(0x02934);
859 yi->reg_2938 = read_reg(0x02938);
860 yi->reg_293c = read_reg(0x0293c);
861 yi->reg_2940 = read_reg(0x02940);
862 yi->reg_2944 = read_reg(0x02944);
863 yi->reg_2948 = read_reg(0x02948);
864 yi->reg_294c = read_reg(0x0294c);
865 yi->reg_2950 = read_reg(0x02950);
866 yi->reg_2954 = read_reg(0x02954);
867 yi->reg_2958 = read_reg(0x02958);
868 yi->reg_295c = read_reg(0x0295c);
869 yi->reg_2960 = read_reg(0x02960);
870 yi->reg_2964 = read_reg(0x02964);
871 yi->reg_2968 = read_reg(0x02968);
872 yi->reg_296c = read_reg(0x0296c);
873 yi->reg_2970 = read_reg(0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300874
Ian Armstrong195b1252007-10-14 13:12:28 -0300875 yi->v_filter_1 = -1;
876 yi->v_filter_2 = -1;
877 yi->h_filter = -1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300878
879 /* Set some valid size info */
Ian Armstrong195b1252007-10-14 13:12:28 -0300880 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
881 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300882
883 /* Bit 2 of reg 2878 indicates current decoder output format
884 0 : NTSC 1 : PAL */
885 if (read_reg(0x2878) & 4)
Ian Armstrong195b1252007-10-14 13:12:28 -0300886 yi->decode_height = 576;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300887 else
Ian Armstrong195b1252007-10-14 13:12:28 -0300888 yi->decode_height = 480;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300889
Ian Armstrong195b1252007-10-14 13:12:28 -0300890 if (!itv->osd_info) {
891 yi->osd_vis_w = 720 - yi->osd_x_offset;
892 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300893 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300894 /* If no visible size set, assume full size */
895 if (!yi->osd_vis_w)
896 yi->osd_vis_w = 720 - yi->osd_x_offset;
897
Ian Armstrong2b057e82007-11-13 19:15:25 -0300898 if (!yi->osd_vis_h) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300899 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300900 } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300901 /* If output video standard has changed, requested height may
Ian Armstrong2b057e82007-11-13 19:15:25 -0300902 not be legal */
903 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
904 yi->osd_vis_h + yi->osd_y_offset,
905 yi->decode_height);
906 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300907 }
908 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300909
910 /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
Hans Verkuil3f983872008-05-01 10:31:12 -0300911 yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300912 if (yi->blanking_ptr) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300913 yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300914 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300915 yi->blanking_dmaptr = 0;
916 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300917 }
918
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300919 /* Enable YUV decoder output */
920 write_reg_sync(0x01, IVTV_REG_VDM);
921
922 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
Ian Armstrong195b1252007-10-14 13:12:28 -0300923 atomic_set(&yi->next_dma_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300924}
925
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300926/* Get next available yuv buffer on PVR350 */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300927static void ivtv_yuv_next_free(struct ivtv *itv)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300928{
929 int draw, display;
930 struct yuv_playback_info *yi = &itv->yuv_info;
931
932 if (atomic_read(&yi->next_dma_frame) == -1)
933 ivtv_yuv_init(itv);
934
935 draw = atomic_read(&yi->next_fill_frame);
936 display = atomic_read(&yi->next_dma_frame);
937
938 if (display > draw)
939 display -= IVTV_YUV_BUFFERS;
940
941 if (draw - display >= yi->max_frames_buffered)
942 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
943 else
944 yi->new_frame_info[draw].update = 0;
945
946 yi->draw_frame = draw;
947}
948
949/* Set up frame according to ivtv_dma_frame parameters */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300950static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300951{
952 struct yuv_playback_info *yi = &itv->yuv_info;
953 u8 frame = yi->draw_frame;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300954 u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
955 struct yuv_frame_info *nf = &yi->new_frame_info[frame];
956 struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
957 int lace_threshold = yi->lace_threshold;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300958
959 /* Preserve old update flag in case we're overwriting a queued frame */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300960 int update = nf->update;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300961
962 /* Take a snapshot of the yuv coordinate information */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300963 nf->src_x = args->src.left;
964 nf->src_y = args->src.top;
965 nf->src_w = args->src.width;
966 nf->src_h = args->src.height;
967 nf->dst_x = args->dst.left;
968 nf->dst_y = args->dst.top;
969 nf->dst_w = args->dst.width;
970 nf->dst_h = args->dst.height;
971 nf->tru_x = args->dst.left;
972 nf->tru_w = args->src_width;
973 nf->tru_h = args->src_height;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300974
975 /* Are we going to offset the Y plane */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300976 nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300977
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300978 nf->update = 0;
979 nf->interlaced_y = 0;
980 nf->interlaced_uv = 0;
981 nf->delay = 0;
982 nf->sync_field = 0;
983 nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300984
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300985 if (lace_threshold < 0)
986 lace_threshold = yi->decode_height - 1;
987
988 /* Work out the lace settings */
989 switch (nf->lace_mode) {
990 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
991 nf->interlaced = 0;
992 if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
993 nf->interlaced_y = 0;
994 else
995 nf->interlaced_y = 1;
996
997 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
998 nf->interlaced_uv = 0;
999 else
1000 nf->interlaced_uv = 1;
1001 break;
1002
1003 case IVTV_YUV_MODE_AUTO:
1004 if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
1005 nf->interlaced = 0;
1006 if ((nf->tru_h < 512) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -03001007 (nf->tru_h > 576 && nf->tru_h < 1021) ||
1008 (nf->tru_w > 720 && nf->tru_h < 1021))
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001009 nf->interlaced_y = 0;
1010 else
1011 nf->interlaced_y = 1;
1012 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1013 nf->interlaced_uv = 0;
1014 else
1015 nf->interlaced_uv = 1;
1016 } else {
1017 nf->interlaced = 1;
1018 nf->interlaced_y = 1;
1019 nf->interlaced_uv = 1;
1020 }
1021 break;
1022
1023 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1024 default:
1025 nf->interlaced = 1;
1026 nf->interlaced_y = 1;
1027 nf->interlaced_uv = 1;
1028 break;
1029 }
1030
1031 if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1032 yi->old_frame_info_args = *nf;
1033 nf->update = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001034 IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001035 }
1036
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001037 nf->update |= update;
1038 nf->sync_field = yi->lace_sync_field;
1039 nf->delay = nf->sync_field != of->sync_field;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001040}
1041
1042/* Frame is complete & ready for display */
1043void ivtv_yuv_frame_complete(struct ivtv *itv)
1044{
1045 atomic_set(&itv->yuv_info.next_fill_frame,
1046 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1047}
1048
Adrian Bunk5eedc462008-04-22 14:41:44 -03001049static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001050{
1051 DEFINE_WAIT(wait);
1052 int rc = 0;
1053 int got_sig = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001054 /* DMA the frame */
1055 mutex_lock(&itv->udma.lock);
1056
1057 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1058 mutex_unlock(&itv->udma.lock);
1059 return rc;
1060 }
1061
1062 ivtv_udma_prepare(itv);
1063 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1064 /* if no UDMA is pending and no UDMA is in progress, then the DMA
Ian Armstrong2b057e82007-11-13 19:15:25 -03001065 is finished */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001066 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1067 /* don't interrupt if the DMA is in progress but break off
Ian Armstrong2b057e82007-11-13 19:15:25 -03001068 a still pending DMA. */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001069 got_sig = signal_pending(current);
1070 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1071 break;
1072 got_sig = 0;
1073 schedule();
1074 }
1075 finish_wait(&itv->dma_waitq, &wait);
1076
1077 /* Unmap Last DMA Xfer */
1078 ivtv_udma_unmap(itv);
1079
1080 if (got_sig) {
1081 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1082 mutex_unlock(&itv->udma.lock);
1083 return -EINTR;
1084 }
1085
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001086 ivtv_yuv_frame_complete(itv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001087
1088 mutex_unlock(&itv->udma.lock);
1089 return rc;
1090}
1091
Ian Armstrong77aded62007-11-05 14:27:09 -03001092/* Setup frame according to V4L2 parameters */
1093void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1094{
1095 struct yuv_playback_info *yi = &itv->yuv_info;
1096 struct ivtv_dma_frame dma_args;
1097
1098 ivtv_yuv_next_free(itv);
1099
1100 /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001101 dma_args.y_source = NULL;
1102 dma_args.uv_source = NULL;
Ian Armstrong77aded62007-11-05 14:27:09 -03001103 dma_args.src.left = 0;
1104 dma_args.src.top = 0;
1105 dma_args.src.width = yi->v4l2_src_w;
1106 dma_args.src.height = yi->v4l2_src_h;
1107 dma_args.dst = yi->main_rect;
1108 dma_args.src_width = yi->v4l2_src_w;
1109 dma_args.src_height = yi->v4l2_src_h;
1110
1111 /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1112 ivtv_yuv_setup_frame(itv, &dma_args);
1113
1114 if (!itv->dma_data_req_offset)
1115 itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1116}
1117
1118/* Attempt to dma a frame from a user buffer */
Al Virob0510f82008-05-21 00:31:41 -03001119int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
Ian Armstrong77aded62007-11-05 14:27:09 -03001120{
1121 struct yuv_playback_info *yi = &itv->yuv_info;
1122 struct ivtv_dma_frame dma_args;
1123
1124 ivtv_yuv_setup_stream_frame(itv);
1125
1126 /* We only need to supply source addresses for this */
1127 dma_args.y_source = src;
1128 dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
1129 return ivtv_yuv_udma_frame(itv, &dma_args);
1130}
1131
1132/* IVTV_IOC_DMA_FRAME ioctl handler */
1133int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1134{
Ian Armstrong2b057e82007-11-13 19:15:25 -03001135/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
Ian Armstrong77aded62007-11-05 14:27:09 -03001136
1137 ivtv_yuv_next_free(itv);
1138 ivtv_yuv_setup_frame(itv, args);
1139 return ivtv_yuv_udma_frame(itv, args);
1140}
1141
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001142void ivtv_yuv_close(struct ivtv *itv)
1143{
Ian Armstrong2b057e82007-11-13 19:15:25 -03001144 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001145 int h_filter, v_filter_1, v_filter_2;
1146
1147 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1148 ivtv_waitq(&itv->vsync_waitq);
1149
Ian Armstrong2bd7ac52008-10-09 12:04:23 -03001150 yi->running = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001151 atomic_set(&yi->next_dma_frame, -1);
1152 atomic_set(&yi->next_fill_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001153
1154 /* Reset registers we have changed so mpeg playback works */
1155
1156 /* If we fully restore this register, the display may remain active.
1157 Restore, but set one bit to blank the video. Firmware will always
1158 clear this bit when needed, so not a problem. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001159 write_reg(yi->reg_2898 | 0x01000000, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001160
Ian Armstrong2b057e82007-11-13 19:15:25 -03001161 write_reg(yi->reg_2834, 0x02834);
1162 write_reg(yi->reg_2838, 0x02838);
1163 write_reg(yi->reg_283c, 0x0283c);
1164 write_reg(yi->reg_2840, 0x02840);
1165 write_reg(yi->reg_2844, 0x02844);
1166 write_reg(yi->reg_2848, 0x02848);
1167 write_reg(yi->reg_2854, 0x02854);
1168 write_reg(yi->reg_285c, 0x0285c);
1169 write_reg(yi->reg_2864, 0x02864);
1170 write_reg(yi->reg_2870, 0x02870);
1171 write_reg(yi->reg_2874, 0x02874);
1172 write_reg(yi->reg_2890, 0x02890);
1173 write_reg(yi->reg_289c, 0x0289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001174
Ian Armstrong2b057e82007-11-13 19:15:25 -03001175 write_reg(yi->reg_2918, 0x02918);
1176 write_reg(yi->reg_291c, 0x0291c);
1177 write_reg(yi->reg_2920, 0x02920);
1178 write_reg(yi->reg_2924, 0x02924);
1179 write_reg(yi->reg_2928, 0x02928);
1180 write_reg(yi->reg_292c, 0x0292c);
1181 write_reg(yi->reg_2930, 0x02930);
1182 write_reg(yi->reg_2934, 0x02934);
1183 write_reg(yi->reg_2938, 0x02938);
1184 write_reg(yi->reg_293c, 0x0293c);
1185 write_reg(yi->reg_2940, 0x02940);
1186 write_reg(yi->reg_2944, 0x02944);
1187 write_reg(yi->reg_2948, 0x02948);
1188 write_reg(yi->reg_294c, 0x0294c);
1189 write_reg(yi->reg_2950, 0x02950);
1190 write_reg(yi->reg_2954, 0x02954);
1191 write_reg(yi->reg_2958, 0x02958);
1192 write_reg(yi->reg_295c, 0x0295c);
1193 write_reg(yi->reg_2960, 0x02960);
1194 write_reg(yi->reg_2964, 0x02964);
1195 write_reg(yi->reg_2968, 0x02968);
1196 write_reg(yi->reg_296c, 0x0296c);
1197 write_reg(yi->reg_2970, 0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001198
1199 /* Prepare to restore filters */
1200
1201 /* First the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001202 if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001203 /* An exact size match uses filter 0 */
1204 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001205 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001206 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001207 h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001208 h_filter = (h_filter >> 1) + (h_filter & 1);
1209 /* Only an exact size match can use filter 0. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001210 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001211 }
1212
1213 /* Now the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001214 if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001215 /* An exact size match uses filter 0/1 */
1216 v_filter_1 = 0;
1217 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001218 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001219 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001220 v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001221 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1222 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001223 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001224 v_filter_2 = v_filter_1;
1225 }
1226
1227 /* Now restore the filters */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001228 ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001229
1230 /* and clear a few registers */
1231 write_reg(0, 0x02814);
1232 write_reg(0, 0x0282c);
1233 write_reg(0, 0x02904);
1234 write_reg(0, 0x02910);
1235
1236 /* Release the blanking buffer */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001237 if (yi->blanking_ptr) {
1238 kfree(yi->blanking_ptr);
1239 yi->blanking_ptr = NULL;
1240 pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001241 }
1242
1243 /* Invalidate the old dimension information */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001244 yi->old_frame_info.src_w = 0;
1245 yi->old_frame_info.src_h = 0;
1246 yi->old_frame_info_args.src_w = 0;
1247 yi->old_frame_info_args.src_h = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001248
1249 /* All done. */
1250 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1251}