blob: 2ad65eb29832754b54a5d190257cadd5d6a09031 [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);
Paul Cassella7fd4b412011-02-12 10:39:51 -030080 uv_pages = 0; /* silence gcc. value is set and consumed only if: */
81 if (y_pages == y_dma.page_count) {
82 uv_pages = get_user_pages(current, current->mm,
83 uv_dma.uaddr, uv_dma.page_count, 0, 1,
84 &dma->map[y_pages], NULL);
85 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030086 up_read(&current->mm->mmap_sem);
87
Paul Cassella7fd4b412011-02-12 10:39:51 -030088 if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
89 int rc = -EFAULT;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030090
Paul Cassella7fd4b412011-02-12 10:39:51 -030091 if (y_pages == y_dma.page_count) {
92 IVTV_DEBUG_WARN
93 ("failed to map uv user pages, returned %d "
94 "expecting %d\n", uv_pages, uv_dma.page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030095
Paul Cassella7fd4b412011-02-12 10:39:51 -030096 if (uv_pages >= 0) {
97 for (i = 0; i < uv_pages; i++)
98 put_page(dma->map[y_pages + i]);
99 rc = -EFAULT;
100 } else {
101 rc = uv_pages;
102 }
103 } else {
104 IVTV_DEBUG_WARN
105 ("failed to map y user pages, returned %d "
106 "expecting %d\n", y_pages, y_dma.page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300107 }
Paul Cassella7fd4b412011-02-12 10:39:51 -0300108 if (y_pages >= 0) {
109 for (i = 0; i < y_pages; i++)
110 put_page(dma->map[i]);
111 /*
112 * Inherit the -EFAULT from rc's
113 * initialization, but allow it to be
114 * overriden by uv_pages above if it was an
115 * actual errno.
116 */
117 } else {
118 rc = y_pages;
119 }
120 return rc;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300121 }
122
Paul Cassella7fd4b412011-02-12 10:39:51 -0300123 dma->page_count = y_pages + uv_pages;
124
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300125 /* Fill & map SG List */
Hans Verkuil8beb0582007-08-19 17:56:41 -0300126 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
Hans Verkuil0989fd2c2007-08-19 12:25:39 -0300127 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
128 for (i = 0; i < dma->page_count; i++) {
129 put_page(dma->map[i]);
130 }
131 dma->page_count = 0;
132 return -ENOMEM;
133 }
Hans Verkuil8ac05ae2009-02-07 07:02:27 -0300134 dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300135
136 /* Fill SG Array with new values */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300137 ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300138
139 /* If we've offset the y plane, ensure top area is blanked */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300140 if (f->offset_y && yi->blanking_dmaptr) {
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300141 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300142 dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300143 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
144 dma->SG_length++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300145 }
146
147 /* Tag SG Array with Interrupt Bit */
148 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
149
150 ivtv_udma_sync_for_device(itv);
151 return 0;
152}
153
154/* We rely on a table held in the firmware - Quick check. */
155int ivtv_yuv_filter_check(struct ivtv *itv)
156{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300157 int i, y, uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300158
Ian Armstrong2b057e82007-11-13 19:15:25 -0300159 for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
160 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
161 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300162 IVTV_WARN ("YUV filter table not found in firmware.\n");
163 return -1;
164 }
165 }
166 return 0;
167}
168
169static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
170{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300171 u32 i, line;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300172
173 /* If any filter is -1, then don't update it */
174 if (h_filter > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300175 if (h_filter > 4)
176 h_filter = 4;
177 i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
178 for (line = 0; line < 16; line++) {
179 write_reg(read_dec(i), 0x02804);
180 write_reg(read_dec(i), 0x0281c);
181 i += 4;
182 write_reg(read_dec(i), 0x02808);
183 write_reg(read_dec(i), 0x02820);
184 i += 4;
185 write_reg(read_dec(i), 0x0280c);
186 write_reg(read_dec(i), 0x02824);
187 i += 4;
188 write_reg(read_dec(i), 0x02810);
189 write_reg(read_dec(i), 0x02828);
190 i += 4;
191 write_reg(read_dec(i), 0x02814);
192 write_reg(read_dec(i), 0x0282c);
193 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300194 write_reg(0, 0x02818);
195 write_reg(0, 0x02830);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300196 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300197 IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300198 }
199
200 if (v_filter_1 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300201 if (v_filter_1 > 4)
202 v_filter_1 = 4;
203 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
204 for (line = 0; line < 16; line++) {
205 write_reg(read_dec(i), 0x02900);
206 i += 4;
207 write_reg(read_dec(i), 0x02904);
208 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300209 write_reg(0, 0x02908);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300210 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300211 IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300212 }
213
214 if (v_filter_2 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300215 if (v_filter_2 > 4)
216 v_filter_2 = 4;
217 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
218 for (line = 0; line < 16; line++) {
219 write_reg(read_dec(i), 0x0290c);
220 i += 4;
221 write_reg(read_dec(i), 0x02910);
222 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300223 write_reg(0, 0x02914);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300224 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300225 IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300226 }
227}
228
Ian Armstrong2b057e82007-11-13 19:15:25 -0300229static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300230{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300231 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300232 u32 reg_2834, reg_2838, reg_283c;
233 u32 reg_2844, reg_2854, reg_285c;
234 u32 reg_2864, reg_2874, reg_2890;
235 u32 reg_2870, reg_2870_base, reg_2870_offset;
236 int x_cutoff;
237 int h_filter;
238 u32 master_width;
239
Ian Armstrong2b057e82007-11-13 19:15:25 -0300240 IVTV_DEBUG_WARN
241 ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
242 f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300243
244 /* How wide is the src image */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300245 x_cutoff = f->src_w + f->src_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300246
247 /* Set the display width */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300248 reg_2834 = f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300249 reg_2838 = reg_2834;
250
251 /* Set the display position */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300252 reg_2890 = f->dst_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300253
254 /* Index into the image horizontally */
255 reg_2870 = 0;
256
257 /* 2870 is normally fudged to align video coords with osd coords.
258 If running full screen, it causes an unwanted left shift
259 Remove the fudge if we almost fill the screen.
260 Gradually adjust the offset to avoid the video 'snapping'
261 left/right if it gets dragged through this region.
262 Only do this if osd is full width. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300263 if (f->vis_w == 720) {
264 if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
265 reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
266 else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
267 reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300268
Ian Armstrong2b057e82007-11-13 19:15:25 -0300269 if (f->dst_w >= f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300270 reg_2870 = reg_2870 << 16 | reg_2870;
271 else
272 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
273 }
274
Ian Armstrong2b057e82007-11-13 19:15:25 -0300275 if (f->dst_w < f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300276 reg_2870 = 0x000d000e - reg_2870;
277 else
278 reg_2870 = 0x0012000e - reg_2870;
279
280 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300281 reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300282
Ian Armstrong2b057e82007-11-13 19:15:25 -0300283 if (f->dst_w >= f->src_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300284 x_cutoff &= ~1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300285 master_width = (f->src_w * 0x00200000) / (f->dst_w);
286 if (master_width * f->dst_w != f->src_w * 0x00200000)
287 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300288 reg_2834 = (reg_2834 << 16) | x_cutoff;
289 reg_2838 = (reg_2838 << 16) | x_cutoff;
290 reg_283c = master_width >> 2;
291 reg_2844 = master_width >> 2;
292 reg_2854 = master_width;
293 reg_285c = master_width >> 1;
294 reg_2864 = master_width >> 1;
295
296 /* We also need to factor in the scaling
297 (src_w - dst_w) / (src_w / 4) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300298 if (f->dst_w > f->src_w)
299 reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300300 else
301 reg_2870_base = 0;
302
303 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
304 reg_2874 = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300305 } else if (f->dst_w < f->src_w / 2) {
306 master_width = (f->src_w * 0x00080000) / f->dst_w;
307 if (master_width * f->dst_w != f->src_w * 0x00080000)
308 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300309 reg_2834 = (reg_2834 << 16) | x_cutoff;
310 reg_2838 = (reg_2838 << 16) | x_cutoff;
311 reg_283c = master_width >> 2;
312 reg_2844 = master_width >> 1;
313 reg_2854 = master_width;
314 reg_285c = master_width >> 1;
315 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300316 reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
317 reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300318 reg_2874 = 0x00000012;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300319 } else {
320 master_width = (f->src_w * 0x00100000) / f->dst_w;
321 if (master_width * f->dst_w != f->src_w * 0x00100000)
322 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300323 reg_2834 = (reg_2834 << 16) | x_cutoff;
324 reg_2838 = (reg_2838 << 16) | x_cutoff;
325 reg_283c = master_width >> 2;
326 reg_2844 = master_width >> 1;
327 reg_2854 = master_width;
328 reg_285c = master_width >> 1;
329 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300330 reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
331 reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300332 reg_2874 = 0x00000001;
333 }
334
335 /* Select the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300336 if (f->src_w == f->dst_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300337 /* An exact size match uses filter 0 */
338 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300339 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300340 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300341 h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300342 h_filter = (h_filter >> 1) + (h_filter & 1);
343 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300344 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300345 }
346
347 write_reg(reg_2834, 0x02834);
348 write_reg(reg_2838, 0x02838);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300349 IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
350 yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300351
352 write_reg(reg_283c, 0x0283c);
353 write_reg(reg_2844, 0x02844);
354
Ian Armstrong2b057e82007-11-13 19:15:25 -0300355 IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
356 yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300357
358 write_reg(0x00080514, 0x02840);
359 write_reg(0x00100514, 0x02848);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300360 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
361 yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300362
363 write_reg(reg_2854, 0x02854);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300364 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
365 yi->reg_2854, reg_2854);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300366
367 write_reg(reg_285c, 0x0285c);
368 write_reg(reg_2864, 0x02864);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300369 IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
370 yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300371
372 write_reg(reg_2874, 0x02874);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300373 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
374 yi->reg_2874, reg_2874);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300375
376 write_reg(reg_2870, 0x02870);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300377 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
378 yi->reg_2870, reg_2870);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300379
Ian Armstrong2b057e82007-11-13 19:15:25 -0300380 write_reg(reg_2890, 0x02890);
381 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
382 yi->reg_2890, reg_2890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300383
384 /* Only update the filter if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300385 if (h_filter != yi->h_filter) {
386 ivtv_yuv_filter(itv, h_filter, -1, -1);
387 yi->h_filter = h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300388 }
389}
390
Ian Armstrong2b057e82007-11-13 19:15:25 -0300391static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300392{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300393 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300394 u32 master_height;
395 u32 reg_2918, reg_291c, reg_2920, reg_2928;
396 u32 reg_2930, reg_2934, reg_293c;
397 u32 reg_2940, reg_2944, reg_294c;
398 u32 reg_2950, reg_2954, reg_2958, reg_295c;
399 u32 reg_2960, reg_2964, reg_2968, reg_296c;
400 u32 reg_289c;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300401 u32 src_major_y, src_minor_y;
402 u32 src_major_uv, src_minor_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300403 u32 reg_2964_base, reg_2968_base;
404 int v_filter_1, v_filter_2;
405
Ian Armstrong2b057e82007-11-13 19:15:25 -0300406 IVTV_DEBUG_WARN
407 ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
408 f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300409
410 /* What scaling mode is being used... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300411 IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
412 f->interlaced_y ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300413
Ian Armstrong2b057e82007-11-13 19:15:25 -0300414 IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
415 f->interlaced_uv ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300416
417 /* What is the source video being treated as... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300418 IVTV_DEBUG_WARN("Source video: %s\n",
419 f->interlaced ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300420
421 /* We offset into the image using two different index methods, so split
422 the y source coord into two parts. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300423 if (f->src_y < 8) {
424 src_minor_uv = f->src_y;
425 src_major_uv = 0;
426 } else {
427 src_minor_uv = 8;
428 src_major_uv = f->src_y - 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300429 }
430
Ian Armstrong2b057e82007-11-13 19:15:25 -0300431 src_minor_y = src_minor_uv;
432 src_major_y = src_major_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300433
Ian Armstrong2b057e82007-11-13 19:15:25 -0300434 if (f->offset_y)
435 src_minor_y += 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300436
Ian Armstrong2b057e82007-11-13 19:15:25 -0300437 if (f->interlaced_y)
438 reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300439 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300440 reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300441
Ian Armstrong2b057e82007-11-13 19:15:25 -0300442 if (f->interlaced_uv)
443 reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300444 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300445 reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300446
Ian Armstrong2b057e82007-11-13 19:15:25 -0300447 reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
448 reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300449
Ian Armstrong2b057e82007-11-13 19:15:25 -0300450 if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
451 master_height = (f->src_h * 0x00400000) / f->dst_h;
452 if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
453 master_height++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300454 reg_2920 = master_height >> 2;
455 reg_2928 = master_height >> 3;
456 reg_2930 = master_height;
457 reg_2940 = master_height >> 1;
458 reg_2964_base >>= 3;
459 reg_2968_base >>= 3;
460 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300461 } else if (f->dst_h >= f->src_h) {
462 master_height = (f->src_h * 0x00400000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300463 master_height = (master_height >> 1) + (master_height & 1);
464 reg_2920 = master_height >> 2;
465 reg_2928 = master_height >> 2;
466 reg_2930 = master_height;
467 reg_2940 = master_height >> 1;
468 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300469 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300470 reg_2964_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300471 } else {
472 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300473 reg_2964_base >>= 2;
474 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300475 if (f->interlaced_uv)
476 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300477 reg_2968_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300478 } else if (f->dst_h >= f->src_h / 2) {
479 master_height = (f->src_h * 0x00200000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300480 master_height = (master_height >> 1) + (master_height & 1);
481 reg_2920 = master_height >> 2;
482 reg_2928 = master_height >> 2;
483 reg_2930 = master_height;
484 reg_2940 = master_height;
485 reg_296c = 0x00000101;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300486 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300487 reg_2964_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300488 } else {
489 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300490 reg_2964_base >>= 1;
491 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300492 if (f->interlaced_uv)
493 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300494 reg_2968_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300495 } else {
496 master_height = (f->src_h * 0x00100000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300497 master_height = (master_height >> 1) + (master_height & 1);
498 reg_2920 = master_height >> 2;
499 reg_2928 = master_height >> 2;
500 reg_2930 = master_height;
501 reg_2940 = master_height;
502 reg_2964_base >>= 1;
503 reg_2968_base >>= 2;
504 reg_296c = 0x00000102;
505 }
506
507 /* FIXME These registers change depending on scaled / unscaled output
508 We really need to work out what they should be */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300509 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300510 reg_2934 = 0x00020000;
511 reg_293c = 0x00100000;
512 reg_2944 = 0x00040000;
513 reg_294c = 0x000b0000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300514 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300515 reg_2934 = 0x00000FF0;
516 reg_293c = 0x00000FF0;
517 reg_2944 = 0x00000FF0;
518 reg_294c = 0x00000FF0;
519 }
520
521 /* The first line to be displayed */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300522 reg_2950 = 0x00010000 + src_major_y;
523 if (f->interlaced_y)
524 reg_2950 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300525 reg_2954 = reg_2950 + 1;
526
Ian Armstrong2b057e82007-11-13 19:15:25 -0300527 reg_2958 = 0x00010000 + (src_major_y >> 1);
528 if (f->interlaced_uv)
529 reg_2958 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300530 reg_295c = reg_2958 + 1;
531
Ian Armstrong2b057e82007-11-13 19:15:25 -0300532 if (yi->decode_height == 480)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300533 reg_289c = 0x011e0017;
534 else
535 reg_289c = 0x01500017;
536
Ian Armstrong2b057e82007-11-13 19:15:25 -0300537 if (f->dst_y < 0)
538 reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300539 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300540 reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300541
542 /* How much of the source to decode.
543 Take into account the source offset */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300544 reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
545 (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300546
547 /* Calculate correct value for register 2964 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300548 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300549 reg_2964 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300550 } else {
551 reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300552 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
553 }
554 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
555 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
556
557 /* Okay, we've wasted time working out the correct value,
558 but if we use it, it fouls the the window alignment.
559 Fudge it to what we want... */
560 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
561 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
562
563 /* Deviate further from what it should be. I find the flicker headache
564 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
565 colours foul. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300566 if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
567 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300568
Ian Armstrong2b057e82007-11-13 19:15:25 -0300569 if (!f->interlaced_y)
570 reg_2964 -= 0x00010001;
571 if (!f->interlaced_uv)
572 reg_2968 -= 0x00010001;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300573
574 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
575 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
576
577 /* Select the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300578 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300579 /* An exact size match uses filter 0/1 */
580 v_filter_1 = 0;
581 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300582 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300583 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300584 v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300585 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
586 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300587 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300588 v_filter_2 = v_filter_1;
589 }
590
591 write_reg(reg_2934, 0x02934);
592 write_reg(reg_293c, 0x0293c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300593 IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
594 yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300595 write_reg(reg_2944, 0x02944);
596 write_reg(reg_294c, 0x0294c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300597 IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
598 yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300599
600 /* Ensure 2970 is 0 (does it ever change ?) */
601/* write_reg(0,0x02970); */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300602/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300603
604 write_reg(reg_2930, 0x02938);
605 write_reg(reg_2930, 0x02930);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300606 IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
607 yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300608
609 write_reg(reg_2928, 0x02928);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300610 write_reg(reg_2928 + 0x514, 0x0292C);
611 IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
612 yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300613
614 write_reg(reg_2920, 0x02920);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300615 write_reg(reg_2920 + 0x514, 0x02924);
616 IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
617 yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300618
Ian Armstrong2b057e82007-11-13 19:15:25 -0300619 write_reg(reg_2918, 0x02918);
620 write_reg(reg_291c, 0x0291C);
621 IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
622 yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300623
624 write_reg(reg_296c, 0x0296c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300625 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
626 yi->reg_296c, reg_296c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300627
628 write_reg(reg_2940, 0x02948);
629 write_reg(reg_2940, 0x02940);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300630 IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
631 yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300632
633 write_reg(reg_2950, 0x02950);
634 write_reg(reg_2954, 0x02954);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300635 IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
636 yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300637
638 write_reg(reg_2958, 0x02958);
639 write_reg(reg_295c, 0x0295C);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300640 IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
641 yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300642
643 write_reg(reg_2960, 0x02960);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300644 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
645 yi->reg_2960, reg_2960);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300646
647 write_reg(reg_2964, 0x02964);
648 write_reg(reg_2968, 0x02968);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300649 IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
650 yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300651
Ian Armstrong2b057e82007-11-13 19:15:25 -0300652 write_reg(reg_289c, 0x0289c);
653 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
654 yi->reg_289c, reg_289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300655
656 /* Only update filter 1 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300657 if (v_filter_1 != yi->v_filter_1) {
658 ivtv_yuv_filter(itv, -1, v_filter_1, -1);
659 yi->v_filter_1 = v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300660 }
661
662 /* Only update filter 2 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300663 if (v_filter_2 != yi->v_filter_2) {
664 ivtv_yuv_filter(itv, -1, -1, v_filter_2);
665 yi->v_filter_2 = v_filter_2;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300666 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300667}
668
669/* Modify the supplied coordinate information to fit the visible osd area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300670static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300671{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300672 struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
673 int osd_crop;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300674 u32 osd_scale;
675 u32 yuv_update = 0;
676
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300677 /* Sorry, but no negative coords for src */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300678 if (f->src_x < 0)
679 f->src_x = 0;
680 if (f->src_y < 0)
681 f->src_y = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300682
683 /* Can only reduce width down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300684 if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
685 f->src_x += osd_crop / 2;
686 f->src_w = (f->src_w - osd_crop) & ~3;
687 f->dst_w = f->src_w / 4;
688 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300689 }
690
691 /* Can only reduce height down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300692 if (f->src_h / f->dst_h >= 2) {
693 /* Overflow may be because we're running progressive,
694 so force mode switch */
695 f->interlaced_y = 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300696 /* Make sure we're still within limits for interlace */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300697 if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300698 /* If we reach here we'll have to force the height. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300699 f->src_y += osd_crop / 2;
700 f->src_h = (f->src_h - osd_crop) & ~3;
701 f->dst_h = f->src_h / 4;
702 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300703 }
704 }
705
706 /* If there's nothing to safe to display, we may as well stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300707 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300708 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300709 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300710 }
711
712 /* Ensure video remains inside OSD area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300713 osd_scale = (f->src_h << 16) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300714
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300715 if ((osd_crop = f->pan_y - f->dst_y) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300716 /* Falls off the upper edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300717 f->src_y += (osd_scale * osd_crop) >> 16;
718 f->src_h -= (osd_scale * osd_crop) >> 16;
719 f->dst_h -= osd_crop;
720 f->dst_y = 0;
721 } else {
722 f->dst_y -= f->pan_y;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300723 }
724
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300725 if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300726 /* Falls off the lower edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300727 f->dst_h -= osd_crop;
728 f->src_h -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300729 }
730
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300731 osd_scale = (f->src_w << 16) / f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300732
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300733 if ((osd_crop = f->pan_x - f->dst_x) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300734 /* Fall off the left edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300735 f->src_x += (osd_scale * osd_crop) >> 16;
736 f->src_w -= (osd_scale * osd_crop) >> 16;
737 f->dst_w -= osd_crop;
738 f->dst_x = 0;
739 } else {
740 f->dst_x -= f->pan_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300741 }
742
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300743 if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300744 /* Falls off the right edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300745 f->dst_w -= osd_crop;
746 f->src_w -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300747 }
748
Ian Armstrong88ab0752008-04-22 14:42:14 -0300749 if (itv->yuv_info.track_osd) {
750 /* The OSD can be moved. Track to it */
751 f->dst_x += itv->yuv_info.osd_x_offset;
752 f->dst_y += itv->yuv_info.osd_y_offset;
753 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300754
755 /* Width & height for both src & dst must be even.
756 Same for coordinates. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300757 f->dst_w &= ~1;
758 f->dst_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300759
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300760 f->src_w += f->src_x & 1;
761 f->src_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300762
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300763 f->src_w &= ~1;
764 f->dst_w &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300765
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300766 f->dst_h &= ~1;
767 f->dst_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300768
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300769 f->src_h += f->src_y & 1;
770 f->src_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300771
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300772 f->src_h &= ~1;
773 f->dst_h &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300774
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300775 /* Due to rounding, we may have reduced the output size to <1/4 of
776 the source. Check again, but this time just resize. Don't change
777 source coordinates */
778 if (f->dst_w < f->src_w / 4) {
779 f->src_w &= ~3;
780 f->dst_w = f->src_w / 4;
781 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300782 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300783 if (f->dst_h < f->src_h / 4) {
784 f->src_h &= ~3;
785 f->dst_h = f->src_h / 4;
786 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300787 }
788
789 /* Check again. If there's nothing to safe to display, stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300790 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300791 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300792 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300793 }
794
795 /* Both x offset & width are linked, so they have to be done together */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300796 if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300797 (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
798 (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300799 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
800 }
801
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300802 if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300803 (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
804 (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
805 (of->lace_mode != f->lace_mode) ||
806 (of->interlaced_y != f->interlaced_y) ||
807 (of->interlaced_uv != f->interlaced_uv)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300808 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
809 }
810
811 return yuv_update;
812}
813
814/* Update the scaling register to the requested value */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300815void ivtv_yuv_work_handler(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300816{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300817 struct yuv_playback_info *yi = &itv->yuv_info;
818 struct yuv_frame_info f;
819 int frame = yi->update_frame;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300820 u32 yuv_update;
821
Ian Armstrong2b057e82007-11-13 19:15:25 -0300822 IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300823 f = yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300824
Ian Armstrong88ab0752008-04-22 14:42:14 -0300825 if (yi->track_osd) {
826 /* Snapshot the osd pan info */
827 f.pan_x = yi->osd_x_pan;
828 f.pan_y = yi->osd_y_pan;
829 f.vis_w = yi->osd_vis_w;
830 f.vis_h = yi->osd_vis_h;
831 } else {
832 /* Not tracking the osd, so assume full screen */
833 f.pan_x = 0;
834 f.pan_y = 0;
835 f.vis_w = 720;
836 f.vis_h = yi->decode_height;
837 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300838
839 /* Calculate the display window coordinates. Exit if nothing left */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300840 if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300841 return;
842
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300843 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
844 write_reg(0x01008080, 0x2898);
845 } else if (yuv_update) {
846 write_reg(0x00108080, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300847
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300848 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300849 ivtv_yuv_handle_horizontal(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300850
851 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300852 ivtv_yuv_handle_vertical(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300853 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300854 yi->old_frame_info = f;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300855}
856
Ian Armstrong2b057e82007-11-13 19:15:25 -0300857static void ivtv_yuv_init(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300858{
Ian Armstrong195b1252007-10-14 13:12:28 -0300859 struct yuv_playback_info *yi = &itv->yuv_info;
860
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300861 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
862
863 /* Take a snapshot of the current register settings */
Ian Armstrong195b1252007-10-14 13:12:28 -0300864 yi->reg_2834 = read_reg(0x02834);
865 yi->reg_2838 = read_reg(0x02838);
866 yi->reg_283c = read_reg(0x0283c);
867 yi->reg_2840 = read_reg(0x02840);
868 yi->reg_2844 = read_reg(0x02844);
869 yi->reg_2848 = read_reg(0x02848);
870 yi->reg_2854 = read_reg(0x02854);
871 yi->reg_285c = read_reg(0x0285c);
872 yi->reg_2864 = read_reg(0x02864);
873 yi->reg_2870 = read_reg(0x02870);
874 yi->reg_2874 = read_reg(0x02874);
875 yi->reg_2898 = read_reg(0x02898);
876 yi->reg_2890 = read_reg(0x02890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300877
Ian Armstrong195b1252007-10-14 13:12:28 -0300878 yi->reg_289c = read_reg(0x0289c);
879 yi->reg_2918 = read_reg(0x02918);
880 yi->reg_291c = read_reg(0x0291c);
881 yi->reg_2920 = read_reg(0x02920);
882 yi->reg_2924 = read_reg(0x02924);
883 yi->reg_2928 = read_reg(0x02928);
884 yi->reg_292c = read_reg(0x0292c);
885 yi->reg_2930 = read_reg(0x02930);
886 yi->reg_2934 = read_reg(0x02934);
887 yi->reg_2938 = read_reg(0x02938);
888 yi->reg_293c = read_reg(0x0293c);
889 yi->reg_2940 = read_reg(0x02940);
890 yi->reg_2944 = read_reg(0x02944);
891 yi->reg_2948 = read_reg(0x02948);
892 yi->reg_294c = read_reg(0x0294c);
893 yi->reg_2950 = read_reg(0x02950);
894 yi->reg_2954 = read_reg(0x02954);
895 yi->reg_2958 = read_reg(0x02958);
896 yi->reg_295c = read_reg(0x0295c);
897 yi->reg_2960 = read_reg(0x02960);
898 yi->reg_2964 = read_reg(0x02964);
899 yi->reg_2968 = read_reg(0x02968);
900 yi->reg_296c = read_reg(0x0296c);
901 yi->reg_2970 = read_reg(0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300902
Ian Armstrong195b1252007-10-14 13:12:28 -0300903 yi->v_filter_1 = -1;
904 yi->v_filter_2 = -1;
905 yi->h_filter = -1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300906
907 /* Set some valid size info */
Ian Armstrong195b1252007-10-14 13:12:28 -0300908 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
909 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300910
911 /* Bit 2 of reg 2878 indicates current decoder output format
912 0 : NTSC 1 : PAL */
913 if (read_reg(0x2878) & 4)
Ian Armstrong195b1252007-10-14 13:12:28 -0300914 yi->decode_height = 576;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300915 else
Ian Armstrong195b1252007-10-14 13:12:28 -0300916 yi->decode_height = 480;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300917
Ian Armstrong195b1252007-10-14 13:12:28 -0300918 if (!itv->osd_info) {
919 yi->osd_vis_w = 720 - yi->osd_x_offset;
920 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300921 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300922 /* If no visible size set, assume full size */
923 if (!yi->osd_vis_w)
924 yi->osd_vis_w = 720 - yi->osd_x_offset;
925
Ian Armstrong2b057e82007-11-13 19:15:25 -0300926 if (!yi->osd_vis_h) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300927 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300928 } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300929 /* If output video standard has changed, requested height may
Ian Armstrong2b057e82007-11-13 19:15:25 -0300930 not be legal */
931 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
932 yi->osd_vis_h + yi->osd_y_offset,
933 yi->decode_height);
934 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300935 }
936 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300937
938 /* 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 -0300939 yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300940 if (yi->blanking_ptr) {
Hans Verkuil8ac05ae2009-02-07 07:02:27 -0300941 yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300942 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300943 yi->blanking_dmaptr = 0;
944 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300945 }
946
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300947 /* Enable YUV decoder output */
948 write_reg_sync(0x01, IVTV_REG_VDM);
949
950 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
Ian Armstrong195b1252007-10-14 13:12:28 -0300951 atomic_set(&yi->next_dma_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300952}
953
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300954/* Get next available yuv buffer on PVR350 */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300955static void ivtv_yuv_next_free(struct ivtv *itv)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300956{
957 int draw, display;
958 struct yuv_playback_info *yi = &itv->yuv_info;
959
960 if (atomic_read(&yi->next_dma_frame) == -1)
961 ivtv_yuv_init(itv);
962
963 draw = atomic_read(&yi->next_fill_frame);
964 display = atomic_read(&yi->next_dma_frame);
965
966 if (display > draw)
967 display -= IVTV_YUV_BUFFERS;
968
969 if (draw - display >= yi->max_frames_buffered)
970 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
971 else
972 yi->new_frame_info[draw].update = 0;
973
974 yi->draw_frame = draw;
975}
976
977/* Set up frame according to ivtv_dma_frame parameters */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300978static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300979{
980 struct yuv_playback_info *yi = &itv->yuv_info;
981 u8 frame = yi->draw_frame;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300982 u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
983 struct yuv_frame_info *nf = &yi->new_frame_info[frame];
984 struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
985 int lace_threshold = yi->lace_threshold;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300986
987 /* Preserve old update flag in case we're overwriting a queued frame */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300988 int update = nf->update;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300989
990 /* Take a snapshot of the yuv coordinate information */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300991 nf->src_x = args->src.left;
992 nf->src_y = args->src.top;
993 nf->src_w = args->src.width;
994 nf->src_h = args->src.height;
995 nf->dst_x = args->dst.left;
996 nf->dst_y = args->dst.top;
997 nf->dst_w = args->dst.width;
998 nf->dst_h = args->dst.height;
999 nf->tru_x = args->dst.left;
1000 nf->tru_w = args->src_width;
1001 nf->tru_h = args->src_height;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001002
1003 /* Are we going to offset the Y plane */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001004 nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001005
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001006 nf->update = 0;
1007 nf->interlaced_y = 0;
1008 nf->interlaced_uv = 0;
1009 nf->delay = 0;
1010 nf->sync_field = 0;
1011 nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001012
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001013 if (lace_threshold < 0)
1014 lace_threshold = yi->decode_height - 1;
1015
1016 /* Work out the lace settings */
1017 switch (nf->lace_mode) {
1018 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
1019 nf->interlaced = 0;
1020 if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
1021 nf->interlaced_y = 0;
1022 else
1023 nf->interlaced_y = 1;
1024
1025 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1026 nf->interlaced_uv = 0;
1027 else
1028 nf->interlaced_uv = 1;
1029 break;
1030
1031 case IVTV_YUV_MODE_AUTO:
1032 if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
1033 nf->interlaced = 0;
1034 if ((nf->tru_h < 512) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -03001035 (nf->tru_h > 576 && nf->tru_h < 1021) ||
1036 (nf->tru_w > 720 && nf->tru_h < 1021))
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001037 nf->interlaced_y = 0;
1038 else
1039 nf->interlaced_y = 1;
1040 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1041 nf->interlaced_uv = 0;
1042 else
1043 nf->interlaced_uv = 1;
1044 } else {
1045 nf->interlaced = 1;
1046 nf->interlaced_y = 1;
1047 nf->interlaced_uv = 1;
1048 }
1049 break;
1050
1051 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1052 default:
1053 nf->interlaced = 1;
1054 nf->interlaced_y = 1;
1055 nf->interlaced_uv = 1;
1056 break;
1057 }
1058
1059 if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1060 yi->old_frame_info_args = *nf;
1061 nf->update = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001062 IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001063 }
1064
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001065 nf->update |= update;
1066 nf->sync_field = yi->lace_sync_field;
1067 nf->delay = nf->sync_field != of->sync_field;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001068}
1069
1070/* Frame is complete & ready for display */
1071void ivtv_yuv_frame_complete(struct ivtv *itv)
1072{
1073 atomic_set(&itv->yuv_info.next_fill_frame,
1074 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1075}
1076
Adrian Bunk5eedc462008-04-22 14:41:44 -03001077static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001078{
1079 DEFINE_WAIT(wait);
1080 int rc = 0;
1081 int got_sig = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001082 /* DMA the frame */
1083 mutex_lock(&itv->udma.lock);
1084
1085 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1086 mutex_unlock(&itv->udma.lock);
1087 return rc;
1088 }
1089
1090 ivtv_udma_prepare(itv);
1091 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1092 /* if no UDMA is pending and no UDMA is in progress, then the DMA
Ian Armstrong2b057e82007-11-13 19:15:25 -03001093 is finished */
Hans Verkuilec105a42009-05-02 11:10:23 -03001094 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
1095 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001096 /* don't interrupt if the DMA is in progress but break off
Ian Armstrong2b057e82007-11-13 19:15:25 -03001097 a still pending DMA. */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001098 got_sig = signal_pending(current);
1099 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1100 break;
1101 got_sig = 0;
1102 schedule();
1103 }
1104 finish_wait(&itv->dma_waitq, &wait);
1105
1106 /* Unmap Last DMA Xfer */
1107 ivtv_udma_unmap(itv);
1108
1109 if (got_sig) {
1110 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1111 mutex_unlock(&itv->udma.lock);
1112 return -EINTR;
1113 }
1114
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001115 ivtv_yuv_frame_complete(itv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001116
1117 mutex_unlock(&itv->udma.lock);
1118 return rc;
1119}
1120
Ian Armstrong77aded62007-11-05 14:27:09 -03001121/* Setup frame according to V4L2 parameters */
1122void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1123{
1124 struct yuv_playback_info *yi = &itv->yuv_info;
1125 struct ivtv_dma_frame dma_args;
1126
1127 ivtv_yuv_next_free(itv);
1128
1129 /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001130 dma_args.y_source = NULL;
1131 dma_args.uv_source = NULL;
Ian Armstrong77aded62007-11-05 14:27:09 -03001132 dma_args.src.left = 0;
1133 dma_args.src.top = 0;
1134 dma_args.src.width = yi->v4l2_src_w;
1135 dma_args.src.height = yi->v4l2_src_h;
1136 dma_args.dst = yi->main_rect;
1137 dma_args.src_width = yi->v4l2_src_w;
1138 dma_args.src_height = yi->v4l2_src_h;
1139
1140 /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1141 ivtv_yuv_setup_frame(itv, &dma_args);
1142
1143 if (!itv->dma_data_req_offset)
1144 itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1145}
1146
1147/* Attempt to dma a frame from a user buffer */
Al Virob0510f82008-05-21 00:31:41 -03001148int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
Ian Armstrong77aded62007-11-05 14:27:09 -03001149{
1150 struct yuv_playback_info *yi = &itv->yuv_info;
1151 struct ivtv_dma_frame dma_args;
Hans Verkuilcdc03782011-10-11 06:06:58 -03001152 int res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001153
1154 ivtv_yuv_setup_stream_frame(itv);
1155
1156 /* We only need to supply source addresses for this */
1157 dma_args.y_source = src;
1158 dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001159 /* Wait for frame DMA. Note that serialize_lock is locked,
1160 so to allow other processes to access the driver while
1161 we are waiting unlock first and later lock again. */
1162 mutex_unlock(&itv->serialize_lock);
1163 res = ivtv_yuv_udma_frame(itv, &dma_args);
1164 mutex_lock(&itv->serialize_lock);
1165 return res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001166}
1167
1168/* IVTV_IOC_DMA_FRAME ioctl handler */
1169int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1170{
Hans Verkuilcdc03782011-10-11 06:06:58 -03001171 int res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001172
Hans Verkuilcdc03782011-10-11 06:06:58 -03001173/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
Ian Armstrong77aded62007-11-05 14:27:09 -03001174 ivtv_yuv_next_free(itv);
1175 ivtv_yuv_setup_frame(itv, args);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001176 /* Wait for frame DMA. Note that serialize_lock is locked,
1177 so to allow other processes to access the driver while
1178 we are waiting unlock first and later lock again. */
1179 mutex_unlock(&itv->serialize_lock);
1180 res = ivtv_yuv_udma_frame(itv, args);
1181 mutex_lock(&itv->serialize_lock);
1182 return res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001183}
1184
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001185void ivtv_yuv_close(struct ivtv *itv)
1186{
Ian Armstrong2b057e82007-11-13 19:15:25 -03001187 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001188 int h_filter, v_filter_1, v_filter_2;
1189
1190 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
Hans Verkuilcdc03782011-10-11 06:06:58 -03001191 mutex_unlock(&itv->serialize_lock);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001192 ivtv_waitq(&itv->vsync_waitq);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001193 mutex_lock(&itv->serialize_lock);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001194
Ian Armstrong2bd7ac52008-10-09 12:04:23 -03001195 yi->running = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001196 atomic_set(&yi->next_dma_frame, -1);
1197 atomic_set(&yi->next_fill_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001198
1199 /* Reset registers we have changed so mpeg playback works */
1200
1201 /* If we fully restore this register, the display may remain active.
1202 Restore, but set one bit to blank the video. Firmware will always
1203 clear this bit when needed, so not a problem. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001204 write_reg(yi->reg_2898 | 0x01000000, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001205
Ian Armstrong2b057e82007-11-13 19:15:25 -03001206 write_reg(yi->reg_2834, 0x02834);
1207 write_reg(yi->reg_2838, 0x02838);
1208 write_reg(yi->reg_283c, 0x0283c);
1209 write_reg(yi->reg_2840, 0x02840);
1210 write_reg(yi->reg_2844, 0x02844);
1211 write_reg(yi->reg_2848, 0x02848);
1212 write_reg(yi->reg_2854, 0x02854);
1213 write_reg(yi->reg_285c, 0x0285c);
1214 write_reg(yi->reg_2864, 0x02864);
1215 write_reg(yi->reg_2870, 0x02870);
1216 write_reg(yi->reg_2874, 0x02874);
1217 write_reg(yi->reg_2890, 0x02890);
1218 write_reg(yi->reg_289c, 0x0289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001219
Ian Armstrong2b057e82007-11-13 19:15:25 -03001220 write_reg(yi->reg_2918, 0x02918);
1221 write_reg(yi->reg_291c, 0x0291c);
1222 write_reg(yi->reg_2920, 0x02920);
1223 write_reg(yi->reg_2924, 0x02924);
1224 write_reg(yi->reg_2928, 0x02928);
1225 write_reg(yi->reg_292c, 0x0292c);
1226 write_reg(yi->reg_2930, 0x02930);
1227 write_reg(yi->reg_2934, 0x02934);
1228 write_reg(yi->reg_2938, 0x02938);
1229 write_reg(yi->reg_293c, 0x0293c);
1230 write_reg(yi->reg_2940, 0x02940);
1231 write_reg(yi->reg_2944, 0x02944);
1232 write_reg(yi->reg_2948, 0x02948);
1233 write_reg(yi->reg_294c, 0x0294c);
1234 write_reg(yi->reg_2950, 0x02950);
1235 write_reg(yi->reg_2954, 0x02954);
1236 write_reg(yi->reg_2958, 0x02958);
1237 write_reg(yi->reg_295c, 0x0295c);
1238 write_reg(yi->reg_2960, 0x02960);
1239 write_reg(yi->reg_2964, 0x02964);
1240 write_reg(yi->reg_2968, 0x02968);
1241 write_reg(yi->reg_296c, 0x0296c);
1242 write_reg(yi->reg_2970, 0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001243
1244 /* Prepare to restore filters */
1245
1246 /* First the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001247 if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001248 /* An exact size match uses filter 0 */
1249 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001250 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001251 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001252 h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001253 h_filter = (h_filter >> 1) + (h_filter & 1);
1254 /* Only an exact size match can use filter 0. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001255 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001256 }
1257
1258 /* Now the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001259 if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001260 /* An exact size match uses filter 0/1 */
1261 v_filter_1 = 0;
1262 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001263 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001264 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001265 v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001266 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1267 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001268 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001269 v_filter_2 = v_filter_1;
1270 }
1271
1272 /* Now restore the filters */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001273 ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001274
1275 /* and clear a few registers */
1276 write_reg(0, 0x02814);
1277 write_reg(0, 0x0282c);
1278 write_reg(0, 0x02904);
1279 write_reg(0, 0x02910);
1280
1281 /* Release the blanking buffer */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001282 if (yi->blanking_ptr) {
1283 kfree(yi->blanking_ptr);
1284 yi->blanking_ptr = NULL;
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001285 pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001286 }
1287
1288 /* Invalidate the old dimension information */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001289 yi->old_frame_info.src_w = 0;
1290 yi->old_frame_info.src_h = 0;
1291 yi->old_frame_info_args.src_w = 0;
1292 yi->old_frame_info_args.src_h = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001293
1294 /* All done. */
1295 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1296}