📄 pxa_camera.c
字号:
/* * pxa_camera.c * * Bulverde Processor Camera Interface driver. * * Copyright (C) 2003, Intel Corporation * Copyright (C) 2003, Montavista Software Inc. * * Author: Intel Corporation Inc. * MontaVista Software, Inc. * source@mvista.com * * 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. * */#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/wrapper.h>#include <linux/videodev.h>#include <linux/pci.h>#include <linux/pm.h>#include <linux/poll.h>#include <linux/wait.h>#ifdef CONFIG_DPM#include <linux/device.h>#include <asm/arch/ldm.h>#endif#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 "pxa_camera.h"#include "adcm2650.h"#include "adcm2650_hw.h"#define PREFIX "PXA camera: "#define CIBR0_PHY (0x50000000 + 0x28)#define CIBR1_PHY (0x50000000 + 0x30)#define CIBR2_PHY (0x50000000 + 0x38)#define MAX_BPP 32#define MAX_WIDTH 1200 //yul 480 640 #define MAX_HEIGHT 1600#define MIN_WIDTH 72#define MIN_HEIGHT 72#define WIDTH_DEFT 240//800 176 yul #define HEIGHT_DEFT 320//600 144 #define FRAMERATE_DEFT 0x0 //0x0 yul(0x7)#define BUF_SIZE_DEFT 0x400000// 0xE1000 0x400000 800*600*4 yul 6 frame#define SINGLE_DESC_TRANS_MAX 8000#define MAX_DESC_NUM 0x400#define MAX_BLOCK_NUM 0x400static camera_context_t *g_camera_context = NULL;static camera_function_t adcm2650_func;wait_queue_head_t camera_wait_q; /* /dev/videoX registration number */static int minor = 0;static int ci_dma_y = -1;static int ci_dma_cb = -1;static int ci_dma_cr = -1;static 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 */#define CICR0 CI_REG((u32)(ci_regs_base) + 0x00)#define CICR1 CI_REG((u32)(ci_regs_base) + 0x04)#define CICR2 CI_REG((u32)(ci_regs_base) + 0x08)#define CICR3 CI_REG((u32)(ci_regs_base) + 0x0c)#define CICR4 CI_REG((u32)(ci_regs_base) + 0x10)#define CISR CI_REG((u32)(ci_regs_base) + 0x14)#define CIFR CI_REG((u32)(ci_regs_base) + 0x18)#define CITOR CI_REG((u32)(ci_regs_base) + 0x1c)#define CIBR0 CI_REG((u32)(ci_regs_base) + 0x28)#define CIBR1 CI_REG((u32)(ci_regs_base) + 0x30)#define CIBR2 CI_REG((u32)(ci_regs_base) + 0x38)/*********************************************************************** * * 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, CI_YCBCR420_PLANAR, CI_YCBCR420, added by yul @2006-1-12 10:04 */ 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 );static void pxa_dma_repeat(camera_context_t *cam_ctx);static void pxa_dma_continue(camera_context_t *cam_ctx);/*************** * * DPM functions * ***************/#ifdef CONFIG_DPMstatic int last_buffer_id;static int pxa_camera_dpm_suspend(struct device *dev, u32 state, u32 level){ printk(KERN_DEBUG PREFIX "DPM suspend (state %d, level %d)\n", state, level); switch (level) { case SUSPEND_POWER_DOWN: if (g_camera_context->dma_started) { printk(KERN_DEBUG PREFIX "DMA running, suspended\n"); last_buffer_id = camera_get_last_frame_buffer_id(g_camera_context); stop_dma_transfer(g_camera_context); } disable_irq(IRQ_CAMERA); CKEN &= ~CKEN24_CAMERA; break; } return 0;}static int pxa_camera_dpm_resume(struct device *dev, u32 level){ printk(KERN_DEBUG PREFIX "DPM resume (level %d)\n", level); switch (level) { case RESUME_POWER_ON: CKEN |= CKEN24_CAMERA; enable_irq(IRQ_CAMERA); if (g_camera_context->dma_started) { printk(KERN_DEBUG PREFIX "resume DMA\n"); start_dma_transfer(g_camera_context, last_buffer_id); } break; } return 0;}static int pxa_camera_dpm_scale(struct bus_op_point *op, u32 level){ printk(KERN_DEBUG PREFIX "DPM scale (level %d)\n", level); /* CCCR is changed - adjust clock */ ci_set_clock(g_camera_context->clk_reg_base, 1, 1, 7 /* MCLK_DEFT in adcm2650.c */); return 0;}static struct device_driver pxa_camera_driver_ldm = { name: "camera", devclass: NULL, probe: NULL, suspend: pxa_camera_dpm_suspend, resume: pxa_camera_dpm_resume, scale: pxa_camera_dpm_scale, remove: NULL,};static struct device pxa_camera_device_ldm = { name: "PXA camera", bus_id: "video", driver: NULL, power_state: DPM_POWER_ON};static void pxa_camera_ldm_register(void){ pxaebc_driver_register(&pxa_camera_driver_ldm); pxaebc_device_register(&pxa_camera_device_ldm);}static void pxa_camera_ldm_unregister(void){ pxaebc_driver_unregister(&pxa_camera_driver_ldm); pxaebc_device_unregister(&pxa_camera_device_ldm);}#endif /* CONFIG_DPM *//*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; // 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;//yulu #if 0 printk("\n camera_context->fifo0_descriptors_virtual = 0x%x",camera_context->fifo0_descriptors_virtual); printk("\n camera_context->fifo0_descriptors_physical = 0x%x",camera_context->fifo0_descriptors_physical); printk("\n camera_context->buffer_physical = 0x%x",camera_context->buffer_physical); printk("\n camera_context->buffer_virtual = 0x%x",camera_context->buffer_virtual);//0xc8862000//0xa0d64000//0xa0400000//0xc8867000#endif 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; 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; } // 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;#if 0 printk("\n camera_context->fifo1_descriptors_virtual = 0x%x",camera_context->fifo1_descriptors_virtual); printk("\n camera_context->fifo1_descriptors_physical = 0x%x",camera_context->fifo1_descriptors_physical); printk("\n camera_context->buffer_physical = 0x%x",camera_context->buffer_physical); printk("\n camera_context->buffer_virtual = 0x%x",camera_context->buffer_virtual);#endif 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; 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; } // 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;#if 0 printk("\n camera_context->fifo2_descriptors_virtual = 0x%x",camera_context->fifo2_descriptors_virtual); printk("\n camera_context->fifo2_descriptors_physical = 0x%x",camera_context->fifo2_descriptors_physical);#endif 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]) = 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]) = des_physical; DCSR(camera_context->dma_channels[1]) |= DCSR_RUN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -