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

📄 camif.c

📁 用于三星S3C2440A和S3C24A0A的VGA或SXGA驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   Copyright (C) 2004 Samsung Electronics  *       SW.LEE <hitchcar@samsung.com> *    * This file is subject to the terms and conditions of the GNU General Public * License 2. See the file COPYING in the main directory of this archive * for more details. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/irq.h>#include <linux/tqueue.h>#include <linux/locks.h>#include <linux/completion.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/miscdevice.h>#include <linux/wait.h>#include <linux/miscdevice.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/hardware.h>#include <asm/uaccess.h>#ifdef CONFIG_ARCH_S3C24A0A#include <asm/arch/S3C24A0.h>#include <asm/arch/clocks.h>#else#include <asm/arch/S3C2440.h>#include <asm/arch/clocks.h>#endif#include "cam_reg.h"//#define SW_DEBUG#include "camif.h"#include "videodev.h"#include "miscdevice.h"static int camif_dma_burst(camif_cfg_t *);static int camif_scaler(camif_cfg_t *);static const char *camif_version =        "$Id: camif.c,v 1.10 2004/06/04 04:24:14 swlee Exp $";	/* For SXGA Image */#define RESERVE_MEM  15*1024*1024#define YUV_MEM      10*1024*1024#define RGB_MEM      (RESERVE_MEM - YUV_MEM)static int camif_malloc(camif_cfg_t *cfg){	unsigned int t_size;	unsigned int daon = cfg->target_x *cfg->target_y;	if(cfg->dma_type & CAMIF_CODEC) {		if (cfg->fmt & CAMIF_OUT_YCBCR420) {			t_size = daon * 3 / 2 ;		}		else  { t_size = daon * 2; /* CAMIF_OUT_YCBCR422 */ }		t_size = t_size *cfg->pp_num;#ifndef SAMSUNG_SXGA_CAM		cfg->pp_virt_buf = consistent_alloc(GFP_KERNEL, t_size, &cfg->pp_phys_buf);#else		printk(KERN_INFO "Reserving High RAM Addresses \n");		cfg->pp_phys_buf = PHYS_OFFSET + (MEM_SIZE - RESERVE_MEM);		cfg->pp_virt_buf = ioremap_nocache(cfg->pp_phys_buf,YUV_MEM);#endif		if ( !cfg->pp_virt_buf ) {			printk(KERN_ERR"CAMERA:Failed to request YCBCR MEM\n");			return -ENOMEM;		}		memset(cfg->pp_virt_buf, 0, t_size);		cfg->pp_totalsize = t_size;		return 0;	}	if ( cfg->dma_type & CAMIF_PREVIEW ) {		if (cfg->fmt & CAMIF_RGB16) 			t_size = daon * 2; /*  4byte per two pixel*/		else {			assert(cfg->fmt & CAMIF_RGB24);			t_size = daon * 4; /* 4byte per one pixel */		}		t_size = t_size * cfg->pp_num;#ifndef SAMSUNG_SXGA_CAM		cfg->pp_virt_buf = consistent_alloc(GFP_KERNEL, t_size, &cfg->pp_phys_buf);#else		printk(KERN_INFO "Reserving High RAM Addresses \n");		cfg->pp_phys_buf = PHYS_OFFSET + (MEM_SIZE - RESERVE_MEM ) + YUV_MEM;		cfg->pp_virt_buf = ioremap_nocache(cfg->pp_phys_buf,RGB_MEM);#endif		if ( !cfg->pp_virt_buf ) { 			printk(KERN_ERR"CAMERA:Failed to request RGB MEM\n");			return -ENOMEM;		}		memset(cfg->pp_virt_buf, 0, t_size);		cfg->pp_totalsize = t_size;		return 0;	}	return 0;		/* Never come. */}static int camif_demalloc(camif_cfg_t *cfg){#ifndef SAMSUNG_SXGA_CAM	if ( cfg->pp_virt_buf ) {		consistent_free(cfg->pp_virt_buf,cfg->pp_totalsize,cfg->pp_phys_buf);		cfg->pp_virt_buf = 0;	}#else	iounmap(cfg->pp_virt_buf);	cfg->pp_virt_buf = 0;#endif	return 0;}/*  * advise a person to use this func in ISR  * index value indicates the next frame count to be used  */int camif_g_frame_num(camif_cfg_t *cfg){	int index = 0;	if (cfg->dma_type & CAMIF_CODEC ) {		index = FRAME_CNT(CICOSTATUS);		DPRINTK("CAMIF_CODEC frame %d \n", index);	}	else {		assert(cfg->dma_type & CAMIF_PREVIEW );		index = FRAME_CNT(CIPRSTATUS);		DPRINTK("CAMIF_PREVIEW frame %d  0x%08X \n", index, CIPRSTATUS);	}	cfg->now_frame_num = (index + 2) % 4; /* When 4 PingPong */	return index; /* meaningless */}static int camif_pp_codec(camif_cfg_t *cfg){	u32 i, c_size; /* Cb,Cr size */	u32 one_p_size;	u32 daon = cfg->target_x * cfg->target_y;	if (cfg->fmt & CAMIF_OUT_YCBCR420) {		c_size = daon /4;	}	else {		assert(cfg->fmt & CAMIF_OUT_YCBCR422);		c_size = daon /2;	}	switch ( cfg->pp_num ) {		case 1 :			for ( i =0 ; i < 4; i=i+1) {				cfg->img_buf[i].virt_y = cfg->pp_virt_buf;				cfg->img_buf[i].phys_y = cfg->pp_phys_buf;				cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon; 				cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon;				cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size;				cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size;				CICOYSA(i)  =  cfg->img_buf[i].phys_y;				CICOCBSA(i) =  cfg->img_buf[i].phys_cb;				CICOCRSA(i) =  cfg->img_buf[i].phys_cr;			}			break;		case 2:#define  TRY   (( i%2 ) ? 1 :0)			one_p_size = daon + 2*c_size;			for (i = 0; i < 4  ; i++) {				cfg->img_buf[i].virt_y = cfg->pp_virt_buf + TRY * one_p_size;				cfg->img_buf[i].phys_y = cfg->pp_phys_buf + TRY * one_p_size;				cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon + TRY * one_p_size;				cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon + TRY * one_p_size;				cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size + TRY * one_p_size;				cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size + TRY * one_p_size;				CICOYSA(i)  = cfg->img_buf[i].phys_y;				CICOCBSA(i) = cfg->img_buf[i].phys_cb;				CICOCRSA(i) = cfg->img_buf[i].phys_cr;			}			break;		case 4: 			one_p_size = daon + 2*c_size;			for (i = 0; i < 4 ; i++) {				cfg->img_buf[i].virt_y = cfg->pp_virt_buf + i * one_p_size;				cfg->img_buf[i].phys_y = cfg->pp_phys_buf + i * one_p_size;				cfg->img_buf[i].virt_cb = cfg->pp_virt_buf + daon + i * one_p_size;				cfg->img_buf[i].phys_cb = cfg->pp_phys_buf + daon + i * one_p_size;				cfg->img_buf[i].virt_cr = cfg->pp_virt_buf + daon + c_size + i * one_p_size;				cfg->img_buf[i].phys_cr = cfg->pp_phys_buf + daon + c_size + i * one_p_size;				CICOYSA(i)  =  cfg->img_buf[i].phys_y;				CICOCBSA(i) =  cfg->img_buf[i].phys_cb;				CICOCRSA(i) =  cfg->img_buf[i].phys_cr;			}			break;		default:			printk("Invalid PingPong Number %d \n",cfg->pp_num);			panic("halt\n");	}	return 0;}/* RGB Buffer Allocation */static int camif_pp_preview(camif_cfg_t *cfg){	int i;	u32 daon = cfg->target_x * cfg->target_y;	if(cfg->fmt & CAMIF_RGB24)  		daon = daon * 4 ;	else {		assert (cfg->fmt & CAMIF_RGB16);		daon = daon *2;	}  	switch ( cfg->pp_num ) {		case 1:			for ( i = 0; i < 4 ; i++ ) {				cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf ;				cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf ;				CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb;			}			break;		case 2:			for ( i = 0; i < 4 ; i++) {				cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf + TRY * daon;				cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf + TRY * daon;				CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb;			}			break;		case 4:			for ( i = 0; i < 4 ; i++) {				cfg->img_buf[i].virt_rgb = cfg->pp_virt_buf + i * daon;				cfg->img_buf[i].phys_rgb = cfg->pp_phys_buf + i * daon;				CIPRCLRSA(i) = cfg->img_buf[i].phys_rgb;			}			break;		default:			printk("Invalid PingPong Number %d \n",cfg->pp_num);			panic("halt\n");	}	return 0;}static int camif_pingpong(camif_cfg_t *cfg){	if (cfg->dma_type & CAMIF_CODEC ) {		camif_pp_codec(cfg);	}	if ( cfg->dma_type & CAMIF_PREVIEW) {		camif_pp_preview(cfg);	}	return 0;}/***********       Image Convert *******************************//*  Return Format  *  Supported by Hardware *  V4L2_PIX_FMT_YUV420, *  V4L2_PIX_FMT_YUV422P, *  V4L2_PIX_FMT_BGR32 (BGR4) * ----------------------------------- *  V4L2_PIX_FMT_RGB565(X)  *  Currenly 2byte --> BGR656 Format *  S3C2440A,S3C24A0 supports vairants with reversed FMT_RGB565     i.e  blue toward the least, red towards the most significant bit     --  by SW.LEE *//*  * After calling camif_g_frame_num, * this func must be called  */u8 * camif_g_frame(camif_cfg_t *cfg){	u8 * ret = NULL;	int cnt = cfg->now_frame_num;	if(cfg->dma_type & CAMIF_PREVIEW) {		ret = cfg->img_buf[cnt].virt_rgb;	}	if (cfg->dma_type & CAMIF_CODEC) {		ret = cfg->img_buf[cnt].virt_y;	}	return ret;}/* This function must be called in module initial time */static int camif_source_fmt(camif_gc_t *gc) {	u32 cmd = 0;	/* Configure CISRCFMT --Source Format */	if (gc->itu_fmt & CAMIF_ITU601) {		cmd = CAMIF_ITU601;	}	else {		assert ( gc->itu_fmt & CAMIF_ITU656);		cmd = CAMIF_ITU656;	}	cmd  |= SOURCE_HSIZE(gc->source_x)| SOURCE_VSIZE(gc->source_y);	/* Order422 */	cmd |=  gc->order422;	CISRCFMT = cmd;	return 0 ;}/*  * Codec Input YCBCR422 will be Fixed  */static int camif_target_fmt(camif_cfg_t *cfg){	u32 cmd = 0;	if (cfg->dma_type & CAMIF_CODEC) {		/* YCBCR setting */  		cmd = TARGET_HSIZE(cfg->target_x)| TARGET_VSIZE(cfg->target_y);		if ( cfg->fmt & CAMIF_OUT_YCBCR420 ) {			cmd |= OUT_YCBCR420|IN_YCBCR422;		}		else { 			assert(cfg->fmt & CAMIF_OUT_YCBCR422);			cmd |= OUT_YCBCR422|IN_YCBCR422;		}		CICOTRGFMT = cmd | cfg->flip;	} 	else {		assert(cfg->dma_type & CAMIF_PREVIEW);		CIPRTRGFMT = 			TARGET_HSIZE(cfg->target_x)|TARGET_VSIZE(cfg->target_y)|cfg->flip;	}	return 0;}void camif_change_flip(camif_cfg_t *cfg){	u32 cmd = 0;	if (cfg->dma_type & CAMIF_CODEC ) {		/* YCBCR setting */  		cmd  = CICOTRGFMT;		cmd &= ~(BIT14|BIT15); /* Clear FLIP Mode */		cmd |= cfg->flip; 		CICOTRGFMT = cmd;	} 	else {		cmd  = CIPRTRGFMT;		cmd &= ~(BIT14|BIT15);		cmd |= cfg->flip;		CICOTRGFMT = cmd; 	}}/* Must: * Before calling this function, * you must use "camif_dynamic_open" * If you want to enable both CODEC and preview *  you must do it at the same time. */int camif_capture_start(camif_cfg_t *cfg){	u32 n_cmd = 0;		/* Next Command */	switch(cfg->exec) {		case CAMIF_BOTH_DMA_ON:			camif_reset(CAMIF_RESET,0); /* Flush Camera Core Buffer */					CIPRSCCTRL |= SCALERSTART;			CICOSCCTRL |= SCALERSTART;			n_cmd = CAMIF_CAP_PREVIEW_ON|CAMIF_CAP_CODEC_ON;			break;		case CAMIF_DMA_ON:			camif_reset(CAMIF_RESET,0); /* Flush Camera Core Buffer */					if (cfg->dma_type&CAMIF_CODEC) {				CICOSCCTRL |= SCALERSTART;				n_cmd = CAMIF_CAP_CODEC_ON;			}else {				CIPRSCCTRL |= SCALERSTART;				n_cmd = CAMIF_CAP_PREVIEW_ON;			}			/* wait until Sync Time expires */			/* First settting, to wait VSYNC fall  */			/* By VESA spec,in 640x480 @60Hz 			   MAX Delay Time is around 64us which "while" has.*/ 			while(VSYNC & CICOSTATUS);			break;		default:			break;	}	CIIMGCPT = n_cmd|CAMIF_CAP_ON;	return 0;}int camif_capture_stop(camif_cfg_t *cfg){	u32 n_cmd = CIIMGCPT;	/* Next Command */	switch(cfg->exec) {		case CAMIF_BOTH_DMA_OFF:			CIPRSCCTRL &= ~SCALERSTART;			CICOSCCTRL &= ~SCALERSTART;			n_cmd = 0;			break;		case CAMIF_DMA_OFF_L_IRQ: /* fall thru */		case CAMIF_DMA_OFF:			if (cfg->dma_type&CAMIF_CODEC) {				CICOSCCTRL &= ~SCALERSTART;				n_cmd &= ~CAMIF_CAP_CODEC_ON;				if (!(n_cmd & CAMIF_CAP_PREVIEW_ON))					n_cmd = 0;			}else {				CIPRSCCTRL &= ~SCALERSTART;				n_cmd &= ~CAMIF_CAP_PREVIEW_ON;				if (!(n_cmd & CAMIF_CAP_CODEC_ON))					n_cmd = 0;			}			break;		default:			panic("Unexpected \n");	}	CIIMGCPT = n_cmd;	if(cfg->exec == CAMIF_DMA_OFF_L_IRQ) { /* Last IRQ  */		if (cfg->dma_type & CAMIF_CODEC) 			CICOCTRL |= LAST_IRQ_EN;		else 			CIPRCTRL |= LAST_IRQ_EN;	} #if 0	else {				/* to make internal state machine of CAMERA stop */		camif_reset(CAMIF_RESET, 0);	}#endif	return 0;}/* LastIRQEn is autoclear */void camif_last_irq_en(camif_cfg_t *cfg){	if(cfg->exec == CAMIF_BOTH_DMA_ON) {		CIPRCTRL |= LAST_IRQ_EN;		CICOCTRL |= LAST_IRQ_EN;	}	else {		if (cfg->dma_type & CAMIF_CODEC) 			CICOCTRL |= LAST_IRQ_EN;		else 			CIPRCTRL |= LAST_IRQ_EN;	}}static int  camif_scaler_internal(u32 srcWidth, u32 dstWidth, u32 *ratio, u32 *shift){	if(srcWidth>=64*dstWidth){		printk(KERN_ERR"CAMERA:out of prescaler range: srcWidth /dstWidth = %d(< 64)\n",			 srcWidth/dstWidth);		return 1;	}	else if(srcWidth>=32*dstWidth){		*ratio=32;		*shift=5;	}	else if(srcWidth>=16*dstWidth){		*ratio=16;		*shift=4;	}	else if(srcWidth>=8*dstWidth){		*ratio=8;		*shift=3;	}	else if(srcWidth>=4*dstWidth){		*ratio=4;		*shift=2;	}	else if(srcWidth>=2*dstWidth){		*ratio=2;		*shift=1;

⌨️ 快捷键说明

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