📄 camif.c
字号:
} else { *ratio=1; *shift=0; } return 0;}int camif_g_fifo_status(camif_cfg_t *cfg) { u32 reg; if (cfg->dma_type & CAMIF_CODEC) { u32 flag = CO_OVERFLOW_Y|CO_OVERFLOW_CB|CO_OVERFLOW_CR; reg = CICOSTATUS; if (reg & flag) { printk("CODEC: FIFO error(0x%08x) and corrected\n",reg); /* FIFO Error Count ++ */ CIWDOFST |= CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR; CIWDOFST &= ~(CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR); return 1; /* Error */ } } if (cfg->dma_type & CAMIF_PREVIEW) { u32 flag = PR_OVERFLOW_CB|PR_OVERFLOW_CR; reg = CIPRSTATUS; if (reg & flag) { printk("PREVIEW:FIFO error(0x%08x) and corrected\n",reg); CIWDOFST |= PR_FIFO_CB|PR_FIFO_CR; CIWDOFST &= ~(CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR); /* FIFO Error Count ++ */ return 1; /* Error */ } } return 0; /* No Error */}/* Policy: * if codec or preview define the win offset, * other must follow that value. */int camif_win_offset(camif_gc_t *gc ){ u32 h = gc->win_hor_ofst; u32 v = gc->win_ver_ofst; /*Clear Overflow */ CIWDOFST = CO_FIFO_Y|CO_FIFO_CB|CO_FIFO_CR|PR_FIFO_CB|PR_FIFO_CB; CIWDOFST = 0; /* ? Dummy */ if (!h && !v) { CIWDOFST = 0; return 0; } CIWDOFST = WINOFEN | WINHOROFST(h) | WINVEROFST(v); return 0;}/* * when you change the resolution in a specific camera, * sometimes, it is necessary to change the polarity * -- SW.LEE */static void camif_polarity(camif_gc_t *gc){ u32 cmd = CIGCTRL; cmd = cmd & ~(BIT26|BIT25|BIT24); /* clear polarity */ if (gc->polarity_pclk) cmd |= GC_INVPOLPCLK; if (gc->polarity_vsync) cmd |= GC_INVPOLVSYNC; if (gc->polarity_href) cmd |= GC_INVPOLHREF; CIGCTRL |= cmd;}int camif_dynamic_open(camif_cfg_t *cfg){ camif_win_offset(cfg->gc); camif_polarity(cfg->gc); if(camif_scaler(cfg)) { printk(KERN_ERR "CAMERA:Preview Scaler, Change WinHorOfset or Target Size\n"); return 1; } camif_target_fmt(cfg); if (camif_dma_burst(cfg)) { printk(KERN_ERR "CAMERA:DMA Busrt Length Error \n"); return 1; } if(camif_malloc(cfg) ) { printk(KERN_ERR " Instead of using consistent_alloc()\n" " lease use dedicated memory allocation for DMA memory\n"); return -1; } camif_pingpong(cfg); return 0;}int camif_dynamic_close(camif_cfg_t *cfg){ camif_demalloc(cfg); return 0;}static int camif_target_area(camif_cfg_t *cfg) { u32 rect = cfg->target_x * cfg->target_y; if (cfg->dma_type & CAMIF_CODEC ) { CICOTAREA = rect; } if (cfg->dma_type & CAMIF_PREVIEW) { CIPRTAREA = rect; } return 0;}static int inline camif_hw_reg(camif_cfg_t *cfg){ u32 cmd = 0; if (cfg->dma_type & CAMIF_CODEC) { CICOSCPRERATIO = PRE_SHIFT(cfg->sc.shfactor) |PRE_HRATIO(cfg->sc.prehratio)|PRE_VRATIO(cfg->sc.prevratio); CICOSCPREDST = PRE_DST_WIDTH(cfg->sc.predst_x)|PRE_DST_HEIGHT(cfg->sc.predst_y); /* Differ from Preview */ if (cfg->sc.scalerbypass) cmd |= SCALERBYPASS; if (cfg->sc.scaleup_h & cfg->sc.scaleup_v) cmd |= BIT30|BIT29; CICOSCCTRL = cmd | MAIN_HRATIO(cfg->sc.mainhratio) |MAIN_VRATIO(cfg->sc.mainvratio); return 0; } else if (cfg->dma_type & CAMIF_PREVIEW) { CIPRSCPRERATIO = PRE_SHIFT(cfg->sc.shfactor) |PRE_HRATIO(cfg->sc.prehratio)|PRE_VRATIO(cfg->sc.prevratio); CIPRSCPREDST = PRE_DST_WIDTH(cfg->sc.predst_x)|PRE_DST_HEIGHT(cfg->sc.predst_y); /* Differ from Codec */ if (cfg->fmt & CAMIF_RGB24) { cmd |= RGB_FMT24; } else { /* RGB16 */; } if (cfg->sc.scaleup_h & cfg->sc.scaleup_v) cmd |= BIT29|BIT28; CIPRSCCTRL = cmd |MAIN_HRATIO(cfg->sc.mainhratio)|S_METHOD |MAIN_VRATIO(cfg->sc.mainvratio); }else { panic("CAMERA:DMA_TYPE Wrong \n"); } return 0;}/* Configure Pre-scaler control & main scaler control register */static int camif_scaler(camif_cfg_t *cfg){ int tx = cfg->target_x,ty=cfg->target_y; int sx, sy; if (tx <= 0 || ty<= 0) panic("CAMERA: Invalid target size \n"); sx = cfg->gc->source_x - 2*cfg->gc->win_hor_ofst; sy = cfg->gc->source_y - 2*cfg->gc->win_ver_ofst; if (sx <= 0 || sy<= 0) panic("CAMERA: Invalid source size \n"); cfg->sc.modified_src_x = sx; cfg->sc.modified_src_y = sy; /* Pre-scaler control register 1 */ camif_scaler_internal(sx,tx,&cfg->sc.prehratio,&cfg->sc.hfactor); camif_scaler_internal(sy,ty,&cfg->sc.prevratio,&cfg->sc.vfactor); if (cfg->dma_type & CAMIF_PREVIEW) { if ( (sx /cfg->sc.prehratio) <= 640 ) {} else { printk(KERN_INFO "CAMERA: Internal Preview line buffer is 640 pixels\n"); return 1; /* Error */ } } cfg->sc.shfactor = 10-(cfg->sc.hfactor+cfg->sc.vfactor); /* Pre-scaler control register 2 */ cfg->sc.predst_x = sx / cfg->sc.prehratio; cfg->sc.predst_y = sy / cfg->sc.prevratio; /* Main-scaler control register */ cfg->sc.mainhratio = (sx << 8)/(tx << cfg->sc.hfactor); cfg->sc.mainvratio = (sy << 8)/(ty << cfg->sc.vfactor); DPRINTK(" sx %d, sy %d tx %d ty %d \n",sx,sy,tx,ty); DPRINTK(" hfactor %d vfactor %d \n",cfg->sc.hfactor,cfg->sc.vfactor); cfg->sc.scaleup_h = (sx <= tx) ? 1: 0; cfg->sc.scaleup_v = (sy <= ty) ? 1: 0; if ( cfg->sc.scaleup_h != cfg->sc.scaleup_v) printk(KERN_ERR "scaleup_h must be same to scaleup_v \n"); camif_hw_reg(cfg); camif_target_area(cfg); return 0;}/****************************************************** CalculateBurstSize - Calculate the busrt lengths Description: - dstHSize: the number of the byte of H Size.********************************************************/static void camif_g_bsize(u32 hsize, u32 *mburst, u32 *rburst){ u32 tmp; tmp = (hsize/4) % 16; switch(tmp) { case 0: *mburst=16; *rburst=16; break; case 4: *mburst=16; *rburst=4; break; case 8: *mburst=16; *rburst=8; break; default: tmp=(hsize/4)%8; switch(tmp) { case 0: *mburst=8; *rburst=8; break; case 4: *mburst=8; *rburst=4; default: *mburst=4; tmp=(hsize/4)%4; *rburst= (tmp) ? tmp: 4; break; } break; }}/* SXGA 1028x1024*//* XGA 1024x768 *//* SVGA 800x600 *//* VGA 640x480 *//* CIF 352x288 *//* QVGA 320x240 *//* QCIF 176x144 *//* ret val 1 : DMA Size Error */#define BURST_ERR 1 static int camif_dma_burst(camif_cfg_t *cfg){ int width = cfg->target_x; if (cfg->dma_type & CAMIF_CODEC ) { u32 yburst_m, yburst_r; u32 cburst_m, cburst_r; /* CODEC DMA WIDHT is multiple of 16 */ if (width %16 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ camif_g_bsize(width,&yburst_m,&yburst_r); camif_g_bsize(width/2,&cburst_m,&cburst_r); CICOCTRL =YBURST_M(yburst_m)|CBURST_M(cburst_m) |YBURST_R(yburst_r)|CBURST_R(cburst_r); } if (cfg->dma_type & CAMIF_PREVIEW) { u32 rgburst_m, rgburst_r; if(cfg->fmt == CAMIF_RGB24) { if (width %2 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ camif_g_bsize(width*4,&rgburst_m,&rgburst_r); } else { /* CAMIF_RGB16 */ if ((width/2) %2 != 0 ) return BURST_ERR; /* DMA Burst Length Error */ camif_g_bsize(width*2,&rgburst_m,&rgburst_r); } CIPRCTRL = RGBURST_M(rgburst_m) | RGBURST_R(rgburst_r); } return 0;}static int camif_gpio_init(void){#ifdef CONFIG_ARCH_S3C24A0A /* S3C24A0A has the dedicated signal pins for Camera */#else set_gpio_ctrl(GPIO_CAMDATA0); set_gpio_ctrl(GPIO_CAMDATA1); set_gpio_ctrl(GPIO_CAMDATA2); set_gpio_ctrl(GPIO_CAMDATA3); set_gpio_ctrl(GPIO_CAMDATA4); set_gpio_ctrl(GPIO_CAMDATA5); set_gpio_ctrl(GPIO_CAMDATA6); set_gpio_ctrl(GPIO_CAMDATA7); set_gpio_ctrl(GPIO_CAMPCLKIN); set_gpio_ctrl(GPIO_CAMVSYNC); set_gpio_ctrl(GPIO_CAMHREF); set_gpio_ctrl(GPIO_CAMPCLKOUT); set_gpio_ctrl(GPIO_CAMRESET);#endif return 0;}#define ROUND_ADD 0x100000#ifdef CONFIG_ARCH_S3C24A0Aint camif_clock_init(camif_gc_t *gc){ unsigned int upll, camclk_div, camclk; if (!gc) camclk = 24000000; else { camclk = gc->camclk; if (camclk > 48000000) printk(KERN_ERR "Wrong Camera Clock\n"); } CLKCON |= CLKCON_CAM_UPLL | CLKCON_CAM_HCLK; upll = get_bus_clk(GET_UPLL); printk(KERN_INFO "CAMERA:Default UPLL %08d and Assing 96Mhz to UPLL\n",upll); UPLLCON = FInsrt(56, fPLL_MDIV) | FInsrt(2, fPLL_PDIV)| FInsrt(1, fPLL_SDIV); upll = get_bus_clk(GET_UPLL); camclk_div = (upll+ROUND_ADD) / camclk - 1; CLKDIVN = (CLKDIVN & 0xFF) | CLKDIVN_CAM(camclk_div); printk(KERN_INFO"CAMERA:upll %d MACRO 0x%08X CLKDIVN 0x%08X \n", upll, CLKDIVN_CAM(camclk_div),CLKDIVN); CIIMGCPT = 0; /* Dummy ? */ return 0;}#elseint camif_clock_init(camif_gc_t *gc){ unsigned int upll, camclk_div, camclk; if (!gc) camclk = 24000000; else { camclk = gc->camclk; if (camclk > 48000000) printk(KERN_ERR "Wrong Camera Clock\n"); } CLKCON |= CLKCON_CAMIF; upll = elfin_get_bus_clk(GET_UPLL); printk(KERN_INFO "CAMERA:Default UPLL %08d and Assing 96Mhz to UPLL\n",upll); { UPLLCON = FInsrt(60, fPLL_MDIV) | FInsrt(4, fPLL_PDIV)| FInsrt(1, fPLL_SDIV); CLKDIVN |= DIVN_UPLL; /* For USB */ upll = elfin_get_bus_clk(GET_UPLL); } camclk_div = (upll+ROUND_ADD) /(camclk * 2) -1; CAMDIVN = CAMCLK_SET_DIV|(camclk_div&0xf); printk(KERN_INFO "CAMERA:upll %08d cam_clk %08d CAMDIVN 0x%08x \n",upll,camclk, CAMDIVN); CIIMGCPT = 0; /* Dummy ? */ return 0;}#endif/* Reset Camera IP in CPU Reset External Sensor */void camif_reset(int is, int delay){ switch (is) { case CAMIF_RESET: CIGCTRL |= GC_SWRST; mdelay(1); CIGCTRL &= ~GC_SWRST; break; case CAMIF_EX_RESET_AH: /*Active High */ CIGCTRL &= ~GC_CAMRST; udelay(200); CIGCTRL |= GC_CAMRST; udelay(delay); CIGCTRL &= ~GC_CAMRST; break; case CAMIF_EX_RESET_AL: /*Active Low */ CIGCTRL |= GC_CAMRST; udelay(200); CIGCTRL &= ~GC_CAMRST; udelay(delay); CIGCTRL |= GC_CAMRST; break; default: break; }} /* For Camera Operation, * we can give the high priority to REQ2 of ARBITER1 *//* Please move me into proper place * camif_gc_t is not because "rmmod imgsenor" will delete the instance of camif_gc_t */static u32 old_priority; static void camif_bus_priority(int flag){ if (flag) {#ifdef CONFIG_ARCH_S3C24A0A old_priority = PRIORITY0; PRIORITY0 = PRIORITY_I_FIX; PRIORITY1 = PRIORITY_I_FIX;#else old_priority = PRIORITY; PRIORITY &= ~(3<<7); PRIORITY |= (1<<7); /* Arbiter 1, REQ2 first */ PRIORITY &= ~(1<<1); /* Disable Priority Rotate */#endif } else {#ifdef CONFIG_ARCH_S3C24A0A PRIORITY0 = old_priority; PRIORITY1 = old_priority;#else PRIORITY = old_priority;#endif }}static void inline camif_clock_off(void){ CIIMGCPT = 0;#if defined (CONFIG_ARCH_S3C24A0A) CLKCON &= ~CLKCON_CAM_UPLL; CLKCON &= ~CLKCON_CAM_HCLK;#else CLKCON &= ~CLKCON_CAMIF;#endif}/* Init external image sensor * Before make some value into image senor, * you must set up the pixel clock. */void camif_setup_sensor(void){ camif_reset(CAMIF_RESET, 0); camif_gpio_init(); camif_clock_init(NULL);/* Sometimes ,Before loading I2C module, we need the reset signal */#ifdef CONFIG_ARCH_S3C24A0A camif_reset(CAMIF_EX_RESET_AL,1000);#else camif_reset(CAMIF_EX_RESET_AH,1000);#endif}void camif_hw_close(camif_cfg_t *cfg){ camif_bus_priority(0); camif_clock_off();}void camif_hw_open(camif_gc_t *gc){ camif_source_fmt(gc); camif_win_offset(gc); camif_bus_priority(1);}/* * Local variables: * tab-width: 8 * c-indent-level: 8 * c-basic-offset: 8 * c-set-style: "K&R" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -