brintos

brintos / linux-shallow public Read only

0
0
Text · 37.4 KiB · 2d92745 Raw
1288 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3    yuv support4 5    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>6 7 */8 9#include "ivtv-driver.h"10#include "ivtv-udma.h"11#include "ivtv-yuv.h"12 13/* YUV buffer offsets */14const u32 yuv_offset[IVTV_YUV_BUFFERS] = {15	0x001a8600,16	0x00240400,17	0x002d8200,18	0x00370000,19	0x00029000,20	0x000C0E00,21	0x006B0400,22	0x0074820023};24 25static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,26				  struct ivtv_dma_frame *args)27{28	struct ivtv_dma_page_info y_dma;29	struct ivtv_dma_page_info uv_dma;30	struct yuv_playback_info *yi = &itv->yuv_info;31	u8 frame = yi->draw_frame;32	struct yuv_frame_info *f = &yi->new_frame_info[frame];33	int y_pages, uv_pages;34	unsigned long y_buffer_offset, uv_buffer_offset;35	int y_decode_height, uv_decode_height, y_size;36 37	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];38	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;39 40	y_decode_height = uv_decode_height = f->src_h + f->src_y;41 42	if (f->offset_y)43		y_buffer_offset += 720 * 16;44 45	if (y_decode_height & 15)46		y_decode_height = (y_decode_height + 16) & ~15;47 48	if (uv_decode_height & 31)49		uv_decode_height = (uv_decode_height + 32) & ~31;50 51	y_size = 720 * y_decode_height;52 53	/* Still in USE */54	if (dma->SG_length || dma->page_count) {55		IVTV_DEBUG_WARN56		    ("prep_user_dma: SG_length %d page_count %d still full?\n",57		     dma->SG_length, dma->page_count);58		return -EBUSY;59	}60 61	ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);62	ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);63 64	/* Pin user pages for DMA Xfer */65	y_pages = pin_user_pages_unlocked(y_dma.uaddr,66			y_dma.page_count, &dma->map[0], 0);67	uv_pages = 0; /* silence gcc. value is set and consumed only if: */68	if (y_pages == y_dma.page_count) {69		uv_pages = pin_user_pages_unlocked(uv_dma.uaddr,70				uv_dma.page_count, &dma->map[y_pages], 0);71	}72 73	if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) {74		int rc = -EFAULT;75 76		if (y_pages == y_dma.page_count) {77			IVTV_DEBUG_WARN78				("failed to map uv user pages, returned %d expecting %d\n",79				 uv_pages, uv_dma.page_count);80 81			if (uv_pages >= 0) {82				unpin_user_pages(&dma->map[y_pages], uv_pages);83				rc = -EFAULT;84			} else {85				rc = uv_pages;86			}87		} else {88			IVTV_DEBUG_WARN89				("failed to map y user pages, returned %d expecting %d\n",90				 y_pages, y_dma.page_count);91		}92		if (y_pages >= 0) {93			unpin_user_pages(dma->map, y_pages);94			/*95			 * Inherit the -EFAULT from rc's96			 * initialization, but allow it to be97			 * overridden by uv_pages above if it was an98			 * actual errno.99			 */100		} else {101			rc = y_pages;102		}103		return rc;104	}105 106	dma->page_count = y_pages + uv_pages;107 108	/* Fill & map SG List */109	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {110		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");111		unpin_user_pages(dma->map, dma->page_count);112		dma->page_count = 0;113		return -ENOMEM;114	}115	dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,116				    dma->page_count, DMA_TO_DEVICE);117	if (!dma->SG_length) {118		IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);119		unpin_user_pages(dma->map, dma->page_count);120		dma->page_count = 0;121		return -EINVAL;122	}123 124	/* Fill SG Array with new values */125	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);126 127	/* If we've offset the y plane, ensure top area is blanked */128	if (f->offset_y && yi->blanking_dmaptr) {129		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);130		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);131		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);132		dma->SG_length++;133	}134 135	/* Tag SG Array with Interrupt Bit */136	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);137 138	ivtv_udma_sync_for_device(itv);139	return 0;140}141 142/* We rely on a table held in the firmware - Quick check. */143int ivtv_yuv_filter_check(struct ivtv *itv)144{145	int i, y, uv;146 147	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {148		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||149		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {150			IVTV_WARN ("YUV filter table not found in firmware.\n");151			return -1;152		}153	}154	return 0;155}156 157static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)158{159	u32 i, line;160 161	/* If any filter is -1, then don't update it */162	if (h_filter > -1) {163		if (h_filter > 4)164			h_filter = 4;165		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);166		for (line = 0; line < 16; line++) {167			write_reg(read_dec(i), 0x02804);168			write_reg(read_dec(i), 0x0281c);169			i += 4;170			write_reg(read_dec(i), 0x02808);171			write_reg(read_dec(i), 0x02820);172			i += 4;173			write_reg(read_dec(i), 0x0280c);174			write_reg(read_dec(i), 0x02824);175			i += 4;176			write_reg(read_dec(i), 0x02810);177			write_reg(read_dec(i), 0x02828);178			i += 4;179			write_reg(read_dec(i), 0x02814);180			write_reg(read_dec(i), 0x0282c);181			i += 8;182			write_reg(0, 0x02818);183			write_reg(0, 0x02830);184		}185		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);186	}187 188	if (v_filter_1 > -1) {189		if (v_filter_1 > 4)190			v_filter_1 = 4;191		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);192		for (line = 0; line < 16; line++) {193			write_reg(read_dec(i), 0x02900);194			i += 4;195			write_reg(read_dec(i), 0x02904);196			i += 8;197			write_reg(0, 0x02908);198		}199		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);200	}201 202	if (v_filter_2 > -1) {203		if (v_filter_2 > 4)204			v_filter_2 = 4;205		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);206		for (line = 0; line < 16; line++) {207			write_reg(read_dec(i), 0x0290c);208			i += 4;209			write_reg(read_dec(i), 0x02910);210			i += 8;211			write_reg(0, 0x02914);212		}213		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);214	}215}216 217static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)218{219	struct yuv_playback_info *yi = &itv->yuv_info;220	u32 reg_2834, reg_2838, reg_283c;221	u32 reg_2844, reg_2854, reg_285c;222	u32 reg_2864, reg_2874, reg_2890;223	u32 reg_2870, reg_2870_base, reg_2870_offset;224	int x_cutoff;225	int h_filter;226	u32 master_width;227 228	IVTV_DEBUG_WARN229	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",230	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);231 232	/* How wide is the src image */233	x_cutoff = f->src_w + f->src_x;234 235	/* Set the display width */236	reg_2834 = f->dst_w;237	reg_2838 = reg_2834;238 239	/* Set the display position */240	reg_2890 = f->dst_x;241 242	/* Index into the image horizontally */243	reg_2870 = 0;244 245	/* 2870 is normally fudged to align video coords with osd coords.246	   If running full screen, it causes an unwanted left shift247	   Remove the fudge if we almost fill the screen.248	   Gradually adjust the offset to avoid the video 'snapping'249	   left/right if it gets dragged through this region.250	   Only do this if osd is full width. */251	if (f->vis_w == 720) {252		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))253			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;254		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))255			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);256 257		if (f->dst_w >= f->src_w)258			reg_2870 = reg_2870 << 16 | reg_2870;259		else260			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);261	}262 263	if (f->dst_w < f->src_w)264		reg_2870 = 0x000d000e - reg_2870;265	else266		reg_2870 = 0x0012000e - reg_2870;267 268	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */269	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;270 271	if (f->dst_w >= f->src_w) {272		x_cutoff &= ~1;273		master_width = (f->src_w * 0x00200000) / (f->dst_w);274		if (master_width * f->dst_w != f->src_w * 0x00200000)275			master_width++;276		reg_2834 = (reg_2834 << 16) | x_cutoff;277		reg_2838 = (reg_2838 << 16) | x_cutoff;278		reg_283c = master_width >> 2;279		reg_2844 = master_width >> 2;280		reg_2854 = master_width;281		reg_285c = master_width >> 1;282		reg_2864 = master_width >> 1;283 284		/* We also need to factor in the scaling285		   (src_w - dst_w) / (src_w / 4) */286		if (f->dst_w > f->src_w)287			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);288		else289			reg_2870_base = 0;290 291		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);292		reg_2874 = 0;293	} else if (f->dst_w < f->src_w / 2) {294		master_width = (f->src_w * 0x00080000) / f->dst_w;295		if (master_width * f->dst_w != f->src_w * 0x00080000)296			master_width++;297		reg_2834 = (reg_2834 << 16) | x_cutoff;298		reg_2838 = (reg_2838 << 16) | x_cutoff;299		reg_283c = master_width >> 2;300		reg_2844 = master_width >> 1;301		reg_2854 = master_width;302		reg_285c = master_width >> 1;303		reg_2864 = master_width >> 1;304		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;305		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;306		reg_2874 = 0x00000012;307	} else {308		master_width = (f->src_w * 0x00100000) / f->dst_w;309		if (master_width * f->dst_w != f->src_w * 0x00100000)310			master_width++;311		reg_2834 = (reg_2834 << 16) | x_cutoff;312		reg_2838 = (reg_2838 << 16) | x_cutoff;313		reg_283c = master_width >> 2;314		reg_2844 = master_width >> 1;315		reg_2854 = master_width;316		reg_285c = master_width >> 1;317		reg_2864 = master_width >> 1;318		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;319		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;320		reg_2874 = 0x00000001;321	}322 323	/* Select the horizontal filter */324	if (f->src_w == f->dst_w) {325		/* An exact size match uses filter 0 */326		h_filter = 0;327	} else {328		/* Figure out which filter to use */329		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;330		h_filter = (h_filter >> 1) + (h_filter & 1);331		/* Only an exact size match can use filter 0 */332		h_filter += !h_filter;333	}334 335	write_reg(reg_2834, 0x02834);336	write_reg(reg_2838, 0x02838);337	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",338		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);339 340	write_reg(reg_283c, 0x0283c);341	write_reg(reg_2844, 0x02844);342 343	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",344		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);345 346	write_reg(0x00080514, 0x02840);347	write_reg(0x00100514, 0x02848);348	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",349		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);350 351	write_reg(reg_2854, 0x02854);352	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",353		       yi->reg_2854, reg_2854);354 355	write_reg(reg_285c, 0x0285c);356	write_reg(reg_2864, 0x02864);357	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",358		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);359 360	write_reg(reg_2874, 0x02874);361	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",362		       yi->reg_2874, reg_2874);363 364	write_reg(reg_2870, 0x02870);365	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",366		       yi->reg_2870, reg_2870);367 368	write_reg(reg_2890, 0x02890);369	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",370		       yi->reg_2890, reg_2890);371 372	/* Only update the filter if we really need to */373	if (h_filter != yi->h_filter) {374		ivtv_yuv_filter(itv, h_filter, -1, -1);375		yi->h_filter = h_filter;376	}377}378 379static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)380{381	struct yuv_playback_info *yi = &itv->yuv_info;382	u32 master_height;383	u32 reg_2918, reg_291c, reg_2920, reg_2928;384	u32 reg_2930, reg_2934, reg_293c;385	u32 reg_2940, reg_2944, reg_294c;386	u32 reg_2950, reg_2954, reg_2958, reg_295c;387	u32 reg_2960, reg_2964, reg_2968, reg_296c;388	u32 reg_289c;389	u32 src_major_y, src_minor_y;390	u32 src_major_uv, src_minor_uv;391	u32 reg_2964_base, reg_2968_base;392	int v_filter_1, v_filter_2;393 394	IVTV_DEBUG_WARN395	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",396	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);397 398	/* What scaling mode is being used... */399	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",400		       f->interlaced_y ? "Interlaced" : "Progressive");401 402	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",403		       f->interlaced_uv ? "Interlaced" : "Progressive");404 405	/* What is the source video being treated as... */406	IVTV_DEBUG_WARN("Source video: %s\n",407			f->interlaced ? "Interlaced" : "Progressive");408 409	/* We offset into the image using two different index methods, so split410	   the y source coord into two parts. */411	if (f->src_y < 8) {412		src_minor_uv = f->src_y;413		src_major_uv = 0;414	} else {415		src_minor_uv = 8;416		src_major_uv = f->src_y - 8;417	}418 419	src_minor_y = src_minor_uv;420	src_major_y = src_major_uv;421 422	if (f->offset_y)423		src_minor_y += 16;424 425	if (f->interlaced_y)426		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);427	else428		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);429 430	if (f->interlaced_uv)431		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);432	else433		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);434 435	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;436	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;437 438	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {439		master_height = (f->src_h * 0x00400000) / f->dst_h;440		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)441			master_height++;442		reg_2920 = master_height >> 2;443		reg_2928 = master_height >> 3;444		reg_2930 = master_height;445		reg_2940 = master_height >> 1;446		reg_2964_base >>= 3;447		reg_2968_base >>= 3;448		reg_296c = 0x00000000;449	} else if (f->dst_h >= f->src_h) {450		master_height = (f->src_h * 0x00400000) / f->dst_h;451		master_height = (master_height >> 1) + (master_height & 1);452		reg_2920 = master_height >> 2;453		reg_2928 = master_height >> 2;454		reg_2930 = master_height;455		reg_2940 = master_height >> 1;456		reg_296c = 0x00000000;457		if (f->interlaced_y) {458			reg_2964_base >>= 3;459		} else {460			reg_296c++;461			reg_2964_base >>= 2;462		}463		if (f->interlaced_uv)464			reg_2928 >>= 1;465		reg_2968_base >>= 3;466	} else if (f->dst_h >= f->src_h / 2) {467		master_height = (f->src_h * 0x00200000) / f->dst_h;468		master_height = (master_height >> 1) + (master_height & 1);469		reg_2920 = master_height >> 2;470		reg_2928 = master_height >> 2;471		reg_2930 = master_height;472		reg_2940 = master_height;473		reg_296c = 0x00000101;474		if (f->interlaced_y) {475			reg_2964_base >>= 2;476		} else {477			reg_296c++;478			reg_2964_base >>= 1;479		}480		if (f->interlaced_uv)481			reg_2928 >>= 1;482		reg_2968_base >>= 2;483	} else {484		master_height = (f->src_h * 0x00100000) / f->dst_h;485		master_height = (master_height >> 1) + (master_height & 1);486		reg_2920 = master_height >> 2;487		reg_2928 = master_height >> 2;488		reg_2930 = master_height;489		reg_2940 = master_height;490		reg_2964_base >>= 1;491		reg_2968_base >>= 2;492		reg_296c = 0x00000102;493	}494 495	/* FIXME These registers change depending on scaled / unscaled output496	   We really need to work out what they should be */497	if (f->src_h == f->dst_h) {498		reg_2934 = 0x00020000;499		reg_293c = 0x00100000;500		reg_2944 = 0x00040000;501		reg_294c = 0x000b0000;502	} else {503		reg_2934 = 0x00000FF0;504		reg_293c = 0x00000FF0;505		reg_2944 = 0x00000FF0;506		reg_294c = 0x00000FF0;507	}508 509	/* The first line to be displayed */510	reg_2950 = 0x00010000 + src_major_y;511	if (f->interlaced_y)512		reg_2950 += 0x00010000;513	reg_2954 = reg_2950 + 1;514 515	reg_2958 = 0x00010000 + (src_major_y >> 1);516	if (f->interlaced_uv)517		reg_2958 += 0x00010000;518	reg_295c = reg_2958 + 1;519 520	if (yi->decode_height == 480)521		reg_289c = 0x011e0017;522	else523		reg_289c = 0x01500017;524 525	if (f->dst_y < 0)526		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);527	else528		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);529 530	/* How much of the source to decode.531	   Take into account the source offset */532	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |533		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);534 535	/* Calculate correct value for register 2964 */536	if (f->src_h == f->dst_h) {537		reg_2964 = 1;538	} else {539		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);540		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);541	}542	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);543	reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);544 545	/* Okay, we've wasted time working out the correct value,546	   but if we use it, it fouls the window alignment.547	   Fudge it to what we want... */548	reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));549	reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));550 551	/* Deviate further from what it should be. I find the flicker headache552	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise553	   colours foul. */554	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))555		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);556 557	if (!f->interlaced_y)558		reg_2964 -= 0x00010001;559	if (!f->interlaced_uv)560		reg_2968 -= 0x00010001;561 562	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);563	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);564 565	/* Select the vertical filter */566	if (f->src_h == f->dst_h) {567		/* An exact size match uses filter 0/1 */568		v_filter_1 = 0;569		v_filter_2 = 1;570	} else {571		/* Figure out which filter to use */572		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;573		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);574		/* Only an exact size match can use filter 0 */575		v_filter_1 += !v_filter_1;576		v_filter_2 = v_filter_1;577	}578 579	write_reg(reg_2934, 0x02934);580	write_reg(reg_293c, 0x0293c);581	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",582		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);583	write_reg(reg_2944, 0x02944);584	write_reg(reg_294c, 0x0294c);585	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",586		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);587 588	/* Ensure 2970 is 0 (does it ever change ?) */589/*	write_reg(0,0x02970); */590/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */591 592	write_reg(reg_2930, 0x02938);593	write_reg(reg_2930, 0x02930);594	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",595		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);596 597	write_reg(reg_2928, 0x02928);598	write_reg(reg_2928 + 0x514, 0x0292C);599	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",600		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);601 602	write_reg(reg_2920, 0x02920);603	write_reg(reg_2920 + 0x514, 0x02924);604	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",605		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);606 607	write_reg(reg_2918, 0x02918);608	write_reg(reg_291c, 0x0291C);609	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",610		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);611 612	write_reg(reg_296c, 0x0296c);613	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",614		       yi->reg_296c, reg_296c);615 616	write_reg(reg_2940, 0x02948);617	write_reg(reg_2940, 0x02940);618	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",619		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);620 621	write_reg(reg_2950, 0x02950);622	write_reg(reg_2954, 0x02954);623	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",624		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);625 626	write_reg(reg_2958, 0x02958);627	write_reg(reg_295c, 0x0295C);628	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",629		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);630 631	write_reg(reg_2960, 0x02960);632	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",633		       yi->reg_2960, reg_2960);634 635	write_reg(reg_2964, 0x02964);636	write_reg(reg_2968, 0x02968);637	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",638		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);639 640	write_reg(reg_289c, 0x0289c);641	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",642		       yi->reg_289c, reg_289c);643 644	/* Only update filter 1 if we really need to */645	if (v_filter_1 != yi->v_filter_1) {646		ivtv_yuv_filter(itv, -1, v_filter_1, -1);647		yi->v_filter_1 = v_filter_1;648	}649 650	/* Only update filter 2 if we really need to */651	if (v_filter_2 != yi->v_filter_2) {652		ivtv_yuv_filter(itv, -1, -1, v_filter_2);653		yi->v_filter_2 = v_filter_2;654	}655}656 657/* Modify the supplied coordinate information to fit the visible osd area */658static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)659{660	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;661	int osd_crop;662	u32 osd_scale;663	u32 yuv_update = 0;664 665	/* Sorry, but no negative coords for src */666	if (f->src_x < 0)667		f->src_x = 0;668	if (f->src_y < 0)669		f->src_y = 0;670 671	/* Can only reduce width down to 1/4 original size */672	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {673		f->src_x += osd_crop / 2;674		f->src_w = (f->src_w - osd_crop) & ~3;675		f->dst_w = f->src_w / 4;676		f->dst_w += f->dst_w & 1;677	}678 679	/* Can only reduce height down to 1/4 original size */680	if (f->src_h / f->dst_h >= 2) {681		/* Overflow may be because we're running progressive,682		   so force mode switch */683		f->interlaced_y = 1;684		/* Make sure we're still within limits for interlace */685		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {686			/* If we reach here we'll have to force the height. */687			f->src_y += osd_crop / 2;688			f->src_h = (f->src_h - osd_crop) & ~3;689			f->dst_h = f->src_h / 4;690			f->dst_h += f->dst_h & 1;691		}692	}693 694	/* If there's nothing to safe to display, we may as well stop now */695	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||696	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {697		return IVTV_YUV_UPDATE_INVALID;698	}699 700	/* Ensure video remains inside OSD area */701	osd_scale = (f->src_h << 16) / f->dst_h;702 703	if ((osd_crop = f->pan_y - f->dst_y) > 0) {704		/* Falls off the upper edge - crop */705		f->src_y += (osd_scale * osd_crop) >> 16;706		f->src_h -= (osd_scale * osd_crop) >> 16;707		f->dst_h -= osd_crop;708		f->dst_y = 0;709	} else {710		f->dst_y -= f->pan_y;711	}712 713	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {714		/* Falls off the lower edge - crop */715		f->dst_h -= osd_crop;716		f->src_h -= (osd_scale * osd_crop) >> 16;717	}718 719	osd_scale = (f->src_w << 16) / f->dst_w;720 721	if ((osd_crop = f->pan_x - f->dst_x) > 0) {722		/* Fall off the left edge - crop */723		f->src_x += (osd_scale * osd_crop) >> 16;724		f->src_w -= (osd_scale * osd_crop) >> 16;725		f->dst_w -= osd_crop;726		f->dst_x = 0;727	} else {728		f->dst_x -= f->pan_x;729	}730 731	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {732		/* Falls off the right edge - crop */733		f->dst_w -= osd_crop;734		f->src_w -= (osd_scale * osd_crop) >> 16;735	}736 737	if (itv->yuv_info.track_osd) {738		/* The OSD can be moved. Track to it */739		f->dst_x += itv->yuv_info.osd_x_offset;740		f->dst_y += itv->yuv_info.osd_y_offset;741	}742 743	/* Width & height for both src & dst must be even.744	   Same for coordinates. */745	f->dst_w &= ~1;746	f->dst_x &= ~1;747 748	f->src_w += f->src_x & 1;749	f->src_x &= ~1;750 751	f->src_w &= ~1;752	f->dst_w &= ~1;753 754	f->dst_h &= ~1;755	f->dst_y &= ~1;756 757	f->src_h += f->src_y & 1;758	f->src_y &= ~1;759 760	f->src_h &= ~1;761	f->dst_h &= ~1;762 763	/* Due to rounding, we may have reduced the output size to <1/4 of764	   the source. Check again, but this time just resize. Don't change765	   source coordinates */766	if (f->dst_w < f->src_w / 4) {767		f->src_w &= ~3;768		f->dst_w = f->src_w / 4;769		f->dst_w += f->dst_w & 1;770	}771	if (f->dst_h < f->src_h / 4) {772		f->src_h &= ~3;773		f->dst_h = f->src_h / 4;774		f->dst_h += f->dst_h & 1;775	}776 777	/* Check again. If there's nothing to safe to display, stop now */778	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||779	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {780		return IVTV_YUV_UPDATE_INVALID;781	}782 783	/* Both x offset & width are linked, so they have to be done together */784	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||785	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||786	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {787		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;788	}789 790	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||791	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||792	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||793	    (of->lace_mode != f->lace_mode) ||794	    (of->interlaced_y != f->interlaced_y) ||795	    (of->interlaced_uv != f->interlaced_uv)) {796		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;797	}798 799	return yuv_update;800}801 802/* Update the scaling register to the requested value */803void ivtv_yuv_work_handler(struct ivtv *itv)804{805	struct yuv_playback_info *yi = &itv->yuv_info;806	struct yuv_frame_info f;807	int frame = yi->update_frame;808	u32 yuv_update;809 810	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);811	f = yi->new_frame_info[frame];812 813	if (yi->track_osd) {814		/* Snapshot the osd pan info */815		f.pan_x = yi->osd_x_pan;816		f.pan_y = yi->osd_y_pan;817		f.vis_w = yi->osd_vis_w;818		f.vis_h = yi->osd_vis_h;819	} else {820		/* Not tracking the osd, so assume full screen */821		f.pan_x = 0;822		f.pan_y = 0;823		f.vis_w = 720;824		f.vis_h = yi->decode_height;825	}826 827	/* Calculate the display window coordinates. Exit if nothing left */828	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))829		return;830 831	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {832		write_reg(0x01008080, 0x2898);833	} else if (yuv_update) {834		write_reg(0x00108080, 0x2898);835 836		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)837			ivtv_yuv_handle_horizontal(itv, &f);838 839		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)840			ivtv_yuv_handle_vertical(itv, &f);841	}842	yi->old_frame_info = f;843}844 845static void ivtv_yuv_init(struct ivtv *itv)846{847	struct yuv_playback_info *yi = &itv->yuv_info;848 849	IVTV_DEBUG_YUV("ivtv_yuv_init\n");850 851	/* Take a snapshot of the current register settings */852	yi->reg_2834 = read_reg(0x02834);853	yi->reg_2838 = read_reg(0x02838);854	yi->reg_283c = read_reg(0x0283c);855	yi->reg_2840 = read_reg(0x02840);856	yi->reg_2844 = read_reg(0x02844);857	yi->reg_2848 = read_reg(0x02848);858	yi->reg_2854 = read_reg(0x02854);859	yi->reg_285c = read_reg(0x0285c);860	yi->reg_2864 = read_reg(0x02864);861	yi->reg_2870 = read_reg(0x02870);862	yi->reg_2874 = read_reg(0x02874);863	yi->reg_2898 = read_reg(0x02898);864	yi->reg_2890 = read_reg(0x02890);865 866	yi->reg_289c = read_reg(0x0289c);867	yi->reg_2918 = read_reg(0x02918);868	yi->reg_291c = read_reg(0x0291c);869	yi->reg_2920 = read_reg(0x02920);870	yi->reg_2924 = read_reg(0x02924);871	yi->reg_2928 = read_reg(0x02928);872	yi->reg_292c = read_reg(0x0292c);873	yi->reg_2930 = read_reg(0x02930);874	yi->reg_2934 = read_reg(0x02934);875	yi->reg_2938 = read_reg(0x02938);876	yi->reg_293c = read_reg(0x0293c);877	yi->reg_2940 = read_reg(0x02940);878	yi->reg_2944 = read_reg(0x02944);879	yi->reg_2948 = read_reg(0x02948);880	yi->reg_294c = read_reg(0x0294c);881	yi->reg_2950 = read_reg(0x02950);882	yi->reg_2954 = read_reg(0x02954);883	yi->reg_2958 = read_reg(0x02958);884	yi->reg_295c = read_reg(0x0295c);885	yi->reg_2960 = read_reg(0x02960);886	yi->reg_2964 = read_reg(0x02964);887	yi->reg_2968 = read_reg(0x02968);888	yi->reg_296c = read_reg(0x0296c);889	yi->reg_2970 = read_reg(0x02970);890 891	yi->v_filter_1 = -1;892	yi->v_filter_2 = -1;893	yi->h_filter = -1;894 895	/* Set some valid size info */896	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;897	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;898 899	/* Bit 2 of reg 2878 indicates current decoder output format900	   0 : NTSC    1 : PAL */901	if (read_reg(0x2878) & 4)902		yi->decode_height = 576;903	else904		yi->decode_height = 480;905 906	if (!itv->osd_info) {907		yi->osd_vis_w = 720 - yi->osd_x_offset;908		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;909	} else {910		/* If no visible size set, assume full size */911		if (!yi->osd_vis_w)912			yi->osd_vis_w = 720 - yi->osd_x_offset;913 914		if (!yi->osd_vis_h) {915			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;916		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {917			/* If output video standard has changed, requested height may918			   not be legal */919			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",920					yi->osd_vis_h + yi->osd_y_offset,921					yi->decode_height);922			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;923		}924	}925 926	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */927	yi->blanking_ptr = kzalloc(720 * 16, GFP_ATOMIC|__GFP_NOWARN);928	if (yi->blanking_ptr) {929		yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev,930						     yi->blanking_ptr,931						     720 * 16, DMA_TO_DEVICE);932	} else {933		yi->blanking_dmaptr = 0;934		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");935	}936 937	/* Enable YUV decoder output */938	write_reg_sync(0x01, IVTV_REG_VDM);939 940	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);941	atomic_set(&yi->next_dma_frame, 0);942}943 944/* Get next available yuv buffer on PVR350 */945static void ivtv_yuv_next_free(struct ivtv *itv)946{947	int draw, display;948	struct yuv_playback_info *yi = &itv->yuv_info;949 950	if (atomic_read(&yi->next_dma_frame) == -1)951		ivtv_yuv_init(itv);952 953	draw = atomic_read(&yi->next_fill_frame);954	display = atomic_read(&yi->next_dma_frame);955 956	if (display > draw)957		display -= IVTV_YUV_BUFFERS;958 959	if (draw - display >= yi->max_frames_buffered)960		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;961	else962		yi->new_frame_info[draw].update = 0;963 964	yi->draw_frame = draw;965}966 967/* Set up frame according to ivtv_dma_frame parameters */968static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)969{970	struct yuv_playback_info *yi = &itv->yuv_info;971	u8 frame = yi->draw_frame;972	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;973	struct yuv_frame_info *nf = &yi->new_frame_info[frame];974	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];975	int lace_threshold = yi->lace_threshold;976 977	/* Preserve old update flag in case we're overwriting a queued frame */978	int update = nf->update;979 980	/* Take a snapshot of the yuv coordinate information */981	nf->src_x = args->src.left;982	nf->src_y = args->src.top;983	nf->src_w = args->src.width;984	nf->src_h = args->src.height;985	nf->dst_x = args->dst.left;986	nf->dst_y = args->dst.top;987	nf->dst_w = args->dst.width;988	nf->dst_h = args->dst.height;989	nf->tru_x = args->dst.left;990	nf->tru_w = args->src_width;991	nf->tru_h = args->src_height;992 993	/* Are we going to offset the Y plane */994	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;995 996	nf->update = 0;997	nf->interlaced_y = 0;998	nf->interlaced_uv = 0;999	nf->delay = 0;1000	nf->sync_field = 0;1001	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;1002 1003	if (lace_threshold < 0)1004		lace_threshold = yi->decode_height - 1;1005 1006	/* Work out the lace settings */1007	switch (nf->lace_mode) {1008	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */1009		nf->interlaced = 0;1010		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))1011			nf->interlaced_y = 0;1012		else1013			nf->interlaced_y = 1;1014 1015		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))1016			nf->interlaced_uv = 0;1017		else1018			nf->interlaced_uv = 1;1019		break;1020 1021	case IVTV_YUV_MODE_AUTO:1022		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {1023			nf->interlaced = 0;1024			if ((nf->tru_h < 512) ||1025			    (nf->tru_h > 576 && nf->tru_h < 1021) ||1026			    (nf->tru_w > 720 && nf->tru_h < 1021))1027				nf->interlaced_y = 0;1028			else1029				nf->interlaced_y = 1;1030			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))1031				nf->interlaced_uv = 0;1032			else1033				nf->interlaced_uv = 1;1034		} else {1035			nf->interlaced = 1;1036			nf->interlaced_y = 1;1037			nf->interlaced_uv = 1;1038		}1039		break;1040 1041	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */1042	default:1043		nf->interlaced = 1;1044		nf->interlaced_y = 1;1045		nf->interlaced_uv = 1;1046		break;1047	}1048 1049	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {1050		yi->old_frame_info_args = *nf;1051		nf->update = 1;1052		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);1053	}1054 1055	nf->update |= update;1056	nf->sync_field = yi->lace_sync_field;1057	nf->delay = nf->sync_field != of->sync_field;1058}1059 1060/* Frame is complete & ready for display */1061void ivtv_yuv_frame_complete(struct ivtv *itv)1062{1063	atomic_set(&itv->yuv_info.next_fill_frame,1064			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);1065}1066 1067static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)1068{1069	DEFINE_WAIT(wait);1070	int rc = 0;1071	int got_sig = 0;1072	/* DMA the frame */1073	mutex_lock(&itv->udma.lock);1074 1075	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {1076		mutex_unlock(&itv->udma.lock);1077		return rc;1078	}1079 1080	ivtv_udma_prepare(itv);1081	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);1082	/* if no UDMA is pending and no UDMA is in progress, then the DMA1083	   is finished */1084	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||1085	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {1086		/* don't interrupt if the DMA is in progress but break off1087		   a still pending DMA. */1088		got_sig = signal_pending(current);1089		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))1090			break;1091		got_sig = 0;1092		schedule();1093	}1094	finish_wait(&itv->dma_waitq, &wait);1095 1096	/* Unmap Last DMA Xfer */1097	ivtv_udma_unmap(itv);1098 1099	if (got_sig) {1100		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");1101		mutex_unlock(&itv->udma.lock);1102		return -EINTR;1103	}1104 1105	ivtv_yuv_frame_complete(itv);1106 1107	mutex_unlock(&itv->udma.lock);1108	return rc;1109}1110 1111/* Setup frame according to V4L2 parameters */1112void ivtv_yuv_setup_stream_frame(struct ivtv *itv)1113{1114	struct yuv_playback_info *yi = &itv->yuv_info;1115	struct ivtv_dma_frame dma_args;1116 1117	ivtv_yuv_next_free(itv);1118 1119	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */1120	dma_args.y_source = NULL;1121	dma_args.uv_source = NULL;1122	dma_args.src.left = 0;1123	dma_args.src.top = 0;1124	dma_args.src.width = yi->v4l2_src_w;1125	dma_args.src.height = yi->v4l2_src_h;1126	dma_args.dst = yi->main_rect;1127	dma_args.src_width = yi->v4l2_src_w;1128	dma_args.src_height = yi->v4l2_src_h;1129 1130	/* ... and use the same setup routine as ivtv_yuv_prep_frame */1131	ivtv_yuv_setup_frame(itv, &dma_args);1132 1133	if (!itv->dma_data_req_offset)1134		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];1135}1136 1137/* Attempt to dma a frame from a user buffer */1138int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)1139{1140	struct yuv_playback_info *yi = &itv->yuv_info;1141	struct ivtv_dma_frame dma_args;1142	int res;1143 1144	ivtv_yuv_setup_stream_frame(itv);1145 1146	/* We only need to supply source addresses for this */1147	dma_args.y_source = src;1148	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);1149	/* Wait for frame DMA. Note that serialize_lock is locked,1150	   so to allow other processes to access the driver while1151	   we are waiting unlock first and later lock again. */1152	mutex_unlock(&itv->serialize_lock);1153	res = ivtv_yuv_udma_frame(itv, &dma_args);1154	mutex_lock(&itv->serialize_lock);1155	return res;1156}1157 1158/* IVTV_IOC_DMA_FRAME ioctl handler */1159int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)1160{1161	int res;1162 1163/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */1164	ivtv_yuv_next_free(itv);1165	ivtv_yuv_setup_frame(itv, args);1166	/* Wait for frame DMA. Note that serialize_lock is locked,1167	   so to allow other processes to access the driver while1168	   we are waiting unlock first and later lock again. */1169	mutex_unlock(&itv->serialize_lock);1170	res = ivtv_yuv_udma_frame(itv, args);1171	mutex_lock(&itv->serialize_lock);1172	return res;1173}1174 1175void ivtv_yuv_close(struct ivtv *itv)1176{1177	struct yuv_playback_info *yi = &itv->yuv_info;1178	int h_filter, v_filter_1, v_filter_2;1179 1180	IVTV_DEBUG_YUV("ivtv_yuv_close\n");1181	mutex_unlock(&itv->serialize_lock);1182	ivtv_waitq(&itv->vsync_waitq);1183	mutex_lock(&itv->serialize_lock);1184 1185	yi->running = 0;1186	atomic_set(&yi->next_dma_frame, -1);1187	atomic_set(&yi->next_fill_frame, 0);1188 1189	/* Reset registers we have changed so mpeg playback works */1190 1191	/* If we fully restore this register, the display may remain active.1192	   Restore, but set one bit to blank the video. Firmware will always1193	   clear this bit when needed, so not a problem. */1194	write_reg(yi->reg_2898 | 0x01000000, 0x2898);1195 1196	write_reg(yi->reg_2834, 0x02834);1197	write_reg(yi->reg_2838, 0x02838);1198	write_reg(yi->reg_283c, 0x0283c);1199	write_reg(yi->reg_2840, 0x02840);1200	write_reg(yi->reg_2844, 0x02844);1201	write_reg(yi->reg_2848, 0x02848);1202	write_reg(yi->reg_2854, 0x02854);1203	write_reg(yi->reg_285c, 0x0285c);1204	write_reg(yi->reg_2864, 0x02864);1205	write_reg(yi->reg_2870, 0x02870);1206	write_reg(yi->reg_2874, 0x02874);1207	write_reg(yi->reg_2890, 0x02890);1208	write_reg(yi->reg_289c, 0x0289c);1209 1210	write_reg(yi->reg_2918, 0x02918);1211	write_reg(yi->reg_291c, 0x0291c);1212	write_reg(yi->reg_2920, 0x02920);1213	write_reg(yi->reg_2924, 0x02924);1214	write_reg(yi->reg_2928, 0x02928);1215	write_reg(yi->reg_292c, 0x0292c);1216	write_reg(yi->reg_2930, 0x02930);1217	write_reg(yi->reg_2934, 0x02934);1218	write_reg(yi->reg_2938, 0x02938);1219	write_reg(yi->reg_293c, 0x0293c);1220	write_reg(yi->reg_2940, 0x02940);1221	write_reg(yi->reg_2944, 0x02944);1222	write_reg(yi->reg_2948, 0x02948);1223	write_reg(yi->reg_294c, 0x0294c);1224	write_reg(yi->reg_2950, 0x02950);1225	write_reg(yi->reg_2954, 0x02954);1226	write_reg(yi->reg_2958, 0x02958);1227	write_reg(yi->reg_295c, 0x0295c);1228	write_reg(yi->reg_2960, 0x02960);1229	write_reg(yi->reg_2964, 0x02964);1230	write_reg(yi->reg_2968, 0x02968);1231	write_reg(yi->reg_296c, 0x0296c);1232	write_reg(yi->reg_2970, 0x02970);1233 1234	/* Prepare to restore filters */1235 1236	/* First the horizontal filter */1237	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {1238		/* An exact size match uses filter 0 */1239		h_filter = 0;1240	} else {1241		/* Figure out which filter to use */1242		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;1243		h_filter = (h_filter >> 1) + (h_filter & 1);1244		/* Only an exact size match can use filter 0. */1245		h_filter += !h_filter;1246	}1247 1248	/* Now the vertical filter */1249	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {1250		/* An exact size match uses filter 0/1 */1251		v_filter_1 = 0;1252		v_filter_2 = 1;1253	} else {1254		/* Figure out which filter to use */1255		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;1256		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);1257		/* Only an exact size match can use filter 0 */1258		v_filter_1 += !v_filter_1;1259		v_filter_2 = v_filter_1;1260	}1261 1262	/* Now restore the filters */1263	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);1264 1265	/* and clear a few registers */1266	write_reg(0, 0x02814);1267	write_reg(0, 0x0282c);1268	write_reg(0, 0x02904);1269	write_reg(0, 0x02910);1270 1271	/* Release the blanking buffer */1272	if (yi->blanking_ptr) {1273		kfree(yi->blanking_ptr);1274		yi->blanking_ptr = NULL;1275		dma_unmap_single(&itv->pdev->dev, yi->blanking_dmaptr,1276				 720 * 16, DMA_TO_DEVICE);1277	}1278 1279	/* Invalidate the old dimension information */1280	yi->old_frame_info.src_w = 0;1281	yi->old_frame_info.src_h = 0;1282	yi->old_frame_info_args.src_w = 0;1283	yi->old_frame_info_args.src_h = 0;1284 1285	/* All done. */1286	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);1287}1288