📄 s3c2440camif.c
字号:
#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/clk.h>#include <linux/random.h>#include <linux/version.h>#include <linux/videodev2.h>#include <linux/dma-mapping.h>#ifdef CONFIG_VIDEO_V4L1_COMPAT#include <linux/videodev.h>#endif#include <linux/interrupt.h>#include <media/video-buf.h>#include <media/v4l2-common.h>#include <linux/highmem.h>#include <asm/io.h>#include <asm/memory.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-gpioj.h>#include <asm/arch/regs-clock.h>#include <asm/arch-s3c2410/map.h>#include "s3c2440camif.h"/* module params. */static int video_nr = -1;module_param(video_nr, int, 0);MODULE_PARM_DESC(video_nr, "minor device number for s3c2440 camif");/* debug print macro. */#undef PDEBUG#ifdef CONFIG_S3C2440_CAMIF_DBG #ifdef __KERNEL__ /* in kernel space */ #define PDEBUG(fmt, args...) printk( KERN_ALERT"%s_%d: "fmt, __FILE__, __LINE__, ## args) #else /* in user space */ #define PDEBUG(fmt, args...) fprintf(stderr, "%s_%d: "fmt, __FILE__, __LINE__, ## args) #endif#else #define PDEBUG(fmt, args...)#endif/* hardware & driver name, version etc. */#define CARD_NAME "s3c2440-camif"#define DRIVER_NAME "s3c2440-camif"#define DRIVER_VERSION KERNEL_VERSION(0,1,1)unsigned long camif_base_addr;/* camera device(s) */static LIST_HEAD(camif_devlist);/* image buffer for previewing. */struct s3c2440camif_buffer img_buff[] ={ { .state = CAMIF_BUFF_INVALID, .img_size = 0, .order = 0, .virt_base = (unsigned long)NULL, .phy_base = (unsigned long)NULL }, { .state = CAMIF_BUFF_INVALID, .img_size = 0, .order = 0, .virt_base = (unsigned long)NULL, .phy_base = (unsigned long)NULL }, { .state = CAMIF_BUFF_INVALID, .img_size = 0, .order = 0, .virt_base = (unsigned long)NULL, .phy_base = (unsigned long)NULL }, { .state = CAMIF_BUFF_INVALID, .img_size = 0, .order = 0, .virt_base = (unsigned long)NULL, .phy_base = (unsigned long)NULL }};/* * struct s3c2440camif_format formats[] */static struct s3c2440camif_format formats[] = { { .description = "RGB 5-6-5", .pixelformat = V4L2_PIX_FMT_RGB565, .depth = 16, }, { .description = "RGB 8-8-8", .pixelformat = V4L2_PIX_FMT_RGB24, .depth = 32, }, { .description = "YCbCr 4:2:0", .pixelformat = V4L2_PIX_FMT_YUV420, .depth = 12, }, { .description = "YCbCr 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .depth = 16, },};static struct v4l2_queryctrl g_ctrls[] ={ { .id = 0, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Horizontal Window Offset", .minimum = 0, .maximum = 632, .step = 8, .default_value = 0 }, { .id = 1, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Virtal Window Offset", .minimum = 0, .maximum = 504, .step = 8, .default_value = 0 }};/* software reset camera interface. */static void __inline__ soft_reset_camif(void){ u32 cigctrl; cigctrl = (1<<31)|(1<<29); iowrite32(cigctrl, S3C244X_CIGCTRL); mdelay(10); cigctrl = (1<<29); iowrite32(cigctrl, S3C244X_CIGCTRL); mdelay(10); PDEBUG("%s() done.\n", __FUNCTION__);}/* software reset camera interface. */static void __inline__ hw_reset_camif(void){ u32 cigctrl; cigctrl = (1<<30)|(1<<29); iowrite32(cigctrl, S3C244X_CIGCTRL); mdelay(10); cigctrl = (1<<29); iowrite32(cigctrl, S3C244X_CIGCTRL); mdelay(10); PDEBUG("%s() done.\n", __FUNCTION__);}/* switch camif from preview path to codec path. */static void __inline__ camif_p2c(struct s3c2440camif_dev * pdev){ /* 1. stop preview. */ { u32 ciprscctrl; ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl &= ~(1<<15); // stop preview scaler. iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); } /* 2. soft-reset camif */ soft_reset_camif(); /* 3. clear all overflow. */ { u32 ciwdofst; ciwdofst = ioread32(S3C244X_CIWDOFST); ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12); iowrite32(ciwdofst, S3C244X_CIWDOFST); ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12)); iowrite32(ciwdofst, S3C244X_CIWDOFST); }}/* switch camif from codec path to preview path. */static void __inline__ camif_c2p(struct s3c2440camif_dev * pdev){ /* 1. stop codec. */ { u32 cicoscctrl; cicoscctrl = ioread32(S3C244X_CICOSCCTRL); cicoscctrl &= ~(1<<15); // stop preview scaler. iowrite32(cicoscctrl, S3C244X_CICOSCCTRL); } /* 2. soft-reset camif. */ soft_reset_camif(); /* 3. clear all overflow. */ { u32 ciwdofst; ciwdofst = ioread32(S3C244X_CIWDOFST); ciwdofst |= (1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12); iowrite32(ciwdofst, S3C244X_CIWDOFST); ciwdofst &= ~((1<<30)|(1<<15)|(1<<14)|(1<<13)|(1<<12)); iowrite32(ciwdofst, S3C244X_CIWDOFST); }}/* calculate main burst size and remained burst size. */static void __inline__ calc_burst_size(u32 pixperword,u32 hSize, u32 *mainBurstSize, u32 *remainedBurstSize){ u32 tmp; tmp = (hSize/pixperword)%16; switch(tmp) { case 0: *mainBurstSize = 16; *remainedBurstSize = 16; break; case 4: *mainBurstSize = 16; *remainedBurstSize = 4; break; case 8: *mainBurstSize=16; *remainedBurstSize = 8; break; default: tmp=(hSize/pixperword)%8; switch(tmp) { case 0: *mainBurstSize = 8; *remainedBurstSize = 8; break; case 4: *mainBurstSize = 8; *remainedBurstSize = 4; default: *mainBurstSize = 4; tmp = (hSize/pixperword)%4; *remainedBurstSize = (tmp)?tmp:4; break; } break; }}/* calculate prescaler ratio and shift. */static void __inline__ calc_prescaler_ratio_shift(u32 SrcSize, u32 DstSize, u32 *ratio, u32 *shift){ if(SrcSize>=64*DstSize) { PDEBUG("Error: out of the prescaler range: SrcSize/DstSize = %d(< 64)\n", SrcSize/DstSize); BUG(); } else if(SrcSize>=32*DstSize) { *ratio=32; *shift=5; } else if(SrcSize>=16*DstSize) { *ratio=16; *shift=4; } else if(SrcSize>=8*DstSize) { *ratio=8; *shift=3; } else if(SrcSize>=4*DstSize) { *ratio=4; *shift=2; } else if(SrcSize>=2*DstSize) { *ratio=2; *shift=1; } else { *ratio=1; *shift=0; } }/* update CISRCFMT only. */static void __inline__ update_source_fmt_regs(struct s3c2440camif_dev * pdev){ u32 cisrcfmt; cisrcfmt = (1<<31) // ITU-R BT.601 YCbCr 8-bit mode |(0<<30) // CB,Cr value offset cntrol for YCbCr |(pdev->srcHsize<<16) // source image width// |(0<<14) // input order is YCbYCr// |(1<<14) // input order is YCrYCb |(2<<14) // input order is CbYCrY// |(3<<14) // input order is CrYCbY |(pdev->srcVsize<<0); // source image height iowrite32(cisrcfmt, S3C244X_CISRCFMT);}/* update registers: * PREVIEW path: * CIPRCLRSA1 ~ CIPRCLRSA4 * CIPRTRGFMT * CIPRCTRL * CIPRSCCTRL * CIPRTAREA * CODEC path: * CICOYSA1 ~ CICOYSA4 * CICOCBSA1 ~ CICOCBSA4 * CICOCRSA1 ~ CICOCRSA4 * CICOTRGFMT * CICOCTRL * CICOTAREA */static void __inline__ update_target_fmt_regs(struct s3c2440camif_dev * pdev){ u32 Ysize, Csize; u32 cicotrgfmt; u32 cicoctrl; u32 ciprtrgfmt; u32 ciprctrl; u32 ciprscctrl; u32 mainBurstSize, remainedBurstSize; switch (formats[pdev->format].pixelformat) { case V4L2_PIX_FMT_RGB565: /* CIPRCLRSA1 ~ CIPRCLRSA4. */ iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1); iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2); iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3); iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4); /* CIPRTRGFMT. */ ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image |(0<<14) // don't mirror or rotation. |(pdev->preTargetVsize<<0); // vertical pixel number of target image iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT); /* CIPRCTRL. */ calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize); PDEBUG("preview main burst leng: %d, remained burst length: %d\n", mainBurstSize, remainedBurstSize); ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14); iowrite32(ciprctrl, S3C244X_CIPRCTRL); /* CIPRSCCTRL. */ ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'. ciprscctrl |= 0<<30; // 16-bits RGB iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB /* CIPRTAREA. */ iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA); break; case V4L2_PIX_FMT_RGB24: /* CIPRCLRSA1 ~ CIPRCLRSA4. */ iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1); iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2); iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3); iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4); /* CIPRTRGFMT. */ ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image |(0<<14) // don't mirror or rotation. |(pdev->preTargetVsize<<0); // vertical pixel number of target image iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT); /* CIPRCTRL. */ calc_burst_size(1, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize); PDEBUG("preview main burst leng: %d, remained burst length: %d", mainBurstSize, remainedBurstSize); ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14); iowrite32(ciprctrl, S3C244X_CIPRCTRL); /* CIPRSCCTRL. */ ciprscctrl = ioread32(S3C244X_CIPRSCCTRL); ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'. ciprscctrl |= 1<<30; // 24-bits RGB iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB /* CIPRTAREA. */ iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA); break; case V4L2_PIX_FMT_YUV420: /* each pixel has one byte(8-bits) Y-weight. */ Ysize = pdev->coTargetHsize * pdev->coTargetVsize; Csize = Ysize / 4; // ?? for YCbCr 4:2:0 iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1); iowrite32(img_buff[0].phy_base + Ysize, S3C244X_CICOCBSA1); iowrite32(img_buff[0].phy_base + Ysize + Csize, S3C244X_CICOCRSA1); iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2); iowrite32(img_buff[1].phy_base + Ysize, S3C244X_CICOCBSA2); iowrite32(img_buff[1].phy_base + Ysize + Csize, S3C244X_CICOCRSA2); iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3); iowrite32(img_buff[2].phy_base + Ysize, S3C244X_CICOCBSA3); iowrite32(img_buff[2].phy_base + Ysize + Csize, S3C244X_CICOCRSA3); iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4); iowrite32(img_buff[3].phy_base + Ysize, S3C244X_CICOCBSA4); iowrite32(img_buff[3].phy_base + Ysize + Csize, S3C244X_CICOCRSA4); /* CICOTRGFMT. */ cicotrgfmt = (1<<31) // YCbCr 4:2:2 codec scaler input image format |(0<<30) // YCbCr 4:2:0 codec scaler output image format |(pdev->coTargetHsize<<16) // target image's horizontal pixel number |(3<<14) // normal, 180 degree rotation. |(pdev->coTargetVsize<<0); iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT); /* CICOCTRL. */ calc_burst_size(4, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); PDEBUG("codec Y main burst leng: %d, remained burst length: %d", mainBurstSize, remainedBurstSize); cicoctrl = (mainBurstSize<<19)|(remainedBurstSize<<14); calc_burst_size(8, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); cicoctrl |= (mainBurstSize<<9)|(remainedBurstSize<<4); iowrite32(cicoctrl, S3C244X_CICOCTRL); /* CICOTAREA. */ iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA); break; case V4L2_PIX_FMT_YUYV: /* each pixel has one byte(8-bits) Y-weight. */ Ysize = pdev->coTargetHsize * pdev->coTargetVsize; Csize = Ysize / 2; // ?? for YCbCr 4:2:2 iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1); iowrite32(img_buff[0].phy_base + Ysize, S3C244X_CICOCBSA1); iowrite32(img_buff[0].phy_base + Ysize + Csize, S3C244X_CICOCRSA1); iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2); iowrite32(img_buff[1].phy_base + Ysize, S3C244X_CICOCBSA2); iowrite32(img_buff[1].phy_base + Ysize + Csize, S3C244X_CICOCRSA2); iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3); iowrite32(img_buff[2].phy_base + Ysize, S3C244X_CICOCBSA3); iowrite32(img_buff[2].phy_base + Ysize + Csize, S3C244X_CICOCRSA3); iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4); iowrite32(img_buff[3].phy_base + Ysize, S3C244X_CICOCBSA4); iowrite32(img_buff[3].phy_base + Ysize + Csize, S3C244X_CICOCRSA4); /* CICOTRGFMT. */ cicotrgfmt = (1<<31) // YCbCr 4:2:2 codec scaler input image format |(1<<30) // YCbCr 4:2:2 codec scaler output image format |(pdev->coTargetHsize<<16) // target image's horizontal pixel number |(3<<14) // normal, 180 degree rotation. |(pdev->coTargetVsize<<0); iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT); /* CICOCTRL. */ calc_burst_size(4, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); PDEBUG("codec Y main burst leng: %d, remained burst length: %d", mainBurstSize, remainedBurstSize); cicoctrl = (mainBurstSize<<19)|(remainedBurstSize<<14); calc_burst_size(8, pdev->coTargetHsize, &mainBurstSize, &remainedBurstSize); cicoctrl |= (mainBurstSize<<9)|(remainedBurstSize<<4); iowrite32(cicoctrl, S3C244X_CICOCTRL); /* CICOTAREA. */ iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA); break; default: PDEBUG("bug here."); BUG(); break; }}/* update CIWDOFST only. */static void __inline__ update_target_wnd_regs(struct s3c2440camif_dev * pdev){ u32 ciwdofst; u32 winHorOfst, winVerOfst; winHorOfst = (pdev->srcHsize - pdev->wndHsize)>>1; winVerOfst = (pdev->srcVsize - pdev->wndVsize)>>1; winHorOfst &= 0xFFFFFFF8; winVerOfst &= 0xFFFFFFF8; if ((winHorOfst == 0)&&(winVerOfst == 0)) { ciwdofst = 0; // disable windows offset. } else { ciwdofst = (1<<31) // window offset enable |(1<<30) // clear the overflow ind flag of input CODEC FIFO Y |(winHorOfst<<16) // windows horizontal offset |(1<<15) // clear the overflow ind flag of input CODEC FIFO Cb |(1<<14) // clear the overflow ind flag of input CODEC FIFO Cr |(1<<13) // clear the overflow ind flag of input PREVIEW FIFO Cb |(1<<12) // clear the overflow ind flag of input PREVIEW FIFO Cr |(winVerOfst<<0); // window vertical offset } iowrite32(ciwdofst, S3C244X_CIWDOFST);}/* update registers: * PREVIEW path: * CIPRSCPRERATIO * CIPRSCPREDST * CIPRSCCTRL * CODEC path: * CICOSCPRERATIO * CICOSCPREDST * CICOSCCTRL */static void __inline__ update_target_zoom_regs(struct s3c2440camif_dev * pdev){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -