int __ispccdc_enable_lsc(u8 enable) { if (!is_isplsc_activated()) return -ENODEV; if (enable) { if (!ispccdc_busy()) { isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_SBL_SHARED_RPORTB | ISPCTRL_SBL_RD_RAM_EN); isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, 0x1); ispccdc_obj.lsc_state = 1; } else { /* Postpone enabling LSC */ ispccdc_obj.lsc_enable = 1; return -EBUSY; } } else { isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, 0xFFFE); ispccdc_obj.lsc_state = ispccdc_obj.lsc_enable = 0; } return 0; }
/* * ispresizer_set_intype - Input type select * @isp_res: Device context. * @type: Pixel format type. */ static void ispresizer_set_intype(struct isp_res_device *res, enum resizer_colors_type type) { struct isp_device *isp = to_isp_device(res); if (type == RSZ_COLOR8) isp_reg_or(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_INPTYP); else isp_reg_and(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_INPTYP); }
/* * ispresizer_set_source - Input source select * @isp_res: Device context. * @source: Input source type * * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from * Preview/CCDC engine, otherwise from memory. */ static void ispresizer_set_source(struct isp_res_device *res, enum resizer_input_entity source) { struct isp_device *isp = to_isp_device(res); if (source == RESIZER_INPUT_MEMORY) isp_reg_or(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_INPSRC); else isp_reg_and(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_INPSRC); }
/* * ispresizer_set_bilinear - Chrominance horizontal algorithm select * @isp_res: Device context. * @type: Filtering interpolation type. * * Filtering that is same as luminance processing is * intended only for downsampling, and bilinear interpolation * is intended only for upsampling. */ static void ispresizer_set_bilinear(struct isp_res_device *res, enum resizer_chroma_algo type) { struct isp_device *isp = to_isp_device(res); if (type == RSZ_BILINEAR) isp_reg_or(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_CBILIN); else isp_reg_and(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_CBILIN); }
/** * ispccdc_config_outlineoffset - Configures the output line offset * @offset: Must be twice the Output width and aligned on 32 byte boundary * @oddeven: Specifies the odd/even line pattern to be chosen to store the * output. * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines. * * - Configures the output line offset when stored in memory * - Sets the odd/even line pattern to store the output * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4)) * - Configures the number of even and odd line fields in case of rearranging * the lines. * * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte * boundary. **/ int ispccdc_config_outlineoffset(u32 offset, u8 oddeven, u8 numlines) { if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) { isp_reg_writel((offset & 0xFFFF), OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF); } else { DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte" " boundary\n"); return -EINVAL; } isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, ~ISPCCDC_SDOFST_FINV); isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, ~ISPCCDC_SDOFST_FOFST_4L); switch (oddeven) { case EVENEVEN: isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT); break; case ODDEVEN: isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT); break; case EVENODD: isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT); break; case ODDODD: isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT); break; default: break; } return 0; }
/** * ispresizer_set_intype - Input type select * @isp_res: Device context. * @type: Pixel format type. */ static inline void ispresizer_set_intype(struct isp_res_device *isp_res, enum resizer_input type) { struct device *dev = to_device(isp_res); if (type == RSZ_MEM_COL8) isp_reg_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_INPTYP); else isp_reg_and(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_INPTYP); dev_dbg(dev, "%s: In type: %u\n", __func__, type); }
/** * ispresizer_set_source - Input source select * @isp_res: Device context. * @source: Input source type * * If this field is set to RSZ_OTFLY_YUV, the resizer input is fed from * Preview/CCDC engine, otherwise from memory. */ static inline void ispresizer_set_source(struct isp_res_device *isp_res, enum resizer_input source) { struct device *dev = to_device(isp_res); if (source != RSZ_OTFLY_YUV) isp_reg_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_INPSRC); else isp_reg_and(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_INPSRC); dev_dbg(dev, "%s: In source: %u\n", __func__, source); }
/** * ispresizer_free - Makes Resizer module free. * * Returns 0 if successful, or -EINVAL if resizer module was already freed. **/ int ispresizer_free() { mutex_lock(&ispres_obj.ispres_mutex); if (ispres_obj.res_inuse) { ispres_obj.res_inuse = 0; mutex_unlock(&ispres_obj.ispres_mutex); isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ~(ISPCTRL_RSZ_CLK_EN | ISPCTRL_SBL_WR0_RAM_EN)); return 0; } else { mutex_unlock(&ispres_obj.ispres_mutex); DPRINTK_ISPRESZ("ISP_ERR : Resizer Module already freed\n"); return -EINVAL; } }
/** * ispccdc_free - Frees the CCDC module. * * Frees the CCDC module so it can be used by another process. * * Returns 0 if successful, or -EINVAL if module has been already freed. **/ int ispccdc_free(void) { mutex_lock(&ispccdc_obj.mutexlock); if (!ispccdc_obj.ccdc_inuse) { mutex_unlock(&ispccdc_obj.mutexlock); DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n"); return -EINVAL; } ispccdc_obj.ccdc_inuse = 0; mutex_unlock(&ispccdc_obj.mutexlock); isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ~(ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN | ISPCTRL_SBL_WR1_RAM_EN)); return 0; }
/** * ispresizer_free - Makes Resizer module free. * * Returns 0 if successful, or -EINVAL if resizer module was already freed. **/ int ispresizer_free(struct isp_res_device *isp_res) { struct device *dev = to_device(isp_res); mutex_lock(&isp_res->ispres_mutex); if (isp_res->res_inuse) { isp_res->res_inuse = 0; mutex_unlock(&isp_res->ispres_mutex); isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ~(ISPCTRL_RSZ_CLK_EN | ISPCTRL_SBL_WR0_RAM_EN)); return 0; } else { mutex_unlock(&isp_res->ispres_mutex); dev_err(dev, "Resizer Module already freed\n"); return -EINVAL; } }
/* * ispresizer_set_ycpos - Luminance and chrominance order * @isp_res: Device context. * @order: order type. */ static void ispresizer_set_ycpos(struct isp_res_device *res, enum v4l2_mbus_pixelcode pixelcode) { struct isp_device *isp = to_isp_device(res); switch (pixelcode) { case V4L2_MBUS_FMT_YUYV16_1X16: isp_reg_or(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ISPRSZ_CNT_YCPOS); break; case V4L2_MBUS_FMT_UYVY16_1X16: isp_reg_and(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_YCPOS); break; default: return; } }
/** * ispresizer_set_start_phase - Sets the horizontal and vertical start phase. * @phase: horizontal and vertical start phase (0 - 7). * * This API just updates the isp_res struct. Actual register write happens in * ispresizer_config_size. **/ void ispresizer_set_start_phase(struct device *dev, struct isprsz_phase *phase) { /* clear bits */ isp_reg_and(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK)); if (phase != NULL) { isp_reg_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ((phase->h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK) | ((phase->v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK)); } else { isp_reg_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ((DEFAULTSTPHASE << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK) | ((DEFAULTSTPHASE << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK)); } }
/** * ispccdc_config_sync_if - Sets the sync i/f params between sensor and CCDC. * @syncif: Structure containing the sync parameters like field state, CCDC in * master/slave mode, raw/yuv data, polarity of data, field, hs, vs * signals. **/ void ispccdc_config_sync_if(struct ispccdc_syncif syncif) { u32 syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); syn_mode |= ISPCCDC_SYN_MODE_VDHDEN; if (syncif.fldstat) syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT; else syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT; syn_mode &= ISPCCDC_SYN_MODE_INPMOD_MASK; ispccdc_obj.syncif_ipmod = syncif.ipmod; switch (syncif.ipmod) { case RAW: break; case YUV16: syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16; break; case YUV8: syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8; break; }; syn_mode &= ISPCCDC_SYN_MODE_DATSIZ_MASK; switch (syncif.datsz) { case DAT8: syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8; break; case DAT10: syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10; break; case DAT11: syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11; break; case DAT12: syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12; break; }; if (syncif.fldmode) syn_mode |= ISPCCDC_SYN_MODE_FLDMODE; else syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE; if (syncif.datapol) syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; else syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL; if (syncif.fldpol) syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; else syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL; if (syncif.hdpol) syn_mode |= ISPCCDC_SYN_MODE_HDPOL; else syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL; if (syncif.vdpol) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; else syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL; if (syncif.ccdc_mastermode) { syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT; isp_reg_writel(syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT | syncif.vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HD_VD_WID); isp_reg_writel(syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT | syncif.hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PIX_LINES); } else syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT); isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); if (!(syncif.bt_r656_en)) { isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, ~ISPCCDC_REC656IF_R656ON); } }
/** * ispccdc_config_datapath - Specifies the input and output modules for CCDC. * @input: Indicates the module that inputs the image to the CCDC. * @output: Indicates the module to which the CCDC outputs the image. * * Configures the default configuration for the CCDC to work with. * * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1), * CCDC_YUV_BT (2), and CCDC_OTHERS (3). * * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1), * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4). * * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input * or output values. **/ int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output) { u32 syn_mode = 0; struct ispccdc_vp vpcfg; struct ispccdc_syncif syncif; struct ispccdc_bclamp blkcfg; u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT | ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT | ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT | ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT | ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT | ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT | ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT | ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT | ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT | ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT | ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT | ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT | ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT | ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT | ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT | ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT; /* CCDC does not convert the image format */ if ((input == CCDC_RAW || input == CCDC_OTHERS) && output == CCDC_YUV_RSZ) { DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC I/O Combination\n"); return -EINVAL; } syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); switch (output) { case CCDC_YUV_RSZ: syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ; syn_mode &= ~ISPCCDC_SYN_MODE_WEN; break; case CCDC_YUV_MEM_RSZ: syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ; ispccdc_obj.wen = 1; syn_mode |= ISPCCDC_SYN_MODE_WEN; break; case CCDC_OTHERS_VP: syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR; syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; syn_mode &= ~ISPCCDC_SYN_MODE_WEN; vpcfg.bitshift_sel = BIT9_0; vpcfg.freq_sel = PIXCLKBY2; ispccdc_config_vp(vpcfg); ispccdc_enable_vp(1); break; case CCDC_OTHERS_MEM: syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR; syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; syn_mode |= ISPCCDC_SYN_MODE_WEN; syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN; isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG); vpcfg.bitshift_sel = BIT11_2; vpcfg.freq_sel = PIXCLKBY2; ispccdc_config_vp(vpcfg); ispccdc_enable_vp(0); break; case CCDC_OTHERS_VP_MEM: syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR; syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; syn_mode |= ISPCCDC_SYN_MODE_WEN; syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN; isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG, ispccdc_obj.wenlog); vpcfg.bitshift_sel = BIT9_0; vpcfg.freq_sel = PIXCLKBY2; ispccdc_config_vp(vpcfg); ispccdc_enable_vp(1); break; default: DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n"); return -EINVAL; }; isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); switch (input) { case CCDC_RAW: syncif.ccdc_mastermode = 0; syncif.datapol = 0; syncif.datsz = DAT10; syncif.fldmode = 0; syncif.fldout = 0; syncif.fldpol = 0; syncif.fldstat = 0; syncif.hdpol = 0; syncif.ipmod = RAW; syncif.vdpol = 0; ispccdc_config_sync_if(syncif); ispccdc_config_imgattr(colptn); blkcfg.dcsubval = 64; ispccdc_config_black_clamp(blkcfg); if (is_isplsc_activated()) { ispccdc_config_lsc(&lsc_config); ispccdc_load_lsc(lsc_gain_table_tmp, LSC_TABLE_INIT_SIZE); } break; case CCDC_YUV_SYNC: syncif.ccdc_mastermode = 0; syncif.datapol = 0; syncif.datsz = DAT8; syncif.fldmode = 0; syncif.fldout = 0; syncif.fldpol = 0; syncif.fldstat = 0; syncif.hdpol = 0; syncif.ipmod = YUV16; syncif.vdpol = 1; ispccdc_config_imgattr(0); ispccdc_config_sync_if(syncif); blkcfg.dcsubval = 0; ispccdc_config_black_clamp(blkcfg); break; case CCDC_YUV_BT: break; case CCDC_OTHERS: break; default: DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n"); return -EINVAL; } ispccdc_obj.ccdc_inpfmt = input; ispccdc_obj.ccdc_outfmt = output; ispccdc_print_status(); isp_print_status(); return 0; }