📄 pxa_camera.c
字号:
/* pxa_camera - main file for camera driver Copyright (C) 2003, Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Code Status: 2004/10/19: Yan Yin <yan.yin@intel.com> - Ported to 2.6 kernel - Made camera driver a loadable module*/ #include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/ctype.h>#include <linux/pagemap.h>#include <linux/interrupt.h>#include <linux/videodev.h>#include <linux/pci.h>#include <linux/pm.h>#include <linux/poll.h>#include <linux/wait.h>#include <linux/cpufreq.h>#include <linux/types.h>#include <asm/mach-types.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/hardware.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/arch/irqs.h>#include <asm/arch/pxa-regs.h>#include "camera.h"#include "ci.h"#if defined (CONFIG_MACH_MAINSTONE) && !defined(CONFIG_ARCH_FS_PXA27X) //hzh#define ADCM2650#elif defined(CONFIG_ARCH_FS_PXA27X) //hzh#define OV9650#else#define OV9640#endif#ifdef ADCM2650#include "adcm2650.h"#include "adcm2650_hw.h"#endif#ifdef OV9640#include "ov9640.h"#include "ov9640_hw.h"#endif#ifdef OV9650 //hzh#include "ov9650.h"//#include "ov9650_hw.h"#endif#define CIBR0_PHY (0x50000000 + 0x28)#define CIBR1_PHY (0x50000000 + 0x30)#define CIBR2_PHY (0x50000000 + 0x38)#ifdef ADCM2650#define MAX_WIDTH 480#define MAX_HEIGHT 640#define MIN_WIDTH 72#define MIN_HEIGHT 72#endif#ifdef OV9640#define MAX_WIDTH 640#define MAX_HEIGHT 480#define MIN_WIDTH 88#define MIN_HEIGHT 72#endif#ifdef OV9650 //hzh#define MAX_WIDTH 1280#define MAX_HEIGHT 1024#define MIN_WIDTH 88#define MIN_HEIGHT 72#endif#define WIDTH_DEFT 176#define HEIGHT_DEFT 144#define FRAMERATE_DEFT 0x0#define BUF_SIZE_DEFT 0xEA600//0xE1000 //hzh#define SINGLE_DESC_TRANS_MAX 8000#define MAX_DESC_NUM 0x400#define MAX_BLOCK_NUM 20/* * Buffer Size Calculate Formula * Buffer_Size = Page_Align (Max(window_size(VGA), window_size(CIF)*3) * Max(BPP)) * Buffer_Size = Page_Align (Max ((640 * 480), (352 * 288 *3)) * 3) = 0xE1000 */static camera_context_t *g_camera_context = NULL;struct device *g_camera_device;#ifdef ADCM2650static camera_function_t adcm2650_func;#endif#ifdef OV9640static camera_function_t ov9640_func;#endif#ifdef OV9650 //hzhstatic camera_function_t ov9650_func;#endifwait_queue_head_t camera_wait_q; /* /dev/videoX registration number */static int minor = 0;int ci_dma_y;int ci_dma_cb;int ci_dma_cr;volatile int task_waiting = 0;static int still_image_mode = 0;static int still_image_rdy = 0;static int first_video_frame = 0;void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs);void pxa_ci_dma_irq_cb(int channel, void *data, struct pt_regs *regs);void pxa_ci_dma_irq_cr(int channel, void *data, struct pt_regs *regs);static unsigned long ci_regs_base = 0; /* for CI registers IOMEM mapping */#define CI_REG(x) (* (volatile u32*)(x) )#define CI_REG_SIZE 0x40 /* 0x5000_0000 --- 0x5000_0038 * 64K */#define CI_REGS_PHYS 0x50000000 /* Start phyical address of CI registers *//*********************************************************************** * * Declarations * ***********************************************************************/// map of camera image format (camera.h) ==> capture interface format (ci.h)static const CI_IMAGE_FORMAT FORMAT_MAPPINGS[] = { CI_RAW8, //RAW CI_RAW9, CI_RAW10, CI_RGB444, //RGB CI_RGB555, CI_RGB565, CI_RGB666_PACKED, //RGB Packed CI_RGB666, CI_RGB888_PACKED, CI_RGB888, CI_RGBT555_0, //RGB+Transparent bit 0 CI_RGBT888_0, CI_RGBT555_1, //RGB+Transparent bit 1 CI_RGBT888_1, CI_INVALID_FORMAT, CI_YCBCR422, //YCBCR CI_YCBCR422_PLANAR, //YCBCR Planaried CI_INVALID_FORMAT, CI_INVALID_FORMAT};static int update_dma_chain( p_camera_context_t camera_context );static void start_dma_transfer( p_camera_context_t camera_context, unsigned block_id );static void stop_dma_transfer( p_camera_context_t camera_context );static int start_capture( p_camera_context_t camera_context, unsigned int block_id, unsigned int frames );void pxa_dma_repeat(camera_context_t *cam_ctx);void pxa_dma_continue(camera_context_t *cam_ctx);/*********************************************************************** * * Private functions * ***********************************************************************//*Generate dma descriptorsPre-condition: these variables must be set properly block_number, fifox_transfer_size dma_descriptors_virtual, dma_descriptors_physical, dma_descirptors_sizePost-condition: these variables will be set fifox_descriptors_virtual, fifox_descriptors_physical fifox_num_descriptors */int update_dma_chain( p_camera_context_t camera_context ){ pxa_dma_desc *cur_des_virtual, *cur_des_physical, *last_des_virtual = NULL; int des_transfer_size, remain_size; unsigned int i,j; int target_physical; int target_virtual; // clear descriptor pointers camera_context->fifo0_descriptors_virtual = camera_context->fifo0_descriptors_physical = 0; camera_context->fifo1_descriptors_virtual = camera_context->fifo1_descriptors_physical = 0; camera_context->fifo2_descriptors_virtual = camera_context->fifo2_descriptors_physical = 0; // calculate how many descriptors are needed per frame camera_context->fifo0_num_descriptors = ( camera_context->fifo0_transfer_size + SINGLE_DESC_TRANS_MAX -1 ) / SINGLE_DESC_TRANS_MAX; camera_context->fifo1_num_descriptors = ( camera_context->fifo1_transfer_size + SINGLE_DESC_TRANS_MAX -1 ) / SINGLE_DESC_TRANS_MAX; camera_context->fifo2_num_descriptors = ( camera_context->fifo2_transfer_size + SINGLE_DESC_TRANS_MAX -1 ) / SINGLE_DESC_TRANS_MAX; // check if enough memory to generate descriptors if ( (camera_context->fifo0_num_descriptors + camera_context->fifo1_num_descriptors + camera_context->fifo2_num_descriptors) * camera_context->block_number > camera_context->dma_descriptors_size) return -1; // generate fifo0 dma chains camera_context->fifo0_descriptors_virtual = (unsigned)camera_context->dma_descriptors_virtual; camera_context->fifo0_descriptors_physical = (unsigned)camera_context->dma_descriptors_physical; cur_des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual; cur_des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical; for(i=0; i<camera_context->block_number; i++) { // in each iteration, generate one dma chain for one frame remain_size = camera_context->fifo0_transfer_size; // assume the blocks are stored consecutively target_physical = (unsigned)camera_context->buffer_physical + camera_context->block_size * i; target_virtual = (unsigned)camera_context->buffer_virtual + camera_context->block_size * i; for(j=0; j<camera_context->fifo0_num_descriptors; j++) { // set descriptor if (remain_size > SINGLE_DESC_TRANS_MAX) des_transfer_size = SINGLE_DESC_TRANS_MAX; else des_transfer_size = remain_size; cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); cur_des_virtual->dsadr = CIBR0_PHY; // FIFO0 physical address cur_des_virtual->dtadr = target_physical; cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; // advance pointers remain_size -= des_transfer_size; cur_des_virtual++; cur_des_physical++; target_physical += des_transfer_size; target_virtual += des_transfer_size; } // stop the dma transfer on one frame captured last_des_virtual = cur_des_virtual - 1; //last_des_virtual->ddadr |= 0x1; } last_des_virtual->ddadr = ((unsigned)camera_context->fifo0_descriptors_physical); // generate fifo1 dma chains if (camera_context->fifo1_transfer_size) { // record fifo1 descriptors' start address camera_context->fifo1_descriptors_virtual = (unsigned)cur_des_virtual; camera_context->fifo1_descriptors_physical = (unsigned)cur_des_physical; for(i=0; i<camera_context->block_number; i++) { // in each iteration, generate one dma chain for one frame remain_size = camera_context->fifo1_transfer_size; // assume the blocks are stored consecutively target_physical = (unsigned)camera_context->buffer_physical + camera_context->block_size * i + camera_context->fifo0_transfer_size; target_virtual = (unsigned)camera_context->buffer_virtual + camera_context->block_size * i + camera_context->fifo0_transfer_size; for(j=0; j<camera_context->fifo1_num_descriptors; j++) { // set descriptor if (remain_size > SINGLE_DESC_TRANS_MAX) des_transfer_size = SINGLE_DESC_TRANS_MAX; else des_transfer_size = remain_size; cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); cur_des_virtual->dsadr = CIBR1_PHY; // FIFO1 physical address cur_des_virtual->dtadr = target_physical; cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; // advance pointers remain_size -= des_transfer_size; cur_des_virtual++; cur_des_physical++; target_physical += des_transfer_size; target_virtual += des_transfer_size; } // stop the dma transfer on one frame captured last_des_virtual = cur_des_virtual - 1; //last_des_virtual->ddadr |= 0x1; } last_des_virtual->ddadr = ((unsigned)camera_context->fifo1_descriptors_physical); } // generate fifo2 dma chains if (camera_context->fifo2_transfer_size) { // record fifo1 descriptors' start address camera_context->fifo2_descriptors_virtual = (unsigned)cur_des_virtual; camera_context->fifo2_descriptors_physical = (unsigned)cur_des_physical; for(i=0; i<camera_context->block_number; i++) { // in each iteration, generate one dma chain for one frame remain_size = camera_context->fifo2_transfer_size; // assume the blocks are stored consecutively target_physical = (unsigned)camera_context->buffer_physical + camera_context->block_size * i + camera_context->fifo0_transfer_size + camera_context->fifo1_transfer_size; for(j=0; j<camera_context->fifo2_num_descriptors; j++) { // set descriptor if (remain_size > SINGLE_DESC_TRANS_MAX) des_transfer_size = SINGLE_DESC_TRANS_MAX; else des_transfer_size = remain_size; cur_des_virtual->ddadr = (unsigned)cur_des_physical + sizeof(pxa_dma_desc); cur_des_virtual->dsadr = CIBR2_PHY; // FIFO2 physical address cur_des_virtual->dtadr = target_physical; cur_des_virtual->dcmd = des_transfer_size | DCMD_FLOWSRC | DCMD_INCTRGADDR | DCMD_BURST32; // advance pointers remain_size -= des_transfer_size; cur_des_virtual++; cur_des_physical++; target_physical += des_transfer_size; } // stop the dma transfer on one frame captured last_des_virtual = cur_des_virtual - 1; //last_des_virtual->ddadr |= 0x1; } last_des_virtual->ddadr = ((unsigned)camera_context->fifo2_descriptors_physical); } return 0; }void start_dma_transfer( p_camera_context_t camera_context, unsigned block_id ){ pxa_dma_desc *des_virtual, *des_physical; if (block_id >= camera_context->block_number) return; // start channel 0 des_virtual = (pxa_dma_desc *)camera_context->fifo0_descriptors_virtual + block_id * camera_context->fifo0_num_descriptors; des_physical = (pxa_dma_desc *)camera_context->fifo0_descriptors_physical + block_id * camera_context->fifo0_num_descriptors; DDADR(camera_context->dma_channels[0]) = (int) des_physical; DCSR(camera_context->dma_channels[0]) |= DCSR_RUN; // start channel 1 if ( camera_context->fifo1_descriptors_virtual ) { des_virtual = (pxa_dma_desc *)camera_context->fifo1_descriptors_virtual + block_id * camera_context->fifo1_num_descriptors; des_physical = (pxa_dma_desc *)camera_context->fifo1_descriptors_physical + block_id * camera_context->fifo1_num_descriptors; DDADR(camera_context->dma_channels[1]) = (int) des_physical; DCSR(camera_context->dma_channels[1]) |= DCSR_RUN; } // start channel 2 if ( camera_context->fifo2_descriptors_virtual ) { des_virtual = (pxa_dma_desc *)camera_context->fifo2_descriptors_virtual + block_id * camera_context->fifo2_num_descriptors; des_physical = (pxa_dma_desc *)camera_context->fifo2_descriptors_physical + block_id * camera_context->fifo2_num_descriptors; DDADR(camera_context->dma_channels[2]) = (int) des_physical; DCSR(camera_context->dma_channels[2]) |= DCSR_RUN; }}void stop_dma_transfer( p_camera_context_t camera_context ){ int ch0, ch1, ch2; ch0 = camera_context->dma_channels[0]; ch1 = camera_context->dma_channels[1]; ch2 = camera_context->dma_channels[2]; DCSR(ch0) &= ~DCSR_RUN; DCSR(ch1) &= ~DCSR_RUN; DCSR(ch2) &= ~DCSR_RUN; return;}int start_capture( p_camera_context_t camera_context, unsigned int block_id, unsigned int frames ){ int status; // clear ci fifo ci_reset_fifo(); ci_clear_int_status(0xFFFFFFFF); // start dma start_dma_transfer(camera_context, block_id); // start capture status = camera_context->camera_functions->start_capture(camera_context, frames); return status;}/*********************************************************************** * * Init/Deinit APIs * ***********************************************************************/int camera_init( p_camera_context_t camera_context ){ int ret = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -