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

📄 mx27_prphw.c

📁 freescale mx27 的TVP5150的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		outv = (unsigned short)(inv / tot) * i;		inv %= tot;		for (i = 0; inv > 0; i++, outv++)			inv -= pscale->ratio[i];	}	if (!(*vout) || ((*vout) > outv))		*vout = outv;	if (pout)		*pout = outv;	return 0;}/*! * @brief Reset PrP block */int prphw_reset(void){	unsigned long val;	unsigned long flag;	int i;	flag = PRP_CNTL_RST;	val = PRP_CNTL_RSTVAL;	__raw_writel(flag, PRP_CNTL);	/* timeout */	for (i = 0; i < 1000; i++) {		if (!(__raw_readl(PRP_CNTL) & flag)) {			pr_debug("PrP reset over\n");			break;		}		msleep(1);	}	/* verify reset value */	if (__raw_readl(PRP_CNTL) != val) {		pr_info("PrP reset err, val = 0x%08X\n", __raw_readl(PRP_CNTL));		return -1;	}	return 0;}/*! * @brief Enable PrP channel. * @param channel	Channel number to be enabled * @return		Zero on success, others on failure */int prphw_enable(int channel){	unsigned long val;	val = __raw_readl(PRP_CNTL);	if (channel & PRP_CHANNEL_1)		val |= PRP_CNTL_CH1EN;	if (channel & PRP_CHANNEL_2)		val |=		    (PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN | PRP_CNTL_AUTODROP);	__raw_writel(val, PRP_CNTL);	return 0;}/*! * @brief Disable PrP channel. * @param channel	Channel number to be disable * @return		Zero on success, others on failure */int prphw_disable(int channel){	unsigned long val;	val = __raw_readl(PRP_CNTL);	if (channel & PRP_CHANNEL_1)		val &= ~PRP_CNTL_CH1EN;	if (channel & PRP_CHANNEL_2)		val &= ~(PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN);	__raw_writel(val, PRP_CNTL);	return 0;}/*! * @brief Set PrP input buffer address. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_inptr(emma_prp_cfg * cfg){	if (cfg->in_csi & PRP_CSI_EN)		return -1;	__raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR);	if (cfg->in_pix == PRP_PIXIN_YUV420) {		u32 size;		size = cfg->in_line_stride * cfg->in_height;		__raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR);		__raw_writel(cfg->in_ptr + size + (size >> 2),			     PRP_SOURCE_CR_PTR);	}	return 0;}/*! * @brief Set PrP channel 1 output buffer 1 address. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_ch1ptr(emma_prp_cfg * cfg){	if (cfg->ch1_pix == PRP_PIX1_UNUSED)		return -1;	__raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR);	/* support double buffer in loop mode only */	if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {		if (cfg->ch1_ptr2)			__raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);		else			__raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR);	}	return 0;}/*! * @brief Set PrP channel 1 output buffer 2 address. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_ch1ptr2(emma_prp_cfg * cfg){	if (cfg->ch1_pix == PRP_PIX1_UNUSED ||	    (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP)		return -1;	if (cfg->ch1_ptr2)		__raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);	else		return -1;	return 0;}/*! * @brief Set PrP channel 2 output buffer 1 address. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_ch2ptr(emma_prp_cfg * cfg){	u32 size;	if (cfg->ch2_pix == PRP_PIX2_UNUSED)		return -1;	__raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR);	if (cfg->ch2_pix == PRP_PIX2_YUV420) {		size = cfg->ch2_width * cfg->ch2_height;		__raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR);		__raw_writel(cfg->ch2_ptr + size + (size >> 2),			     PRP_DEST_CR_PTR);	}	__raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B1, PRP_CNTL);	return 0;}/*! * @brief Set PrP channel 2 output buffer 2 address. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_ch2ptr2(emma_prp_cfg * cfg){	u32 size;	if (cfg->ch2_pix == PRP_PIX2_UNUSED ||	    (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP)		return -1;	__raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR);	if (cfg->ch2_pix == PRP_PIX2_YUV420) {		size = cfg->ch2_width * cfg->ch2_height;		__raw_writel(cfg->ch2_ptr2 + size, PRP_SOURCE_CB_PTR);		__raw_writel(cfg->ch2_ptr2 + size + (size >> 2),			     PRP_SOURCE_CR_PTR);	}	__raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B2, PRP_CNTL);	return 0;}/*! * @brief Build CSC table * @param csc	CSC table *		in	csc[0]=index		0..3 : A.1 A.0 B.1 B.0 *			csc[1]=direction	0 : YUV2RGB  1 : RGB2YUV *		out	csc[0..4] are coefficients c[9] is offset *			csc[0..8] are coefficients c[9] is offset */void csc_tbl(short csc[10]){	static const unsigned short _r2y[][9] = {		{0x4D, 0x4B, 0x3A, 0x57, 0x55, 0x40, 0x40, 0x6B, 0x29},		{0x42, 0x41, 0x32, 0x4C, 0x4A, 0x38, 0x38, 0x5E, 0x24},		{0x36, 0x5C, 0x25, 0x3B, 0x63, 0x40, 0x40, 0x74, 0x18},		{0x2F, 0x4F, 0x20, 0x34, 0x57, 0x38, 0x38, 0x66, 0x15},	};	static const unsigned short _y2r[][5] = {		{0x80, 0xb4, 0x2c, 0x5b, 0x0e4},		{0x95, 0xcc, 0x32, 0x68, 0x104},		{0x80, 0xca, 0x18, 0x3c, 0x0ec},		{0x95, 0xe5, 0x1b, 0x44, 0x1e0},	};	unsigned short *_csc;	int _csclen;	csc[9] = csc[0] & 1;	_csclen = csc[0] & 3;	if (csc[1]) {		_csc = (unsigned short *)_r2y[_csclen];		_csclen = sizeof(_r2y[0]);	} else {		_csc = (unsigned short *)_y2r[_csclen];		_csclen = sizeof(_y2r[0]);		memset(csc + 5, 0, sizeof(short) * 4);	}	memcpy(csc, _csc, _csclen);}/*! * @brief Setup PrP resize coefficient registers * * @param ch	PrP channel number * @param dir	Direction, 0 - horizontal, 1 - vertical * @param scale	The pointer to scale_t structure */static void prp_set_scaler(int ch, int dir, scale_t * scale){	int i;	unsigned int coeff[2];	unsigned int valid;	for (coeff[0] = coeff[1] = valid = 0, i = 19; i >= 0; i--) {		int j;		j = i > 9 ? 1 : 0;		coeff[j] = (coeff[j] << BC_COEF) |		    (scale->tbl[i] & (SZ_COEF - 1));		if (i == 5 || i == 15)			coeff[j] <<= 1;		valid = (valid << 1) | (scale->tbl[i] >> BC_COEF);	}	valid |= (scale->len << 24) | ((2 - scale->algo) << 31);	for (i = 0; i < 2; i++)		(*PRP_RSZ_COEFF)[1 - ch][dir].coeff[i] = coeff[i];	(*PRP_RSZ_COEFF)[1 - ch][dir].cntl = valid;}/*! * @brief Setup PrP registers relevant to input. * @param cfg		Pointer to PrP configuration parameter * @param prp_cntl	Holds the value for PrP control register * @return		Zero on success, others on failure */static int prphw_input_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){	unsigned long mask;	switch (cfg->in_pix) {	case PRP_PIXIN_YUV420:		*prp_cntl |= PRP_CNTL_IN_YUV420;		mask = 0x7;		break;	case PRP_PIXIN_YUYV:	case PRP_PIXIN_YVYU:	case PRP_PIXIN_UYVY:	case PRP_PIXIN_VYUY:		*prp_cntl |= PRP_CNTL_IN_YUV422;		mask = 0x1;		break;	case PRP_PIXIN_RGB565:		*prp_cntl |= PRP_CNTL_IN_RGB16;		mask = 0x1;		break;	case PRP_PIXIN_RGB888:		*prp_cntl |= PRP_CNTL_IN_RGB32;		mask = 0;		break;	default:		pr_debug("Unsupported input pix format 0x%08X\n", cfg->in_pix);		return -1;	}	/* align the input image width */	if (cfg->in_width & mask) {		pr_debug("in_width misaligned. in_width=%d\n", cfg->in_width);		return -1;	}	if ((cfg->in_width < PRP_MIN_IN_WIDTH)	    || (cfg->in_width > PRP_MAX_IN_WIDTH)) {		pr_debug("Unsupported input width %d\n", cfg->in_width);		return -1;	}	cfg->in_height &= ~1;	/* truncate to make even */	if ((cfg->in_height < PRP_MIN_IN_HEIGHT)	    || (cfg->in_height > PRP_MAX_IN_HEIGHT)) {		pr_debug("Unsupported input height %d\n", cfg->in_height);		return -1;	}	if (!(cfg->in_csi & PRP_CSI_EN))		if (!cfg->in_line_stride)			cfg->in_line_stride = cfg->in_width;	__raw_writel(cfg->in_pix, PRP_SRC_PIXEL_FORMAT_CNTL);	__raw_writel((cfg->in_width << 16) | cfg->in_height,		     PRP_SOURCE_FRAME_SIZE);	__raw_writel((cfg->in_line_skip << 16) | cfg->in_line_stride,		     PRP_SOURCE_LINE_STRIDE);	if (!(cfg->in_csi & PRP_CSI_EN)) {		__raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR);		if (cfg->in_pix == PRP_PIXIN_YUV420) {			unsigned int size;			size = cfg->in_line_stride * cfg->in_height;			__raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR);			__raw_writel(cfg->in_ptr + size + (size >> 2),				     PRP_SOURCE_CR_PTR);		}	}	/* always cropping */	*prp_cntl |= PRP_CNTL_WINEN;	/* color space conversion */	if (!cfg->in_csc[1]) {		if (cfg->in_csc[0] > 3) {			pr_debug("in_csc invalid 0x%X\n", cfg->in_csc[0]);			return -1;		}		if ((cfg->in_pix == PRP_PIXIN_RGB565)		    || (cfg->in_pix == PRP_PIXIN_RGB888))			cfg->in_csc[1] = 1;		else			cfg->in_csc[0] = 0;		csc_tbl(cfg->in_csc);	}	__raw_writel((cfg->in_csc[0] << 21) | (cfg->in_csc[1] << 11)		     | cfg->in_csc[2], PRP_CSC_COEF_012);	__raw_writel((cfg->in_csc[3] << 21) | (cfg->in_csc[4] << 11)		     | cfg->in_csc[5], PRP_CSC_COEF_345);	__raw_writel((cfg->in_csc[6] << 21) | (cfg->in_csc[7] << 11)		     | cfg->in_csc[8] | (cfg->in_csc[9] << 31),		     PRP_CSC_COEF_678);	if (cfg->in_csi & PRP_CSI_EN) {		*prp_cntl |= PRP_CNTL_CSI;		/* loop mode enable, ch1 ch2 together */		if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP)			*prp_cntl |= (PRP_CNTL_CH1_LOOP | PRP_CNTL_CH2_LOOP);	}	return 0;}/*! * @brief Setup PrP registers relevant to channel 2. * @param cfg		Pointer to PrP configuration parameter * @param prp_cntl	Holds the value for PrP control register * @return		Zero on success, others on failure */static int prphw_ch2_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){	switch (cfg->ch2_pix) {	case PRP_PIX2_YUV420:		*prp_cntl |= PRP_CNTL_CH2_YUV420;		break;	case PRP_PIX2_YUV422:		*prp_cntl |= PRP_CNTL_CH2_YUV422;		break;	case PRP_PIX2_YUV444:		*prp_cntl |= PRP_CNTL_CH2_YUV444;		break;	case PRP_PIX2_UNUSED:		return 0;	default:		pr_debug("Unsupported channel 2 pix format 0x%08X\n",			 cfg->ch2_pix);		return -1;	}	if (cfg->ch2_pix == PRP_PIX2_YUV420) {		cfg->ch2_height &= ~1;	/* ensure U/V presence */		cfg->ch2_width &= ~7;	/* ensure U/V word aligned */	} else if (cfg->ch2_pix == PRP_PIX2_YUV422) {		cfg->ch2_width &= ~1;	/* word aligned */	}	__raw_writel((cfg->ch2_width << 16) | cfg->ch2_height,		     PRP_CH2_OUT_IMAGE_SIZE);	if (cfg->ch2_pix == PRP_PIX2_YUV420) {		u32 size;		/* Luminanance band start address */		__raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR);		if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {			if (!cfg->ch2_ptr2)				__raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR);			else				__raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR);		}		/* Cb and Cr band start address */		size = cfg->ch2_width * cfg->ch2_height;		__raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR);		__raw_writel(cfg->ch2_ptr + size + (size >> 2),			     PRP_DEST_CR_PTR);		if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {			if (!cfg->ch2_ptr2) {				__raw_writel(cfg->ch2_ptr + size,					     PRP_SOURCE_CB_PTR);				__raw_writel(cfg->ch2_ptr + size + (size >> 2),					     PRP_SOURCE_CR_PTR);			} else {				__raw_writel(cfg->ch2_ptr2 + size,					     PRP_SOURCE_CB_PTR);				__raw_writel(cfg->ch2_ptr2 + size + (size >> 2),					     PRP_SOURCE_CR_PTR);			}		}	} else {		/* Pixel interleaved YUV422 or YUV444 */		__raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR);		if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {			if (!cfg->ch2_ptr2)				__raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR);			else				__raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR);		}	}	*prp_cntl |= PRP_CNTL_CH2B1 | PRP_CNTL_CH2B2;	return 0;}/*! * @brief Setup PrP registers relevant to channel 1. * @param cfg		Pointer to PrP configuration parameter * @param prp_cntl	Holds the value for PrP control register * @return		Zero on success, others on failure */static int prphw_ch1_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){	int ch1_bpp = 0;	switch (cfg->ch1_pix) {	case PRP_PIX1_RGB332:		*prp_cntl |= PRP_CNTL_CH1_RGB8;		ch1_bpp = 1;		break;	case PRP_PIX1_RGB565:		*prp_cntl |= PRP_CNTL_CH1_RGB16;		ch1_bpp = 2;		break;	case PRP_PIX1_RGB888:		*prp_cntl |= PRP_CNTL_CH1_RGB32;		ch1_bpp = 4;		break;	case PRP_PIX1_YUYV:	case PRP_PIX1_YVYU:	case PRP_PIX1_UYVY:	case PRP_PIX1_VYUY:		*prp_cntl |= PRP_CNTL_CH1_YUV422;		ch1_bpp = 2;		break;	case PRP_PIX1_UNUSED:		return 0;	default:		pr_debug("Unsupported channel 1 pix format 0x%08X\n",			 cfg->ch1_pix);		return -1;	}	/* parallel or cascade resize */	if (cfg->ch1_scale.algo & PRP_ALGO_BYPASS)		*prp_cntl |= PRP_CNTL_UNCHAIN;	/* word align */	if (ch1_bpp == 2)		cfg->ch1_width &= ~1;	else if (ch1_bpp == 1)		cfg->ch1_width &= ~3;	if (!cfg->ch1_stride)		cfg->ch1_stride = cfg->ch1_width;	__raw_writel(cfg->ch1_pix, PRP_CH1_PIXEL_FORMAT_CNTL);	__raw_writel((cfg->ch1_width << 16) | cfg->ch1_height,		     PRP_CH1_OUT_IMAGE_SIZE);//#ifdef CONFIG_MXC_TVIN_TVP5150	// gary modify#if defined(CONFIG_MXC_TVIN_TVP5150) || defined(CONFIG_MXC_TVIN_TVP5150_MODULE)	__raw_writel(cfg->ch1_stride * ch1_bpp * 2, PRP_CH1_LINE_STRIDE);#else		__raw_writel(cfg->ch1_stride * ch1_bpp , PRP_CH1_LINE_STRIDE);#endif	__raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR);//#ifdef CONFIG_MXC_TVIN_TVP5150	// gary modify#if defined(CONFIG_MXC_TVIN_TVP5150) || defined(CONFIG_MXC_TVIN_TVP5150_MODULE)	if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {			__raw_writel(cfg->ch1_ptr + cfg->ch1_stride*ch1_bpp,					 PRP_DEST_RGB2_PTR);	}#else	/* double buffer for loop mode */	if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {		if (cfg->ch1_ptr2)			__raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);		else			__raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR);	}#endif		return 0;}/*! * @brief Setup PrP registers. * @param cfg	Pointer to PrP configuration parameter * @return	Zero on success, others on failure */int prphw_cfg(emma_prp_cfg * cfg){	unsigned long prp_cntl = 0;	unsigned long val;	/* input pixel format checking */	if (prphw_input_cfg(cfg, &prp_cntl))		return -1;	if (prphw_ch2_cfg(cfg, &prp_cntl))		return -1;	if (prphw_ch1_cfg(cfg, &prp_cntl))		return -1;	/* register setting */	__raw_writel(prp_cntl, PRP_CNTL);	/* interrupt configuration */	val = PRP_INTRCNTL_RDERR | PRP_INTRCNTL_LBOVF;	if (cfg->ch1_pix != PRP_PIX1_UNUSED)		val |= PRP_INTRCNTL_CH1FC | PRP_INTRCNTL_CH1WERR;	if (cfg->ch2_pix != PRP_PIX2_UNUSED)		val |=		    PRP_INTRCNTL_CH2FC | PRP_INTRCNTL_CH2WERR |		    PRP_INTRCNTL_CH2OVF;	__raw_writel(val, PRP_INTRCNTL);	prp_set_scaler(1, 0, &cfg->scale[0]);	/* Channel 1 width */	prp_set_scaler(1, 1, &cfg->scale[1]);	/* Channel 1 height */	prp_set_scaler(0, 0, &cfg->scale[2]);	/* Channel 2 width */	prp_set_scaler(0, 1, &cfg->scale[3]);	/* Channel 2 height */	return 0;}/*! * @brief Check PrP interrupt status. * @return	PrP interrupt status */int prphw_isr(void){	int status;	status = __raw_readl(PRP_INTRSTATUS) & 0x1FF;	if (status & (PRP_INTRSTAT_RDERR | PRP_INTRSTAT_CH1WERR |		      PRP_INTRSTAT_CH2WERR))		pr_debug("isr bus error. status= 0x%08X\n", status);	else if (status & PRP_INTRSTAT_CH2OVF)		pr_debug("isr ch 2 buffer overflow. status= 0x%08X\n", status);	else if (status & PRP_INTRSTAT_LBOVF)		pr_debug("isr line buffer overflow. status= 0x%08X\n", status);	/* silicon bug?? enable bit does not self clear? */	if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH1_LOOP))		__raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH1EN),			     PRP_CNTL);	if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH2_LOOP))		__raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH2EN),			     PRP_CNTL);	__raw_writel(status, PRP_INTRSTATUS);	/* clr irq */	return status;}static struct clk *emma_clk;/*! * @brief  PrP module clock enable */void prphw_init(void){	emma_clk = clk_get(NULL, "emma_clk");	clk_enable(emma_clk);}/*! * @brief PrP module clock disable */void prphw_exit(void){	clk_disable(emma_clk);	clk_put(emma_clk);}

⌨️ 快捷键说明

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