new file mode 100644
@@ -0,0 +1,42 @@
+/*
+ * Support for Moorestown Langwell Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) Silicon Image 2008 www.siliconimage.com
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Xiaolin Zhang <xiaolin.zhang@intel.com>
+ */
+#define MRV_MEAN_LUMA_ARR_SIZE_COL 5
+#define MRV_MEAN_LUMA_ARR_SIZE_ROW 5
+#define MRV_MEAN_LUMA_ARR_SIZE \
+ (MRV_MEAN_LUMA_ARR_SIZE_COL*MRV_MEAN_LUMA_ARR_SIZE_ROW)
+int ci_isp_meas_exposure_initialize_module(void);
+
+int ci_isp_meas_exposure_set_config(const struct ci_isp_window *wnd,
+ const struct ci_isp_exp_ctrl *isp_exp_ctrl);
+int ci_isp_meas_exposure_get_config(struct ci_isp_window *wnd,
+ struct ci_isp_exp_ctrl *isp_exp_ctrl);
+
+int ci_isp_meas_exposure_get_mean_luma_values(
+ struct ci_isp_mean_luma *mrv_mean_luma);
+int ci_isp_meas_exposure_get_mean_luma_by_num(
+ u8 BlockNum, u8 *luma);
+int ci_isp_meas_exposure_get_mean_luma_by_pos(
+ u8 XPos, u8 YPos, u8 *luma);
+int mrst_isp_set_color_conversion_ex(void);
new file mode 100644
@@ -0,0 +1,1639 @@
+/*
+ * Support for Moorestown Langwell Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
+ *
+ * Copyright (c) Silicon Image 2008 www.siliconimage.com
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Xiaolin Zhang <xiaolin.zhang@intel.com>
+ */
+
+#include "mrstisp_stdinc.h"
+
+int mrst_isp_set_color_conversion_ex(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_0, MRV_ISP_CC_COEFF_0, 0x00001021);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_1, MRV_ISP_CC_COEFF_1, 0x00001040);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_2, MRV_ISP_CC_COEFF_2, 0x0000100D);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_3, MRV_ISP_CC_COEFF_3, 0x00000FED);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_4, MRV_ISP_CC_COEFF_4, 0x00000FDB);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_5, MRV_ISP_CC_COEFF_5, 0x00001038);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_6, MRV_ISP_CC_COEFF_6, 0x00001038);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_7, MRV_ISP_CC_COEFF_7, 0x00000FD1);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_8, MRV_ISP_CC_COEFF_8, 0x00000FF7);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Selects the ISP path that will become active while processing
+ * data coming from an image sensor configured by the given ISI
+ * configuration struct.
+ */
+enum ci_isp_path ci_isp_select_path(const struct ci_sensor_config *isi_cfg,
+ u8 *words_per_pixel)
+{
+ u8 words;
+ enum ci_isp_path ret_val;
+
+ switch (isi_cfg->mode) {
+ case SENSOR_MODE_DATA:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 1;
+ break;
+ case SENSOR_MODE_PICT:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 1;
+ break;
+ case SENSOR_MODE_RGB565:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 2;
+ break;
+ case SENSOR_MODE_BT601:
+ ret_val = CI_ISP_PATH_YCBCR;
+ words = 2;
+ break;
+ case SENSOR_MODE_BT656:
+ ret_val = CI_ISP_PATH_YCBCR;
+ words = 2;
+ break;
+ case SENSOR_MODE_BAYER:
+ ret_val = CI_ISP_PATH_BAYER;
+ words = 1;
+ break;
+
+ case SENSOR_MODE_SMIA:
+ switch (isi_cfg->smia_mode) {
+ case SENSOR_SMIA_MODE_RAW_12:
+ case SENSOR_SMIA_MODE_RAW_10:
+ case SENSOR_SMIA_MODE_RAW_8:
+ case SENSOR_SMIA_MODE_RAW_8_TO_10_DECOMP:
+ ret_val = CI_ISP_PATH_BAYER;
+ words = 1;
+ break;
+ case SENSOR_SMIA_MODE_YUV_422:
+ ret_val = CI_ISP_PATH_YCBCR;
+ words = 2;
+ break;
+ case SENSOR_SMIA_MODE_YUV_420:
+ case SENSOR_SMIA_MODE_RGB_444:
+ case SENSOR_SMIA_MODE_RGB_565:
+ case SENSOR_SMIA_MODE_RGB_888:
+ case SENSOR_SMIA_MODE_COMPRESSED:
+ case SENSOR_SMIA_MODE_RAW_7:
+ case SENSOR_SMIA_MODE_RAW_6:
+ default:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 1;
+ break;
+ }
+ break;
+
+ case SENSOR_MODE_MIPI:
+ switch (isi_cfg->mipi_mode) {
+ case SENSOR_MIPI_MODE_RAW_12:
+ case SENSOR_MIPI_MODE_RAW_10:
+ case SENSOR_MIPI_MODE_RAW_8:
+ ret_val = CI_ISP_PATH_BAYER;
+ words = 1;
+ break;
+ case SENSOR_MIPI_MODE_YUV422_8:
+ case SENSOR_MIPI_MODE_YUV422_10:
+ ret_val = CI_ISP_PATH_YCBCR;
+ words = 2;
+ break;
+ case SENSOR_MIPI_MODE_YUV420_8:
+ case SENSOR_MIPI_MODE_YUV420_10:
+ case SENSOR_MIPI_MODE_LEGACY_YUV420_8:
+ case SENSOR_MIPI_MODE_YUV420_CSPS_8:
+ case SENSOR_MIPI_MODE_YUV420_CSPS_10:
+ case SENSOR_MIPI_MODE_RGB444:
+ case SENSOR_MIPI_MODE_RGB555:
+ case SENSOR_MIPI_MODE_RGB565:
+ case SENSOR_MIPI_MODE_RGB666:
+ case SENSOR_MIPI_MODE_RGB888:
+ case SENSOR_MIPI_MODE_RAW_7:
+ case SENSOR_MIPI_MODE_RAW_6:
+ default:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 1;
+ break;
+ }
+ break;
+ case SENSOR_MODE_BAY_BT656:
+ ret_val = CI_ISP_PATH_BAYER;
+ words = 1;
+ break;
+ case SENSOR_MODE_RAW_BT656:
+ ret_val = CI_ISP_PATH_RAW;
+ words = 1;
+ break;
+ default:
+ ret_val = CI_ISP_PATH_UNKNOWN;
+ words = 1;
+ }
+
+ if (words_per_pixel)
+ *words_per_pixel = words ;
+ return ret_val;
+}
+
+/*
+ * configures the input acquisition according to the
+ * given config structure
+ */
+int ci_isp_set_input_aquisition(const struct ci_sensor_config *isi_cfg)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_ctrl = REG_READ(mrv_reg->isp_ctrl);
+ u32 isp_acq_prop = REG_READ(mrv_reg->isp_acq_prop);
+ u8 sample_factor;
+ u8 black_lines;
+
+ if (ci_isp_select_path(isi_cfg, &sample_factor)
+ == CI_ISP_PATH_UNKNOWN) {
+ eprintk("failed to select path");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->mode) {
+ case SENSOR_MODE_DATA:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_DATA);
+ break;
+ case SENSOR_MODE_PICT:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RAW);
+ break;
+ case SENSOR_MODE_RGB565:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RAW);
+ break;
+ case SENSOR_MODE_BT601:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_601);
+ break;
+ case SENSOR_MODE_BT656:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_656);
+ break;
+ case SENSOR_MODE_BAYER:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RGB);
+ break;
+ case SENSOR_MODE_BAY_BT656:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RGB656);
+ break;
+ case SENSOR_MODE_RAW_BT656:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RAW656);
+ break;
+
+ case SENSOR_MODE_SMIA:
+ switch (isi_cfg->smia_mode) {
+ case SENSOR_SMIA_MODE_RAW_12:
+ case SENSOR_SMIA_MODE_RAW_10:
+ case SENSOR_SMIA_MODE_RAW_8:
+ case SENSOR_SMIA_MODE_RAW_8_TO_10_DECOMP:
+ case SENSOR_SMIA_MODE_RAW_7:
+ case SENSOR_SMIA_MODE_RAW_6:
+ case SENSOR_SMIA_MODE_YUV_422:
+ case SENSOR_SMIA_MODE_YUV_420:
+ case SENSOR_SMIA_MODE_RGB_888:
+ case SENSOR_SMIA_MODE_RGB_565:
+ case SENSOR_SMIA_MODE_RGB_444:
+ case SENSOR_SMIA_MODE_COMPRESSED:
+ return CI_STATUS_SUCCESS;
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+ break;
+
+ case SENSOR_MODE_MIPI:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_MODE,
+ MRV_ISP_ISP_MODE_RGB);
+ REG_WRITE(mrv_reg->mipi_img_data_sel, 0x02b);
+ break;
+
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->bus_width) {
+ case SENSOR_BUSWIDTH_12BIT:
+ /* 000- 12Bit external Interface */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION,
+ MRV_ISP_INPUT_SELECTION_12EXT);
+ break;
+ case SENSOR_BUSWIDTH_10BIT_ZZ:
+ /* 001- 10Bit Interface, append 2 zeroes as LSBs */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION,
+ MRV_ISP_INPUT_SELECTION_10ZERO);
+ break;
+ case SENSOR_BUSWIDTH_10BIT_EX:
+ /* 010- 10Bit Interface, append 2 MSBs as LSBs */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION,
+ MRV_ISP_INPUT_SELECTION_10MSB);
+ break;
+ case SENSOR_BUSWIDTH_8BIT_ZZ:
+ /* 011- 8Bit Interface, append 4 zeroes as LSBs */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION,
+ MRV_ISP_INPUT_SELECTION_8ZERO);
+ break;
+ case SENSOR_BUSWIDTH_8BIT_EX:
+ /* 100- 8Bit Interface, append 4 MSBs as LSBs */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION,
+ MRV_ISP_INPUT_SELECTION_8MSB);
+ break;
+ /* 101...111 reserved */
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->field_sel) {
+ case SENSOR_FIELDSEL_ODD:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_FIELD_SELECTION,
+ MRV_ISP_FIELD_SELECTION_ODD);
+ break;
+ case SENSOR_FIELDSEL_EVEN:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_FIELD_SELECTION,
+ MRV_ISP_FIELD_SELECTION_EVEN);
+ break;
+ case SENSOR_FIELDSEL_BOTH:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_FIELD_SELECTION,
+ MRV_ISP_FIELD_SELECTION_BOTH);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->ycseq) {
+ case SENSOR_YCSEQ_CRYCBY:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CCIR_SEQ,
+ MRV_ISP_CCIR_SEQ_CRYCBY);
+ break;
+ case SENSOR_YCSEQ_CBYCRY:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CCIR_SEQ,
+ MRV_ISP_CCIR_SEQ_CBYCRY);
+ break;
+ case SENSOR_YCSEQ_YCRYCB:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CCIR_SEQ,
+ MRV_ISP_CCIR_SEQ_YCRYCB);
+ break;
+ case SENSOR_YCSEQ_YCBYCR:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CCIR_SEQ,
+ MRV_ISP_CCIR_SEQ_YCBYCR);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->conv422) {
+ case SENSOR_CONV422_INTER:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CONV_422,
+ MRV_ISP_CONV_422_INTER);
+ break;
+
+ case SENSOR_CONV422_NOCOSITED:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CONV_422,
+ MRV_ISP_CONV_422_NONCO);
+ break;
+ case SENSOR_CONV422_COSITED:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_CONV_422,
+ MRV_ISP_CONV_422_CO);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->bpat) {
+ case SENSOR_BPAT_BGBGGRGR:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_BAYER_PAT,
+ MRV_ISP_BAYER_PAT_BG);
+ break;
+ case SENSOR_BPAT_GBGBRGRG:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_BAYER_PAT,
+ MRV_ISP_BAYER_PAT_GB);
+ break;
+ case SENSOR_BPAT_GRGRBGBG:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_BAYER_PAT,
+ MRV_ISP_BAYER_PAT_GR);
+ break;
+ case SENSOR_BPAT_RGRGGBGB:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_BAYER_PAT,
+ MRV_ISP_BAYER_PAT_RG);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->vpol) {
+ case SENSOR_VPOL_POS:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_VSYNC_POL, 1);
+ break;
+ case SENSOR_VPOL_NEG:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_VSYNC_POL, 0);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->hpol) {
+ /* vsync_pol = 1 triggers on positive edge whereas */
+ /* hsync_pol = 1 triggers on negative edge and vice versa */
+ case SENSOR_HPOL_SYNCPOS:
+ /* trigger on negative edge */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 1);
+ break;
+ case SENSOR_HPOL_SYNCNEG:
+ /* trigger on positive edge */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 0);
+ break;
+ case SENSOR_HPOL_REFPOS:
+ /* trigger on positive edge */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 0);
+ break;
+ case SENSOR_HPOL_REFNEG:
+ /* trigger on negative edge */
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 1);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ switch (isi_cfg->edge) {
+ case SENSOR_EDGE_RISING:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_SAMPLE_EDGE, 1);
+ break;
+ case SENSOR_EDGE_FALLING:
+ REG_SET_SLICE(isp_acq_prop, MRV_ISP_SAMPLE_EDGE, 0);
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+ dprintk(2, "isp_acq_prop = 0x%x", isp_acq_prop);
+
+ /* now write values to registers */
+ REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl);
+ REG_WRITE(mrv_reg->isp_acq_prop, isp_acq_prop);
+
+ /* number of additional black lines at frame start */
+ switch (isi_cfg->bls) {
+ case SENSOR_BLS_OFF:
+ black_lines = 0;
+ break;
+ case SENSOR_BLS_TWO_LINES:
+ black_lines = 2;
+ break;
+ case SENSOR_BLS_FOUR_LINES:
+ black_lines = 4;
+ break;
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ REG_SET_SLICE(mrv_reg->isp_acq_h_offs, MRV_ISP_ACQ_H_OFFS,
+ 0 * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_offs, MRV_ISP_ACQ_V_OFFS, 0);
+
+ dprintk(2, "res = %x", isi_cfg->res);
+ switch (isi_cfg->res) {
+ /* 88x72 */
+ case SENSOR_RES_QQCIF:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QQCIF_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QQCIF_SIZE_V + black_lines);
+ break;
+ /* 160x120 */
+ case SENSOR_RES_QQVGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QQVGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QQVGA_SIZE_V + black_lines);
+ break;
+ /* 176x144 */
+ case SENSOR_RES_QCIF:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QCIF_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QCIF_SIZE_V + black_lines);
+ break;
+ /* 320x240 */
+ case SENSOR_RES_QVGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QVGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QVGA_SIZE_V + black_lines);
+ break;
+ /* 352x288 */
+ case SENSOR_RES_CIF:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ CIF_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ CIF_SIZE_V + black_lines);
+ break;
+ /* 640x480 */
+ case SENSOR_RES_VGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ VGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ VGA_SIZE_V + black_lines);
+ break;
+ /* 800x600 */
+ case SENSOR_RES_SVGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ SVGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ SVGA_SIZE_V + black_lines);
+ break;
+ /* 1024x768 */
+ case SENSOR_RES_XGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ XGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ XGA_SIZE_V + black_lines);
+ break;
+ case SENSOR_RES_720P:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ RES_720P_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ RES_720P_SIZE_V + black_lines);
+ break;
+ /* 1280x960 */
+ case SENSOR_RES_XGA_PLUS:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ XGA_PLUS_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ XGA_PLUS_SIZE_V + black_lines);
+ break;
+ /* 1280x1024 */
+ case SENSOR_RES_SXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ SXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ SXGA_SIZE_V + black_lines);
+ break;
+ /* 1600x1200 */
+ case SENSOR_RES_UXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QSVGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QSVGA_SIZE_V + black_lines);
+ break;
+ /* 1920x1280 */
+ case SENSOR_RES_1080P:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ 1920 * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ 1080 + black_lines);
+ break;
+ /* 2048x1536 */
+ case SENSOR_RES_QXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QXGA_SIZE_V + black_lines);
+ break;
+ /* 2586x2048 */
+ case SENSOR_RES_QSXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QSXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QSXGA_SIZE_V + black_lines);
+ break;
+ /* 2600x2048 */
+ case SENSOR_RES_QSXGA_PLUS:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QSXGA_PLUS_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QSXGA_PLUS_SIZE_V + black_lines);
+ break;
+ /* 2600x1950 */
+ case SENSOR_RES_QSXGA_PLUS2:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QSXGA_PLUS2_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QSXGA_PLUS2_SIZE_V + black_lines);
+ break;
+ /* 2686x2048, 5.30M */
+ case SENSOR_RES_QSXGA_PLUS3:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QSXGA_PLUS3_SIZE_V * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QSXGA_PLUS3_SIZE_V + black_lines);
+ break;
+ /* 2592*1944 5M */
+ case SENSOR_RES_QXGA_PLUS:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QXGA_PLUS_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QXGA_PLUS_SIZE_V + black_lines);
+ break;
+ /* 3200x2048, 6.56M */
+ case SENSOR_RES_WQSXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ WQSXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ WQSXGA_SIZE_V + black_lines);
+ break;
+ /* 3200x2400, 7.68M */
+ case SENSOR_RES_QUXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ QUXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ QUXGA_SIZE_V + black_lines);
+ break;
+ /* 3840x2400, 9.22M */
+ case SENSOR_RES_WQUXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ WQUXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ WQUXGA_SIZE_V + black_lines);
+ break;
+ /* 4096x3072, 12.59M */
+ case SENSOR_RES_HXGA:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ HXGA_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ HXGA_SIZE_V + black_lines);
+ break;
+ /* 4080x1024 */
+ case SENSOR_RES_YUV_HMAX:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ YUV_HMAX_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ YUV_HMAX_SIZE_V);
+ break;
+ /* 1024x4080 */
+ case SENSOR_RES_YUV_VMAX:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ YUV_VMAX_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ YUV_VMAX_SIZE_V);
+ break;
+ /* 4096x2048 */
+ case SENSOR_RES_RAWMAX:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ RAWMAX_SIZE_H);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ RAWMAX_SIZE_V);
+ break;
+ /* 352x240 */
+ case SENSOR_RES_BP1:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ BP1_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ BP1_SIZE_V);
+ break;
+ /* 720x480 */
+ case SENSOR_RES_L_AFM:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ L_AFM_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ L_AFM_SIZE_V);
+ break;
+ /* 128x96 */
+ case SENSOR_RES_M_AFM:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ M_AFM_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ M_AFM_SIZE_V);
+ break;
+ /* 64x32 */
+ case SENSOR_RES_S_AFM:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ S_AFM_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ S_AFM_SIZE_V);
+ break;
+ /* 1304x980 */
+ case SENSOR_RES_VGA_PLUS:
+ REG_SET_SLICE(mrv_reg->isp_acq_h_size, MRV_ISP_ACQ_H_SIZE,
+ VGA_PLUS_SIZE_H * sample_factor);
+ REG_SET_SLICE(mrv_reg->isp_acq_v_size, MRV_ISP_ACQ_V_SIZE,
+ VGA_PLUS_SIZE_V);
+ break;
+
+ default:
+ return CI_STATUS_NOTSUPP;
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * sets output window
+ */
+void ci_isp_set_output_formatter(const struct ci_isp_window *window,
+ enum ci_isp_conf_update_time update_time)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (window) {
+ REG_SET_SLICE(mrv_reg->isp_out_h_offs, MRV_IS_IS_H_OFFS,
+ window->hoffs);
+ REG_SET_SLICE(mrv_reg->isp_out_v_offs, MRV_IS_IS_V_OFFS,
+ window->voffs);
+ REG_SET_SLICE(mrv_reg->isp_out_h_size, MRV_IS_IS_H_SIZE,
+ window->hsize);
+ REG_SET_SLICE(mrv_reg->isp_out_v_size, MRV_IS_IS_V_SIZE,
+ window->vsize);
+
+ REG_SET_SLICE(mrv_reg->isp_is_h_offs, MRV_IS_IS_H_OFFS, 0);
+ REG_SET_SLICE(mrv_reg->isp_is_v_offs, MRV_IS_IS_V_OFFS, 0);
+ REG_SET_SLICE(mrv_reg->isp_is_h_size, MRV_IS_IS_H_SIZE,
+ window->hsize);
+ REG_SET_SLICE(mrv_reg->isp_is_v_size, MRV_IS_IS_V_SIZE,
+ window->vsize);
+
+ switch (update_time) {
+ case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+ /* frame synchronous update of shadow registers */
+ REG_SET_SLICE(mrv_reg->isp_ctrl,
+ MRV_ISP_ISP_GEN_CFG_UPD, ON);
+ break;
+ case CI_ISP_CFG_UPDATE_IMMEDIATE:
+ /* immediate update of shadow registers */
+ REG_SET_SLICE(mrv_reg->isp_ctrl,
+ MRV_ISP_ISP_CFG_UPD, ON);
+ break;
+ case CI_ISP_CFG_UPDATE_LATER:
+ /* no update from within this function */
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * programs the given Bayer pattern demosaic parameters
+ */
+void ci_isp_set_demosaic(enum ci_isp_demosaic_mode demosaic_mode,
+ u8 demosaic_th)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_demosaic = REG_READ(mrv_reg->isp_demosaic);
+
+ switch (demosaic_mode) {
+ case CI_ISP_DEMOSAIC_STANDARD:
+ REG_SET_SLICE(isp_demosaic, MRV_ISP_DEMOSAIC_MODE,
+ MRV_ISP_DEMOSAIC_MODE_STD);
+ break;
+ case CI_ISP_DEMOSAIC_ENHANCED:
+ REG_SET_SLICE(isp_demosaic, MRV_ISP_DEMOSAIC_MODE,
+ MRV_ISP_DEMOSAIC_MODE_ENH);
+ break;
+ default:
+ WARN_ON(!(false));
+ }
+
+ REG_SET_SLICE(isp_demosaic, MRV_ISP_DEMOSAIC_TH, demosaic_th);
+ REG_WRITE(mrv_reg->isp_demosaic, isp_demosaic);
+}
+
+/*
+ * Sets the dedicated AWB block mode.
+ */
+int ci_isp_set_wb_mode(enum ci_isp_awb_mode wb_mode)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ switch (wb_mode) {
+ case CI_ISP_AWB_COMPLETELY_OFF:
+ /* manual WB, no measurements*/
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MODE,
+ MRV_ISP_AWB_MODE_NOMEAS);
+ /* switch ABW block off */
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_AWB_ENABLE,
+ DISABLE);
+ break;
+ case CI_ISP_AWB_MAN_MEAS:
+ case CI_ISP_AWB_AUTO:
+ case CI_ISP_AWB_MAN_PUSH_AUTO:
+ case CI_ISP_AWB_ONLY_MEAS:
+ /* manual white balance, measure YCbCr means */
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MODE,
+ MRV_ISP_AWB_MODE_MEAS);
+ /* switch ABW block on */
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_AWB_ENABLE,
+ ENABLE);
+ break;
+ case CI_ISP_AWB_MAN_NOMEAS:
+ /* manual white balance, no measurements */
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MODE,
+ MRV_ISP_AWB_MODE_NOMEAS);
+ /* switch ABW block on */
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_AWB_ENABLE,
+ ENABLE);
+ break;
+ default:
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MODE,
+ MRV_ISP_AWB_MODE_NOMEAS);
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_AWB_ENABLE,
+ DISABLE);
+ return CI_STATUS_FAILURE;
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_get_wb_mode(enum ci_isp_awb_mode *wb_mode)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!wb_mode)
+ return CI_STATUS_NULL_POINTER;
+
+ if (REG_GET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_AWB_ENABLE) ==
+ DISABLE) {
+ *wb_mode = CI_ISP_AWB_COMPLETELY_OFF;
+ } else {
+
+ switch (REG_GET_SLICE(mrv_reg->isp_awb_prop,
+ MRV_ISP_AWB_MODE)) {
+ case MRV_ISP_AWB_MODE_MEAS:
+ *wb_mode = CI_ISP_AWB_MAN_MEAS;
+ break;
+ case MRV_ISP_AWB_MODE_NOMEAS:
+ *wb_mode = CI_ISP_AWB_MAN_NOMEAS;
+ break;
+ default:
+ *wb_mode = CI_ISP_AWB_COMPLETELY_OFF;
+ return CI_STATUS_FAILURE;
+ }
+ }
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_set_wb_meas_config(const struct ci_isp_wb_meas_config
+ *wb_meas_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_awb_thresh = REG_READ(mrv_reg->isp_awb_thresh);
+
+ if (!wb_meas_config)
+ return CI_STATUS_NULL_POINTER;
+
+ /* measurement window */
+ REG_SET_SLICE(mrv_reg->isp_awb_h_size, MRV_ISP_AWB_H_SIZE,
+ (u32) wb_meas_config->awb_window.hsize);
+ REG_SET_SLICE(mrv_reg->isp_awb_v_size, MRV_ISP_AWB_V_SIZE,
+ (u32) wb_meas_config->awb_window.vsize);
+ REG_SET_SLICE(mrv_reg->isp_awb_h_offs, MRV_ISP_AWB_H_OFFS,
+ (u32) wb_meas_config->awb_window.hoffs);
+ REG_SET_SLICE(mrv_reg->isp_awb_v_offs, MRV_ISP_AWB_V_OFFS,
+ (u32) wb_meas_config->awb_window.voffs);
+
+ /* adjust awb properties (Y_MAX compare) */
+ if (wb_meas_config->max_y == 0) {
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MAX_EN,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MAX_EN,
+ ENABLE);
+ }
+
+ /* measurement thresholds */
+ REG_SET_SLICE(isp_awb_thresh, MRV_ISP_AWB_MAX_Y,
+ (u32) wb_meas_config->max_y);
+ REG_SET_SLICE(isp_awb_thresh, MRV_ISP_AWB_MIN_Y__MAX_G,
+ (u32) wb_meas_config->min_y_max_g);
+ REG_SET_SLICE(isp_awb_thresh, MRV_ISP_AWB_MAX_CSUM,
+ (u32) wb_meas_config->max_csum);
+ REG_SET_SLICE(isp_awb_thresh, MRV_ISP_AWB_MIN_C,
+ (u32) wb_meas_config->min_c);
+ REG_WRITE(mrv_reg->isp_awb_thresh, isp_awb_thresh);
+ REG_SET_SLICE(mrv_reg->isp_awb_ref, MRV_ISP_AWB_REF_CR__MAX_R,
+ (u32)(wb_meas_config->ref_cr_max_r));
+ REG_SET_SLICE(mrv_reg->isp_awb_ref, MRV_ISP_AWB_REF_CB__MAX_B,
+ (u32)(wb_meas_config->ref_cb_max_b));
+
+ /* amount of measurement frames */
+ REG_SET_SLICE(mrv_reg->isp_awb_frames, MRV_ISP_AWB_FRAMES,
+ (u32) wb_meas_config->frames);
+
+ /* set measurement mode */
+ REG_SET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MEAS_MODE,
+ (u32)(wb_meas_config->meas_mode));
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_get_wb_meas_config(struct ci_isp_wb_meas_config *wb_meas_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!wb_meas_config)
+ return CI_STATUS_NULL_POINTER;
+
+ /* measurement window */
+ wb_meas_config->awb_window.hsize =
+ (u16) REG_GET_SLICE(mrv_reg->isp_awb_h_size, MRV_ISP_AWB_H_SIZE);
+ wb_meas_config->awb_window.vsize =
+ (u16) REG_GET_SLICE(mrv_reg->isp_awb_v_size, MRV_ISP_AWB_V_SIZE);
+ wb_meas_config->awb_window.hoffs =
+ (u16) REG_GET_SLICE(mrv_reg->isp_awb_h_offs, MRV_ISP_AWB_H_OFFS);
+ wb_meas_config->awb_window.voffs =
+ (u16) REG_GET_SLICE(mrv_reg->isp_awb_v_offs, MRV_ISP_AWB_V_OFFS);
+
+ /* measurement thresholds */
+ wb_meas_config->min_c =
+ (u8) REG_GET_SLICE(mrv_reg->isp_awb_thresh, MRV_ISP_AWB_MIN_C);
+ wb_meas_config->max_csum =
+ (u8) REG_GET_SLICE(mrv_reg->isp_awb_thresh, MRV_ISP_AWB_MAX_CSUM);
+ wb_meas_config->min_y_max_g =
+ (u8) REG_GET_SLICE(mrv_reg->isp_awb_thresh,
+ MRV_ISP_AWB_MIN_Y__MAX_G);
+ wb_meas_config->max_y =
+ (u8) REG_GET_SLICE(mrv_reg->isp_awb_thresh, MRV_ISP_AWB_MAX_Y);
+ wb_meas_config->ref_cb_max_b =
+ (u8)REG_GET_SLICE(mrv_reg->isp_awb_ref, MRV_ISP_AWB_REF_CB__MAX_B);
+ wb_meas_config->ref_cr_max_r =
+ (u8)REG_GET_SLICE(mrv_reg->isp_awb_ref, MRV_ISP_AWB_REF_CR__MAX_R);
+
+ /* amount of measurement frames */
+ wb_meas_config->frames =
+ (u8) REG_GET_SLICE(mrv_reg->isp_awb_frames, MRV_ISP_AWB_FRAMES);
+
+ /* overwrite max_y if the feature is disabled */
+ if (REG_GET_SLICE(mrv_reg->isp_awb_prop, MRV_ISP_AWB_MAX_EN) ==
+ DISABLE) {
+ wb_meas_config->max_y = 0;
+ }
+
+ /* get measurement mode */
+ wb_meas_config->meas_mode = REG_GET_SLICE(mrv_reg->isp_awb_prop,
+ MRV_ISP_AWB_MEAS_MODE);
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_get_wb_meas(struct ci_sensor_awb_mean *awb_mean)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (awb_mean == NULL)
+ return CI_STATUS_NULL_POINTER;
+
+ awb_mean->white = REG_GET_SLICE(mrv_reg->isp_awb_white_cnt,
+ MRV_ISP_AWB_WHITE_CNT);
+ awb_mean->mean_y_g = (u8) REG_GET_SLICE(mrv_reg->isp_awb_mean,
+ MRV_ISP_AWB_MEAN_Y__G);
+ awb_mean->mean_cb_b = (u8) REG_GET_SLICE(mrv_reg->isp_awb_mean,
+ MRV_ISP_AWB_MEAN_CB__B);
+ awb_mean->mean_cr_r = (u8) REG_GET_SLICE(mrv_reg->isp_awb_mean,
+ MRV_ISP_AWB_MEAN_CR__R);
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * calculates left-top and right-bottom register values
+ * for a given AF measurement window
+ */
+static int ci_isp_afm_wnd2_regs(const struct ci_isp_window *wnd, u32 *lt,
+ u32 *rb)
+{
+ WARN_ON(!((wnd != NULL) && (lt != NULL) && (rb != NULL)));
+
+ if (wnd->hsize && wnd->vsize) {
+ u32 left = wnd->hoffs;
+ u32 top = wnd->voffs;
+ u32 right = left + wnd->hsize - 1;
+ u32 bottom = top + wnd->vsize - 1;
+
+ if ((left < MRV_AFM_A_H_L_MIN)
+ || (left > MRV_AFM_A_H_L_MAX)
+ || (top < MRV_AFM_A_V_T_MIN)
+ || (top > MRV_AFM_A_V_T_MAX)
+ || (right < MRV_AFM_A_H_R_MIN)
+ || (right > MRV_AFM_A_H_R_MAX)
+ || (bottom < MRV_AFM_A_V_B_MIN)
+ || (bottom > MRV_AFM_A_V_B_MAX)) {
+ return CI_STATUS_OUTOFRANGE;
+ }
+
+ /* combine the values and return */
+ REG_SET_SLICE(*lt, MRV_AFM_A_H_L, left);
+ REG_SET_SLICE(*lt, MRV_AFM_A_V_T, top);
+ REG_SET_SLICE(*rb, MRV_AFM_A_H_R, right);
+ REG_SET_SLICE(*rb, MRV_AFM_A_V_B, bottom);
+ } else {
+ *lt = 0;
+ *rb = 0;
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_set_auto_focus(const struct ci_isp_af_config *af_config)
+{
+
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 result = CI_STATUS_SUCCESS;
+ u32 lt;
+ u32 rb;
+ /* disable measurement module */
+ REG_SET_SLICE(mrv_reg->isp_afm_ctrl, MRV_AFM_AFM_EN, DISABLE);
+
+ if (!af_config)
+ return result;
+
+ result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_a), <, &rb);
+ /* set measurement window boundaries */
+ if (result != CI_STATUS_SUCCESS)
+ return result;
+
+ REG_WRITE(mrv_reg->isp_afm_lt_a, lt);
+ REG_WRITE(mrv_reg->isp_afm_rb_a, rb);
+
+ result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_b),
+ <, &rb);
+
+ if (result != CI_STATUS_SUCCESS)
+ return result;
+
+ REG_WRITE(mrv_reg->isp_afm_lt_b, lt);
+ REG_WRITE(mrv_reg->isp_afm_rb_b, rb);
+
+ result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_c),
+ <, &rb);
+
+ if (result != CI_STATUS_SUCCESS)
+ return result;
+
+ REG_WRITE(mrv_reg->isp_afm_lt_c, lt);
+ REG_WRITE(mrv_reg->isp_afm_rb_c, rb);
+
+ /* set other af measurement paraneters */
+ REG_SET_SLICE(mrv_reg->isp_afm_thres, MRV_AFM_AFM_THRES,
+ af_config->threshold);
+ REG_SET_SLICE(mrv_reg->isp_afm_var_shift, MRV_AFM_LUM_VAR_SHIFT,
+ (af_config->var_shift >> 16));
+ REG_SET_SLICE(mrv_reg->isp_afm_var_shift, MRV_AFM_AFM_VAR_SHIFT,
+ (af_config->var_shift >> 0));
+
+ /* enable measurement module */
+ REG_SET_SLICE(mrv_reg->isp_afm_ctrl, MRV_AFM_AFM_EN, ENABLE);
+
+ return result;
+}
+
+
+void ci_isp_get_auto_focus_meas(struct ci_isp_af_meas *af_meas)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ WARN_ON(!(af_meas != NULL));
+
+ af_meas->afm_sum_a =
+ REG_GET_SLICE(mrv_reg->isp_afm_sum_a, MRV_AFM_AFM_SUM_A);
+ af_meas->afm_sum_b =
+ REG_GET_SLICE(mrv_reg->isp_afm_sum_b, MRV_AFM_AFM_SUM_B);
+ af_meas->afm_sum_c =
+ REG_GET_SLICE(mrv_reg->isp_afm_sum_c, MRV_AFM_AFM_SUM_C);
+ af_meas->afm_lum_a =
+ REG_GET_SLICE(mrv_reg->isp_afm_lum_a, MRV_AFM_AFM_LUM_A);
+ af_meas->afm_lum_b =
+ REG_GET_SLICE(mrv_reg->isp_afm_lum_b, MRV_AFM_AFM_LUM_B);
+ af_meas->afm_lum_c =
+ REG_GET_SLICE(mrv_reg->isp_afm_lum_c, MRV_AFM_AFM_LUM_C);
+}
+
+int ci_isp_set_ls_correction(struct ci_sensor_ls_corr_config *ls_corr_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 i, n;
+ u32 data = 0;
+ int enabled = false;
+
+ if (!ls_corr_config) {
+ REG_SET_SLICE(mrv_reg->isp_lsc_ctrl, MRV_LSC_LSC_EN, DISABLE);
+ return CI_STATUS_SUCCESS;
+ }
+
+ if (REG_GET_SLICE(mrv_reg->isp_lsc_ctrl, MRV_LSC_LSC_EN)) {
+ REG_SET_SLICE(mrv_reg->isp_lsc_ctrl,
+ MRV_LSC_LSC_EN, DISABLE);
+ msleep(1000);
+ enabled = true;
+ }
+
+ /* clear address counters */
+ REG_WRITE(mrv_reg->isp_lsc_r_table_addr, 0);
+ REG_WRITE(mrv_reg->isp_lsc_g_table_addr, 0);
+ REG_WRITE(mrv_reg->isp_lsc_b_table_addr, 0);
+
+ WARN_ON(!(((CI_ISP_MAX_LSC_SECTORS + 1) *
+ ((CI_ISP_MAX_LSC_SECTORS + 2) / 2)) ==
+ (MRV_LSC_R_RAM_ADDR_MAX + 1)));
+
+ /* 17 steps */
+ for (n = 0;
+ n < ((CI_ISP_MAX_LSC_SECTORS + 1) *
+ (CI_ISP_MAX_LSC_SECTORS + 1));
+ n += CI_ISP_MAX_LSC_SECTORS + 1) {
+ for (i = 0; i < (CI_ISP_MAX_LSC_SECTORS); i += 2) {
+ REG_SET_SLICE(data, MRV_LSC_R_SAMPLE_0,
+ ls_corr_config->ls_rdata_tbl[n + i]);
+ REG_SET_SLICE(data, MRV_LSC_R_SAMPLE_1,
+ ls_corr_config->ls_rdata_tbl
+ [n + i + 1]);
+ REG_WRITE(mrv_reg->isp_lsc_r_table_data, data);
+ REG_SET_SLICE(data, MRV_LSC_G_SAMPLE_0,
+ ls_corr_config->ls_gdata_tbl
+ [n + i]);
+ REG_SET_SLICE(data, MRV_LSC_G_SAMPLE_1,
+ ls_corr_config->ls_gdata_tbl
+ [n + i + 1]);
+ REG_WRITE(mrv_reg->isp_lsc_g_table_data, data);
+ REG_SET_SLICE(data, MRV_LSC_B_SAMPLE_0,
+ ls_corr_config->ls_bdata_tbl[n + i]);
+ REG_SET_SLICE(data, MRV_LSC_B_SAMPLE_1,
+ ls_corr_config->ls_bdata_tbl
+ [n + i + 1]);
+ REG_WRITE(mrv_reg->isp_lsc_b_table_data, data);
+ }
+
+ REG_SET_SLICE(data, MRV_LSC_R_SAMPLE_0,
+ ls_corr_config->ls_rdata_tbl
+ [n + CI_ISP_MAX_LSC_SECTORS]);
+ REG_SET_SLICE(data, MRV_LSC_R_SAMPLE_1, 0);
+ REG_WRITE(mrv_reg->isp_lsc_r_table_data, data);
+ REG_SET_SLICE(data, MRV_LSC_G_SAMPLE_0,
+ ls_corr_config->ls_gdata_tbl
+ [n + CI_ISP_MAX_LSC_SECTORS]);
+ REG_SET_SLICE(data, MRV_LSC_G_SAMPLE_1, 0);
+ REG_WRITE(mrv_reg->isp_lsc_g_table_data, data);
+ REG_SET_SLICE(data, MRV_LSC_B_SAMPLE_0,
+ ls_corr_config->ls_bdata_tbl
+ [n + CI_ISP_MAX_LSC_SECTORS]);
+ REG_SET_SLICE(data, MRV_LSC_B_SAMPLE_1, 0);
+ REG_WRITE(mrv_reg->isp_lsc_b_table_data, data);
+ }
+
+ /* program x size tables */
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_01, MRV_LSC_X_SECT_SIZE_0,
+ ls_corr_config->ls_xsize_tbl[0]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_01, MRV_LSC_X_SECT_SIZE_1,
+ ls_corr_config->ls_xsize_tbl[1]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_23, MRV_LSC_X_SECT_SIZE_2,
+ ls_corr_config->ls_xsize_tbl[2]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_23, MRV_LSC_X_SECT_SIZE_3,
+ ls_corr_config->ls_xsize_tbl[3]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_45, MRV_LSC_X_SECT_SIZE_4,
+ ls_corr_config->ls_xsize_tbl[4]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_45, MRV_LSC_X_SECT_SIZE_5,
+ ls_corr_config->ls_xsize_tbl[5]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_67, MRV_LSC_X_SECT_SIZE_6,
+ ls_corr_config->ls_xsize_tbl[6]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xsize_67, MRV_LSC_X_SECT_SIZE_7,
+ ls_corr_config->ls_xsize_tbl[7]);
+
+ /* program y size tables */
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_01, MRV_LSC_Y_SECT_SIZE_0,
+ ls_corr_config->ls_ysize_tbl[0]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_01, MRV_LSC_Y_SECT_SIZE_1,
+ ls_corr_config->ls_ysize_tbl[1]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_23, MRV_LSC_Y_SECT_SIZE_2,
+ ls_corr_config->ls_ysize_tbl[2]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_23, MRV_LSC_Y_SECT_SIZE_3,
+ ls_corr_config->ls_ysize_tbl[3]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_45, MRV_LSC_Y_SECT_SIZE_4,
+ ls_corr_config->ls_ysize_tbl[4]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_45, MRV_LSC_Y_SECT_SIZE_5,
+ ls_corr_config->ls_ysize_tbl[5]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_67, MRV_LSC_Y_SECT_SIZE_6,
+ ls_corr_config->ls_ysize_tbl[6]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ysize_67, MRV_LSC_Y_SECT_SIZE_7,
+ ls_corr_config->ls_ysize_tbl[7]);
+
+ /* program x grad tables */
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_01, MRV_LSC_XGRAD_0,
+ ls_corr_config->ls_xgrad_tbl[0]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_01, MRV_LSC_XGRAD_1,
+ ls_corr_config->ls_xgrad_tbl[1]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_23, MRV_LSC_XGRAD_2,
+ ls_corr_config->ls_xgrad_tbl[2]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_23, MRV_LSC_XGRAD_3,
+ ls_corr_config->ls_xgrad_tbl[3]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_45, MRV_LSC_XGRAD_4,
+ ls_corr_config->ls_xgrad_tbl[4]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_45, MRV_LSC_XGRAD_5,
+ ls_corr_config->ls_xgrad_tbl[5]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_67, MRV_LSC_XGRAD_6,
+ ls_corr_config->ls_xgrad_tbl[6]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_xgrad_67, MRV_LSC_XGRAD_7,
+ ls_corr_config->ls_xgrad_tbl[7]);
+
+ /* program y grad tables */
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_01, MRV_LSC_YGRAD_0,
+ ls_corr_config->ls_ygrad_tbl[0]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_01, MRV_LSC_YGRAD_1,
+ ls_corr_config->ls_ygrad_tbl[1]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_23, MRV_LSC_YGRAD_2,
+ ls_corr_config->ls_ygrad_tbl[2]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_23, MRV_LSC_YGRAD_3,
+ ls_corr_config->ls_ygrad_tbl[3]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_45, MRV_LSC_YGRAD_4,
+ ls_corr_config->ls_ygrad_tbl[4]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_45, MRV_LSC_YGRAD_5,
+ ls_corr_config->ls_ygrad_tbl[5]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_67, MRV_LSC_YGRAD_6,
+ ls_corr_config->ls_ygrad_tbl[6]);
+ REG_SET_SLICE(mrv_reg->isp_lsc_ygrad_67, MRV_LSC_YGRAD_7,
+ ls_corr_config->ls_ygrad_tbl[7]);
+
+ if (enabled) {
+ /* switch on lens chading correction */
+ REG_SET_SLICE(mrv_reg->isp_lsc_ctrl,
+ MRV_LSC_LSC_EN, ENABLE);
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_ls_correction_on_off(int ls_corr_on_off)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (ls_corr_on_off) {
+ /* switch on lens chading correction */
+ REG_SET_SLICE(mrv_reg->isp_lsc_ctrl, MRV_LSC_LSC_EN, ENABLE);
+ } else {
+ /* switch off lens chading correction */
+ REG_SET_SLICE(mrv_reg->isp_lsc_ctrl, MRV_LSC_LSC_EN, DISABLE);
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Sets the Bad Pixel Correction configuration
+ */
+int ci_isp_set_bp_correction(const struct ci_isp_bp_corr_config
+ *bp_corr_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_bp_ctrl = REG_READ(mrv_reg->isp_bp_ctrl);
+
+ if (!bp_corr_config) {
+ /* disable correction module */
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_HOT_COR_EN, DISABLE);
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_DEAD_COR_EN, DISABLE);
+ } else {
+ if (bp_corr_config->bp_corr_type == CI_ISP_BP_CORR_DIRECT) {
+ u32 isp_bp_cfg1 = REG_READ(mrv_reg->isp_bp_cfg1);
+ u32 isp_bp_cfg2 = REG_READ(mrv_reg->isp_bp_cfg2);
+
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_COR_TYPE,
+ MRV_BP_COR_TYPE_DIRECT);
+
+ WARN_ON(!(!REG_GET_SLICE(mrv_reg->isp_bp_ctrl,
+ MRV_BP_BP_DET_EN)));
+
+ /* threshold register only used for direct mode */
+ REG_SET_SLICE(isp_bp_cfg1, MRV_BP_HOT_THRES,
+ bp_corr_config->bp_abs_hot_thres);
+ REG_SET_SLICE(isp_bp_cfg1, MRV_BP_DEAD_THRES,
+ bp_corr_config->bp_abs_dead_thres);
+ REG_WRITE(mrv_reg->isp_bp_cfg1, isp_bp_cfg1);
+ REG_SET_SLICE(isp_bp_cfg2, MRV_BP_DEV_HOT_THRES,
+ bp_corr_config->bp_dev_hot_thres);
+ REG_SET_SLICE(isp_bp_cfg2, MRV_BP_DEV_DEAD_THRES,
+ bp_corr_config->bp_dev_dead_thres);
+ REG_WRITE(mrv_reg->isp_bp_cfg2, isp_bp_cfg2);
+ } else {
+ /* use bad pixel table */
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_COR_TYPE,
+ MRV_BP_COR_TYPE_TABLE);
+ }
+
+ if (bp_corr_config->bp_corr_rep == CI_ISP_BP_CORR_REP_LIN) {
+ /* use linear approch */
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_REP_APPR,
+ MRV_BP_REP_APPR_INTERPOL);
+ } else {
+ /* use best neighbour */
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_REP_APPR,
+ MRV_BP_REP_APPR_NEAREST);
+ }
+
+ switch (bp_corr_config->bp_corr_mode) {
+ case CI_ISP_BP_CORR_HOT_EN:
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_HOT_COR_EN, ENABLE);
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_DEAD_COR_EN, DISABLE);
+ break;
+ case CI_ISP_BP_CORR_DEAD_EN:
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_HOT_COR_EN, DISABLE);
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_DEAD_COR_EN, ENABLE);
+ break;
+ case CI_ISP_BP_CORR_HOT_DEAD_EN:
+ default:
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_HOT_COR_EN, ENABLE);
+ REG_SET_SLICE(isp_bp_ctrl, MRV_BP_DEAD_COR_EN, ENABLE);
+ break;
+ }
+ }
+
+ REG_WRITE(mrv_reg->isp_bp_ctrl, isp_bp_ctrl);
+
+ return CI_STATUS_SUCCESS;
+
+}
+
+/*
+ * Sets the Bad Pixel configuration for detection
+ */
+int ci_isp_set_bp_detection(const struct ci_isp_bp_det_config *bp_det_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!bp_det_config) {
+ REG_SET_SLICE(mrv_reg->isp_bp_ctrl, MRV_BP_BP_DET_EN, DISABLE);
+ } else {
+ WARN_ON(!(REG_GET_SLICE(mrv_reg->isp_bp_ctrl, MRV_BP_COR_TYPE)
+ == MRV_BP_COR_TYPE_TABLE));
+
+ /* set dead threshold for bad pixel detection */
+ REG_SET_SLICE(mrv_reg->isp_bp_cfg1, MRV_BP_DEAD_THRES,
+ bp_det_config->bp_dead_thres);
+
+ /* enable measurement module */
+ REG_SET_SLICE(mrv_reg->isp_bp_ctrl, MRV_BP_BP_DET_EN, ENABLE);
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_clear_bp_int(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ /* clear bp_det irq (only if it is signalled to prevent loss of irqs) */
+ if (REG_GET_SLICE(mrv_reg->isp_ris, MRV_ISP_RIS_BP_DET))
+ REG_SET_SLICE(mrv_reg->isp_icr, MRV_ISP_ICR_BP_DET, 1);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Initializes Isp filter registers with default reset values.
+ */
+static int ci_isp_initialize_filter_registers(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ mrv_reg->isp_filt_mode = 0x00000000;
+ mrv_reg->isp_filt_fac_sh1 = 0x00000010;
+ mrv_reg->isp_filt_fac_sh0 = 0x0000000C;
+ mrv_reg->isp_filt_fac_mid = 0x0000000A;
+ mrv_reg->isp_filt_fac_bl0 = 0x00000006;
+ mrv_reg->isp_filt_fac_bl1 = 0x00000002;
+ mrv_reg->isp_filt_thresh_bl0 = 0x0000000D;
+ mrv_reg->isp_filt_thresh_bl1 = 0x00000005;
+ mrv_reg->isp_filt_thresh_sh0 = 0x0000001A;
+ mrv_reg->isp_filt_thresh_sh1 = 0x0000002C;
+ mrv_reg->isp_filt_lum_weight = 0x00032040;
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_activate_filter(int activate_filter)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ int retval = CI_STATUS_SUCCESS;
+
+ /* Initialize ISP filter control registers first */
+ retval = ci_isp_initialize_filter_registers();
+ if (retval != CI_STATUS_SUCCESS)
+ return retval;
+
+ /* Activate or deactivate filter algorythm */
+ REG_SET_SLICE(mrv_reg->isp_filt_mode, MRV_FILT_FILT_ENABLE,
+ (activate_filter) ? ENABLE : DISABLE);
+
+ return retval;
+}
+
+/*
+ * Write coefficient and threshold values into Isp filter
+ * registers for noise, sharpness and blurring filtering.
+ */
+u32 sharp_fac_table[11][5] = {
+ /* fac1_sh1, fac_sh0, fac_mid, fac_bl0, fac_bl1 */
+ {0x00000004, 0x00000004, 0x00000004, 0x00000002, 0x00000000},
+ {0x00000008, 0x00000007, 0x00000006, 0x00000002, 0x00000000},
+ {0x0000000C, 0x0000000A, 0x00000008, 0x00000004, 0x00000000},
+ {0x00000010, 0x0000000C, 0x0000000A, 0x00000006, 0x00000002},
+ {0x00000016, 0x00000010, 0x0000000C, 0x00000008, 0x00000004},
+ {0x0000001B, 0x00000014, 0x00000010, 0x0000000A, 0x00000004},
+ {0x00000020, 0x0000001A, 0x00000013, 0x0000000C, 0x00000006},
+ {0x00000026, 0x0000001E, 0x00000017, 0x00000010, 0x00000008},
+ {0x0000002C, 0x00000024, 0x0000001D, 0x00000015, 0x0000000D},
+ {0x00000030, 0x0000002A, 0x00000022, 0x0000001A, 0x00000014},
+ {0x0000003F, 0x00000030, 0x00000028, 0x00000024, 0x00000020},
+
+};
+
+u32 noise_table[12][7] = {
+ /* sh1, sh0, bl0, bl1, mode, vmode, hmode */
+ {0x000000, 0x000000, 0x000000, 0x000000, 6, 1, 0},
+ {33, 18, 8, 2, 6, 3, 3},
+ {44, 26, 13, 4, 3, 3},
+ {51, 36, 23, 10, 4, 3, 3},
+ {67, 41, 26, 15, 3, 3, 3},
+ {100, 75, 50, 20, 3, 3, 3},
+ {120, 90, 60, 26, 2, 3, 3},
+ {150, 120, 80, 51, 2, 3, 3},
+ {200, 170, 140, 100, 2, 3, 3},
+ {300, 250, 180, 150, 0, 3, 3},
+ {1023, 1023, 1023, 1023, 0, 3, 3},
+ /* noise reduction level 99 */
+ {0x000003FF, 0x000003FF, 0x000003FF, 0x000003FF, 0, 0, 0},
+};
+
+int ci_isp_set_filter_params(u8 noise_reduc_level, u8 sharp_level)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_filt_mode = 0;
+
+ if (!REG_GET_SLICE(mrv_reg->isp_filt_mode, MRV_FILT_FILT_ENABLE))
+ return CI_STATUS_CANCELED;
+
+ REG_WRITE(mrv_reg->isp_filt_mode, isp_filt_mode);
+
+ if (sharp_level > 10)
+ return CI_STATUS_OUTOFRANGE;
+ if (noise_reduc_level != 99 && noise_reduc_level > 10)
+ return CI_STATUS_OUTOFRANGE;
+
+ if (noise_reduc_level == 99) {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1, noise_table[11][0]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+ MRV_FILT_FILT_THRESH_SH0, noise_table[11][1]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+ MRV_FILT_FILT_THRESH_BL0, noise_table[11][2]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+ MRV_FILT_FILT_THRESH_BL1, noise_table[11][3]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+ noise_table[11][4]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+ noise_table[11][5]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+ noise_table[11][6]);
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1,
+ noise_table[noise_reduc_level][0]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+ MRV_FILT_FILT_THRESH_SH0,
+ noise_table[noise_reduc_level][1]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+ MRV_FILT_FILT_THRESH_BL0,
+ noise_table[noise_reduc_level][2]);
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+ MRV_FILT_FILT_THRESH_BL1,
+ noise_table[noise_reduc_level][3]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+ noise_table[noise_reduc_level][4]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+ noise_table[noise_reduc_level][5]);
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+ noise_table[noise_reduc_level][6]);
+ }
+
+ if (noise_reduc_level == 9) {
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+ (sharp_level > 3) ? 2 : 1);
+ }
+
+ if (noise_reduc_level == 10) {
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+ (sharp_level > 5) ? 2 :
+ ((sharp_level > 3) ? 1 : 0));
+ }
+
+ /* sharp setting */
+ if (sharp_level == 8) {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+ MRV_FILT_FILT_THRESH_SH0, 0x00000013);
+ if (REG_GET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1) > 0x0000008A) {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1,
+ 0x0000008A);
+ }
+ } else if (sharp_level == 9) {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+ MRV_FILT_FILT_THRESH_SH0, 0x00000013);
+ if (REG_GET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1) > 0x0000008A) {
+ REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+ MRV_FILT_FILT_THRESH_SH1,
+ 0x0000008A);
+ }
+ }
+
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+ MRV_FILT_FILT_FAC_SH1, sharp_fac_table[sharp_level][0]);
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+ MRV_FILT_FILT_FAC_SH0, sharp_fac_table[sharp_level][1]);
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+ MRV_FILT_FILT_FAC_MID, sharp_fac_table[sharp_level][2]);
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+ MRV_FILT_FILT_FAC_BL0, sharp_fac_table[sharp_level][3]);
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+ MRV_FILT_FILT_FAC_BL1, sharp_fac_table[sharp_level][4]);
+
+ if (noise_reduc_level > 7) {
+ if (sharp_level > 7) {
+ u32 filt_fac_bl0 = REG_GET_SLICE
+ (mrv_reg->isp_filt_fac_bl0,
+ MRV_FILT_FILT_FAC_BL0);
+ u32 filt_fac_bl1 =
+ REG_GET_SLICE(mrv_reg->isp_filt_fac_bl1,
+ MRV_FILT_FILT_FAC_BL1);
+ /* * 0.50 */
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+ MRV_FILT_FILT_FAC_BL0,
+ (filt_fac_bl0) >> 1);
+ /* * 0.25 */
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+ MRV_FILT_FILT_FAC_BL1,
+ (filt_fac_bl1) >> 2);
+ } else if (sharp_level > 4) {
+ u32 filt_fac_bl0 =
+ REG_GET_SLICE(mrv_reg->isp_filt_fac_bl0,
+ MRV_FILT_FILT_FAC_BL0);
+ u32 filt_fac_bl1 =
+ REG_GET_SLICE(mrv_reg->
+ isp_filt_fac_bl1,
+ MRV_FILT_FILT_FAC_BL1);
+ /* * 0.75 */
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+ MRV_FILT_FILT_FAC_BL0,
+ (filt_fac_bl0 * 3) >> 2);
+ /* * 0.50 */
+ REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+ MRV_FILT_FILT_FAC_BL1,
+ (filt_fac_bl1) >> 1);
+ }
+ }
+
+ /* Set ISP filter mode register values */
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_MODE,
+ MRV_FILT_FILT_MODE_DYNAMIC);
+
+ /* enable filter */
+ REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_ENABLE, ENABLE);
+ REG_WRITE(mrv_reg->isp_filt_mode, isp_filt_mode);
+
+ return CI_STATUS_SUCCESS;
+}
+
+int ci_isp_meas_exposure_initialize_module(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ REG_SET_SLICE(mrv_reg->isp_exp_h_size, MRV_AE_ISP_EXP_H_SIZE, 0);
+ REG_SET_SLICE(mrv_reg->isp_exp_v_size, MRV_AE_ISP_EXP_V_SIZE, 0);
+ REG_SET_SLICE(mrv_reg->isp_exp_h_offset, MRV_AE_ISP_EXP_H_OFFSET, 0);
+ REG_SET_SLICE(mrv_reg->isp_exp_v_offset, MRV_AE_ISP_EXP_V_OFFSET, 0);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Configures the exposure measurement module.
+ */
+int ci_isp_meas_exposure_set_config(const struct ci_isp_window *wnd,
+ const struct ci_isp_exp_ctrl *isp_exp_ctrl)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!wnd) {
+ REG_SET_SLICE(mrv_reg->isp_exp_ctrl, MRV_AE_AUTOSTOP, ON);
+ REG_SET_SLICE(mrv_reg->isp_exp_ctrl, MRV_AE_EXP_START, OFF);
+ return CI_STATUS_SUCCESS;
+ }
+
+ /* range check */
+ if ((wnd->hoffs > MRV_AE_ISP_EXP_H_OFFSET_MAX)
+ || (wnd->hsize > MRV_AE_ISP_EXP_H_SIZE_MAX)
+ || (wnd->voffs > MRV_AE_ISP_EXP_V_OFFSET_MAX)
+ || (wnd->vsize > MRV_AE_ISP_EXP_V_SIZE_MAX)
+ || (wnd->vsize & ~MRV_AE_ISP_EXP_V_SIZE_VALID_MASK))
+ return CI_STATUS_OUTOFRANGE;
+
+ /* configure measurement windows */
+ REG_SET_SLICE(mrv_reg->isp_exp_h_size, MRV_AE_ISP_EXP_H_SIZE,
+ wnd->hsize);
+ REG_SET_SLICE(mrv_reg->isp_exp_v_size, MRV_AE_ISP_EXP_V_SIZE,
+ wnd->vsize);
+ REG_SET_SLICE(mrv_reg->isp_exp_h_offset, MRV_AE_ISP_EXP_H_OFFSET,
+ wnd->hoffs);
+ REG_SET_SLICE(mrv_reg->isp_exp_v_offset, MRV_AE_ISP_EXP_V_OFFSET,
+ wnd->voffs);
+
+ /* set exposure measurement mode */
+ REG_SET_SLICE(mrv_reg->isp_exp_ctrl, MRV_AE_EXP_MEAS_MODE,
+ (isp_exp_ctrl->exp_meas_mode) ? ON : OFF);
+
+ /* set or clear AE autostop bit */
+ REG_SET_SLICE(mrv_reg->isp_exp_ctrl, MRV_AE_AUTOSTOP,
+ (isp_exp_ctrl->auto_stop) ? ON : OFF);
+ REG_SET_SLICE(mrv_reg->isp_exp_ctrl, MRV_AE_EXP_START,
+ (isp_exp_ctrl->exp_start) ? ON : OFF);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Programs the given gamma curve for the input gamma
+ * block. Enables or disables gamma processing for the
+ * input gamma block.
+ */
+void ci_isp_set_gamma(const struct ci_sensor_gamma_curve *r,
+ const struct ci_sensor_gamma_curve *g,
+ const struct ci_sensor_gamma_curve *b)
+{
+ struct isp_register *mrv_reg = (struct isp_register *)MEM_MRV_REG_BASE;
+ const u8 shift_val = 16 - 12 /*MARVIN_FEATURE_CAMBUSWIDTH*/;
+ const u16 round_ofs = 0 << (shift_val - 1);
+ s32 i;
+
+ if (r) {
+ REG_WRITE(mrv_reg->isp_gamma_dx_lo, r->gamma_dx0);
+ REG_WRITE(mrv_reg->isp_gamma_dx_hi, r->gamma_dx1);
+
+ for (i = 0; i < MRV_ISP_GAMMA_R_Y_ARR_SIZE; i++) {
+ REG_SET_SLICE(mrv_reg->isp_gamma_r_y[i],
+ MRV_ISP_GAMMA_R_Y,
+ (r->isp_gamma_y[i] + round_ofs) >> shift_val);
+ REG_SET_SLICE(mrv_reg->isp_gamma_g_y[i],
+ MRV_ISP_GAMMA_G_Y,
+ (g->isp_gamma_y[i] + round_ofs) >> shift_val);
+ REG_SET_SLICE(mrv_reg->isp_gamma_b_y[i],
+ MRV_ISP_GAMMA_B_Y,
+ (b->isp_gamma_y[i] + round_ofs) >> shift_val);
+ }
+
+ REG_SET_SLICE(mrv_reg->isp_ctrl,
+ MRV_ISP_ISP_GAMMA_IN_ENABLE, ENABLE);
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_ctrl,
+ MRV_ISP_ISP_GAMMA_IN_ENABLE, DISABLE);
+ }
+}
+
+/*
+ * Programs the given gamma curve for the output gamma
+ * block. Enables or disables gamma processing for the
+ * output gamma block.
+ */
+void ci_isp_set_gamma2(const struct ci_isp_gamma_out_curve *gamma)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ s32 i;
+
+ if (gamma) {
+ WARN_ON(!(MRV_ISP_GAMMA_OUT_Y_ARR_SIZE ==
+ CI_ISP_GAMMA_OUT_CURVE_ARR_SIZE));
+
+ for (i = 0; i < MRV_ISP_GAMMA_OUT_Y_ARR_SIZE; i++) {
+ REG_SET_SLICE(mrv_reg->isp_gamma_out_y[i],
+ MRV_ISP_ISP_GAMMA_OUT_Y,
+ gamma->isp_gamma_y[i]);
+ }
+
+ REG_SET_SLICE(mrv_reg->isp_gamma_out_mode, MRV_ISP_EQU_SEGM,
+ gamma->gamma_segmentation);
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_GAMMA_OUT_ENABLE,
+ ENABLE);
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_ctrl,
+ MRV_ISP_ISP_GAMMA_OUT_ENABLE, DISABLE);
+ }
+
+}