⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mx27_pp.c

📁 LINUX下的ov2640驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
		coeff |= 1;	} else {		/*		 * src inc field is 2 bit wide, for 4+, use special		 * code 0:0:1 to prevent dest inc		 */		coeff |= PP_SKIP;		coeff <<= 1;		coeff |= 1;		nxt -= PP_SKIP;		do {			pr_debug("tbl = %03X\n", coeff);			scale_tbl[k++] = coeff;			coeff = (nxt > PP_SKIP) ? PP_SKIP : nxt;			coeff <<= 1;		} while ((nxt -= PP_SKIP) > 0);	}	pr_debug("tbl = %03X\n", coeff);	scale_tbl[k++] = coeff;	return k;}/*! * @brief Get approximate ratio * * @param pscale	The pointer to scale_t structure which holdes * 			coefficient tables * @param mt		Scale ratio numerator * @param nt		Scale ratio denominator * @param *n		denominator of approximate ratio * @return		numerator of approximate ratio */static int approx_ratio(int mt, int nt, int *n){	int index = sizeof(pp_coeftab) / sizeof(pp_coeftab[0]) / 2;	int left = 0;	int right = index - 1;	int nom = 0, den = 0;	while (index > 0) {		nom = pp_coeftab[(((right + left) >> 1) << 1)];		den = pp_coeftab[(((right + left) >> 1) << 1) + 1];		if ((nom * nt - mt * den) > 0) {			left = (right + left) >> 1;		} else {			right = (right + left) >> 1;		}		index = index >> 1;	}	*n = pp_coeftab[right * 2 + 1];	nom = pp_coeftab[right * 2];	return nom;}/* * @brief Build PP coefficient table * Build PP coefficient table for one dimension (width or height) * based on given input and output resolution * * @param inv	input resolution * @param outv	output resolution * @param k	index of free table entry * * @return	The index of the next free coefficient entry on success *		-1 on failure */static int scale_1d(int inv, int outv, int k){	int v;			/* overflow counter */	int coeff, nxt;		/* table output */	if (inv == outv)		return scale_0d(k, 1, 1, 1);	/* force scaling */	v = 0;	if (inv < outv) {		/* upscale: mix <= 2 input pixels per output pixel */		do {			coeff = outv - v;			v += inv;			if (v >= outv) {				v -= outv;				nxt = 1;			} else				nxt = 0;			pr_debug("upscale: coeff = %d/%d nxt = %d\n", coeff,				 outv, nxt);			k = scale_0d(k, coeff, outv, nxt);			if (k < 0)				return -1;		} while (v);	} else if (inv >= 2 * outv) {		/* PP doesn't support resize ratio > 2:1 except 4:1. */		if ((inv != 2 * outv) && (inv != 4 * outv))			return -1;		/* downscale: >=2:1 bilinear approximation */		coeff = inv - 2 * outv;		v = 0;		nxt = 0;		do {			v += coeff;			nxt = 2;			while (v >= outv) {				v -= outv;				nxt++;			}			pr_debug("downscale: coeff = 1/2 nxt = %d\n", nxt);			k = scale_0d(k, 1, 2, nxt);			if (k < 0)				return -1;		} while (v);	} else {		/* downscale: bilinear */		int in_pos_inc = 2 * outv;		int out_pos = inv;		int out_pos_inc = 2 * inv;		int init_carry = inv - outv;		int carry = init_carry;		v = outv + in_pos_inc;		do {			coeff = v - out_pos;			out_pos += out_pos_inc;			carry += out_pos_inc;			for (nxt = 0; v < out_pos; nxt++) {				v += in_pos_inc;				carry -= in_pos_inc;			}			pr_debug("downscale: coeff = %d/%d nxt = %d\n", coeff,				 in_pos_inc, nxt);			k = scale_0d(k, coeff, in_pos_inc, nxt);			if (k < 0)				return -1;		} while (carry != init_carry);	}	return k;}/* * @brief Build PP coefficient table * Build PP coefficient table for one dimension (width or height) * based on given input and output resolution. The given input * and output resolution might be not supported due to hardware * limits. In this case this functin rounds the input and output * to closest possible values and return them to caller. * * @param inv	input resolution, might be modified after the call * @param outv	output resolution, might be modified after the call * @param k	index of free table entry * * @return	The index of the next free coefficient entry on success *		-1 on failure */static int scale_1d_smart(int *inv, int *outv, int index){	int len, num, den, approx_num, approx_den;	static int num1, den1;	if (!inv || !outv)		return -1;	/* Both should be non-zero */	if (!(*inv) || !(*outv))		return -1;	if ((*outv > 4 * (*inv))	    || ((*inv > 2 * (*outv)) && (*inv != 4 * (*outv)))) {		pr_debug("unsupported pp resize ration: inv/outv = %d/%d\n",			 *inv, *outv);		return -1;	}	num = ratio(*inv, *outv, &den);	if (index == 0) {		if ((num > 20) || (den > 20)) {			approx_num = approx_ratio(num, den, &approx_den);			num = approx_num;			den = approx_den;		}	} else {		if ((num > (40 - index)) || (den > (40 - index))) {			approx_num = approx_ratio(num, den, &approx_den);			num = approx_num;			den = approx_den;		}		if ((num == num1) && (den == den1)) {			return index;		}	}	if ((len = scale_1d(num, den, index)) < 0) {		return -1;	} else {		if (index == 0) {			num1 = num;			den1 = den;		}		return len;	}}/* * @brief Build PP coefficient table for both width and height * Build PP coefficient table for both width and height based on * given resizing ratios. * * @param sz	Structure contains resizing ratio informations * * @return	0 on success, others on failure */static int scale_2d(emma_pp_scale * sz){	int inv, outv;	/* horizontal resizing. parameter check - must provide in size */	if (!sz->in.width)		return -1;	/* Resizing based on num:den */	inv = sz->num.width;	outv = sz->den.width;	if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) {		/* Resizing succeeded */		sz->den.width = outv;		sz->out.width = (sz->in.width * outv) / inv;	} else {		/* Resizing based on in:out */		inv = sz->in.width;		outv = sz->out.width;		if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) {			/* Resizing succeeded */			sz->out.width = outv;			sz->num.width = ratio(sz->in.width, sz->out.width,					      &sz->den.width);		} else			return -1;	}	sz->out.width &= ~1;	/* vertical resizing. parameter check - must provide in size */	if (!sz->in.height)		return -1;	/* Resizing based on num:den */	inv = sz->num.height;	outv = sz->den.height;	if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) {		/* Resizing succeeded */		sz->den.height = outv;		sz->out.height = (sz->in.height * outv) / inv;	} else {		/* Resizing based on in:out */		inv = sz->in.height;		outv = sz->out.height;		if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) {			/* Resizing succeeded */			sz->out.height = outv;			sz->num.height = ratio(sz->in.height, sz->out.height,					       &sz->den.height);		} else			return -1;	}	return 0;}/*! * @brief Set PP resizing registers. * @param sz	Pointer to pp scaling structure * @return	Zero on success, others on failure */static int pphw_scale(emma_pp_scale * sz){	__raw_writel((sz->out.width << 16) | sz->out.height,		     PP_DEST_IMAGE_SIZE);	__raw_writel(((g_hlen - 1) << 16) | (g_vlen ==					     g_hlen ? 0 : (g_hlen << 8)) |		     (g_vlen - 1), PP_RESIZE_INDEX);	for (g_hlen = 0; g_hlen < g_vlen; g_hlen++)		__raw_writel(scale_tbl[g_hlen],			     PP_RESIZE_COEF_TBL + g_hlen * 4);	return 0;}/*! * @brief Reset PP. * @return	Zero on success, others on failure */static int pphw_reset(void){	int i;	__raw_writel(0x100, PP_CNTL);	/* timeout */	for (i = 0; i < 1000; i++) {		if (!(__raw_readl(PP_CNTL) & 0x100)) {			pr_debug("pp reset over\n");			break;		}	}	/* check reset value */	if (__raw_readl(PP_CNTL) != 0x876) {		pr_debug("pp reset value err = 0x%08X\n", __raw_readl(PP_CNTL));		return -1;	}	return 0;}/*! * @brief Enable or disable PP. * @param flag	Zero to disable PP, others to enable PP * @return	Zero on success, others on failure */static int pphw_enable(int flag){	int ret = 0;	if (flag)		__raw_writel(__raw_readl(PP_CNTL) | 1, PP_CNTL);	else		ret = pphw_reset();	return ret;}/*! * @brief Set PP input address. * @param cfg	The pointer to PP configuration parameter * @return	Zero on success, others on failure */static int pphw_ptr(emma_pp_cfg * cfg){	if (!cfg->ptr.u) {		int size;		/* yuv - packed */		size = PP_CALC_Y_SIZE(cfg);		cfg->ptr.u = cfg->ptr.y + size;		cfg->ptr.v = cfg->ptr.u + (size >> 2);		/* yuv packed with qp appended */		if (!cfg->ptr.qp)			cfg->ptr.qp = cfg->ptr.v + (size >> 2);	}	__raw_writel(cfg->ptr.y, PP_SOURCE_Y_PTR);	__raw_writel(cfg->ptr.u, PP_SOURCE_CB_PTR);	__raw_writel(cfg->ptr.v, PP_SOURCE_CR_PTR);	__raw_writel(cfg->ptr.qp, PP_QUANTIZER_PTR);	return 0;}/*! * @brief Set PP output address. * @param cfg	The pointer to PP configuration parameter * @return	Zero on success, others on failure */static int pphw_outptr(emma_pp_cfg * cfg){	__raw_writel(cfg->outptr, PP_DEST_RGB_PTR);	return 0;}/*! * @brief Configuration PP. * @param cfg	The pointer to PP configuration parameter * @return	Zero on success, others on failure */static int pphw_cfg(emma_pp_cfg * cfg){	int rt;	register int r;	pphw_scale(&cfg->dim);	if (!cfg->in_y_stride)		cfg->in_y_stride = cfg->dim.in.width;	if (!cfg->out_stride)		cfg->out_stride = cfg->dim.out.width;	r = __raw_readl(PP_CNTL) & ~EN_MASK;	/* config parms */	r |= cfg->operation & EN_MASK;	if (cfg->operation & EN_MACROBLOCK) {		/* Macroblock Mode */		r |= 0x0200;		__raw_writel(0x06, PP_INTRCNTL);	} else {		/* Frame mode */		__raw_writel(0x05, PP_INTRCNTL);	}	if (cfg->red_width | cfg->green_width | cfg->blue_width) {		/* color conversion to be performed */		r |= EN_CSC;		if (!(cfg->red_offset | cfg->green_offset)) {			/* auto offset B:G:R LSb to Msb */			cfg->green_offset = cfg->blue_offset + cfg->blue_width;			cfg->red_offset = cfg->green_offset + cfg->green_width;		}		if (!cfg->rgb_resolution) {			/* derive minimum resolution required */			int w, w2;			w = cfg->red_offset + cfg->red_width;			w2 = cfg->blue_offset + cfg->blue_width;			if (w < w2)				w = w2;			w2 = cfg->green_offset + cfg->green_width;			if (w < w2)				w = w2;			if (w > 16)				w = 24;			else if (w > 8)				w = 16;			else				w = 8;			cfg->rgb_resolution = w;		}		/* 00,11 - 32 bpp, 10 - 16 bpp, 01 - 8 bpp */		r &= ~0xC00;		if (cfg->rgb_resolution < 32)			r |= (cfg->rgb_resolution << 7);		__raw_writel((cfg->red_offset << 26) |			     (cfg->green_offset << 21) |			     (cfg->blue_offset << 16) |			     (cfg->red_width << 8) |			     (cfg->green_width << 4) |			     cfg->blue_width, PP_DEST_FRAME_FMT_CNTL);	} else {		/* add YUV422 formatting */		static const unsigned int _422[] = {			0x62000888,			0x60100888,			0x43080888,			0x41180888		};		__raw_writel(_422[(cfg->blue_offset >> 3) & 3],			     PP_DEST_FRAME_FMT_CNTL);		cfg->rgb_resolution = 16;		r &= ~0xC00;		r |= (cfg->rgb_resolution << 7);	}	/* add csc formatting */	if (!cfg->csc_table[1]) {		static const unsigned short _csc[][6] = {			{0x80, 0xb4, 0x2c, 0x5b, 0x0e4, 0},			{0x95, 0xcc, 0x32, 0x68, 0x104, 1},			{0x80, 0xca, 0x18, 0x3c, 0x0ec, 0},			{0x95, 0xe5, 0x1b, 0x44, 0x10e, 1},		};		memcpy(cfg->csc_table, _csc[cfg->csc_table[0]],		       sizeof(_csc[0]));	}	__raw_writel((cfg->csc_table[0] << 24) |		     (cfg->csc_table[1] << 16) |		     (cfg->csc_table[2] << 8) |		     cfg->csc_table[3], PP_CSC_COEF_0123);	__raw_writel((cfg->csc_table[5] ? (1 << 9) : 0) | cfg->csc_table[4],		     PP_CSC_COEF_4);	__raw_writel(r, PP_CNTL);	pphw_ptr(cfg);	pphw_outptr(cfg);	/*	 * #MB in a row = input_width / 16pix	 * 1 byte per QP per MB	 * QP must be formatted to be 4-byte aligned	 * YUV lines are to be 4-byte aligned as well	 * So Y is 8 byte aligned, as U = V = Y/2 for 420	 * MPEG MBs are 16x16 anyway	 */	__raw_writel((cfg->dim.in.width << 16) | cfg->dim.in.height,		     PP_PROCESS_FRAME_PARA);	__raw_writel(cfg->in_y_stride | (PP_CALC_QP_WIDTH(cfg) << 16),		     PP_SOURCE_FRAME_WIDTH);	/* in bytes */	rt = cfg->rgb_resolution >> 3;	if (rt == 3)		rt = 4;	__raw_writel(cfg->out_stride * rt, PP_DEST_DISPLAY_WIDTH);	pp_dump();	return 0;}/*! * @brief Check PP interrupt status. * @return	PP interrupt status */static int pphw_isr(void){	unsigned long status;	pr_debug("pp: in isr.\n");	status = __raw_readl(PP_INTRSTATUS) & 7;	if (!status) {		pr_debug("pp: not my isr err.\n");		return status;	}	if (status & 4)		pr_debug("pp: isr state error.\n");	/* clear interrupt status */	__raw_writel(status, PP_INTRSTATUS);	return status;}static struct clk *emma_clk;/*! * @brief PP module clock enable */static void pphw_init(void){	emma_clk = clk_get(NULL, "emma_clk");	clk_enable(emma_clk);}/*! * @brief PP module clock disable */static void pphw_exit(void){	clk_disable(emma_clk);	clk_put(emma_clk);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -