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

📄 mx27_pp.c

📁 LINUX下的ov2640驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. *//* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html *//*! * @file mx27_pp.c * * @brief MX27 V4L2 Video Output Driver * * Video4Linux2 Output Device using MX27 eMMA Post-processing functionality. * * @ingroup MXC_V4L2_OUTPUT */#include <linux/kernel.h>#include <linux/string.h>#include <linux/module.h>#include <linux/fb.h>#include <linux/clk.h>#include <linux/interrupt.h>#include <asm/io.h>#include "mx27_pp.h"#include "mxc_v4l2_output.h"#define SCALE_RETRY	32	/* to be more relax, less precise */#define PP_SKIP		1#define PP_TBL_MAX	40static unsigned short scale_tbl[PP_TBL_MAX];static int g_hlen, g_vlen;static emma_pp_cfg g_pp_cfg;static int g_disp_num = 0;static char pp_dev[] = "emma_pp";/*! * @brief PP resizing routines */static int gcd(int x, int y);static int ratio(int x, int y, int *den);static int scale_0d(int k, int coeff, int base, int nxt);static int scale_1d(int inv, int outv, int k);static int scale_1d_smart(int *inv, int *outv, int index);static int scale_2d(emma_pp_scale * sz);static irqreturn_t pp_isr(int irq, void *dev_id);static int set_output_addr(emma_pp_cfg * cfg, vout_data * vout);static int pphw_reset(void);static int pphw_enable(int flag);static int pphw_ptr(emma_pp_cfg * cfg);static int pphw_outptr(emma_pp_cfg * cfg);static int pphw_cfg(emma_pp_cfg * cfg);static int pphw_isr(void);static void pphw_init(void);static void pphw_exit(void);#define PP_DUMP(reg)	pr_debug("%s\t = 0x%08X\n", #reg, __raw_readl(reg))void pp_dump(void){	PP_DUMP(PP_CNTL);	PP_DUMP(PP_INTRCNTL);	PP_DUMP(PP_INTRSTATUS);	PP_DUMP(PP_SOURCE_Y_PTR);	PP_DUMP(PP_SOURCE_CB_PTR);	PP_DUMP(PP_SOURCE_CR_PTR);	PP_DUMP(PP_DEST_RGB_PTR);	PP_DUMP(PP_QUANTIZER_PTR);	PP_DUMP(PP_PROCESS_FRAME_PARA);	PP_DUMP(PP_SOURCE_FRAME_WIDTH);	PP_DUMP(PP_DEST_DISPLAY_WIDTH);	PP_DUMP(PP_DEST_IMAGE_SIZE);	PP_DUMP(PP_DEST_FRAME_FMT_CNTL);	PP_DUMP(PP_RESIZE_INDEX);	PP_DUMP(PP_CSC_COEF_0123);	PP_DUMP(PP_CSC_COEF_4);}static const unsigned char pp_coeftab[] = {	2, 1,	19, 10,	17, 9,	15, 8,	13, 7,	11, 6,	20, 11,	9, 5,	16, 9,	7, 4,	19, 11,	12, 7,	17, 10,	5, 3,	18, 11,	13, 8,	8, 5,	19, 12,	11, 7,	14, 9,	17, 11,	20, 13,	3, 2,	19, 13,	16, 11,	13, 9,	10, 7,	17, 12,	7, 5,	18, 13,	11, 8,	15, 11,	19, 14,	4, 3,	17, 13,	13, 10,	9, 7,	14, 11,	19, 15,	5, 4,	16, 13,	11, 9,	17, 14,	6, 5,	19, 16,	13, 11,	20, 17,	7, 6,	15, 13,	8, 7,	17, 15,	9, 8,	19, 17,	10, 9,	11, 10,	12, 11,	13, 12,	14, 13,	15, 14,	16, 15,	17, 16,	18, 17,	19, 18,	20, 19,	1, 1,	19, 20,	18, 19,	17, 18,	16, 17,	15, 16,	14, 15,	13, 14,	12, 13,	11, 12,	10, 11,	9, 10,	17, 19,	8, 9,	15, 17,	7, 8,	13, 15,	6, 7,	17, 20,	11, 13,	16, 19,	5, 6,	14, 17,	9, 11,	13, 16,	4, 5,	15, 19,	11, 14,	7, 9,	10, 13,	13, 17,	3, 4,	14, 19,	11, 15,	8, 11,	13, 18,	5, 7,	12, 17,	7, 10,	9, 13,	11, 16,	13, 19,	2, 3,	13, 20,	11, 17,	9, 14,	7, 11,	12, 19,	5, 8,	8, 13,	11, 18,	3, 5,	10, 17,	7, 12,	11, 19,	4, 7,	9, 16,	5, 9,	11, 20,	6, 11,	7, 13,	8, 15,	9, 17,	10, 19,	1, 2,	9, 19,	8, 17,	7, 15,	6, 13,	5, 11,	9, 20,	4, 9,	7, 16,	3, 7,	8, 19,	5, 12,	7, 17,	2, 5,	7, 18,	5, 13,	3, 8,	7, 19,	4, 11,	5, 14,	6, 17,	7, 20,	1, 3,	6, 19,	5, 16,	4, 13,	3, 10,	5, 17,	2, 7,	5, 18,	3, 11,	4, 15,	5, 19,	1, 4};/*! * @brief Set PP input address. * @param ptr	The pointer to the Y value of input * @return	Zero on success, others on failure */int pp_ptr(unsigned long ptr){	g_pp_cfg.ptr.y = ptr;	g_pp_cfg.ptr.u = g_pp_cfg.ptr.v = g_pp_cfg.ptr.qp = 0;	return pphw_ptr(&g_pp_cfg);}/*! * @brief Enable or disable PP. * @param flag	Zero to disable PP, others to enable PP * @return	Zero on success, others on failure */int pp_enable(int flag){	return pphw_enable(flag);}/*! * @brief Get the display No. of last completed PP frame. * @return	The display No. of last completed PP frame. */int pp_num_last(void){	return (g_disp_num ? 0 : 1);}/*! * @brief Initialize PP. * @param vout	Pointer to _vout_data structure * @return	Zero on success, others on failure */int pp_init(vout_data * vout){	pphw_init();	pphw_enable(0);	enable_irq(INT_EMMAPP);	return request_irq(INT_EMMAPP, pp_isr, 0, pp_dev, vout);}/*! * @brief Deinitialize PP. * @param vout	Pointer to _vout_data structure */void pp_exit(vout_data * vout){	disable_irq(INT_EMMAPP);	free_irq(INT_EMMAPP, vout);	pphw_enable(0);	pphw_exit();}/*! * @brief Configure PP. * @param vout	Pointer to _vout_data structure * @return	Zero on success, others on failure */int pp_cfg(vout_data * vout){	if (!vout)		return -1;	/* PP accepts YUV420 input only */	if (vout->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) {		pr_debug("unsupported pixel format.\n");		return -1;	}	g_pp_cfg.operation = 0;	memset(g_pp_cfg.csc_table, 0, sizeof(g_pp_cfg.csc_table));	/* Convert output pixel format to PP required format */	switch (vout->v4l2_fb.fmt.pixelformat) {	case V4L2_PIX_FMT_BGR32:		g_pp_cfg.red_width = 8;		g_pp_cfg.green_width = 8;		g_pp_cfg.blue_width = 8;		g_pp_cfg.red_offset = 8;		g_pp_cfg.green_offset = 16;		g_pp_cfg.blue_offset = 24;		g_pp_cfg.rgb_resolution = 32;		break;	case V4L2_PIX_FMT_RGB32:		g_pp_cfg.red_width = 8;		g_pp_cfg.green_width = 8;		g_pp_cfg.blue_width = 8;		g_pp_cfg.red_offset = 24;		g_pp_cfg.green_offset = 16;		g_pp_cfg.blue_offset = 8;		g_pp_cfg.rgb_resolution = 32;		break;	case V4L2_PIX_FMT_YUYV:		g_pp_cfg.red_width = 0;		g_pp_cfg.green_width = 0;		g_pp_cfg.blue_width = 0;		g_pp_cfg.red_offset = 0;		g_pp_cfg.green_offset = 0;		g_pp_cfg.blue_offset = PP_PIX_YUYV;		g_pp_cfg.rgb_resolution = 16;		break;	case V4L2_PIX_FMT_UYVY:		g_pp_cfg.red_width = 0;		g_pp_cfg.green_width = 0;		g_pp_cfg.blue_width = 0;		g_pp_cfg.red_offset = 0;		g_pp_cfg.green_offset = 0;		g_pp_cfg.blue_offset = PP_PIX_UYVY;		g_pp_cfg.rgb_resolution = 16;		break;	case V4L2_PIX_FMT_RGB565:	default:		g_pp_cfg.red_width = 5;		g_pp_cfg.green_width = 6;		g_pp_cfg.blue_width = 5;		g_pp_cfg.red_offset = 11;		g_pp_cfg.green_offset = 5;		g_pp_cfg.blue_offset = 0;		g_pp_cfg.rgb_resolution = 16;		break;	}	if (vout->ipu_buf[0] != -1)		g_pp_cfg.ptr.y =		    (unsigned int)vout->queue_buf_paddr[vout->ipu_buf[0]];	else		g_pp_cfg.ptr.y = 0;	g_pp_cfg.ptr.u = g_pp_cfg.ptr.v = g_pp_cfg.ptr.qp = 0;	g_pp_cfg.dim.in.width = vout->v2f.fmt.pix.width;	g_pp_cfg.dim.in.height = vout->v2f.fmt.pix.height;	g_pp_cfg.dim.out.width = vout->crop_current.width;	g_pp_cfg.dim.out.height = vout->crop_current.height;	g_pp_cfg.dim.num.width = 0;	g_pp_cfg.dim.num.height = 0;	g_pp_cfg.dim.den.width = 0;	g_pp_cfg.dim.den.height = 0;	if (scale_2d(&g_pp_cfg.dim)) {		pr_debug("unsupported resize ratio.\n");		return -1;	}	g_pp_cfg.dim.out.width = vout->crop_current.width;	g_pp_cfg.dim.out.height = vout->crop_current.height;	g_pp_cfg.in_y_stride = 0;	if (set_output_addr(&g_pp_cfg, vout)) {		pr_debug("failed to set pp output address.\n");		return -1;	}	return pphw_cfg(&g_pp_cfg);}irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id);/*! * @brief PP IRQ handler. */static irqreturn_t pp_isr(int irq, void *dev_id){	int status;	vout_data *vout = dev_id;	status = pphw_isr();	if ((status & 0x1) == 0) {	/* Not frame complete interrupt */		pr_debug("not pp frame complete interrupt\n");		return IRQ_HANDLED;	}	if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {		g_disp_num = g_disp_num ? 0 : 1;		g_pp_cfg.outptr = (unsigned int)vout->display_bufs[g_disp_num];		pphw_outptr(&g_pp_cfg);	}	return mxc_v4l2out_pp_in_irq_handler(irq, dev_id);}/*! * @brief Set PP output address. * @param cfg	Pointer to emma_pp_cfg structure * @param vout	Pointer to _vout_data structure * @return	Zero on success, others on failure */static int set_output_addr(emma_pp_cfg * cfg, vout_data * vout){	if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {		g_disp_num = 0;		cfg->outptr = (unsigned int)vout->display_bufs[g_disp_num];		cfg->out_stride = vout->crop_current.width;		return 0;	} else {		struct fb_info *fb;		fb = registered_fb[vout->output_fb_num[vout->cur_disp_output]];		if (!fb)			return -1;		cfg->outptr = fb->fix.smem_start;		cfg->outptr += vout->crop_current.top * fb->var.xres_virtual		    * (fb->var.bits_per_pixel >> 3)		    + vout->crop_current.left * (fb->var.bits_per_pixel >> 3);		cfg->out_stride = fb->var.xres_virtual;		return 0;	}}/*! * @brief Get maximum common divisor. * @param x	First input value * @param y	Second input value * @return	Maximum common divisor of x and y */static int gcd(int x, int y){	int k;	if (x < y) {		k = x;		x = y;		y = k;	}	while ((k = x % y)) {		x = y;		y = k;	}	return y;}/*! * @brief Get ratio. * @param x	First input value * @param y	Second input value * @param den	Denominator of the ratio (corresponding to y) * @return	Numerator of the ratio (corresponding to x) */static int ratio(int x, int y, int *den){	int g;	if (!x || !y)		return 0;	g = gcd(x, y);	*den = y / g;	return x / g;}/*! * @brief Build PP coefficient entry * Build one or more coefficient entries for PP coefficient table based * on given coefficient. * * @param k	The index of the coefficient in coefficient table * @param coeff	The weighting coefficient * @param base	The base of the coefficient * @param nxt	Number of pixels to be read * * @return	The index of the next coefficient entry on success *		-1 on failure */static int scale_0d(int k, int coeff, int base, int nxt){	if (k >= PP_TBL_MAX) {		/* no more space in table */		pr_debug("no space in scale table, k = %d\n", k);		return -1;	}	coeff = ((coeff << BC_COEF) + (base >> 1)) / base;	/*	 * Valid values for weighting coefficient are 0, 2 to 30, and 31.	 * A value of 31 is treated as 32 and therefore 31 is an	 * invalid co-efficient.	 */	if (coeff >= SZ_COEF - 1)		coeff--;	else if (coeff == 1)		coeff++;	coeff = coeff << BC_NXT;	if (nxt < SZ_NXT) {		coeff |= nxt;		coeff <<= 1;

⌨️ 快捷键说明

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