📄 camif_innovator.c
字号:
/* * camif_innovator.c * * Implementation of Camera Interface for OMAP1510 Innovator platform. * * Copyright (C) 2003-2004 MontaVista Software, Inc. * * Author: MontaVista Software, Inc. * stevel@mvista.com or source@mvista.com * * Modifications: * * Oct 2003: MontaVista Software Inc. source@mvista.com * Added OMAP1610 support * * May 2004: MontaVista Software Inc. stevel@mvista.com * - stripped out old NO_DMA support. * - added support for OV9640 camera detection. * - some minor fixes to the camera API. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/config.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/videodev.h>#include <linux/version.h>#include <linux/interrupt.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/dma.h>#ifdef CONFIG_ARCH_OMAP730#include <asm/arch/omap730_config.h>#endif#define MODULE_NAME "camif"#include "common.h"#include "camif.h"static struct camera_interface * this;static void (*capture_callback)(void *);static void* callback_data;static u8* capture_buffer;#undef MEASURE_FRstatic volatile u32 *omap_product_id = (volatile u32 *)OMAP_PROD_ID_1;// DMA global control registerstatic volatile u16 * dma_gcr = (u16 *)(OMAP_DMA_BASE + 0x400);static volatile dma_regs_t * camera_dma_regs = NULL;static volatile camera_regs_t * camera_regs = NULL;static int snapshot_active = 0;static int streaming_active = 0;static int camera_module_present = 0;static int current_exclk = 24*10; // MHz * 10static spinlock_t camif_lock;static wait_queue_head_t vsync_wait;#define FIFO_TRIGGER_LVL 32#define DMA_DEST_AMODE AMODE_POST_INC#define DMA_FRAME_INDEX 0#define DMA_ELEM_INDEX 0#define DMA_ELEM_SIZE 4#define DMA_DEST_PORT PORT_EMIFFstatic inline int is_omap_1623(void){ return (*omap_product_id >> 1) == OMAP1623_PROD_ID;}static inline u32 get_imgsize_bits(void){ if (this->camera) { switch (this->camera->imgfmt) { case VGA: return IMGSIZE_VGA; case CIF: return IMGSIZE_CIF; case QVGA: return IMGSIZE_QVGA; default: return IMGSIZE_QCIF; } } return IMGSIZE_QCIF;}static inline void camif_mode_set(u32 mask){ u32 itstat = camera_regs->it_status ; itstat = 0; camera_regs->mode |= mask;}static inline void camif_mode_clear(u32 mask){ u32 itstat = camera_regs->it_status ; itstat = 0; camera_regs->mode &= ~mask;}static inline void camif_cleanfifo(void){ ENTRY(); camera_regs->ctrlclock &= ~LCLK_EN; camif_mode_set(RAZ_FIFO); udelay(10); camif_mode_clear(RAZ_FIFO); camera_regs->ctrlclock |= LCLK_EN; EXIT();}static inline u32 mhzx10_to_foscmod(int mhzx10){ switch (mhzx10) { case 60: return FOSCMOD_6MHz; case 80: return FOSCMOD_8MHz; case 96: return FOSCMOD_9_6MHz; case 120: return FOSCMOD_12MHz; case 240: default: /* gotta use DPLL source for 24 MHz */ return FOSCMOD_24MHz | DPLL_EN; }}static inline void camif_start(int exclk){ u32 clkbits = mhzx10_to_foscmod(exclk); // take camera interface out of reset camera_regs->gpio = CAM_RST; // reset mode camera_regs->mode = (get_imgsize_bits() | (FIFO_TRIGGER_LVL << THRESHOLD_BIT)); // start the camera interface clocks camera_regs->ctrlclock = (MCLK_EN | LCLK_EN | CAMEXCLK_EN | clkbits); mdelay(10); current_exclk = exclk;}static inline void camif_stop(void){ camera_regs->ctrlclock = 0; // stop clocks camera_regs->gpio = 0; // put camera interface in reset mdelay(10);}#ifdef MEASURE_FRextern unsigned long do_getmachinecycles(void);extern unsigned long machinecycles_to_usecs(unsigned long mputicks);static unsigned long dmac_sum;static unsigned long dmac_delta;static unsigned long dmac_N;#endifstatic void dma_callback(void *client_data){ unsigned long flags; spin_lock_irqsave(&camif_lock, flags); snapshot_active = 0; if (streaming_active) { camif_cleanfifo(); camera_dma_regs->ccr |= DCCR_EN; // restart DMA } else { camif_mode_clear(EN_DMA | EN_FIFO_FULL); } spin_unlock_irqrestore(&camif_lock, flags);#ifdef MEASURE_FR if (dmac_delta) { dmac_sum += machinecycles_to_usecs(do_getmachinecycles() - dmac_delta); dmac_N++; } dmac_delta = do_getmachinecycles();#endif // callback to V4L2 layer capture_callback(callback_data); EXIT();}// SystemDMA initstatic int dma_init(void){ ENTRY(); *dma_gcr = 0x0004; // dma free running EXIT(); return 0;}static void dma_start(void){ dma_addr_t physbuf; int width = omap_image_size[this->camera->imgfmt].width; int height = omap_image_size[this->camera->imgfmt].height; int Bpp = (omap_pixfmt_depth[this->camera->pixfmt] + 7) >> 3; u16 port = 0; ENTRY(); if (!this->camera) return; if ( is_omap_1623() ) port = (PORT_OCP_T1 << DCSDP_SRC_PORT_BIT); else port = (PORT_TIPB << DCSDP_SRC_PORT_BIT); camera_dma_regs->csdp = DATA_TYPE_S32 | port | (DMA_DEST_PORT << DCSDP_DEST_PORT_BIT); //dbg("%04x --> CSDP\n", camera_dma_regs->csdp); /* * sync on camera fifo, no autoinit, high pri, * frame sync, src const, dst post inc */ camera_dma_regs->ccr = ((DMA_DEST_AMODE << DCCR_DST_AMODE_BIT) | (AMODE_CONST << DCCR_SRC_AMODE_BIT) | DCCR_PRIO | DCCR_FS | eCameraRx); if (streaming_active) camera_dma_regs->ccr |= (DCCR_AI | DCCR_REPEAT); //dbg("%04x --> CCR\n", camera_dma_regs->ccr); camera_dma_regs->cicr = 0x0020; // enable block interrupt if ( is_omap_1623() ) { camera_dma_regs->cssa_l = (OMAP1623_CAM_CAMDATA_REG & 0xffff); camera_dma_regs->cssa_u = ((OMAP1623_CAM_CAMDATA_REG>>16) & 0xffff); } else { camera_dma_regs->cssa_l = (CAM_CAMDATA_REG & 0xffff); camera_dma_regs->cssa_u = ((CAM_CAMDATA_REG>>16) & 0xffff); } //dbg("%04x --> CSSA_L\n", camera_dma_regs->cssa_l); //dbg("%04x --> CSSA_U\n", camera_dma_regs->cssa_u); /* * elements per frame must be FIFO trigger level when * using frame sync */ camera_dma_regs->cen = FIFO_TRIGGER_LVL; // TODO: make sure this divides to a whole number. camera_dma_regs->cfn = (width * height * Bpp) / (DMA_ELEM_SIZE * FIFO_TRIGGER_LVL);#ifdef CONFIG_ARCH_OMAP1510 camera_dma_regs->cfi = DMA_FRAME_INDEX; camera_dma_regs->cei = DMA_ELEM_INDEX;#else camera_dma_regs->csfi = DMA_FRAME_INDEX; camera_dma_regs->csei = DMA_ELEM_INDEX; camera_dma_regs->cdfi = DMA_FRAME_INDEX; camera_dma_regs->cdei = DMA_ELEM_INDEX;#endif physbuf = (dma_addr_t)virt_to_phys(capture_buffer);#if 1 //dbg("regs->csr = 0x%08x\n", camera_dma_regs->csr); camera_dma_regs->cdsa_l = physbuf & 0xffff; camera_dma_regs->cdsa_u = (physbuf >> 16) & 0xffff; //dbg("%04x --> CDSA_L\n", camera_dma_regs->cdsa_l); //dbg("%04x --> CDSA_U\n", camera_dma_regs->cdsa_u); camera_dma_regs->ccr |= DCCR_EN; // start transfer;#else omap_start_dma((dma_regs_t *)camera_dma_regs, physbuf, 0);#endif EXIT();}static void camera_interrupt(int irq, void *client_data, struct pt_regs *regs){ u32 itstat; ENTRY(); spin_lock(&camif_lock); itstat = camera_regs->it_status; if (itstat & V_UP) { if (snapshot_active || streaming_active) { camif_cleanfifo(); camif_mode_clear(EN_V_UP); camif_mode_set(EN_DMA | EN_FIFO_FULL); dma_start(); } wake_up_interruptible(&vsync_wait); } if (itstat & V_DOWN) { wake_up_interruptible(&vsync_wait); } if (itstat & H_UP) { dbg("H_UP set\n"); } if (itstat & H_DOWN) { dbg("H_DOWN set\n"); } if (itstat & FIFO_FULL) { camif_cleanfifo(); dbg("FIFO_FULL set\n"); } spin_unlock(&camif_lock); EXIT();}static void camif_wait_for_vsync_edge(u32 edge_mask){ ENTRY(); camif_mode_set(edge_mask); // wait for VSYNC edge do { interruptible_sleep_on(&vsync_wait); } while (signal_pending(current)); camif_mode_clear(edge_mask); camif_cleanfifo(); EXIT();}static int camif_snapshot(u8* buf, int size){ unsigned long flags; spin_lock_irqsave(&camif_lock, flags); if (!this->camera) { spin_unlock_irqrestore(&camif_lock, flags); return -ENODEV; } if (snapshot_active) { dbg("already active!\n"); spin_unlock_irqrestore(&camif_lock, flags); return 0; } if (streaming_active) { dbg("streaming is active!\n"); spin_unlock_irqrestore(&camif_lock, flags); return -EINVAL; } capture_buffer = buf; snapshot_active = 1; camif_mode_set(EN_V_UP); //dbg("mode = 0x%08x\n", camera_regs->mode); spin_unlock_irqrestore(&camif_lock, flags); return 0;}static int camif_start_streaming(u8* buf, int size){ unsigned long flags; spin_lock_irqsave(&camif_lock, flags); if (!this->camera) { spin_unlock_irqrestore(&camif_lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -