blob: f7299d3d82449ddaefc1ee76fd3f8cb33650e5b4 [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 */
Dave Hansend4edcf02016-02-12 13:01:56 -080078 y_pages = get_user_pages_unlocked(y_dma.uaddr,
Lorenzo Stoakesc1641542016-10-13 01:20:13 +010079 y_dma.page_count, &dma->map[0], FOLL_FORCE);
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) {
Dave Hansend4edcf02016-02-12 13:01:56 -080082 uv_pages = get_user_pages_unlocked(uv_dma.uaddr,
Lorenzo Stoakesc1641542016-10-13 01:20:13 +010083 uv_dma.page_count, &dma->map[y_pages],
84 FOLL_FORCE);
Paul Cassella7fd4b412011-02-12 10:39:51 -030085 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030086
Paul Cassella7fd4b412011-02-12 10:39:51 -030087 if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
88 int rc = -EFAULT;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030089
Paul Cassella7fd4b412011-02-12 10:39:51 -030090 if (y_pages == y_dma.page_count) {
91 IVTV_DEBUG_WARN
92 ("failed to map uv user pages, returned %d "
93 "expecting %d\n", uv_pages, uv_dma.page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -030094
Paul Cassella7fd4b412011-02-12 10:39:51 -030095 if (uv_pages >= 0) {
96 for (i = 0; i < uv_pages; i++)
97 put_page(dma->map[y_pages + i]);
98 rc = -EFAULT;
99 } else {
100 rc = uv_pages;
101 }
102 } else {
103 IVTV_DEBUG_WARN
104 ("failed to map y user pages, returned %d "
105 "expecting %d\n", y_pages, y_dma.page_count);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300106 }
Paul Cassella7fd4b412011-02-12 10:39:51 -0300107 if (y_pages >= 0) {
108 for (i = 0; i < y_pages; i++)
109 put_page(dma->map[i]);
110 /*
111 * Inherit the -EFAULT from rc's
112 * initialization, but allow it to be
113 * overriden by uv_pages above if it was an
114 * actual errno.
115 */
116 } else {
117 rc = y_pages;
118 }
119 return rc;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300120 }
121
Paul Cassella7fd4b412011-02-12 10:39:51 -0300122 dma->page_count = y_pages + uv_pages;
123
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300124 /* Fill & map SG List */
Hans Verkuil8beb0582007-08-19 17:56:41 -0300125 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 -0300126 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
127 for (i = 0; i < dma->page_count; i++) {
128 put_page(dma->map[i]);
129 }
130 dma->page_count = 0;
131 return -ENOMEM;
132 }
Hans Verkuil8ac05ae2009-02-07 07:02:27 -0300133 dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300134
135 /* Fill SG Array with new values */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300136 ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300137
138 /* If we've offset the y plane, ensure top area is blanked */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300139 if (f->offset_y && yi->blanking_dmaptr) {
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300140 dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300141 dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300142 dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
143 dma->SG_length++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300144 }
145
146 /* Tag SG Array with Interrupt Bit */
147 dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
148
149 ivtv_udma_sync_for_device(itv);
150 return 0;
151}
152
153/* We rely on a table held in the firmware - Quick check. */
154int ivtv_yuv_filter_check(struct ivtv *itv)
155{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300156 int i, y, uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300157
Ian Armstrong2b057e82007-11-13 19:15:25 -0300158 for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
159 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
160 (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300161 IVTV_WARN ("YUV filter table not found in firmware.\n");
162 return -1;
163 }
164 }
165 return 0;
166}
167
168static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
169{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300170 u32 i, line;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300171
172 /* If any filter is -1, then don't update it */
173 if (h_filter > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300174 if (h_filter > 4)
175 h_filter = 4;
176 i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
177 for (line = 0; line < 16; line++) {
178 write_reg(read_dec(i), 0x02804);
179 write_reg(read_dec(i), 0x0281c);
180 i += 4;
181 write_reg(read_dec(i), 0x02808);
182 write_reg(read_dec(i), 0x02820);
183 i += 4;
184 write_reg(read_dec(i), 0x0280c);
185 write_reg(read_dec(i), 0x02824);
186 i += 4;
187 write_reg(read_dec(i), 0x02810);
188 write_reg(read_dec(i), 0x02828);
189 i += 4;
190 write_reg(read_dec(i), 0x02814);
191 write_reg(read_dec(i), 0x0282c);
192 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300193 write_reg(0, 0x02818);
194 write_reg(0, 0x02830);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300195 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300196 IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300197 }
198
199 if (v_filter_1 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300200 if (v_filter_1 > 4)
201 v_filter_1 = 4;
202 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
203 for (line = 0; line < 16; line++) {
204 write_reg(read_dec(i), 0x02900);
205 i += 4;
206 write_reg(read_dec(i), 0x02904);
207 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300208 write_reg(0, 0x02908);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300209 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300210 IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300211 }
212
213 if (v_filter_2 > -1) {
Ian Armstrong2b057e82007-11-13 19:15:25 -0300214 if (v_filter_2 > 4)
215 v_filter_2 = 4;
216 i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
217 for (line = 0; line < 16; line++) {
218 write_reg(read_dec(i), 0x0290c);
219 i += 4;
220 write_reg(read_dec(i), 0x02910);
221 i += 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300222 write_reg(0, 0x02914);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300223 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300224 IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300225 }
226}
227
Ian Armstrong2b057e82007-11-13 19:15:25 -0300228static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300229{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300230 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300231 u32 reg_2834, reg_2838, reg_283c;
232 u32 reg_2844, reg_2854, reg_285c;
233 u32 reg_2864, reg_2874, reg_2890;
234 u32 reg_2870, reg_2870_base, reg_2870_offset;
235 int x_cutoff;
236 int h_filter;
237 u32 master_width;
238
Ian Armstrong2b057e82007-11-13 19:15:25 -0300239 IVTV_DEBUG_WARN
240 ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
241 f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300242
243 /* How wide is the src image */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300244 x_cutoff = f->src_w + f->src_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300245
246 /* Set the display width */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300247 reg_2834 = f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300248 reg_2838 = reg_2834;
249
250 /* Set the display position */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300251 reg_2890 = f->dst_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300252
253 /* Index into the image horizontally */
254 reg_2870 = 0;
255
256 /* 2870 is normally fudged to align video coords with osd coords.
257 If running full screen, it causes an unwanted left shift
258 Remove the fudge if we almost fill the screen.
259 Gradually adjust the offset to avoid the video 'snapping'
260 left/right if it gets dragged through this region.
261 Only do this if osd is full width. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300262 if (f->vis_w == 720) {
263 if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
264 reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
265 else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
266 reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300267
Ian Armstrong2b057e82007-11-13 19:15:25 -0300268 if (f->dst_w >= f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300269 reg_2870 = reg_2870 << 16 | reg_2870;
270 else
271 reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
272 }
273
Ian Armstrong2b057e82007-11-13 19:15:25 -0300274 if (f->dst_w < f->src_w)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300275 reg_2870 = 0x000d000e - reg_2870;
276 else
277 reg_2870 = 0x0012000e - reg_2870;
278
279 /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300280 reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300281
Ian Armstrong2b057e82007-11-13 19:15:25 -0300282 if (f->dst_w >= f->src_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300283 x_cutoff &= ~1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300284 master_width = (f->src_w * 0x00200000) / (f->dst_w);
285 if (master_width * f->dst_w != f->src_w * 0x00200000)
286 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300287 reg_2834 = (reg_2834 << 16) | x_cutoff;
288 reg_2838 = (reg_2838 << 16) | x_cutoff;
289 reg_283c = master_width >> 2;
290 reg_2844 = master_width >> 2;
291 reg_2854 = master_width;
292 reg_285c = master_width >> 1;
293 reg_2864 = master_width >> 1;
294
295 /* We also need to factor in the scaling
296 (src_w - dst_w) / (src_w / 4) */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300297 if (f->dst_w > f->src_w)
298 reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300299 else
300 reg_2870_base = 0;
301
302 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
303 reg_2874 = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300304 } else if (f->dst_w < f->src_w / 2) {
305 master_width = (f->src_w * 0x00080000) / f->dst_w;
306 if (master_width * f->dst_w != f->src_w * 0x00080000)
307 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300308 reg_2834 = (reg_2834 << 16) | x_cutoff;
309 reg_2838 = (reg_2838 << 16) | x_cutoff;
310 reg_283c = master_width >> 2;
311 reg_2844 = master_width >> 1;
312 reg_2854 = master_width;
313 reg_285c = master_width >> 1;
314 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300315 reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
316 reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300317 reg_2874 = 0x00000012;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300318 } else {
319 master_width = (f->src_w * 0x00100000) / f->dst_w;
320 if (master_width * f->dst_w != f->src_w * 0x00100000)
321 master_width++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300322 reg_2834 = (reg_2834 << 16) | x_cutoff;
323 reg_2838 = (reg_2838 << 16) | x_cutoff;
324 reg_283c = master_width >> 2;
325 reg_2844 = master_width >> 1;
326 reg_2854 = master_width;
327 reg_285c = master_width >> 1;
328 reg_2864 = master_width >> 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300329 reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
330 reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300331 reg_2874 = 0x00000001;
332 }
333
334 /* Select the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300335 if (f->src_w == f->dst_w) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300336 /* An exact size match uses filter 0 */
337 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300338 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300339 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300340 h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300341 h_filter = (h_filter >> 1) + (h_filter & 1);
342 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300343 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300344 }
345
346 write_reg(reg_2834, 0x02834);
347 write_reg(reg_2838, 0x02838);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300348 IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
349 yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300350
351 write_reg(reg_283c, 0x0283c);
352 write_reg(reg_2844, 0x02844);
353
Ian Armstrong2b057e82007-11-13 19:15:25 -0300354 IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
355 yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300356
357 write_reg(0x00080514, 0x02840);
358 write_reg(0x00100514, 0x02848);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300359 IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
360 yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300361
362 write_reg(reg_2854, 0x02854);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300363 IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
364 yi->reg_2854, reg_2854);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300365
366 write_reg(reg_285c, 0x0285c);
367 write_reg(reg_2864, 0x02864);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300368 IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
369 yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300370
371 write_reg(reg_2874, 0x02874);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300372 IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
373 yi->reg_2874, reg_2874);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300374
375 write_reg(reg_2870, 0x02870);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300376 IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
377 yi->reg_2870, reg_2870);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300378
Ian Armstrong2b057e82007-11-13 19:15:25 -0300379 write_reg(reg_2890, 0x02890);
380 IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
381 yi->reg_2890, reg_2890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300382
383 /* Only update the filter if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300384 if (h_filter != yi->h_filter) {
385 ivtv_yuv_filter(itv, h_filter, -1, -1);
386 yi->h_filter = h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300387 }
388}
389
Ian Armstrong2b057e82007-11-13 19:15:25 -0300390static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300391{
Ian Armstrong2b057e82007-11-13 19:15:25 -0300392 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300393 u32 master_height;
394 u32 reg_2918, reg_291c, reg_2920, reg_2928;
395 u32 reg_2930, reg_2934, reg_293c;
396 u32 reg_2940, reg_2944, reg_294c;
397 u32 reg_2950, reg_2954, reg_2958, reg_295c;
398 u32 reg_2960, reg_2964, reg_2968, reg_296c;
399 u32 reg_289c;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300400 u32 src_major_y, src_minor_y;
401 u32 src_major_uv, src_minor_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300402 u32 reg_2964_base, reg_2968_base;
403 int v_filter_1, v_filter_2;
404
Ian Armstrong2b057e82007-11-13 19:15:25 -0300405 IVTV_DEBUG_WARN
406 ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
407 f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300408
409 /* What scaling mode is being used... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300410 IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
411 f->interlaced_y ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300412
Ian Armstrong2b057e82007-11-13 19:15:25 -0300413 IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
414 f->interlaced_uv ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300415
416 /* What is the source video being treated as... */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300417 IVTV_DEBUG_WARN("Source video: %s\n",
418 f->interlaced ? "Interlaced" : "Progressive");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300419
420 /* We offset into the image using two different index methods, so split
421 the y source coord into two parts. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300422 if (f->src_y < 8) {
423 src_minor_uv = f->src_y;
424 src_major_uv = 0;
425 } else {
426 src_minor_uv = 8;
427 src_major_uv = f->src_y - 8;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300428 }
429
Ian Armstrong2b057e82007-11-13 19:15:25 -0300430 src_minor_y = src_minor_uv;
431 src_major_y = src_major_uv;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300432
Ian Armstrong2b057e82007-11-13 19:15:25 -0300433 if (f->offset_y)
434 src_minor_y += 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300435
Ian Armstrong2b057e82007-11-13 19:15:25 -0300436 if (f->interlaced_y)
437 reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300438 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300439 reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300440
Ian Armstrong2b057e82007-11-13 19:15:25 -0300441 if (f->interlaced_uv)
442 reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300443 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300444 reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300445
Ian Armstrong2b057e82007-11-13 19:15:25 -0300446 reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
447 reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300448
Ian Armstrong2b057e82007-11-13 19:15:25 -0300449 if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
450 master_height = (f->src_h * 0x00400000) / f->dst_h;
451 if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
452 master_height++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300453 reg_2920 = master_height >> 2;
454 reg_2928 = master_height >> 3;
455 reg_2930 = master_height;
456 reg_2940 = master_height >> 1;
457 reg_2964_base >>= 3;
458 reg_2968_base >>= 3;
459 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300460 } else if (f->dst_h >= f->src_h) {
461 master_height = (f->src_h * 0x00400000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300462 master_height = (master_height >> 1) + (master_height & 1);
463 reg_2920 = master_height >> 2;
464 reg_2928 = master_height >> 2;
465 reg_2930 = master_height;
466 reg_2940 = master_height >> 1;
467 reg_296c = 0x00000000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300468 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300469 reg_2964_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300470 } else {
471 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300472 reg_2964_base >>= 2;
473 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300474 if (f->interlaced_uv)
475 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300476 reg_2968_base >>= 3;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300477 } else if (f->dst_h >= f->src_h / 2) {
478 master_height = (f->src_h * 0x00200000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300479 master_height = (master_height >> 1) + (master_height & 1);
480 reg_2920 = master_height >> 2;
481 reg_2928 = master_height >> 2;
482 reg_2930 = master_height;
483 reg_2940 = master_height;
484 reg_296c = 0x00000101;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300485 if (f->interlaced_y) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300486 reg_2964_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300487 } else {
488 reg_296c++;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300489 reg_2964_base >>= 1;
490 }
Ian Armstrong2b057e82007-11-13 19:15:25 -0300491 if (f->interlaced_uv)
492 reg_2928 >>= 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300493 reg_2968_base >>= 2;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300494 } else {
495 master_height = (f->src_h * 0x00100000) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300496 master_height = (master_height >> 1) + (master_height & 1);
497 reg_2920 = master_height >> 2;
498 reg_2928 = master_height >> 2;
499 reg_2930 = master_height;
500 reg_2940 = master_height;
501 reg_2964_base >>= 1;
502 reg_2968_base >>= 2;
503 reg_296c = 0x00000102;
504 }
505
506 /* FIXME These registers change depending on scaled / unscaled output
507 We really need to work out what they should be */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300508 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300509 reg_2934 = 0x00020000;
510 reg_293c = 0x00100000;
511 reg_2944 = 0x00040000;
512 reg_294c = 0x000b0000;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300513 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300514 reg_2934 = 0x00000FF0;
515 reg_293c = 0x00000FF0;
516 reg_2944 = 0x00000FF0;
517 reg_294c = 0x00000FF0;
518 }
519
520 /* The first line to be displayed */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300521 reg_2950 = 0x00010000 + src_major_y;
522 if (f->interlaced_y)
523 reg_2950 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300524 reg_2954 = reg_2950 + 1;
525
Ian Armstrong2b057e82007-11-13 19:15:25 -0300526 reg_2958 = 0x00010000 + (src_major_y >> 1);
527 if (f->interlaced_uv)
528 reg_2958 += 0x00010000;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300529 reg_295c = reg_2958 + 1;
530
Ian Armstrong2b057e82007-11-13 19:15:25 -0300531 if (yi->decode_height == 480)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300532 reg_289c = 0x011e0017;
533 else
534 reg_289c = 0x01500017;
535
Ian Armstrong2b057e82007-11-13 19:15:25 -0300536 if (f->dst_y < 0)
537 reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300538 else
Ian Armstrong2b057e82007-11-13 19:15:25 -0300539 reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300540
541 /* How much of the source to decode.
542 Take into account the source offset */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300543 reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
544 (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300545
546 /* Calculate correct value for register 2964 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300547 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300548 reg_2964 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300549 } else {
550 reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300551 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
552 }
553 reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
554 reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
555
556 /* Okay, we've wasted time working out the correct value,
557 but if we use it, it fouls the the window alignment.
558 Fudge it to what we want... */
559 reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
560 reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
561
562 /* Deviate further from what it should be. I find the flicker headache
563 inducing so try to reduce it slightly. Leave 2968 as-is otherwise
564 colours foul. */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300565 if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
566 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300567
Ian Armstrong2b057e82007-11-13 19:15:25 -0300568 if (!f->interlaced_y)
569 reg_2964 -= 0x00010001;
570 if (!f->interlaced_uv)
571 reg_2968 -= 0x00010001;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300572
573 reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
574 reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
575
576 /* Select the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300577 if (f->src_h == f->dst_h) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300578 /* An exact size match uses filter 0/1 */
579 v_filter_1 = 0;
580 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300581 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300582 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300583 v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300584 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
585 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300586 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300587 v_filter_2 = v_filter_1;
588 }
589
590 write_reg(reg_2934, 0x02934);
591 write_reg(reg_293c, 0x0293c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300592 IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
593 yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300594 write_reg(reg_2944, 0x02944);
595 write_reg(reg_294c, 0x0294c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300596 IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
597 yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300598
599 /* Ensure 2970 is 0 (does it ever change ?) */
600/* write_reg(0,0x02970); */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300601/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300602
603 write_reg(reg_2930, 0x02938);
604 write_reg(reg_2930, 0x02930);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300605 IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
606 yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300607
608 write_reg(reg_2928, 0x02928);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300609 write_reg(reg_2928 + 0x514, 0x0292C);
610 IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
611 yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300612
613 write_reg(reg_2920, 0x02920);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300614 write_reg(reg_2920 + 0x514, 0x02924);
615 IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
616 yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300617
Ian Armstrong2b057e82007-11-13 19:15:25 -0300618 write_reg(reg_2918, 0x02918);
619 write_reg(reg_291c, 0x0291C);
620 IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
621 yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300622
623 write_reg(reg_296c, 0x0296c);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300624 IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
625 yi->reg_296c, reg_296c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300626
627 write_reg(reg_2940, 0x02948);
628 write_reg(reg_2940, 0x02940);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300629 IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
630 yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300631
632 write_reg(reg_2950, 0x02950);
633 write_reg(reg_2954, 0x02954);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300634 IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
635 yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300636
637 write_reg(reg_2958, 0x02958);
638 write_reg(reg_295c, 0x0295C);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300639 IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
640 yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300641
642 write_reg(reg_2960, 0x02960);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300643 IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
644 yi->reg_2960, reg_2960);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300645
646 write_reg(reg_2964, 0x02964);
647 write_reg(reg_2968, 0x02968);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300648 IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
649 yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300650
Ian Armstrong2b057e82007-11-13 19:15:25 -0300651 write_reg(reg_289c, 0x0289c);
652 IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
653 yi->reg_289c, reg_289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300654
655 /* Only update filter 1 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300656 if (v_filter_1 != yi->v_filter_1) {
657 ivtv_yuv_filter(itv, -1, v_filter_1, -1);
658 yi->v_filter_1 = v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300659 }
660
661 /* Only update filter 2 if we really need to */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300662 if (v_filter_2 != yi->v_filter_2) {
663 ivtv_yuv_filter(itv, -1, -1, v_filter_2);
664 yi->v_filter_2 = v_filter_2;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300665 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300666}
667
668/* Modify the supplied coordinate information to fit the visible osd area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300669static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300670{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300671 struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
672 int osd_crop;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300673 u32 osd_scale;
674 u32 yuv_update = 0;
675
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300676 /* Sorry, but no negative coords for src */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300677 if (f->src_x < 0)
678 f->src_x = 0;
679 if (f->src_y < 0)
680 f->src_y = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300681
682 /* Can only reduce width down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300683 if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
684 f->src_x += osd_crop / 2;
685 f->src_w = (f->src_w - osd_crop) & ~3;
686 f->dst_w = f->src_w / 4;
687 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300688 }
689
690 /* Can only reduce height down to 1/4 original size */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300691 if (f->src_h / f->dst_h >= 2) {
692 /* Overflow may be because we're running progressive,
693 so force mode switch */
694 f->interlaced_y = 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300695 /* Make sure we're still within limits for interlace */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300696 if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300697 /* If we reach here we'll have to force the height. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300698 f->src_y += osd_crop / 2;
699 f->src_h = (f->src_h - osd_crop) & ~3;
700 f->dst_h = f->src_h / 4;
701 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300702 }
703 }
704
705 /* If there's nothing to safe to display, we may as well stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300706 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300707 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300708 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300709 }
710
711 /* Ensure video remains inside OSD area */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300712 osd_scale = (f->src_h << 16) / f->dst_h;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300713
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300714 if ((osd_crop = f->pan_y - f->dst_y) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300715 /* Falls off the upper edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300716 f->src_y += (osd_scale * osd_crop) >> 16;
717 f->src_h -= (osd_scale * osd_crop) >> 16;
718 f->dst_h -= osd_crop;
719 f->dst_y = 0;
720 } else {
721 f->dst_y -= f->pan_y;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300722 }
723
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300724 if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300725 /* Falls off the lower edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300726 f->dst_h -= osd_crop;
727 f->src_h -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300728 }
729
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300730 osd_scale = (f->src_w << 16) / f->dst_w;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300731
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300732 if ((osd_crop = f->pan_x - f->dst_x) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300733 /* Fall off the left edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300734 f->src_x += (osd_scale * osd_crop) >> 16;
735 f->src_w -= (osd_scale * osd_crop) >> 16;
736 f->dst_w -= osd_crop;
737 f->dst_x = 0;
738 } else {
739 f->dst_x -= f->pan_x;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300740 }
741
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300742 if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300743 /* Falls off the right edge - crop */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300744 f->dst_w -= osd_crop;
745 f->src_w -= (osd_scale * osd_crop) >> 16;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300746 }
747
Ian Armstrong88ab0752008-04-22 14:42:14 -0300748 if (itv->yuv_info.track_osd) {
749 /* The OSD can be moved. Track to it */
750 f->dst_x += itv->yuv_info.osd_x_offset;
751 f->dst_y += itv->yuv_info.osd_y_offset;
752 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300753
754 /* Width & height for both src & dst must be even.
755 Same for coordinates. */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300756 f->dst_w &= ~1;
757 f->dst_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300758
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300759 f->src_w += f->src_x & 1;
760 f->src_x &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300761
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300762 f->src_w &= ~1;
763 f->dst_w &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300764
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300765 f->dst_h &= ~1;
766 f->dst_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300767
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300768 f->src_h += f->src_y & 1;
769 f->src_y &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300770
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300771 f->src_h &= ~1;
772 f->dst_h &= ~1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300773
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300774 /* Due to rounding, we may have reduced the output size to <1/4 of
775 the source. Check again, but this time just resize. Don't change
776 source coordinates */
777 if (f->dst_w < f->src_w / 4) {
778 f->src_w &= ~3;
779 f->dst_w = f->src_w / 4;
780 f->dst_w += f->dst_w & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300781 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300782 if (f->dst_h < f->src_h / 4) {
783 f->src_h &= ~3;
784 f->dst_h = f->src_h / 4;
785 f->dst_h += f->dst_h & 1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300786 }
787
788 /* Check again. If there's nothing to safe to display, stop now */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300789 if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300790 (int)f->src_w <= 2 || (int)f->src_h <= 2) {
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300791 return IVTV_YUV_UPDATE_INVALID;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300792 }
793
794 /* Both x offset & width are linked, so they have to be done together */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300795 if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300796 (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
797 (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300798 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
799 }
800
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300801 if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -0300802 (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
803 (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
804 (of->lace_mode != f->lace_mode) ||
805 (of->interlaced_y != f->interlaced_y) ||
806 (of->interlaced_uv != f->interlaced_uv)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300807 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
808 }
809
810 return yuv_update;
811}
812
813/* Update the scaling register to the requested value */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300814void ivtv_yuv_work_handler(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300815{
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300816 struct yuv_playback_info *yi = &itv->yuv_info;
817 struct yuv_frame_info f;
818 int frame = yi->update_frame;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300819 u32 yuv_update;
820
Ian Armstrong2b057e82007-11-13 19:15:25 -0300821 IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300822 f = yi->new_frame_info[frame];
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300823
Ian Armstrong88ab0752008-04-22 14:42:14 -0300824 if (yi->track_osd) {
825 /* Snapshot the osd pan info */
826 f.pan_x = yi->osd_x_pan;
827 f.pan_y = yi->osd_y_pan;
828 f.vis_w = yi->osd_vis_w;
829 f.vis_h = yi->osd_vis_h;
830 } else {
831 /* Not tracking the osd, so assume full screen */
832 f.pan_x = 0;
833 f.pan_y = 0;
834 f.vis_w = 720;
835 f.vis_h = yi->decode_height;
836 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300837
838 /* Calculate the display window coordinates. Exit if nothing left */
Ian Armstrong2b057e82007-11-13 19:15:25 -0300839 if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300840 return;
841
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300842 if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
843 write_reg(0x01008080, 0x2898);
844 } else if (yuv_update) {
845 write_reg(0x00108080, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300846
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300847 if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300848 ivtv_yuv_handle_horizontal(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300849
850 if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300851 ivtv_yuv_handle_vertical(itv, &f);
Ian Armstrong0bfeb042007-10-14 13:08:02 -0300852 }
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300853 yi->old_frame_info = f;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300854}
855
Ian Armstrong2b057e82007-11-13 19:15:25 -0300856static void ivtv_yuv_init(struct ivtv *itv)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300857{
Ian Armstrong195b1252007-10-14 13:12:28 -0300858 struct yuv_playback_info *yi = &itv->yuv_info;
859
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300860 IVTV_DEBUG_YUV("ivtv_yuv_init\n");
861
862 /* Take a snapshot of the current register settings */
Ian Armstrong195b1252007-10-14 13:12:28 -0300863 yi->reg_2834 = read_reg(0x02834);
864 yi->reg_2838 = read_reg(0x02838);
865 yi->reg_283c = read_reg(0x0283c);
866 yi->reg_2840 = read_reg(0x02840);
867 yi->reg_2844 = read_reg(0x02844);
868 yi->reg_2848 = read_reg(0x02848);
869 yi->reg_2854 = read_reg(0x02854);
870 yi->reg_285c = read_reg(0x0285c);
871 yi->reg_2864 = read_reg(0x02864);
872 yi->reg_2870 = read_reg(0x02870);
873 yi->reg_2874 = read_reg(0x02874);
874 yi->reg_2898 = read_reg(0x02898);
875 yi->reg_2890 = read_reg(0x02890);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300876
Ian Armstrong195b1252007-10-14 13:12:28 -0300877 yi->reg_289c = read_reg(0x0289c);
878 yi->reg_2918 = read_reg(0x02918);
879 yi->reg_291c = read_reg(0x0291c);
880 yi->reg_2920 = read_reg(0x02920);
881 yi->reg_2924 = read_reg(0x02924);
882 yi->reg_2928 = read_reg(0x02928);
883 yi->reg_292c = read_reg(0x0292c);
884 yi->reg_2930 = read_reg(0x02930);
885 yi->reg_2934 = read_reg(0x02934);
886 yi->reg_2938 = read_reg(0x02938);
887 yi->reg_293c = read_reg(0x0293c);
888 yi->reg_2940 = read_reg(0x02940);
889 yi->reg_2944 = read_reg(0x02944);
890 yi->reg_2948 = read_reg(0x02948);
891 yi->reg_294c = read_reg(0x0294c);
892 yi->reg_2950 = read_reg(0x02950);
893 yi->reg_2954 = read_reg(0x02954);
894 yi->reg_2958 = read_reg(0x02958);
895 yi->reg_295c = read_reg(0x0295c);
896 yi->reg_2960 = read_reg(0x02960);
897 yi->reg_2964 = read_reg(0x02964);
898 yi->reg_2968 = read_reg(0x02968);
899 yi->reg_296c = read_reg(0x0296c);
900 yi->reg_2970 = read_reg(0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300901
Ian Armstrong195b1252007-10-14 13:12:28 -0300902 yi->v_filter_1 = -1;
903 yi->v_filter_2 = -1;
904 yi->h_filter = -1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300905
906 /* Set some valid size info */
Ian Armstrong195b1252007-10-14 13:12:28 -0300907 yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
908 yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300909
910 /* Bit 2 of reg 2878 indicates current decoder output format
911 0 : NTSC 1 : PAL */
912 if (read_reg(0x2878) & 4)
Ian Armstrong195b1252007-10-14 13:12:28 -0300913 yi->decode_height = 576;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300914 else
Ian Armstrong195b1252007-10-14 13:12:28 -0300915 yi->decode_height = 480;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300916
Ian Armstrong195b1252007-10-14 13:12:28 -0300917 if (!itv->osd_info) {
918 yi->osd_vis_w = 720 - yi->osd_x_offset;
919 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300920 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300921 /* If no visible size set, assume full size */
922 if (!yi->osd_vis_w)
923 yi->osd_vis_w = 720 - yi->osd_x_offset;
924
Ian Armstrong2b057e82007-11-13 19:15:25 -0300925 if (!yi->osd_vis_h) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300926 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrong2b057e82007-11-13 19:15:25 -0300927 } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
Ian Armstrong195b1252007-10-14 13:12:28 -0300928 /* If output video standard has changed, requested height may
Ian Armstrong2b057e82007-11-13 19:15:25 -0300929 not be legal */
930 IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
931 yi->osd_vis_h + yi->osd_y_offset,
932 yi->decode_height);
933 yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
Ian Armstrongb4b38bd2007-08-03 09:44:13 -0300934 }
935 }
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300936
937 /* 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 -0300938 yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300939 if (yi->blanking_ptr) {
Hans Verkuil8ac05ae2009-02-07 07:02:27 -0300940 yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
Ian Armstrong2b057e82007-11-13 19:15:25 -0300941 } else {
Ian Armstrong195b1252007-10-14 13:12:28 -0300942 yi->blanking_dmaptr = 0;
943 IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300944 }
945
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300946 /* Enable YUV decoder output */
947 write_reg_sync(0x01, IVTV_REG_VDM);
948
949 set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
Ian Armstrong195b1252007-10-14 13:12:28 -0300950 atomic_set(&yi->next_dma_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -0300951}
952
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300953/* Get next available yuv buffer on PVR350 */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300954static void ivtv_yuv_next_free(struct ivtv *itv)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300955{
956 int draw, display;
957 struct yuv_playback_info *yi = &itv->yuv_info;
958
959 if (atomic_read(&yi->next_dma_frame) == -1)
960 ivtv_yuv_init(itv);
961
962 draw = atomic_read(&yi->next_fill_frame);
963 display = atomic_read(&yi->next_dma_frame);
964
965 if (display > draw)
966 display -= IVTV_YUV_BUFFERS;
967
968 if (draw - display >= yi->max_frames_buffered)
969 draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
970 else
971 yi->new_frame_info[draw].update = 0;
972
973 yi->draw_frame = draw;
974}
975
976/* Set up frame according to ivtv_dma_frame parameters */
Adrian Bunk5eedc462008-04-22 14:41:44 -0300977static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300978{
979 struct yuv_playback_info *yi = &itv->yuv_info;
980 u8 frame = yi->draw_frame;
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300981 u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
982 struct yuv_frame_info *nf = &yi->new_frame_info[frame];
983 struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
984 int lace_threshold = yi->lace_threshold;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300985
986 /* Preserve old update flag in case we're overwriting a queued frame */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300987 int update = nf->update;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -0300988
989 /* Take a snapshot of the yuv coordinate information */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -0300990 nf->src_x = args->src.left;
991 nf->src_y = args->src.top;
992 nf->src_w = args->src.width;
993 nf->src_h = args->src.height;
994 nf->dst_x = args->dst.left;
995 nf->dst_y = args->dst.top;
996 nf->dst_w = args->dst.width;
997 nf->dst_h = args->dst.height;
998 nf->tru_x = args->dst.left;
999 nf->tru_w = args->src_width;
1000 nf->tru_h = args->src_height;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001001
1002 /* Are we going to offset the Y plane */
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001003 nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001004
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001005 nf->update = 0;
1006 nf->interlaced_y = 0;
1007 nf->interlaced_uv = 0;
1008 nf->delay = 0;
1009 nf->sync_field = 0;
1010 nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001011
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001012 if (lace_threshold < 0)
1013 lace_threshold = yi->decode_height - 1;
1014
1015 /* Work out the lace settings */
1016 switch (nf->lace_mode) {
1017 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
1018 nf->interlaced = 0;
1019 if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
1020 nf->interlaced_y = 0;
1021 else
1022 nf->interlaced_y = 1;
1023
1024 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1025 nf->interlaced_uv = 0;
1026 else
1027 nf->interlaced_uv = 1;
1028 break;
1029
1030 case IVTV_YUV_MODE_AUTO:
1031 if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
1032 nf->interlaced = 0;
1033 if ((nf->tru_h < 512) ||
Ian Armstrong2b057e82007-11-13 19:15:25 -03001034 (nf->tru_h > 576 && nf->tru_h < 1021) ||
1035 (nf->tru_w > 720 && nf->tru_h < 1021))
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001036 nf->interlaced_y = 0;
1037 else
1038 nf->interlaced_y = 1;
1039 if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
1040 nf->interlaced_uv = 0;
1041 else
1042 nf->interlaced_uv = 1;
1043 } else {
1044 nf->interlaced = 1;
1045 nf->interlaced_y = 1;
1046 nf->interlaced_uv = 1;
1047 }
1048 break;
1049
1050 case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
1051 default:
1052 nf->interlaced = 1;
1053 nf->interlaced_y = 1;
1054 nf->interlaced_uv = 1;
1055 break;
1056 }
1057
1058 if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
1059 yi->old_frame_info_args = *nf;
1060 nf->update = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001061 IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001062 }
1063
Ian Armstrong3b5c1c82007-10-22 14:24:26 -03001064 nf->update |= update;
1065 nf->sync_field = yi->lace_sync_field;
1066 nf->delay = nf->sync_field != of->sync_field;
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001067}
1068
1069/* Frame is complete & ready for display */
1070void ivtv_yuv_frame_complete(struct ivtv *itv)
1071{
1072 atomic_set(&itv->yuv_info.next_fill_frame,
1073 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1074}
1075
Adrian Bunk5eedc462008-04-22 14:41:44 -03001076static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001077{
1078 DEFINE_WAIT(wait);
1079 int rc = 0;
1080 int got_sig = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001081 /* DMA the frame */
1082 mutex_lock(&itv->udma.lock);
1083
1084 if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1085 mutex_unlock(&itv->udma.lock);
1086 return rc;
1087 }
1088
1089 ivtv_udma_prepare(itv);
1090 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1091 /* if no UDMA is pending and no UDMA is in progress, then the DMA
Ian Armstrong2b057e82007-11-13 19:15:25 -03001092 is finished */
Hans Verkuilec105a42009-05-02 11:10:23 -03001093 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
1094 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001095 /* don't interrupt if the DMA is in progress but break off
Ian Armstrong2b057e82007-11-13 19:15:25 -03001096 a still pending DMA. */
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001097 got_sig = signal_pending(current);
1098 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1099 break;
1100 got_sig = 0;
1101 schedule();
1102 }
1103 finish_wait(&itv->dma_waitq, &wait);
1104
1105 /* Unmap Last DMA Xfer */
1106 ivtv_udma_unmap(itv);
1107
1108 if (got_sig) {
1109 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1110 mutex_unlock(&itv->udma.lock);
1111 return -EINTR;
1112 }
1113
Ian Armstronga3e5f5e2007-10-20 14:52:55 -03001114 ivtv_yuv_frame_complete(itv);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001115
1116 mutex_unlock(&itv->udma.lock);
1117 return rc;
1118}
1119
Ian Armstrong77aded62007-11-05 14:27:09 -03001120/* Setup frame according to V4L2 parameters */
1121void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1122{
1123 struct yuv_playback_info *yi = &itv->yuv_info;
1124 struct ivtv_dma_frame dma_args;
1125
1126 ivtv_yuv_next_free(itv);
1127
1128 /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
Harvey Harrisona6a3a172008-04-28 16:50:03 -07001129 dma_args.y_source = NULL;
1130 dma_args.uv_source = NULL;
Ian Armstrong77aded62007-11-05 14:27:09 -03001131 dma_args.src.left = 0;
1132 dma_args.src.top = 0;
1133 dma_args.src.width = yi->v4l2_src_w;
1134 dma_args.src.height = yi->v4l2_src_h;
1135 dma_args.dst = yi->main_rect;
1136 dma_args.src_width = yi->v4l2_src_w;
1137 dma_args.src_height = yi->v4l2_src_h;
1138
1139 /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1140 ivtv_yuv_setup_frame(itv, &dma_args);
1141
1142 if (!itv->dma_data_req_offset)
1143 itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1144}
1145
1146/* Attempt to dma a frame from a user buffer */
Al Virob0510f82008-05-21 00:31:41 -03001147int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
Ian Armstrong77aded62007-11-05 14:27:09 -03001148{
1149 struct yuv_playback_info *yi = &itv->yuv_info;
1150 struct ivtv_dma_frame dma_args;
Hans Verkuilcdc03782011-10-11 06:06:58 -03001151 int res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001152
1153 ivtv_yuv_setup_stream_frame(itv);
1154
1155 /* We only need to supply source addresses for this */
1156 dma_args.y_source = src;
1157 dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001158 /* Wait for frame DMA. Note that serialize_lock is locked,
1159 so to allow other processes to access the driver while
1160 we are waiting unlock first and later lock again. */
1161 mutex_unlock(&itv->serialize_lock);
1162 res = ivtv_yuv_udma_frame(itv, &dma_args);
1163 mutex_lock(&itv->serialize_lock);
1164 return res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001165}
1166
1167/* IVTV_IOC_DMA_FRAME ioctl handler */
1168int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1169{
Hans Verkuilcdc03782011-10-11 06:06:58 -03001170 int res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001171
Hans Verkuilcdc03782011-10-11 06:06:58 -03001172/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
Ian Armstrong77aded62007-11-05 14:27:09 -03001173 ivtv_yuv_next_free(itv);
1174 ivtv_yuv_setup_frame(itv, args);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001175 /* Wait for frame DMA. Note that serialize_lock is locked,
1176 so to allow other processes to access the driver while
1177 we are waiting unlock first and later lock again. */
1178 mutex_unlock(&itv->serialize_lock);
1179 res = ivtv_yuv_udma_frame(itv, args);
1180 mutex_lock(&itv->serialize_lock);
1181 return res;
Ian Armstrong77aded62007-11-05 14:27:09 -03001182}
1183
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001184void ivtv_yuv_close(struct ivtv *itv)
1185{
Ian Armstrong2b057e82007-11-13 19:15:25 -03001186 struct yuv_playback_info *yi = &itv->yuv_info;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001187 int h_filter, v_filter_1, v_filter_2;
1188
1189 IVTV_DEBUG_YUV("ivtv_yuv_close\n");
Hans Verkuilcdc03782011-10-11 06:06:58 -03001190 mutex_unlock(&itv->serialize_lock);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001191 ivtv_waitq(&itv->vsync_waitq);
Hans Verkuilcdc03782011-10-11 06:06:58 -03001192 mutex_lock(&itv->serialize_lock);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001193
Ian Armstrong2bd7ac52008-10-09 12:04:23 -03001194 yi->running = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001195 atomic_set(&yi->next_dma_frame, -1);
1196 atomic_set(&yi->next_fill_frame, 0);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001197
1198 /* Reset registers we have changed so mpeg playback works */
1199
1200 /* If we fully restore this register, the display may remain active.
1201 Restore, but set one bit to blank the video. Firmware will always
1202 clear this bit when needed, so not a problem. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001203 write_reg(yi->reg_2898 | 0x01000000, 0x2898);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001204
Ian Armstrong2b057e82007-11-13 19:15:25 -03001205 write_reg(yi->reg_2834, 0x02834);
1206 write_reg(yi->reg_2838, 0x02838);
1207 write_reg(yi->reg_283c, 0x0283c);
1208 write_reg(yi->reg_2840, 0x02840);
1209 write_reg(yi->reg_2844, 0x02844);
1210 write_reg(yi->reg_2848, 0x02848);
1211 write_reg(yi->reg_2854, 0x02854);
1212 write_reg(yi->reg_285c, 0x0285c);
1213 write_reg(yi->reg_2864, 0x02864);
1214 write_reg(yi->reg_2870, 0x02870);
1215 write_reg(yi->reg_2874, 0x02874);
1216 write_reg(yi->reg_2890, 0x02890);
1217 write_reg(yi->reg_289c, 0x0289c);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001218
Ian Armstrong2b057e82007-11-13 19:15:25 -03001219 write_reg(yi->reg_2918, 0x02918);
1220 write_reg(yi->reg_291c, 0x0291c);
1221 write_reg(yi->reg_2920, 0x02920);
1222 write_reg(yi->reg_2924, 0x02924);
1223 write_reg(yi->reg_2928, 0x02928);
1224 write_reg(yi->reg_292c, 0x0292c);
1225 write_reg(yi->reg_2930, 0x02930);
1226 write_reg(yi->reg_2934, 0x02934);
1227 write_reg(yi->reg_2938, 0x02938);
1228 write_reg(yi->reg_293c, 0x0293c);
1229 write_reg(yi->reg_2940, 0x02940);
1230 write_reg(yi->reg_2944, 0x02944);
1231 write_reg(yi->reg_2948, 0x02948);
1232 write_reg(yi->reg_294c, 0x0294c);
1233 write_reg(yi->reg_2950, 0x02950);
1234 write_reg(yi->reg_2954, 0x02954);
1235 write_reg(yi->reg_2958, 0x02958);
1236 write_reg(yi->reg_295c, 0x0295c);
1237 write_reg(yi->reg_2960, 0x02960);
1238 write_reg(yi->reg_2964, 0x02964);
1239 write_reg(yi->reg_2968, 0x02968);
1240 write_reg(yi->reg_296c, 0x0296c);
1241 write_reg(yi->reg_2970, 0x02970);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001242
1243 /* Prepare to restore filters */
1244
1245 /* First the horizontal filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001246 if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001247 /* An exact size match uses filter 0 */
1248 h_filter = 0;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001249 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001250 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001251 h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001252 h_filter = (h_filter >> 1) + (h_filter & 1);
1253 /* Only an exact size match can use filter 0. */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001254 h_filter += !h_filter;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001255 }
1256
1257 /* Now the vertical filter */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001258 if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001259 /* An exact size match uses filter 0/1 */
1260 v_filter_1 = 0;
1261 v_filter_2 = 1;
Ian Armstrong2b057e82007-11-13 19:15:25 -03001262 } else {
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001263 /* Figure out which filter to use */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001264 v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001265 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1266 /* Only an exact size match can use filter 0 */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001267 v_filter_1 += !v_filter_1;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001268 v_filter_2 = v_filter_1;
1269 }
1270
1271 /* Now restore the filters */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001272 ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001273
1274 /* and clear a few registers */
1275 write_reg(0, 0x02814);
1276 write_reg(0, 0x0282c);
1277 write_reg(0, 0x02904);
1278 write_reg(0, 0x02910);
1279
1280 /* Release the blanking buffer */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001281 if (yi->blanking_ptr) {
1282 kfree(yi->blanking_ptr);
1283 yi->blanking_ptr = NULL;
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001284 pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001285 }
1286
1287 /* Invalidate the old dimension information */
Ian Armstrong2b057e82007-11-13 19:15:25 -03001288 yi->old_frame_info.src_w = 0;
1289 yi->old_frame_info.src_h = 0;
1290 yi->old_frame_info_args.src_w = 0;
1291 yi->old_frame_info_args.src_h = 0;
Hans Verkuil1a0adaf2007-04-27 12:31:25 -03001292
1293 /* All done. */
1294 clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1295}