11a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil/*
21a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    yuv support
31a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
41a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>
51a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
61a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    This program is free software; you can redistribute it and/or modify
71a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    it under the terms of the GNU General Public License as published by
81a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    the Free Software Foundation; either version 2 of the License, or
91a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    (at your option) any later version.
101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    This program is distributed in the hope that it will be useful,
121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    but WITHOUT ANY WARRANTY; without even the implied warranty of
131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    GNU General Public License for more details.
151a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    You should have received a copy of the GNU General Public License
171a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    along with this program; if not, write to the Free Software
181a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
191a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil */
201a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
211a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil#include "ivtv-driver.h"
221a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil#include "ivtv-udma.h"
2383df8e7b0d7b319f9ce9773eaf4b1da324ae17d7Hans Verkuil#include "ivtv-yuv.h"
241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
25a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong/* YUV buffer offsets */
26a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrongconst u32 yuv_offset[IVTV_YUV_BUFFERS] = {
27a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x001a8600,
28a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x00240400,
29a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x002d8200,
30a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x00370000,
31a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x00029000,
32a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x000C0E00,
33a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x006B0400,
34a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	0x00748200
35612570f2c4794bbf4e5bfa8648b61fbfc9cd8501Hans Verkuil};
36612570f2c4794bbf4e5bfa8648b61fbfc9cd8501Hans Verkuil
371a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuilstatic int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
382b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong				  struct ivtv_dma_frame *args)
391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
401a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	struct ivtv_dma_page_info y_dma;
411a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	struct ivtv_dma_page_info uv_dma;
423b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
433b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	u8 frame = yi->draw_frame;
443b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_frame_info *f = &yi->new_frame_info[frame];
451a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int i;
461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int y_pages, uv_pages;
471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	unsigned long y_buffer_offset, uv_buffer_offset;
481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int y_decode_height, uv_decode_height, y_size;
491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5033c0fcad2160bc211272295e862c6f708118d006Hans Verkuil	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
521a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
532b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	y_decode_height = uv_decode_height = f->src_h + f->src_y;
541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
553b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->offset_y)
561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		y_buffer_offset += 720 * 16;
571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (y_decode_height & 15)
591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		y_decode_height = (y_decode_height + 16) & ~15;
601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (uv_decode_height & 31)
621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		uv_decode_height = (uv_decode_height + 32) & ~31;
631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
641a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	y_size = 720 * y_decode_height;
651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Still in USE */
671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (dma->SG_length || dma->page_count) {
682b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		IVTV_DEBUG_WARN
692b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
702b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		     dma->SG_length, dma->page_count);
711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		return -EBUSY;
721a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
731a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
751a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Get user pages for DMA Xfer */
781a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	down_read(&current->mm->mmap_sem);
791a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
807fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella	uv_pages = 0; /* silence gcc. value is set and consumed only if: */
817fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella	if (y_pages == y_dma.page_count) {
827fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		uv_pages = get_user_pages(current, current->mm,
837fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella					  uv_dma.uaddr, uv_dma.page_count, 0, 1,
847fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella					  &dma->map[y_pages], NULL);
857fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella	}
861a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	up_read(&current->mm->mmap_sem);
871a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
887fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella	if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {
897fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		int rc = -EFAULT;
907fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella
917fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		if (y_pages == y_dma.page_count) {
927fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			IVTV_DEBUG_WARN
937fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				("failed to map uv user pages, returned %d "
947fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				 "expecting %d\n", uv_pages, uv_dma.page_count);
957fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella
967fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			if (uv_pages >= 0) {
977fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				for (i = 0; i < uv_pages; i++)
987fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella					put_page(dma->map[y_pages + i]);
997fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				rc = -EFAULT;
1007fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			} else {
1017fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				rc = uv_pages;
1027fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			}
1037fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		} else {
1047fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			IVTV_DEBUG_WARN
1057fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				("failed to map y user pages, returned %d "
1067fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				 "expecting %d\n", y_pages, y_dma.page_count);
1071a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
1087fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		if (y_pages >= 0) {
1097fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			for (i = 0; i < y_pages; i++)
1107fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella				put_page(dma->map[i]);
1117fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			/*
1127fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			 * Inherit the -EFAULT from rc's
1137fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			 * initialization, but allow it to be
1147fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			 * overriden by uv_pages above if it was an
1157fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			 * actual errno.
1167fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			 */
1177fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		} else {
1187fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella			rc = y_pages;
1197fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		}
1207fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella		return rc;
1211a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
1221a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1237fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella	dma->page_count = y_pages + uv_pages;
1247fd4b41f053681cccf188cc1731ae43fe38fa969Paul Cassella
1251a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Fill & map SG List */
1268beb058f1ecde7bc0554d18ce1baa18b5dfb02d3Hans Verkuil	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
1270989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
1280989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil		for (i = 0; i < dma->page_count; i++) {
1290989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil			put_page(dma->map[i]);
1300989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil		}
1310989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil		dma->page_count = 0;
1320989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil		return -ENOMEM;
1330989fd2c88a11aa5014b2b348ed51872d14d536dHans Verkuil	}
1348ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil	dma->SG_length = pci_map_sg(itv->pdev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
1351a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1361a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Fill SG Array with new values */
1372b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
1381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* If we've offset the y plane, ensure top area is blanked */
1402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->offset_y && yi->blanking_dmaptr) {
1413b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
1422b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
1433b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
1443b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		dma->SG_length++;
1451a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
1461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Tag SG Array with Interrupt Bit */
1481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
1491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1501a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_udma_sync_for_device(itv);
1511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	return 0;
1521a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
1531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil/* We rely on a table held in the firmware - Quick check. */
1551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuilint ivtv_yuv_filter_check(struct ivtv *itv)
1561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
1572b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	int i, y, uv;
1581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1592b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
1602b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
1612b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
1621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			IVTV_WARN ("YUV filter table not found in firmware.\n");
1631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			return -1;
1641a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
1651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
1661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	return 0;
1671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
1681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1691a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuilstatic void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
1701a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
1712b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	u32 i, line;
1721a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1731a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* If any filter is -1, then don't update it */
1741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (h_filter > -1) {
1752b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (h_filter > 4)
1762b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			h_filter = 4;
1772b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
1782b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		for (line = 0; line < 16; line++) {
1792b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02804);
1802b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x0281c);
1812b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
1822b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02808);
1832b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02820);
1842b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
1852b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x0280c);
1862b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02824);
1872b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
1882b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02810);
1892b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02828);
1902b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
1912b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02814);
1922b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x0282c);
1932b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 8;
1941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			write_reg(0, 0x02818);
1951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			write_reg(0, 0x02830);
1961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
1972b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
1981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
1991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (v_filter_1 > -1) {
2012b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (v_filter_1 > 4)
2022b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			v_filter_1 = 4;
2032b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
2042b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		for (line = 0; line < 16; line++) {
2052b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02900);
2062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
2072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02904);
2082b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 8;
2091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			write_reg(0, 0x02908);
2101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
2112b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
2121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
2131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (v_filter_2 > -1) {
2152b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (v_filter_2 > 4)
2162b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			v_filter_2 = 4;
2172b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
2182b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		for (line = 0; line < 16; line++) {
2192b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x0290c);
2202b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 4;
2212b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			write_reg(read_dec(i), 0x02910);
2222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			i += 8;
2231a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			write_reg(0, 0x02914);
2241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
2252b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
2261a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
2271a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
2281a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2292b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrongstatic void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
2301a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
2312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
2321a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2834, reg_2838, reg_283c;
2331a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2844, reg_2854, reg_285c;
2341a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2864, reg_2874, reg_2890;
2351a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2870, reg_2870_base, reg_2870_offset;
2361a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int x_cutoff;
2371a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int h_filter;
2381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 master_width;
2391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_WARN
2412b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
2422b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
2431a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2441a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* How wide is the src image */
2452b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	x_cutoff = f->src_w + f->src_x;
2461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Set the display width */
2482b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2834 = f->dst_w;
2491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2838 = reg_2834;
2501a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Set the display position */
2522b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2890 = f->dst_x;
2531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Index into the image horizontally */
2551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2870 = 0;
2561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* 2870 is normally fudged to align video coords with osd coords.
2581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   If running full screen, it causes an unwanted left shift
2591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Remove the fudge if we almost fill the screen.
2601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Gradually adjust the offset to avoid the video 'snapping'
2611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   left/right if it gets dragged through this region.
2621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Only do this if osd is full width. */
2632b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->vis_w == 720) {
2642b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
2652b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
2662b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
2672b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
2681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2692b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->dst_w >= f->src_w)
2701a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2870 = reg_2870 << 16 | reg_2870;
2711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		else
2721a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
2731a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
2741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2752b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->dst_w < f->src_w)
2761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2870 = 0x000d000e - reg_2870;
2771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
2781a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2870 = 0x0012000e - reg_2870;
2791a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2801a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
2812b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
2821a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2832b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->dst_w >= f->src_w) {
2841a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		x_cutoff &= ~1;
2852b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_width = (f->src_w * 0x00200000) / (f->dst_w);
2862b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (master_width * f->dst_w != f->src_w * 0x00200000)
2872b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			master_width++;
2881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2834 = (reg_2834 << 16) | x_cutoff;
2891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2838 = (reg_2838 << 16) | x_cutoff;
2901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_283c = master_width >> 2;
2911a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2844 = master_width >> 2;
2921a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2854 = master_width;
2931a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_285c = master_width >> 1;
2941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2864 = master_width >> 1;
2951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
2961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* We also need to factor in the scaling
2971a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		   (src_w - dst_w) / (src_w / 4) */
2982b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->dst_w > f->src_w)
2992b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
3001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		else
3011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2870_base = 0;
3021a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
3041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2874 = 0;
3052b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else if (f->dst_w < f->src_w / 2) {
3062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_width = (f->src_w * 0x00080000) / f->dst_w;
3072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (master_width * f->dst_w != f->src_w * 0x00080000)
3082b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			master_width++;
3091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2834 = (reg_2834 << 16) | x_cutoff;
3101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2838 = (reg_2838 << 16) | x_cutoff;
3111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_283c = master_width >> 2;
3121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2844 = master_width >> 1;
3131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2854 = master_width;
3141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_285c = master_width >> 1;
3151a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2864 = master_width >> 1;
3162b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
3172b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
3181a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2874 = 0x00000012;
3192b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
3202b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_width = (f->src_w * 0x00100000) / f->dst_w;
3212b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (master_width * f->dst_w != f->src_w * 0x00100000)
3222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			master_width++;
3231a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2834 = (reg_2834 << 16) | x_cutoff;
3241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2838 = (reg_2838 << 16) | x_cutoff;
3251a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_283c = master_width >> 2;
3261a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2844 = master_width >> 1;
3271a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2854 = master_width;
3281a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_285c = master_width >> 1;
3291a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2864 = master_width >> 1;
3302b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
3312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
3321a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2874 = 0x00000001;
3331a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
3341a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3351a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Select the horizontal filter */
3362b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->src_w == f->dst_w) {
3371a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* An exact size match uses filter 0 */
3381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		h_filter = 0;
3392b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
3401a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Figure out which filter to use */
3412b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
3421a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		h_filter = (h_filter >> 1) + (h_filter & 1);
3431a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Only an exact size match can use filter 0 */
3442b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		h_filter += !h_filter;
3451a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
3461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2834, 0x02834);
3481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2838, 0x02838);
3492b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
3502b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
3511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3521a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_283c, 0x0283c);
3531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2844, 0x02844);
3541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3552b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
3562b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
3571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0x00080514, 0x02840);
3591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0x00100514, 0x02848);
3602b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
3612b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
3621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2854, 0x02854);
3642b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
3652b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2854, reg_2854);
3661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_285c, 0x0285c);
3681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2864, 0x02864);
3692b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
3702b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
3711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3721a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2874, 0x02874);
3732b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
3742b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2874, reg_2874);
3751a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2870, 0x02870);
3772b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
3782b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2870, reg_2870);
3791a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3802b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_2890, 0x02890);
3812b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
3822b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2890, reg_2890);
3831a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3841a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Only update the filter if we really need to */
3852b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (h_filter != yi->h_filter) {
3862b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		ivtv_yuv_filter(itv, h_filter, -1, -1);
3872b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		yi->h_filter = h_filter;
3881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
3891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
3901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
3912b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrongstatic void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
3921a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
3932b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
3941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 master_height;
3951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2918, reg_291c, reg_2920, reg_2928;
3961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2930, reg_2934, reg_293c;
3971a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2940, reg_2944, reg_294c;
3981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2950, reg_2954, reg_2958, reg_295c;
3991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2960, reg_2964, reg_2968, reg_296c;
4001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_289c;
4012b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	u32 src_major_y, src_minor_y;
4022b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	u32 src_major_uv, src_minor_uv;
4031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 reg_2964_base, reg_2968_base;
4041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int v_filter_1, v_filter_2;
4051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_WARN
4072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
4082b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
4091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* What scaling mode is being used... */
4112b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
4122b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       f->interlaced_y ? "Interlaced" : "Progressive");
4131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4142b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
4152b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       f->interlaced_uv ? "Interlaced" : "Progressive");
4161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4171a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* What is the source video being treated as... */
4182b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_WARN("Source video: %s\n",
4192b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			f->interlaced ? "Interlaced" : "Progressive");
4201a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4211a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* We offset into the image using two different index methods, so split
4221a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   the y source coord into two parts. */
4232b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->src_y < 8) {
4242b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		src_minor_uv = f->src_y;
4252b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		src_major_uv = 0;
4262b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
4272b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		src_minor_uv = 8;
4282b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		src_major_uv = f->src_y - 8;
4291a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
4301a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	src_minor_y = src_minor_uv;
4322b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	src_major_y = src_major_uv;
4331a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4342b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->offset_y)
4352b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		src_minor_y += 16;
4361a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4372b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->interlaced_y)
4382b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
4391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
4402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
4411a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4422b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->interlaced_uv)
4432b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
4441a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
4452b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
4461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4472b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
4482b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
4491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
4502b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
4512b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_height = (f->src_h * 0x00400000) / f->dst_h;
4522b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
4532b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			master_height++;
4541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2920 = master_height >> 2;
4551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2928 = master_height >> 3;
4561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2930 = master_height;
4571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2940 = master_height >> 1;
4581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2964_base >>= 3;
4591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2968_base >>= 3;
4601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_296c = 0x00000000;
4612b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else if (f->dst_h >= f->src_h) {
4622b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_height = (f->src_h * 0x00400000) / f->dst_h;
4631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		master_height = (master_height >> 1) + (master_height & 1);
4641a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2920 = master_height >> 2;
4651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2928 = master_height >> 2;
4661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2930 = master_height;
4671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2940 = master_height >> 1;
4681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_296c = 0x00000000;
4692b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->interlaced_y) {
4701a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2964_base >>= 3;
4712b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		} else {
4722b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_296c++;
4731a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2964_base >>= 2;
4741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
4752b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->interlaced_uv)
4762b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_2928 >>= 1;
4771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2968_base >>= 3;
4782b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else if (f->dst_h >= f->src_h / 2) {
4792b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_height = (f->src_h * 0x00200000) / f->dst_h;
4801a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		master_height = (master_height >> 1) + (master_height & 1);
4811a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2920 = master_height >> 2;
4821a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2928 = master_height >> 2;
4831a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2930 = master_height;
4841a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2940 = master_height;
4851a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_296c = 0x00000101;
4862b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->interlaced_y) {
4871a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2964_base >>= 2;
4882b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		} else {
4892b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_296c++;
4901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			reg_2964_base >>= 1;
4911a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
4922b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (f->interlaced_uv)
4932b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			reg_2928 >>= 1;
4941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2968_base >>= 2;
4952b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
4962b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		master_height = (f->src_h * 0x00100000) / f->dst_h;
4971a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		master_height = (master_height >> 1) + (master_height & 1);
4981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2920 = master_height >> 2;
4991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2928 = master_height >> 2;
5001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2930 = master_height;
5011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2940 = master_height;
5021a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2964_base >>= 1;
5031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2968_base >>= 2;
5041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_296c = 0x00000102;
5051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
5061a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5071a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* FIXME These registers change depending on scaled / unscaled output
5081a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   We really need to work out what they should be */
5092b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->src_h == f->dst_h) {
5101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2934 = 0x00020000;
5111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_293c = 0x00100000;
5121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2944 = 0x00040000;
5131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_294c = 0x000b0000;
5142b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
5151a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2934 = 0x00000FF0;
5161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_293c = 0x00000FF0;
5171a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2944 = 0x00000FF0;
5181a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_294c = 0x00000FF0;
5191a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
5201a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5211a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* The first line to be displayed */
5222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2950 = 0x00010000 + src_major_y;
5232b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->interlaced_y)
5242b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2950 += 0x00010000;
5251a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2954 = reg_2950 + 1;
5261a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5272b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2958 = 0x00010000 + (src_major_y >> 1);
5282b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->interlaced_uv)
5292b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2958 += 0x00010000;
5301a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_295c = reg_2958 + 1;
5311a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5322b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (yi->decode_height == 480)
5331a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_289c = 0x011e0017;
5341a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
5351a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_289c = 0x01500017;
5361a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5372b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->dst_y < 0)
5382b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
5391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
5402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
5411a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5421a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* How much of the source to decode.
5431a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Take into account the source offset */
5442b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
5452b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
5461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Calculate correct value for register 2964 */
5482b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->src_h == f->dst_h) {
5491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2964 = 1;
5502b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
5512b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
5521a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
5531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
5541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
5551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
5561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Okay, we've wasted time working out the correct value,
5581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   but if we use it, it fouls the the window alignment.
5591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Fudge it to what we want... */
5601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
5611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
5621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Deviate further from what it should be. I find the flicker headache
5641a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
5651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   colours foul. */
5662b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
5672b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
5681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5692b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (!f->interlaced_y)
5702b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2964 -= 0x00010001;
5712b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (!f->interlaced_uv)
5722b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		reg_2968 -= 0x00010001;
5731a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
5751a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
5761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Select the vertical filter */
5782b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (f->src_h == f->dst_h) {
5791a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* An exact size match uses filter 0/1 */
5801a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_1 = 0;
5811a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_2 = 1;
5822b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
5831a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Figure out which filter to use */
5842b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
5851a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
5861a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Only an exact size match can use filter 0 */
5872b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		v_filter_1 += !v_filter_1;
5881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_2 = v_filter_1;
5891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
5901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
5911a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2934, 0x02934);
5921a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_293c, 0x0293c);
5932b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
5942b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
5951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2944, 0x02944);
5961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_294c, 0x0294c);
5972b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
5982b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
5991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Ensure 2970 is 0 (does it ever change ?) */
6011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil/*	write_reg(0,0x02970); */
6022b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
6031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2930, 0x02938);
6051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2930, 0x02930);
6062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
6072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
6081a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2928, 0x02928);
6102b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_2928 + 0x514, 0x0292C);
6112b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
6122b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
6131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2920, 0x02920);
6152b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_2920 + 0x514, 0x02924);
6162b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
6172b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
6181a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6192b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_2918, 0x02918);
6202b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_291c, 0x0291C);
6212b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
6222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
6231a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_296c, 0x0296c);
6252b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
6262b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_296c, reg_296c);
6271a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6281a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2940, 0x02948);
6291a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2940, 0x02940);
6302b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
6312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
6321a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6331a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2950, 0x02950);
6341a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2954, 0x02954);
6352b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
6362b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
6371a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2958, 0x02958);
6391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_295c, 0x0295C);
6402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
6412b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
6421a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6431a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2960, 0x02960);
6442b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
6452b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2960, reg_2960);
6461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2964, 0x02964);
6481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(reg_2968, 0x02968);
6492b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
6502b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
6511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6522b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(reg_289c, 0x0289c);
6532b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
6542b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		       yi->reg_289c, reg_289c);
6551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Only update filter 1 if we really need to */
6572b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (v_filter_1 != yi->v_filter_1) {
6582b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
6592b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		yi->v_filter_1 = v_filter_1;
6601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
6611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Only update filter 2 if we really need to */
6632b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (v_filter_2 != yi->v_filter_2) {
6642b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
6652b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		yi->v_filter_2 = v_filter_2;
6661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
6671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
6681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6691a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil/* Modify the supplied coordinate information to fit the visible osd area */
6703b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrongstatic u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
6711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
6723b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
6733b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	int osd_crop;
6741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 osd_scale;
6751a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 yuv_update = 0;
6761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Sorry, but no negative coords for src */
6783b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->src_x < 0)
6793b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_x = 0;
6803b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->src_y < 0)
6813b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_y = 0;
6821a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6831a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Can only reduce width down to 1/4 original size */
6843b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
6853b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_x += osd_crop / 2;
6863b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_w = (f->src_w - osd_crop) & ~3;
6873b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w = f->src_w / 4;
6883b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w += f->dst_w & 1;
6891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
6901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
6911a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Can only reduce height down to 1/4 original size */
6923b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->src_h / f->dst_h >= 2) {
6933b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		/* Overflow may be because we're running progressive,
6943b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		   so force mode switch */
6953b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->interlaced_y = 1;
6961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Make sure we're still within limits for interlace */
6973b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
6981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			/* If we reach here we'll have to force the height. */
6993b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			f->src_y += osd_crop / 2;
7003b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			f->src_h = (f->src_h - osd_crop) & ~3;
7013b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			f->dst_h = f->src_h / 4;
7023b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			f->dst_h += f->dst_h & 1;
7031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		}
7041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7061a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* If there's nothing to safe to display, we may as well stop now */
7073b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
7082b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
7090bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		return IVTV_YUV_UPDATE_INVALID;
7101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Ensure video remains inside OSD area */
7133b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	osd_scale = (f->src_h << 16) / f->dst_h;
7141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7153b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
7161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Falls off the upper edge - crop */
7173b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_y += (osd_scale * osd_crop) >> 16;
7183b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_h -= (osd_scale * osd_crop) >> 16;
7193b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_h -= osd_crop;
7203b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_y = 0;
7213b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	} else {
7223b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_y -= f->pan_y;
7231a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7253b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
7261a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Falls off the lower edge - crop */
7273b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_h -= osd_crop;
7283b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_h -= (osd_scale * osd_crop) >> 16;
7291a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7301a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7313b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	osd_scale = (f->src_w << 16) / f->dst_w;
7321a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7333b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
7341a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Fall off the left edge - crop */
7353b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_x += (osd_scale * osd_crop) >> 16;
7363b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_w -= (osd_scale * osd_crop) >> 16;
7373b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w -= osd_crop;
7383b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_x = 0;
7393b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	} else {
7403b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_x -= f->pan_x;
7411a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7421a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7433b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
7441a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Falls off the right edge - crop */
7453b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w -= osd_crop;
7463b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_w -= (osd_scale * osd_crop) >> 16;
7471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
74988ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong	if (itv->yuv_info.track_osd) {
75088ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		/* The OSD can be moved. Track to it */
75188ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f->dst_x += itv->yuv_info.osd_x_offset;
75288ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f->dst_y += itv->yuv_info.osd_y_offset;
75388ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong	}
7541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Width & height for both src & dst must be even.
7561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Same for coordinates. */
7573b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_w &= ~1;
7583b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_x &= ~1;
7591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7603b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_w += f->src_x & 1;
7613b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_x &= ~1;
7621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7633b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_w &= ~1;
7643b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_w &= ~1;
7651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7663b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_h &= ~1;
7673b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_y &= ~1;
7681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7693b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_h += f->src_y & 1;
7703b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_y &= ~1;
7711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7723b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->src_h &= ~1;
7733b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f->dst_h &= ~1;
7741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7753b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	/* Due to rounding, we may have reduced the output size to <1/4 of
7763b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	   the source. Check again, but this time just resize. Don't change
7773b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	   source coordinates */
7783b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->dst_w < f->src_w / 4) {
7793b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_w &= ~3;
7803b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w = f->src_w / 4;
7813b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_w += f->dst_w & 1;
7821a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7833b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (f->dst_h < f->src_h / 4) {
7843b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->src_h &= ~3;
7853b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_h = f->src_h / 4;
7863b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		f->dst_h += f->dst_h & 1;
7871a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Check again. If there's nothing to safe to display, stop now */
7903b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
7912b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
7920bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		return IVTV_YUV_UPDATE_INVALID;
7931a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
7941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
7951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Both x offset & width are linked, so they have to be done together */
7963b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
7972b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
7982b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
7991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
8001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
8011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8023b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
8032b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
8042b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
8052b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->lace_mode != f->lace_mode) ||
8062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->interlaced_y != f->interlaced_y) ||
8072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	    (of->interlaced_uv != f->interlaced_uv)) {
8081a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
8091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
8101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	return yuv_update;
8121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
8131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil/* Update the scaling register to the requested value */
8152b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrongvoid ivtv_yuv_work_handler(struct ivtv *itv)
8161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
8173b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
8183b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_frame_info f;
8193b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	int frame = yi->update_frame;
8201a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	u32 yuv_update;
8211a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
8233b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	f = yi->new_frame_info[frame];
8241a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
82588ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong	if (yi->track_osd) {
82688ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		/* Snapshot the osd pan info */
82788ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.pan_x = yi->osd_x_pan;
82888ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.pan_y = yi->osd_y_pan;
82988ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.vis_w = yi->osd_vis_w;
83088ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.vis_h = yi->osd_vis_h;
83188ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong	} else {
83288ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		/* Not tracking the osd, so assume full screen */
83388ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.pan_x = 0;
83488ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.pan_y = 0;
83588ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.vis_w = 720;
83688ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong		f.vis_h = yi->decode_height;
83788ab075aee974f70b7b0273a964810698c8a5b95Ian Armstrong	}
8381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8391a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Calculate the display window coordinates. Exit if nothing left */
8402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
8411a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		return;
8421a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8430bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
8440bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		write_reg(0x01008080, 0x2898);
8450bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong	} else if (yuv_update) {
8460bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		write_reg(0x00108080, 0x2898);
8471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8480bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
8493b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			ivtv_yuv_handle_horizontal(itv, &f);
8500bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong
8510bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
8523b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			ivtv_yuv_handle_vertical(itv, &f);
8530bfeb04a9f3ad9ad8c9bbba062231ff1a76e4465Ian Armstrong	}
8543b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	yi->old_frame_info = f;
8551a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
8561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8572b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrongstatic void ivtv_yuv_init(struct ivtv *itv)
8581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
859195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
860195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong
8611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	IVTV_DEBUG_YUV("ivtv_yuv_init\n");
8621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
8631a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Take a snapshot of the current register settings */
864195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2834 = read_reg(0x02834);
865195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2838 = read_reg(0x02838);
866195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_283c = read_reg(0x0283c);
867195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2840 = read_reg(0x02840);
868195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2844 = read_reg(0x02844);
869195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2848 = read_reg(0x02848);
870195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2854 = read_reg(0x02854);
871195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_285c = read_reg(0x0285c);
872195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2864 = read_reg(0x02864);
873195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2870 = read_reg(0x02870);
874195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2874 = read_reg(0x02874);
875195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2898 = read_reg(0x02898);
876195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2890 = read_reg(0x02890);
877195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong
878195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_289c = read_reg(0x0289c);
879195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2918 = read_reg(0x02918);
880195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_291c = read_reg(0x0291c);
881195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2920 = read_reg(0x02920);
882195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2924 = read_reg(0x02924);
883195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2928 = read_reg(0x02928);
884195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_292c = read_reg(0x0292c);
885195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2930 = read_reg(0x02930);
886195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2934 = read_reg(0x02934);
887195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2938 = read_reg(0x02938);
888195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_293c = read_reg(0x0293c);
889195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2940 = read_reg(0x02940);
890195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2944 = read_reg(0x02944);
891195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2948 = read_reg(0x02948);
892195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_294c = read_reg(0x0294c);
893195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2950 = read_reg(0x02950);
894195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2954 = read_reg(0x02954);
895195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2958 = read_reg(0x02958);
896195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_295c = read_reg(0x0295c);
897195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2960 = read_reg(0x02960);
898195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2964 = read_reg(0x02964);
899195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2968 = read_reg(0x02968);
900195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_296c = read_reg(0x0296c);
901195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->reg_2970 = read_reg(0x02970);
902195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong
903195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->v_filter_1 = -1;
904195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->v_filter_2 = -1;
905195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->h_filter = -1;
9061a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9071a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Set some valid size info */
908195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
909195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
9101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Bit 2 of reg 2878 indicates current decoder output format
9121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   0 : NTSC    1 : PAL */
9131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (read_reg(0x2878) & 4)
914195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		yi->decode_height = 576;
9151a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	else
916195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		yi->decode_height = 480;
917b4b38bd63c07c8927b43c6c378eca1db10fdaf2eIan Armstrong
918195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	if (!itv->osd_info) {
919195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		yi->osd_vis_w = 720 - yi->osd_x_offset;
920195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
921b4b38bd63c07c8927b43c6c378eca1db10fdaf2eIan Armstrong	} else {
922195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		/* If no visible size set, assume full size */
923195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		if (!yi->osd_vis_w)
924195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong			yi->osd_vis_w = 720 - yi->osd_x_offset;
925195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong
9262b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		if (!yi->osd_vis_h) {
927195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
9282b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
929195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong			/* If output video standard has changed, requested height may
9302b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			   not be legal */
9312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
9322b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong					yi->osd_vis_h + yi->osd_y_offset,
9332b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong					yi->decode_height);
9342b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
935b4b38bd63c07c8927b43c6c378eca1db10fdaf2eIan Armstrong		}
936b4b38bd63c07c8927b43c6c378eca1db10fdaf2eIan Armstrong	}
9371a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9381a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
9393f98387efa9333c5765d36e144c47c107d6ba64aHans Verkuil	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);
9402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (yi->blanking_ptr) {
9418ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil		yi->blanking_dmaptr = pci_map_single(itv->pdev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
9422b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
943195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		yi->blanking_dmaptr = 0;
944195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
9451a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
9461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9471a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Enable YUV decoder output */
9481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg_sync(0x01, IVTV_REG_VDM);
9491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9501a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
951195b1252517d504391d29f71b789d4c1c9f605e0Ian Armstrong	atomic_set(&yi->next_dma_frame, 0);
9521a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
9531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
954a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong/* Get next available yuv buffer on PVR350 */
9555eedc466758b5743512d38b5d1eab6f799a39e00Adrian Bunkstatic void ivtv_yuv_next_free(struct ivtv *itv)
9561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
957a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	int draw, display;
958a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
9591a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
960a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	if (atomic_read(&yi->next_dma_frame) == -1)
961a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong		ivtv_yuv_init(itv);
9621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
963a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	draw = atomic_read(&yi->next_fill_frame);
964a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	display = atomic_read(&yi->next_dma_frame);
9651a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
966a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	if (display > draw)
967a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong		display -= IVTV_YUV_BUFFERS;
9681a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
969a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	if (draw - display >= yi->max_frames_buffered)
970a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
971a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	else
972a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong		yi->new_frame_info[draw].update = 0;
973a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong
974a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	yi->draw_frame = draw;
975a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong}
976a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong
977a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong/* Set up frame according to ivtv_dma_frame parameters */
9785eedc466758b5743512d38b5d1eab6f799a39e00Adrian Bunkstatic void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
979a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong{
980a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
981a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	u8 frame = yi->draw_frame;
9823b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
9833b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
9843b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
9853b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	int lace_threshold = yi->lace_threshold;
986a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong
987a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	/* Preserve old update flag in case we're overwriting a queued frame */
9883b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	int update = nf->update;
9891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
9901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Take a snapshot of the yuv coordinate information */
9913b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->src_x = args->src.left;
9923b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->src_y = args->src.top;
9933b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->src_w = args->src.width;
9943b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->src_h = args->src.height;
9953b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->dst_x = args->dst.left;
9963b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->dst_y = args->dst.top;
9973b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->dst_w = args->dst.width;
9983b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->dst_h = args->dst.height;
9993b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->tru_x = args->dst.left;
10003b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->tru_w = args->src_width;
10013b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->tru_h = args->src_height;
1002bfd7beacff2b5c811badb587a74c3dfbf7f98721Ian Armstrong
10031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Are we going to offset the Y plane */
10043b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
10051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
10063b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->update = 0;
10073b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->interlaced_y = 0;
10083b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->interlaced_uv = 0;
10093b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->delay = 0;
10103b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->sync_field = 0;
10113b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
10123b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong
10133b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (lace_threshold < 0)
10143b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		lace_threshold = yi->decode_height - 1;
10153b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong
10163b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	/* Work out the lace settings */
10173b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	switch (nf->lace_mode) {
10183b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
10193b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		nf->interlaced = 0;
10203b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
10213b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_y = 0;
10223b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		else
10233b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_y = 1;
10243b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong
10253b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
10263b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_uv = 0;
10273b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		else
10283b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_uv = 1;
10293b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		break;
10303b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong
10313b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	case IVTV_YUV_MODE_AUTO:
10323b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
10333b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced = 0;
10343b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			if ((nf->tru_h < 512) ||
10352b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
10362b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong			    (nf->tru_w > 720 && nf->tru_h < 1021))
10373b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong				nf->interlaced_y = 0;
10383b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			else
10393b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong				nf->interlaced_y = 1;
10403b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
10413b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong				nf->interlaced_uv = 0;
10423b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			else
10433b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong				nf->interlaced_uv = 1;
10443b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		} else {
10453b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced = 1;
10463b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_y = 1;
10473b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong			nf->interlaced_uv = 1;
10483b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		}
10493b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		break;
10503b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong
10513b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
10523b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	default:
10533b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		nf->interlaced = 1;
10543b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		nf->interlaced_y = 1;
10553b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		nf->interlaced_uv = 1;
10563b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		break;
10571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
10581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
10593b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
10603b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		yi->old_frame_info_args = *nf;
10613b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong		nf->update = 1;
10622b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
10633b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	}
1064943e8910db31e36d945f2bf7d4c273ca5fa01f6eIan Armstrong
10653b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->update |= update;
10663b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->sync_field = yi->lace_sync_field;
10673b5c1c8e71eb8fe2297a5884db59108e3c8b44c5Ian Armstrong	nf->delay = nf->sync_field != of->sync_field;
1068a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong}
1069a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong
1070a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong/* Frame is complete & ready for display */
1071a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrongvoid ivtv_yuv_frame_complete(struct ivtv *itv)
1072a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong{
1073a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	atomic_set(&itv->yuv_info.next_fill_frame,
1074a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1075a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong}
1076a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong
10775eedc466758b5743512d38b5d1eab6f799a39e00Adrian Bunkstatic int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1078a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong{
1079a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	DEFINE_WAIT(wait);
1080a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	int rc = 0;
1081a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	int got_sig = 0;
10821a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* DMA the frame */
10831a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	mutex_lock(&itv->udma.lock);
10841a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
10851a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
10861a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		mutex_unlock(&itv->udma.lock);
10871a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		return rc;
10881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
10891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
10901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_udma_prepare(itv);
10911a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
10921a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* if no UDMA is pending and no UDMA is in progress, then the DMA
10932b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	   is finished */
1094ec105a42ac397366e05888ea96503ab3b57f79adHans Verkuil	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
1095ec105a42ac397366e05888ea96503ab3b57f79adHans Verkuil	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
10961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* don't interrupt if the DMA is in progress but break off
10972b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		   a still pending DMA. */
10981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		got_sig = signal_pending(current);
10991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
11001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil			break;
11011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		got_sig = 0;
11021a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		schedule();
11031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
11041a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	finish_wait(&itv->dma_waitq, &wait);
11051a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11061a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Unmap Last DMA Xfer */
11071a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_udma_unmap(itv);
11081a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11091a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	if (got_sig) {
11101a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
11111a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		mutex_unlock(&itv->udma.lock);
11121a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		return -EINTR;
11131a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
11141a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
1115a3e5f5e2dfb50bebca24329e5377d804c6e3eb1bIan Armstrong	ivtv_yuv_frame_complete(itv);
11161a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11171a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	mutex_unlock(&itv->udma.lock);
11181a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	return rc;
11191a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
11201a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
112177aded6ba51f01335840ce8e18b413067810b68eIan Armstrong/* Setup frame according to V4L2 parameters */
112277aded6ba51f01335840ce8e18b413067810b68eIan Armstrongvoid ivtv_yuv_setup_stream_frame(struct ivtv *itv)
112377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong{
112477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
112577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	struct ivtv_dma_frame dma_args;
112677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
112777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	ivtv_yuv_next_free(itv);
112877aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
112977aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
1130a6a3a17b7fdaf824e6d73e8e4a94c9d149302f74Harvey Harrison	dma_args.y_source = NULL;
1131a6a3a17b7fdaf824e6d73e8e4a94c9d149302f74Harvey Harrison	dma_args.uv_source = NULL;
113277aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src.left = 0;
113377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src.top = 0;
113477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src.width = yi->v4l2_src_w;
113577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src.height = yi->v4l2_src_h;
113677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.dst = yi->main_rect;
113777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src_width = yi->v4l2_src_w;
113877aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.src_height = yi->v4l2_src_h;
113977aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
114077aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
114177aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	ivtv_yuv_setup_frame(itv, &dma_args);
114277aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
114377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	if (!itv->dma_data_req_offset)
114477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
114577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong}
114677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
114777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong/* Attempt to dma a frame from a user buffer */
1148b0510f8dc73dce56f35337487c6374ae84b15446Al Viroint ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
114977aded6ba51f01335840ce8e18b413067810b68eIan Armstrong{
115077aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
115177aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	struct ivtv_dma_frame dma_args;
1152cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	int res;
115377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
115477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	ivtv_yuv_setup_stream_frame(itv);
115577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
115677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	/* We only need to supply source addresses for this */
115777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.y_source = src;
115877aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
1159cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	/* Wait for frame DMA. Note that serialize_lock is locked,
1160cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	   so to allow other processes to access the driver while
1161cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	   we are waiting unlock first and later lock again. */
1162cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_unlock(&itv->serialize_lock);
1163cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	res = ivtv_yuv_udma_frame(itv, &dma_args);
1164cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_lock(&itv->serialize_lock);
1165cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	return res;
116677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong}
116777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
116877aded6ba51f01335840ce8e18b413067810b68eIan Armstrong/* IVTV_IOC_DMA_FRAME ioctl handler */
116977aded6ba51f01335840ce8e18b413067810b68eIan Armstrongint ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
117077aded6ba51f01335840ce8e18b413067810b68eIan Armstrong{
1171cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	int res;
117277aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
1173cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
117477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	ivtv_yuv_next_free(itv);
117577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	ivtv_yuv_setup_frame(itv, args);
1176cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	/* Wait for frame DMA. Note that serialize_lock is locked,
1177cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	   so to allow other processes to access the driver while
1178cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	   we are waiting unlock first and later lock again. */
1179cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_unlock(&itv->serialize_lock);
1180cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	res = ivtv_yuv_udma_frame(itv, args);
1181cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_lock(&itv->serialize_lock);
1182cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	return res;
118377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong}
118477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
11851a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuilvoid ivtv_yuv_close(struct ivtv *itv)
11861a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil{
11872b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	struct yuv_playback_info *yi = &itv->yuv_info;
11881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	int h_filter, v_filter_1, v_filter_2;
11891a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11901a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1191cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_unlock(&itv->serialize_lock);
11921a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	ivtv_waitq(&itv->vsync_waitq);
1193cdc037817cc15caf931cd3476970860d62f1985cHans Verkuil	mutex_lock(&itv->serialize_lock);
11941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11952bd7ac55c31cb4f42e331d69dde9fc034a68944fIan Armstrong	yi->running = 0;
11962b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	atomic_set(&yi->next_dma_frame, -1);
11972b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	atomic_set(&yi->next_fill_frame, 0);
11981a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
11991a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Reset registers we have changed so mpeg playback works */
12001a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12011a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* If we fully restore this register, the display may remain active.
12021a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   Restore, but set one bit to blank the video. Firmware will always
12031a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	   clear this bit when needed, so not a problem. */
12042b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2898 | 0x01000000, 0x2898);
12052b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong
12062b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2834, 0x02834);
12072b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2838, 0x02838);
12082b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_283c, 0x0283c);
12092b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2840, 0x02840);
12102b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2844, 0x02844);
12112b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2848, 0x02848);
12122b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2854, 0x02854);
12132b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_285c, 0x0285c);
12142b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2864, 0x02864);
12152b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2870, 0x02870);
12162b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2874, 0x02874);
12172b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2890, 0x02890);
12182b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_289c, 0x0289c);
12192b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong
12202b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2918, 0x02918);
12212b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_291c, 0x0291c);
12222b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2920, 0x02920);
12232b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2924, 0x02924);
12242b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2928, 0x02928);
12252b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_292c, 0x0292c);
12262b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2930, 0x02930);
12272b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2934, 0x02934);
12282b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2938, 0x02938);
12292b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_293c, 0x0293c);
12302b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2940, 0x02940);
12312b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2944, 0x02944);
12322b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2948, 0x02948);
12332b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_294c, 0x0294c);
12342b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2950, 0x02950);
12352b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2954, 0x02954);
12362b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2958, 0x02958);
12372b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_295c, 0x0295c);
12382b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2960, 0x02960);
12392b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2964, 0x02964);
12402b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2968, 0x02968);
12412b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_296c, 0x0296c);
12422b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	write_reg(yi->reg_2970, 0x02970);
12431a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12441a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Prepare to restore filters */
12451a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12461a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* First the horizontal filter */
12472b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
12481a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* An exact size match uses filter 0 */
12491a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		h_filter = 0;
12502b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
12511a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Figure out which filter to use */
12522b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
12531a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		h_filter = (h_filter >> 1) + (h_filter & 1);
12541a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Only an exact size match can use filter 0. */
12552b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		h_filter += !h_filter;
12561a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
12571a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12581a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Now the vertical filter */
12592b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
12601a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* An exact size match uses filter 0/1 */
12611a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_1 = 0;
12621a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_2 = 1;
12632b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	} else {
12641a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Figure out which filter to use */
12652b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
12661a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
12671a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		/* Only an exact size match can use filter 0 */
12682b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		v_filter_1 += !v_filter_1;
12691a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil		v_filter_2 = v_filter_1;
12701a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
12711a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12721a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Now restore the filters */
12732b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
12741a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12751a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* and clear a few registers */
12761a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0, 0x02814);
12771a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0, 0x0282c);
12781a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0, 0x02904);
12791a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	write_reg(0, 0x02910);
12801a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12811a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Release the blanking buffer */
12822b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	if (yi->blanking_ptr) {
12832b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		kfree(yi->blanking_ptr);
12842b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong		yi->blanking_ptr = NULL;
12858ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil		pci_unmap_single(itv->pdev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
12861a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	}
12871a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12881a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* Invalidate the old dimension information */
12892b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	yi->old_frame_info.src_w = 0;
12902b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	yi->old_frame_info.src_h = 0;
12912b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	yi->old_frame_info_args.src_w = 0;
12922b057e8dc6cc8318956fef92b77a4e86985e84d9Ian Armstrong	yi->old_frame_info_args.src_h = 0;
12931a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil
12941a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	/* All done. */
12951a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
12961a0adaf37c30e89e44d1470ef604a930999a5826Hans Verkuil}
1297