📄 camif_mx2ads.c
字号:
/* drivers/media/video/mx2ads/camif_mx2ads.c * * Implementation of Camera Interface for MX2ADS platform. * this driver based on media/video/omap/camif_innovator.c * * Copyright (C) 2004 MontaVista Software, Inc. * * Author: MontaVista Software, Inc. * source@mvista.com * * 2004 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */#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>#include <asm/hardware.h>#include <asm/arch/gpio.h>#include <asm/arch/pll.h>#include "prpscale.h"#define MODULE_NAME "camif"#include "common.h"#include "camif.h"static struct camera_interface * this;static canif_chan_stat_t chan_stat[CAMIF_CHANNELS_NUM];static unsigned long camera_clk = 20000000; /* default camera clock*/static spinlock_t camif_lock;static int camera_module_present = 0;static int mem_region_reserved = 0;static int camif_close(int chan);extern const struct image_size mx2ads_image_size[]; /***************************************************************************//* EMMA functionality *//***************************************************************************/static inline voidemma_disable_interrupts(int chan){ if (chan == 0) { PRP_INTRCNTL &= ~(PRP2_ICR_CH1 | PRP_INTRCNTL_CH1ERR); } else { PRP_INTRCNTL &= ~(PRP2_ICR_CH2 | PRP_INTRCNTL_CH2ERR); }}static inline voidemma_enable_interrupts(int chan){ if (chan == 0) { PRP_INTRCNTL |= (PRP2_ICR_CH1 | PRP_INTRCNTL_CH1ERR); } else { PRP_INTRCNTL |= (PRP2_ICR_CH2 | PRP_INTRCNTL_CH2ERR); }}static void emma_prp_isr(int irq, void *client_data, struct pt_regs *regs){ unsigned long flags; unsigned int isr_reg = PRP_INTRSTATUS; int i; canif_chan_stat_t *cstat; unsigned int chan_masks[CAMIF_CHANNELS_NUM] = { (PRP_INTRSTAT_CH1BUF2 | PRP_INTRSTAT_CH1BUF1), (PRP_INTRSTAT_CH2BUF2 | PRP_INTRSTAT_CH2BUF1) }; unsigned int chan_en = 0; spin_lock_irqsave(&camif_lock, flags); PRP_INTRSTATUS = isr_reg; if (isr_reg & (chan_masks[0] | chan_masks[1])) { for (i = 0, cstat = &(chan_stat[0]); i< CAMIF_CHANNELS_NUM; i++, cstat++) { if (!(isr_reg & chan_masks[i])) { continue; } /* It seems hw bug: Channel bit does not cleared after * interrupt recieving */ PRP_CNTL &= ~(1<<i); /* Clear the channel */ /* callback to V4L2 layer */ cstat->capture_callback(cstat->callback_data); if (cstat->snapshot_active) { cstat->snapshot_active = 0; } if (cstat->abort) { cstat->abort = 0; cstat->streaming_active = 0; wake_up_interruptible (&cstat->abortqueue); emma_disable_interrupts(i); } } } else { err("eMMa Interrupt error %x\n", PRP_INTRSTATUS); /* TODO Reset should be done after eMMa error */ } /* Engage all channels in same time */ for (i = 0, cstat = &(chan_stat[0]); i< CAMIF_CHANNELS_NUM; i++, cstat++) { if (cstat->streaming_active || cstat->snapshot_active) { chan_en |= 1 << i; } } PRP_CNTL |= chan_en; spin_unlock_irqrestore(&camif_lock, flags);}typedef struct _coeff_t { unsigned int coeff[2]; unsigned int cntl;}coeff_t[2][2];static voidprp_set_scaler(int ch, int dir, scale_t *scale){ int i; unsigned int coeff[2]; unsigned int valid; volatile coeff_t *prpregs = (void*)&(PRP2_RSZ1_HCOEF1); 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++) { (*prpregs)[ch][dir].coeff[i] = coeff[i]; } (*prpregs)[ch][dir].cntl = valid;}static intemma_prp_scale(unsigned int channel, int camwidth, int camheight, unsigned short *prpwidth, unsigned short *prpheight){ int ret; scale_t scale[2]; unsigned short res_width, res_height; memset(scale, 0, sizeof(scale)); scale[0].algo = 0; scale[1].algo = 0; ret = prp_scale(&(scale[0]), 0, 0, camwidth, prpwidth, &res_width); if (ret) { err("Width rescaling error\n"); return ret; } *prpwidth = res_width; ret = prp_scale(&(scale[1]), 0 , 1, camheight, prpheight, &res_height); if (ret) { err("Height rescaling error\n"); return ret; } *prpheight = res_height; prp_set_scaler(channel, 0, &(scale[0])); prp_set_scaler(channel, 1, &(scale[1])); return 0;}#define CSC_RGB_TO_YUV (0)#define CSC_YUV_TO_RGB (1)#define EQUATION_A1 (0)#define EQUATION_A0 (1)#define EQUATION_B1 (2)#define EQUATION_B0 (3)/* Lasr coeficient define Video range */static const unsigned shortcsc_convmatrix[2][4][10] = { { /* RGB to YUV conversion */ {0x4D, 0x4B, 0x3A, 0x57, 0x55, 0x40, 0x40, 0x6B, 0x29, 0x01 },/* A1 */ {0x42, 0x41, 0x32, 0x4C, 0x4A, 0x38, 0x38, 0x5E, 0x24, 0x00 },/* A0 */ {0x36, 0x5C, 0x25, 0x3B, 0x63, 0x40, 0x40, 0x74, 0x18, 0x01 },/* B1 */ {0x2F, 0x4F, 0x20, 0x34, 0x57, 0x38, 0x38, 0x66, 0x15, 0x00 },/* B0 */ }, { /* YUV to RGB */ {0x80, 0xb4, 0x2c, 0x5b, 0x0e4, 0x00, 0x00, 0x00, 0x00, 0x01},/* A1 */ {0x95, 0xcc, 0x32, 0x68, 0x104, 0x00, 0x00, 0x00, 0x00, 0x00},/* A0 */ {0x80, 0xca, 0x18, 0x3c, 0x0ec, 0x00, 0x00, 0x00, 0x00, 0x01},/* B1 */ {0x95, 0xe5, 0x1b, 0x44, 0x1e0, 0x00, 0x00, 0x00, 0x00, 0x00},/* B0 */ }};/* Return pointer to appropriative coeficient set *//* FIXME: Currently only YUV with full range (0-255) is used (A1 equation ). To * used YCrCb special color type or ioctl should be implemented */const unsigned short * get_csc_coefs(void){ enum pixel_format camfmt = this->camera->pixfmt; int conversion = 0; int equation = EQUATION_A1; switch (camfmt) { case YUV: conversion = CSC_YUV_TO_RGB; break; case RGB565: conversion = CSC_RGB_TO_YUV; break; default: return NULL; } return csc_convmatrix[conversion][equation];}static intemma_set_videoformat(void){ unsigned short const *csc_coefs; csc_coefs = get_csc_coefs(); if (!csc_coefs) { return -EINVAL; } PRP2_CSC_COEF0 = (csc_coefs[0] << 21) | (csc_coefs[1] << 11) | csc_coefs[2]; PRP2_CSC_COEF1 = (csc_coefs[3] << 21) | (csc_coefs[4] << 11) | csc_coefs[5]; PRP2_CSC_COEF2 = (csc_coefs[6] << 21) | (csc_coefs[7] << 11) | csc_coefs[8] | (csc_coefs[9] << 31); return 0;}static intemma_set_format(unsigned int chan, struct v4l2_pix_format *fmt){ unsigned int camwidth = mx2ads_image_size[this->camera->imgfmt].width; unsigned int camheight= mx2ads_image_size[this->camera->imgfmt].height; unsigned short prpwidth = fmt->width; unsigned short prpheight = fmt->height; if (emma_prp_scale(chan, camwidth, camheight, &prpwidth, &prpheight)) { return -EINVAL; } if (chan == 0) { PRP_CH1_OUT_IMAGE_SIZE = ((prpwidth & 0x7FF) << 16) | ((prpheight & 0x7FF)) ; PRP_CH1_DEST_FRAME_CNTL = prpwidth * fmt->depth/8; } else { PRP_CH2_OUT_IMAGE_SIZE = ((prpwidth & 0x7FF) << 16) | ((prpheight & 0x7FF)) ; } chan_stat[chan].width = prpwidth; chan_stat[chan].height = prpheight; chan_stat[chan].depth = fmt->depth; /* set videoformat */ if (emma_set_videoformat()) { err("eMMa does not support current cumera format\n"); return -EINVAL; } return 0;}/************************************************************************** * MX21 CSI module specific functions **************************************************************************//* Dma channel for data tranfer between CSI and memory buffer *//* Pointer to the memory area for image capturing via DMA and size of memory area */static int camif_set_format(unsigned int chan, struct v4l2_pix_format* fmt){ unsigned int prppixfmtreg; unsigned int prp_cntl = 0, prp_cntl_mask = 0xFFFFFFFF, reg; int ret; unsigned long flags; canif_chan_stat_t *cstat = &(chan_stat[chan]); if (cstat->snapshot_active || cstat->streaming_active) { return -EINVAL; } spin_lock_irqsave(&camif_lock, flags); if (chan_stat[1-chan].opened) { unsigned int camwidth = mx2ads_image_size[this->camera->imgfmt].width; unsigned int camheight= mx2ads_image_size[this->camera->imgfmt].height; if ((fmt->width > camwidth) || (fmt->height > camheight)) { err("Dynamic change resolution currently is not " "supported\n Please open channel with greatest " "resolution first\n"); spin_unlock_irqrestore(&camif_lock, flags); return -EINVAL; } } else { /* No active channel */ if(this->camera) { struct v4l2_pix_format camfmt = *fmt; camfmt.pixelformat = V4L2_PIX_FMT_RGB565; /* Trying to change format on camera */ /*FIXME: It seems the prp cannot accept image in 176x144 * format so trying to workarond this: Setup 320x240 * resolution and use prp scaling to get requested * resolution */ unsigned int res = fmt->width * fmt->height; if ((res > (160 * 120)) && (res <= (176 * 144))) { camfmt.width = 320; camfmt.height = 240; } if (this->camera->set_format(&camfmt)) { /* FIXME: In this case we can try to set pixel * format of same kind, but which is uspported * by camera (e.g. if RGB 555 is not supported * but RGB565 is supported try to change to * RGB565) which is supported. After the eMMa * hardware will be initialized, the conversion * will be done by PRP module */ /* Currently the feature described above does * not supported */ err("Unable to set request format\n"); spin_unlock_irqrestore(&camif_lock, flags); return -EINVAL; } prp_cntl_mask &= ~(PRP2_CNTL_IN_RGB32); prppixfmtreg = 0x2CA00565; PRP_SOURCE_FRAME_FORMAT_CNTL = prppixfmtreg; prp_cntl |= PRP2_CNTL_IN_RGB; PRP_SOURCE_FRAME_SIZE = ((camfmt.width & 0x7FF) << 16) |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -