new file mode 100644
@@ -0,0 +1,173 @@
+/*
+ * 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>
+ */
+
+#ifndef _MRV_H
+#define _MRV_H
+
+/* move structure definination to ci_isp_common.h */
+#include "ci_isp_common.h"
+
+/* sensor struct related functions */
+int ci_isp_bp_write_table(
+ const struct ci_sensor_bp_table *bp_table
+);
+int ci_isp_bp_read_table(struct ci_sensor_bp_table *bp_table);
+enum ci_isp_path ci_isp_select_path(
+ const struct ci_sensor_config *isi_cfg,
+ u8 *words_per_pixel
+);
+int ci_isp_set_input_aquisition(
+ const struct ci_sensor_config *isi_cfg
+);
+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
+);
+int ci_isp_get_wb_meas(struct ci_sensor_awb_mean *awb_mean);
+int ci_isp_set_bp_correction(
+ const struct ci_isp_bp_corr_config *bp_corr_config
+);
+int ci_isp_set_bp_detection(
+ const struct ci_isp_bp_det_config *bp_det_config
+);
+int ci_isp_clear_bp_int(void);
+u32 ci_isp_get_frame_end_irq_mask_dma(void);
+u32 ci_isp_get_frame_end_irq_mask_isp(void);
+int ci_isp_wait_for_frame_end(struct mrst_isp_device *intel);
+void ci_isp_set_output_formatter(
+ const struct ci_isp_window *window,
+ enum ci_isp_conf_update_time update_time
+);
+
+int ci_isp_is_set_config(const struct ci_isp_is_config *is_config);
+int ci_isp_set_data_path(
+ enum ci_isp_ycs_chn_mode ycs_chn_mode,
+ enum ci_isp_dp_switch dp_switch
+);
+void ci_isp_res_set_main_resize(const struct ci_isp_scale *scale,
+ enum ci_isp_conf_update_time update_time,
+ const struct ci_isp_rsz_lut *rsz_lut
+);
+void ci_isp_res_get_main_resize(struct ci_isp_scale *scale);
+void ci_isp_res_set_self_resize(const struct ci_isp_scale *scale,
+ enum ci_isp_conf_update_time update_time,
+ const struct ci_isp_rsz_lut *rsz_lut
+);
+void ci_isp_res_get_self_resize(struct ci_isp_scale *scale);
+int ci_isp_mif_set_main_buffer(
+ const struct ci_isp_mi_path_conf *mrv_mi_path_conf,
+ enum ci_isp_conf_update_time update_time
+);
+int ci_isp_mif_set_self_buffer(
+ const struct ci_isp_mi_path_conf *mrv_mi_path_conf,
+ enum ci_isp_conf_update_time update_time
+);
+
+int ci_isp_mif_set_dma_buffer(
+ const struct ci_isp_mi_path_conf *mrv_mi_path_conf
+);
+
+void ci_isp_mif_disable_all_paths(int perform_wait_for_frame_end);
+int ci_isp_mif_get_main_buffer(
+ struct ci_isp_mi_path_conf *mrv_mi_path_conf
+);
+int ci_isp_mif_get_self_buffer(
+ struct ci_isp_mi_path_conf *mrv_mi_path_conf
+);
+int ci_isp_mif_set_path_and_orientation(
+ const struct ci_isp_mi_ctrl *mrv_mi_ctrl
+);
+int ci_isp_mif_get_path_and_orientation(
+ struct ci_isp_mi_ctrl *mrv_mi_ctrl
+);
+int ci_isp_mif_set_configuration(
+ const struct ci_isp_mi_ctrl *mrv_mi_ctrl,
+ const struct ci_isp_mi_path_conf *mrv_mi_mp_path_conf,
+ const struct ci_isp_mi_path_conf *mrv_mi_sp_path_conf,
+ const struct ci_isp_mi_dma_conf *mrv_mi_dma_conf
+);
+int ci_isp_mif_set_dma_config(
+ const struct ci_isp_mi_dma_conf *mrv_mi_dma_conf
+);
+int ci_isp_mif_get_pixel_per32_bit_of_line(
+ u8 *pixel_per32_bit,
+ enum ci_isp_mif_col_format mrv_mif_sp_format,
+ enum ci_isp_mif_pic_form mrv_mif_pic_form,
+ int luminance_buffer
+);
+void ci_isp_set_ext_ycmode(void);
+int ci_isp_set_mipi_smia(u32 mode);
+void ci_isp_sml_out_set_path(enum ci_isp_data_path main_path);
+u32 ci_isp_mif_get_byte_cnt(void);
+void ci_isp_start(
+ u16 number_of_frames,
+ enum ci_isp_conf_update_time update_time
+);
+int ci_isp_jpe_init_ex(
+ u16 hsize,
+ u16 vsize,
+ u8 compression_ratio,
+ u8 jpe_scale
+);
+void ci_isp_reset_interrupt_status(void);
+void ci_isp_get_output_formatter(struct ci_isp_window *window);
+int ci_isp_set_auto_focus(const struct ci_isp_af_config *af_config);
+void ci_isp_get_auto_focus_meas(struct ci_isp_af_meas *af_meas);
+int ci_isp_chk_bp_int_stat(void);
+int ci_isp_bls_get_measured_values(
+ struct ci_isp_bls_measured *bls_measured
+);
+int ci_isp_get_wb_meas_config(
+ struct ci_isp_wb_meas_config *wb_meas_config
+);
+void ci_isp_col_set_color_processing(
+ const struct ci_isp_color_settings *col
+);
+int ci_isp_ie_set_config(const struct ci_isp_ie_config *ie_config);
+int ci_isp_set_ls_correction(struct ci_sensor_ls_corr_config *ls_corr_config);
+int ci_isp_ls_correction_on_off(int ls_corr_on_off);
+int ci_isp_activate_filter(int activate_filter);
+int ci_isp_set_filter_params(u8 noise_reduc_level, u8 sharp_level);
+int ci_isp_bls_set_config(const struct ci_isp_bls_config *bls_config);
+int ci_isp_set_wb_mode(enum ci_isp_awb_mode wb_mode);
+int ci_isp_set_wb_meas_config(
+ const struct ci_isp_wb_meas_config *wb_meas_config
+);
+int ci_isp_set_wb_auto_hw_config(
+ const struct ci_isp_wb_auto_hw_config *wb_auto_hw_config
+);
+void ci_isp_init(void);
+void ci_isp_off(void);
+void ci_isp_stop(enum ci_isp_conf_update_time update_time);
+void ci_isp_mif_reset_offsets(enum ci_isp_conf_update_time update_time);
+void ci_isp_set_gamma2(const struct ci_isp_gamma_out_curve *gamma);
+void ci_isp_set_demosaic(
+ enum ci_isp_demosaic_mode demosaic_mode,
+ u8 demosaic_th
+);
+void mrst_isp_disable_interrupt(struct mrst_isp_device *isp);
+void mrst_isp_enable_interrupt(struct mrst_isp_device *isp);
+#endif
new file mode 100644
@@ -0,0 +1,1362 @@
+/*
+ * 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"
+
+static unsigned long jiffies_start;
+
+void mrst_timer_start(void)
+{
+ jiffies_start = jiffies;
+}
+
+void mrst_timer_stop(void)
+{
+ jiffies_start = 0;
+}
+
+unsigned long mrst_get_micro_sec(void)
+{
+ unsigned long time_diff = 0;
+
+ time_diff = jiffies - jiffies_start;
+
+ return jiffies_to_msecs(time_diff);
+}
+
+/*
+ * Returns the ISP hardware ID.
+ */
+static u32 ci_isp_get_ci_isp_id(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 result = 0;
+
+ result = REG_GET_SLICE(mrv_reg->vi_id, MRV_REV_ID);
+
+ return result;
+}
+
+/*
+ * Gets the hardware ID and compares it with the expected one.
+ */
+static int ci_isp_verify_chip_id(void)
+{
+ u32 mrv_id = ci_isp_get_ci_isp_id();
+ dprintk(1, "HW-Id: 0x%08X", mrv_id);
+
+ if (mrv_id != 0x20453010) {
+ /* marvin5_v4_r20 */
+ eprintk("HW-Id does not match! read:0x%08X, expected:0x%08X",
+ mrv_id, 0x20453010);
+ return CI_STATUS_FAILURE;
+ }
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Triggers an entire reset of MARVIN (equaling an asynchronous
+ * hardware reset).
+ * Checks the hardware ID. A debug warning is issued if the
+ * module ID does not match the expected ID.
+ * Enables all clocks of all sub-modules.
+ * MARVIN is in idle state afterwards.
+ */
+void ci_isp_init(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ ci_isp_verify_chip_id();
+
+ /* enable main clock */
+ REG_SET_SLICE(mrv_reg->vi_ccl, MRV_VI_CCLFDIS, MRV_VI_CCLFDIS_ENABLE);
+
+ /*
+ * enable all clocks to make sure that all submodules will be able to
+ * perform the reset correctly
+ */
+ REG_SET_SLICE(mrv_reg->vi_iccl, MRV_VI_ALL_CLK_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->vi_ircl, MRV_VI_MARVIN_RST, ON);
+ msleep(CI_ISP_DELAY_AFTER_RESET);
+}
+
+void ci_isp_off(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ REG_SET_SLICE(mrv_reg->vi_ccl, MRV_VI_CCLFDIS,
+ MRV_VI_CCLFDIS_DISABLE);
+ REG_SET_SLICE(mrv_reg->vi_iccl, MRV_VI_ALL_CLK_ENABLE, DISABLE);
+}
+
+u32 ci_isp_get_frame_end_irq_mask_isp(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ switch (REG_GET_SLICE(mrv_reg->vi_dpcl, MRV_VI_DMA_SWITCH)) {
+ case MRV_VI_DMA_SWITCH_IE:
+ return 0;
+ case MRV_VI_DMA_SWITCH_SELF:
+ case MRV_VI_DMA_SWITCH_SI:
+ case MRV_VI_DMA_SWITCH_JPG:
+ default:
+ {
+ switch (REG_GET_SLICE
+ (mrv_reg->vi_dpcl, MRV_VI_CHAN_MODE)) {
+ case MRV_VI_CHAN_MODE_MP:
+ return MRV_MI_MP_FRAME_END_MASK;
+ case MRV_VI_CHAN_MODE_SP:
+ return MRV_MI_SP_FRAME_END_MASK;
+ case MRV_VI_CHAN_MODE_MP_SP:
+ return MRV_MI_MP_FRAME_END_MASK |
+ MRV_MI_SP_FRAME_END_MASK;
+ default:
+ return 0;
+ }
+ }
+ }
+
+}
+
+/*
+ * Programs the number of frames to capture. Clears frame end
+ * interrupt to allow waiting in ci_isp_wait_for_frame_end().
+ * Enables the ISP input acquisition and output formatter.
+ * If immediate=false, the hardware assures that enabling is
+ * done frame synchronously.
+ */
+void ci_isp_start(u16 number_of_frames,
+ enum ci_isp_conf_update_time update_time)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_ctrl = REG_READ(mrv_reg->isp_ctrl);
+ u32 eof_irq_mask = ci_isp_get_frame_end_irq_mask_isp();
+
+ /* max. 10 bits allowed */
+ WARN_ON(!(number_of_frames <= MRV_ISP_ACQ_NR_FRAMES_MAX));
+ REG_SET_SLICE(mrv_reg->isp_acq_nr_frames, MRV_ISP_ACQ_NR_FRAMES,
+ number_of_frames);
+
+ /* clear frame end interrupt */
+ REG_WRITE(mrv_reg->mi_icr, eof_irq_mask);
+
+ /*
+ * Input Acquisition is always enabled synchronous to the image sensor
+ * (no configuration update required). As soon as the input
+ * acquisition is started bit in_enable_shd in the register
+ * isp_flags_shd is set by hardware. In the following a frame end
+ * recognized by the input acquisition unit leads to
+ * ris_in_frame_end=1 in isp_ris. However a recognized frame end and
+ * no signaled errors are no guarantee for a valid configuration.
+ */
+
+ /*
+ * The output formatter is enabled frame synchronously according to
+ * the internal sync signals. Bit MRV_GEN_CFG_UPD has to be set. Bit
+ * isp_on_shd in isp_flags_shd is set when the output formatter is
+ * started. A recognized frame end is signaled with ris_out_frame_end
+ * in isp_ris.
+ */
+
+ /*
+ * The configuration of the input acquisition and the output
+ * formatter has to be correct to generate proper internal sync
+ * signals and thus a proper frame-synchronous update signal.
+ */
+
+ /* If the output formatter does not start check the following:
+ * sync polarities
+ * sample edge
+ * mode in register isp_ctrl
+ * sampling window of input acquisition <= picture size of image
+ * sensor
+ * output formatter window <= sampling window of input
+ * acquisition
+ */
+
+ /*
+ * If problems with the window sizes are suspected preferably add some
+ * offsets and reduce the window sizes, so that the above relations
+ * are true by all means.
+ */
+
+ switch (update_time) {
+ case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, ENABLE);
+ break;
+ case CI_ISP_CFG_UPDATE_IMMEDIATE:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CFG_UPD, ENABLE);
+ break;
+ case CI_ISP_CFG_UPDATE_LATER:
+ break;
+ default:
+ break;
+ }
+
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_INFORM_ENABLE, ENABLE);
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_ENABLE, ENABLE);
+ REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl);
+
+ dprintk(3, "ISP_CTRL = 0x%08X", mrv_reg->isp_ctrl);
+}
+
+/*
+ * Clear frame end interrupt to allow waiting in
+ * ci_isp_wait_for_frame_end(). Disable output formatter (frame
+ * synchronously).
+ */
+void ci_isp_stop(enum ci_isp_conf_update_time update_time)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_ctrl = REG_READ(mrv_reg->isp_ctrl);
+ u32 eof_irq_mask = ci_isp_get_frame_end_irq_mask_isp();
+
+ /* clear frame end interrupt */
+ REG_WRITE(mrv_reg->mi_icr, eof_irq_mask);
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_ENABLE, DISABLE);
+
+ switch (update_time) {
+ case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, ENABLE);
+ break;
+ case CI_ISP_CFG_UPDATE_IMMEDIATE:
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CFG_UPD, ENABLE);
+ break;
+ case CI_ISP_CFG_UPDATE_LATER:
+ break;
+ default:
+ break;
+ }
+
+ REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl);
+}
+
+/*
+ * Changes the data path settings.
+ */
+int ci_isp_set_data_path(enum ci_isp_ycs_chn_mode ycs_chn_mode,
+ enum ci_isp_dp_switch dp_switch)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 vi_dpcl = REG_READ(mrv_reg->vi_dpcl);
+ u32 vi_chan_mode;
+ u32 vi_mp_mux;
+
+ /* get desired setting for ycs_chan_mode (or vi_chan_mode) bits */
+ switch (ycs_chn_mode) {
+ case CI_ISP_YCS_OFF:
+ vi_chan_mode = MRV_VI_CHAN_MODE_OFF;
+ break;
+ case CI_ISP_YCS_Y:
+ vi_chan_mode = MRV_VI_CHAN_MODE_Y;
+ break;
+ case CI_ISP_YCS_MVRAW:
+ vi_chan_mode = MRV_VI_CHAN_MODE_MP_RAW;
+ break;
+ case CI_ISP_YCS_MV:
+ vi_chan_mode = MRV_VI_CHAN_MODE_MP;
+ break;
+ case CI_ISP_YCS_SP:
+ vi_chan_mode = MRV_VI_CHAN_MODE_SP;
+ break;
+ case CI_ISP_YCS_MV_SP:
+ vi_chan_mode = MRV_VI_CHAN_MODE_MP_SP;
+ break;
+ default:
+ eprintk("unknown value for ycs_chn_mode");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ if (vi_chan_mode & ~(MRV_VI_CHAN_MODE_MASK >> MRV_VI_CHAN_MODE_SHIFT)) {
+ eprintk("enum ci_isp_ycs_chn_mode not supported");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ /* get desired setting for vi_dp_switch (or vi_dp_mux) bits */
+ switch (dp_switch) {
+ case CI_ISP_DP_RAW:
+ vi_mp_mux = MRV_VI_MP_MUX_RAW;
+ break;
+ case CI_ISP_DP_JPEG:
+ vi_mp_mux = MRV_VI_MP_MUX_JPEG;
+ break;
+ case CI_ISP_DP_MV:
+ vi_mp_mux = MRV_VI_MP_MUX_MP;
+ break;
+ default:
+ eprintk("unknown value for dp_switch");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ if (vi_mp_mux & ~MRV_VI_MP_MUX_MASK) {
+ eprintk("dp_switch value not supported");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ /* program settings into MARVIN vi_dpcl register */
+ REG_SET_SLICE(vi_dpcl, MRV_VI_CHAN_MODE, vi_chan_mode);
+ REG_SET_SLICE(vi_dpcl, MRV_VI_MP_MUX, vi_mp_mux);
+ REG_WRITE(mrv_reg->vi_dpcl, vi_dpcl);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Changes the data path settings to SMIA or MIPI.
+ */
+int ci_isp_set_mipi_smia(u32 mode)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 if_select;
+
+ /* get desired setting for if_select bits */
+ switch (mode) {
+ case SENSOR_MODE_SMIA:
+ if_select = MRV_IF_SELECT_SMIA;
+ break;
+ case SENSOR_MODE_MIPI:
+ if_select = MRV_IF_SELECT_MIPI;
+ break;
+ case SENSOR_MODE_BAYER:
+ case SENSOR_MODE_BT601:
+ case SENSOR_MODE_BT656:
+ case SENSOR_MODE_PICT:
+ case SENSOR_MODE_DATA:
+ case SENSOR_MODE_BAY_BT656:
+ case SENSOR_MODE_RAW_BT656:
+ if_select = MRV_IF_SELECT_PAR;
+ break;
+ default:
+ eprintk("unknown value for mode");
+ return CI_STATUS_NOTSUPP;
+ }
+
+ /* program settings into MARVIN vi_dpcl register */
+ REG_SET_SLICE(mrv_reg->vi_dpcl, MRV_IF_SELECT, if_select);
+
+ if (if_select == MRV_IF_SELECT_MIPI)
+ REG_WRITE(mrv_reg->mipi_ctrl, 0x1001);
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Waits until the specified bits becomes signaled in the mi_ris
+ * register.
+ */
+static int ci_isp_wait_for_mi(struct mrst_isp_device *intel, u32 bit_mask)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 irq;
+ static int err_frame_cnt;
+ mrst_timer_start();
+ /*
+ * Wait for the curr BitMask. If the BitMask is zero, then it's no
+ * waiting.
+ */
+ while ((mrv_reg->mi_ris & bit_mask) != bit_mask) {
+
+ irq = REG_READ(mrv_reg->isp_ris);
+ if (irq & (MRV_ISP_RIS_DATA_LOSS_MASK
+ | MRV_ISP_RIS_PIC_SIZE_ERR_MASK)){
+ err_frame_cnt++;
+ dprintk(1, "irq = 0x%x, err rumber = %d", irq,
+ err_frame_cnt);
+ }
+ if (mrst_get_micro_sec() > 1000) {
+ dprintk(1, "time out");
+ mrst_timer_stop();
+ /*
+ * Try to recover. Softreset of submodules (but not
+ * entire marvin) resets processing and status
+ * information, but not configuration register
+ * content. Bits are sticky. So we have to clear them.
+ * Reset affects the MARVIN 1..2 clock cycles after
+ * the bits are set to high. So we don't have to wait
+ * in software before clearing them.
+ */
+ REG_SET_SLICE(mrv_reg->vi_ircl,
+ MRV_VI_ALL_SOFT_RST, ON);
+ REG_SET_SLICE(mrv_reg->vi_ircl,
+ MRV_VI_ALL_SOFT_RST, OFF);
+ msleep(CI_ISP_DELAY_AFTER_RESET);
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_CFG_UPD,
+ ON);
+ return CI_STATUS_FAILURE;
+ }
+ }
+
+ mrst_timer_stop();
+ if (REG_GET_SLICE(mrv_reg->isp_ris, MRV_ISP_RIS_DATA_LOSS))
+ dprintk(1, "no failure, but MRV_ISPINT_DATA_LOSS");
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Waits until a frame is written to memory (frame end
+ * interrupt occurs).
+ * Waits for the frame end interrupt of the memory
+ * interface.
+ */
+int ci_isp_wait_for_frame_end(struct mrst_isp_device *intel)
+{
+ return ci_isp_wait_for_mi(intel, ci_isp_get_frame_end_irq_mask_isp());
+}
+
+void ci_isp_reset_interrupt_status(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ /* ISP interrupt clear register */
+ REG_SET_SLICE(mrv_reg->isp_icr, MRV_ISP_ICR_ALL, ON);
+ REG_SET_SLICE(mrv_reg->isp_err_clr, MRV_ISP_ALL_ERR, ON);
+ REG_SET_SLICE(mrv_reg->mi_icr, MRV_MI_ALLIRQS, ON);
+ /* JPEG error interrupt clear register */
+ REG_SET_SLICE(mrv_reg->jpe_error_icr, MRV_JPE_ALL_ERR, ON);
+ /* JPEG status interrupt clear register */
+ REG_SET_SLICE(mrv_reg->jpe_status_icr, MRV_JPE_ALL_STAT, ON);
+
+ REG_WRITE(mrv_reg->mipi_icr, 0xffffffff);
+}
+
+void mrst_isp_disable_interrupt(struct mrst_isp_device *isp)
+{
+ struct isp_register *mrv_reg = (struct isp_register *)MEM_MRV_REG_BASE;
+ REG_SET_SLICE(mrv_reg->isp_imsc, MRV_ISP_IMSC_ALL, OFF);
+ REG_SET_SLICE(mrv_reg->mi_imsc, MRV_MI_ALLIRQS, OFF);
+ REG_SET_SLICE(mrv_reg->jpe_error_imr, MRV_JPE_ALL_ERR, OFF);
+ REG_SET_SLICE(mrv_reg->jpe_status_imr, MRV_JPE_ALL_STAT, OFF);
+ REG_WRITE(mrv_reg->mipi_imsc, 0x00000000);
+}
+
+void mrst_isp_enable_interrupt(struct mrst_isp_device *isp)
+{
+ struct isp_register *mrv_reg = (struct isp_register *)MEM_MRV_REG_BASE;
+
+ REG_SET_SLICE(mrv_reg->isp_imsc, MRV_ISP_IMSC_DATA_LOSS, ON);
+ REG_SET_SLICE(mrv_reg->isp_imsc, MRV_ISP_IMSC_PIC_SIZE_ERR, ON);
+ REG_WRITE(mrv_reg->mi_imsc, MRV_MI_MP_FRAME_END_MASK);
+ REG_SET_SLICE(mrv_reg->mi_imsc, MRV_MI_MBLK_LINE, ON);
+ REG_SET_SLICE(mrv_reg->jpe_error_imr, MRV_JPE_ALL_ERR, ON);
+ REG_SET_SLICE(mrv_reg->jpe_status_imr, MRV_JPE_ALL_STAT, ON);
+ REG_WRITE(mrv_reg->mipi_imsc, 0x00f00000);
+
+ ci_isp_reset_interrupt_status();
+}
+
+/*
+ * Set extended mode with unrestricted values for YCbCr
+ * Y (0-255) CbCr (0-255)
+ */
+void ci_isp_set_ext_ycmode(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_ctrl = REG_READ(mrv_reg->isp_ctrl);
+
+ /* modify isp_ctrl register */
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CSM_C_RANGE,
+ MRV_ISP_ISP_CSM_C_RANGE_FULL);
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CSM_Y_RANGE,
+ MRV_ISP_ISP_CSM_Y_RANGE_FULL);
+ REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl);
+
+ /* program RGB to YUV color conversion with extended range */
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_0, MRV_ISP_CC_COEFF_0, 0x0026);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_1, MRV_ISP_CC_COEFF_1, 0x004B);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_2, MRV_ISP_CC_COEFF_2, 0x000F);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_3, MRV_ISP_CC_COEFF_3, 0x01EA);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_4, MRV_ISP_CC_COEFF_4, 0x01D6);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_5, MRV_ISP_CC_COEFF_5, 0x0040);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_6, MRV_ISP_CC_COEFF_6, 0x0040);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_7, MRV_ISP_CC_COEFF_7, 0x01CA);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_8, MRV_ISP_CC_COEFF_8, 0x01F6);
+}
+
+void ci_isp_set_yc_mode(void)
+{
+ struct isp_register *mrv_reg = (struct isp_register *)MEM_MRV_REG_BASE;
+ u32 isp_ctrl = REG_READ(mrv_reg->isp_ctrl);
+
+ /* modify isp_ctrl register */
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CSM_C_RANGE,
+ MRV_ISP_ISP_CSM_Y_RANGE_BT601);
+ REG_SET_SLICE(isp_ctrl, MRV_ISP_ISP_CSM_Y_RANGE,
+ MRV_ISP_ISP_CSM_Y_RANGE_BT601);
+ REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl);
+
+ /* program RGB to YUV color conversion with extended range */
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_0, MRV_ISP_CC_COEFF_0, 0x0021);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_1, MRV_ISP_CC_COEFF_1, 0x0040);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_2, MRV_ISP_CC_COEFF_2, 0x000D);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_3, MRV_ISP_CC_COEFF_3, 0x01ED);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_4, MRV_ISP_CC_COEFF_4, 0x01DB);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_5, MRV_ISP_CC_COEFF_5, 0x0038);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_6, MRV_ISP_CC_COEFF_6, 0x0038);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_7, MRV_ISP_CC_COEFF_7, 0x01D1);
+ REG_SET_SLICE(mrv_reg->isp_cc_coeff_8, MRV_ISP_CC_COEFF_8, 0x01F7);
+}
+
+/*
+ * writes the color values for contrast, brightness,
+ * saturation and hue into the appropriate Marvin
+ * registers
+ */
+void ci_isp_col_set_color_processing(
+ const struct ci_isp_color_settings *col)
+{
+ struct isp_register *mrv_reg =
+ (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (col == NULL)
+ mrv_reg->c_proc_ctrl = 0;
+ else {
+ mrv_reg->c_proc_contrast = col->contrast;
+ mrv_reg->c_proc_brightness = col->brightness;
+ mrv_reg->c_proc_saturation = col->saturation;
+ mrv_reg->c_proc_hue = col->hue;
+
+ if (col->flags & CI_ISP_CPROC_C_OUT_RANGE) {
+ mrv_reg->c_proc_ctrl =
+ mrv_reg->c_proc_ctrl | CI_ISP_CPROC_C_OUT_RANGE;
+ }
+
+ if (col->flags & CI_ISP_CPROC_Y_IN_RANGE) {
+ mrv_reg->c_proc_ctrl =
+ mrv_reg->c_proc_ctrl | CI_ISP_CPROC_Y_IN_RANGE;
+ }
+
+ if (col->flags & CI_ISP_CPROC_Y_OUT_RANGE) {
+ mrv_reg->c_proc_ctrl =
+ mrv_reg->c_proc_ctrl | CI_ISP_CPROC_Y_OUT_RANGE;
+ }
+
+ if (col->flags & CI_ISP_CPROC_ENABLE) {
+ mrv_reg->c_proc_ctrl =
+ mrv_reg->c_proc_ctrl | CI_ISP_CPROC_ENABLE;
+ }
+ }
+}
+
+/*
+ * Translates a chrominance component value from usual
+ * representation (range 16..240, 128=neutral grey)
+ * to the one used by the ie_tint register
+ * The value is returned as 32 bit unsigned to support shift
+ * operation without explicit cast.
+ * The translation formular implemented here is taken from
+ * the image effects functional specification document,
+ * Doc-ID 30-001-481.130, revision 1.1 from november, 21st. 2005
+ */
+static u32 ci_isp_ie_tint_cx2_reg_val(u8 cx)
+{
+ s32 temp;
+ u32 reg_val;
+
+ temp = 128 - (s32) cx;
+ temp = ((temp * 64) / 110);
+
+ /* convert from two's complement to sign/value */
+ if (temp < 0) {
+ reg_val = 0x80;
+ temp *= (-1);
+ } else
+ reg_val = 0;
+
+ /* saturate at 7 bits */
+ if (temp > 0x7F)
+ temp = 0x7F;
+
+ /* combine sign and value to build the regiter value */
+ reg_val |= (u32) temp;
+
+ return reg_val;
+}
+
+/*
+ * Translates usual (decimal) matrix coefficient into the
+ * 4 bit register representation (used in the ie_mat_X registers).
+ * for unsupported decimal numbers, a supported replacement is
+ * selected automatically.
+ * The value is returned as 32 bit unsigned to support shift
+ * operation without explicit cast.
+ * The translation formular implemented here is taken from
+ * the image effects functional specification document,
+ * Doc-ID 30-001-481.130, revision 1.1 from november, 21st. 2005
+ */
+static u32 ci_isp_ie_mx_dec2_reg_val(s8 dec)
+{
+ u32 val;
+ switch (dec) {
+ case -2:
+ val = 0x0d;
+ break;
+ case -1:
+ val = 0x0c;
+ break;
+ case 0:
+ val = 0x00;
+ break;
+ case 1:
+ val = 0x08;
+ break;
+ case 2:
+ val = 0x09;
+ break;
+ default:
+ if (dec <= (-6))
+ val = 0x0f;
+ else if (dec <= (-3))
+ val = 0x0e;
+ else if (dec < 6)
+ val = 0x0a;
+ else
+ val = 0x0b;
+ break;
+ }
+
+ return val;
+}
+
+/*
+ * translates the values of the given configuration
+ * structure into register settings for the image effects
+ * submodule and loads the registers.
+ */
+int ci_isp_ie_set_config(const struct ci_isp_ie_config *ie_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!ie_config) {
+ REG_SET_SLICE(mrv_reg->img_eff_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_BYPASS);
+ } else {
+ /* apply the given settings */
+ u32 ul_ie_ctrl = REG_READ(mrv_reg->img_eff_ctrl);
+ u32 ul_ie_csel = REG_READ(mrv_reg->img_eff_color_sel);
+ u32 ul_ie_tint = REG_READ(mrv_reg->img_eff_tint);
+ u32 ul_ie_mat1 = REG_READ(mrv_reg->img_eff_mat_1);
+ u32 ul_ie_mat2 = REG_READ(mrv_reg->img_eff_mat_2);
+ u32 ul_ie_mat3 = REG_READ(mrv_reg->img_eff_mat_3);
+ u32 ul_ie_mat4 = REG_READ(mrv_reg->img_eff_mat_4);
+ u32 ul_ie_mat5 = REG_READ(mrv_reg->img_eff_mat_5);
+
+ /* overall operation mode */
+ switch (ie_config->mode) {
+ case CI_ISP_IE_MODE_OFF:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_BYPASS);
+ break;
+ case CI_ISP_IE_MODE_GRAYSCALE:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_GRAY);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ case CI_ISP_IE_MODE_NEGATIVE:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_NEGATIVE);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ case CI_ISP_IE_MODE_SEPIA:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_SEPIA);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ case CI_ISP_IE_MODE_COLOR_SEL:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_COLOR_SEL);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ case CI_ISP_IE_MODE_EMBOSS:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_EMBOSS);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ case CI_ISP_IE_MODE_SKETCH:
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_EFFECT_MODE,
+ MRV_IMGEFF_EFFECT_MODE_SKETCH);
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_BYPASS_MODE,
+ MRV_IMGEFF_BYPASS_MODE_PROCESS);
+ break;
+ default:
+ return CI_STATUS_OUTOFRANGE;
+ }
+
+ /* use next frame sync update */
+ REG_SET_SLICE(ul_ie_ctrl, MRV_IMGEFF_CFG_UPD, ON);
+
+ /* color selection settings */
+ REG_SET_SLICE(ul_ie_csel, MRV_IMGEFF_COLOR_THRESHOLD,
+ (u32) (ie_config->color_thres));
+ REG_SET_SLICE(ul_ie_csel, MRV_IMGEFF_COLOR_SELECTION,
+ (u32) (ie_config->color_sel));
+
+ /* tint color settings */
+ REG_SET_SLICE(ul_ie_tint, MRV_IMGEFF_INCR_CB,
+ ci_isp_ie_tint_cx2_reg_val(ie_config->tint_cb));
+ REG_SET_SLICE(ul_ie_tint, MRV_IMGEFF_INCR_CR,
+ ci_isp_ie_tint_cx2_reg_val(ie_config->tint_cr));
+
+ /* matrix coefficients */
+ REG_SET_SLICE(ul_ie_mat1, MRV_IMGEFF_EMB_COEF_11_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_11));
+ REG_SET_SLICE(ul_ie_mat1, MRV_IMGEFF_EMB_COEF_12_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_12));
+ REG_SET_SLICE(ul_ie_mat1, MRV_IMGEFF_EMB_COEF_13_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_13));
+ REG_SET_SLICE(ul_ie_mat1, MRV_IMGEFF_EMB_COEF_21_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_21));
+ REG_SET_SLICE(ul_ie_mat2, MRV_IMGEFF_EMB_COEF_22_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_22));
+ REG_SET_SLICE(ul_ie_mat2, MRV_IMGEFF_EMB_COEF_23_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_23));
+ REG_SET_SLICE(ul_ie_mat2, MRV_IMGEFF_EMB_COEF_31_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_31));
+ REG_SET_SLICE(ul_ie_mat2, MRV_IMGEFF_EMB_COEF_32_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_32));
+ REG_SET_SLICE(ul_ie_mat3, MRV_IMGEFF_EMB_COEF_33_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_emboss.
+ coeff_33));
+ REG_SET_SLICE(ul_ie_mat3, MRV_IMGEFF_SKET_COEF_11_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_11));
+ REG_SET_SLICE(ul_ie_mat3, MRV_IMGEFF_SKET_COEF_12_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_12));
+ REG_SET_SLICE(ul_ie_mat3, MRV_IMGEFF_SKET_COEF_13_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_13));
+ REG_SET_SLICE(ul_ie_mat4, MRV_IMGEFF_SKET_COEF_21_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_21));
+ REG_SET_SLICE(ul_ie_mat4, MRV_IMGEFF_SKET_COEF_22_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_22));
+ REG_SET_SLICE(ul_ie_mat4, MRV_IMGEFF_SKET_COEF_23_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_23));
+ REG_SET_SLICE(ul_ie_mat4, MRV_IMGEFF_SKET_COEF_31_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_31));
+ REG_SET_SLICE(ul_ie_mat5, MRV_IMGEFF_SKET_COEF_32_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_32));
+ REG_SET_SLICE(ul_ie_mat5, MRV_IMGEFF_SKET_COEF_33_4,
+ ci_isp_ie_mx_dec2_reg_val(ie_config->mat_sketch.
+ coeff_33));
+
+ /* write changed values back to registers */
+ REG_WRITE(mrv_reg->img_eff_ctrl, ul_ie_ctrl);
+ REG_WRITE(mrv_reg->img_eff_color_sel, ul_ie_csel);
+ REG_WRITE(mrv_reg->img_eff_tint, ul_ie_tint);
+ REG_WRITE(mrv_reg->img_eff_mat_1, ul_ie_mat1);
+ REG_WRITE(mrv_reg->img_eff_mat_2, ul_ie_mat2);
+ REG_WRITE(mrv_reg->img_eff_mat_3, ul_ie_mat3);
+ REG_WRITE(mrv_reg->img_eff_mat_4, ul_ie_mat4);
+ REG_WRITE(mrv_reg->img_eff_mat_5, ul_ie_mat5);
+
+ /* frame synchronous update of shadow registers */
+ REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, ON);
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Applies the new image stabilisation settings to the module.
+ */
+int ci_isp_is_set_config(const struct ci_isp_is_config *is_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!is_config) {
+ eprintk("is_config NULL");
+ return CI_STATUS_NULL_POINTER;
+ }
+
+ /* set maximal margin distance for X */
+ if (is_config->max_dx > MRV_IS_IS_MAX_DX_MAX) {
+ REG_SET_SLICE(mrv_reg->isp_is_max_dx, MRV_IS_IS_MAX_DX,
+ (u32) (MRV_IS_IS_MAX_DX_MAX));
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_is_max_dx, MRV_IS_IS_MAX_DX,
+ (u32) (is_config->max_dx));
+ }
+
+ /* set maximal margin distance for Y */
+ if (is_config->max_dy > MRV_IS_IS_MAX_DY_MAX) {
+ REG_SET_SLICE(mrv_reg->isp_is_max_dy, MRV_IS_IS_MAX_DY,
+ (u32) (MRV_IS_IS_MAX_DY_MAX));
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_is_max_dy, MRV_IS_IS_MAX_DY,
+ (u32) (is_config->max_dy));
+ }
+
+ REG_SET_SLICE(mrv_reg->isp_is_h_offs, MRV_IS_IS_H_OFFS,
+ (u32) (is_config->mrv_is_window.hoffs));
+ REG_SET_SLICE(mrv_reg->isp_is_v_offs, MRV_IS_IS_V_OFFS,
+ (u32) (is_config->mrv_is_window.voffs));
+ REG_SET_SLICE(mrv_reg->isp_is_h_size, MRV_IS_IS_H_SIZE,
+ (u32) (is_config->mrv_is_window.hsize));
+ REG_SET_SLICE(mrv_reg->isp_is_v_size, MRV_IS_IS_V_SIZE,
+ (u32) (is_config->mrv_is_window.vsize));
+
+ return CI_STATUS_SUCCESS;
+}
+
+static int ci_isp_bls_set_fixed_values(const struct ci_isp_bls_subtraction
+ *bls_subtraction)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+ if (!bls_subtraction)
+ return CI_STATUS_NULL_POINTER;
+
+ if ((bls_subtraction->fixed_a > MRV_ISP_BLS_FIX_SUB_MAX) ||
+ (bls_subtraction->fixed_b > MRV_ISP_BLS_FIX_SUB_MAX) ||
+ (bls_subtraction->fixed_c > MRV_ISP_BLS_FIX_SUB_MAX) ||
+ (bls_subtraction->fixed_d > MRV_ISP_BLS_FIX_SUB_MAX) ||
+ (bls_subtraction->fixed_a < (s16) MRV_ISP_BLS_FIX_SUB_MIN) ||
+ (bls_subtraction->fixed_b < (s16) MRV_ISP_BLS_FIX_SUB_MIN) ||
+ (bls_subtraction->fixed_c < (s16) MRV_ISP_BLS_FIX_SUB_MIN) ||
+ (bls_subtraction->fixed_d < (s16) MRV_ISP_BLS_FIX_SUB_MIN)) {
+ return CI_STATUS_OUTOFRANGE;
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_bls_a_fixed, MRV_BLS_BLS_A_FIXED,
+ bls_subtraction->fixed_a);
+ REG_SET_SLICE(mrv_reg->isp_bls_b_fixed, MRV_BLS_BLS_B_FIXED, \
+ bls_subtraction->fixed_b);
+ REG_SET_SLICE(mrv_reg->isp_bls_c_fixed, MRV_BLS_BLS_C_FIXED,
+ bls_subtraction->fixed_c);
+ REG_SET_SLICE(mrv_reg->isp_bls_d_fixed, MRV_BLS_BLS_D_FIXED,
+ bls_subtraction->fixed_d);
+ }
+
+ return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Sets the desired configuration values to the BLS registers,
+ * if possible. In the case the parameter (bls_config == NULL)
+ * the BLS module will be deactivated.
+ */
+int ci_isp_bls_set_config(const struct ci_isp_bls_config *bls_config)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 isp_bls_ctrl = 0;
+
+ int error = CI_STATUS_FAILURE;
+
+ if (!bls_config) {
+ REG_SET_SLICE(mrv_reg->isp_bls_ctrl,
+ MRV_BLS_BLS_ENABLE, DISABLE);
+ return CI_STATUS_SUCCESS;
+ }
+
+ /* measurement window 2, enable_window =0 */
+ if (bls_config->isp_bls_window2.enable_window) {
+ if ((bls_config->isp_bls_window2.start_h >
+ MRV_BLS_BLS_H2_START_MAX)
+ || (bls_config->isp_bls_window2.stop_h >
+ MRV_BLS_BLS_H2_STOP_MAX)
+ || (bls_config->isp_bls_window2.start_v >
+ MRV_BLS_BLS_V2_START_MAX)
+ || (bls_config->isp_bls_window2.stop_v >
+ MRV_BLS_BLS_V2_STOP_MAX)) {
+ return CI_STATUS_OUTOFRANGE;
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_bls_h2_start,
+ MRV_BLS_BLS_H2_START,
+ bls_config->isp_bls_window2.start_h);
+ REG_SET_SLICE(mrv_reg->isp_bls_h2_stop,
+ MRV_BLS_BLS_H2_STOP,
+ bls_config->isp_bls_window2.stop_h);
+ REG_SET_SLICE(mrv_reg->isp_bls_v2_start,
+ MRV_BLS_BLS_V2_START,
+ bls_config->isp_bls_window2.start_v);
+ REG_SET_SLICE(mrv_reg->isp_bls_v2_stop,
+ MRV_BLS_BLS_V2_STOP,
+ bls_config->isp_bls_window2.stop_v);
+ }
+ }
+
+ /* measurement window 1, enable_window=0 */
+ if (bls_config->isp_bls_window1.enable_window) {
+ if ((bls_config->isp_bls_window1.start_h >
+ MRV_BLS_BLS_H1_START_MAX)
+ || (bls_config->isp_bls_window1.stop_h >
+ MRV_BLS_BLS_H1_STOP_MAX)
+ || (bls_config->isp_bls_window1.start_v >
+ MRV_BLS_BLS_V1_START_MAX)
+ || (bls_config->isp_bls_window1.stop_v >
+ MRV_BLS_BLS_V1_STOP_MAX)) {
+ return CI_STATUS_OUTOFRANGE;
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_bls_h1_start,
+ MRV_BLS_BLS_H1_START,
+ bls_config->isp_bls_window1.start_h);
+ REG_SET_SLICE(mrv_reg->isp_bls_h1_stop,
+ MRV_BLS_BLS_H1_STOP,
+ bls_config->isp_bls_window1.stop_h);
+ REG_SET_SLICE(mrv_reg->isp_bls_v1_start,
+ MRV_BLS_BLS_V1_START,
+ bls_config->isp_bls_window1.start_v);
+ REG_SET_SLICE(mrv_reg->isp_bls_v1_stop,
+ MRV_BLS_BLS_V1_STOP,
+ bls_config->isp_bls_window1.stop_v);
+ }
+ }
+
+ if (bls_config->bls_samples > MRV_BLS_BLS_SAMPLES_MAX) {
+ return CI_STATUS_OUTOFRANGE;
+ } else {
+ REG_SET_SLICE(mrv_reg->isp_bls_samples, MRV_BLS_BLS_SAMPLES,
+ bls_config->bls_samples);
+ }
+
+ /* fixed subtraction values, enable_automatic=0 */
+ if (!bls_config->enable_automatic) {
+ error = ci_isp_bls_set_fixed_values(
+ &(bls_config->bls_subtraction));
+ if (error != CI_STATUS_SUCCESS)
+ return error;
+ }
+
+ if ((bls_config->disable_h) || (bls_config->disable_v))
+ return CI_STATUS_OUTOFRANGE;
+
+ isp_bls_ctrl = REG_READ(mrv_reg->isp_bls_ctrl);
+
+ /* enable measurement window(s) */
+ REG_SET_SLICE(isp_bls_ctrl, MRV_BLS_WINDOW_ENABLE,
+ ((bls_config->isp_bls_window1.enable_window)
+ ? MRV_BLS_WINDOW_ENABLE_WND1 : 0) |
+ ((bls_config->isp_bls_window2.enable_window)
+ ? MRV_BLS_WINDOW_ENABLE_WND2 : 0));
+
+ REG_SET_SLICE(isp_bls_ctrl, MRV_BLS_BLS_MODE,
+ (bls_config->enable_automatic) ? MRV_BLS_BLS_MODE_MEAS :
+ MRV_BLS_BLS_MODE_FIX);
+
+ /* enable module */
+ REG_SET_SLICE(isp_bls_ctrl, MRV_BLS_BLS_ENABLE, ENABLE);
+
+ /* write into register */
+ REG_WRITE(mrv_reg->isp_bls_ctrl, isp_bls_ctrl);
+
+ return CI_STATUS_SUCCESS;
+}
+
+#define RSZ_FLAGS_MASK (RSZ_UPSCALE_ENABLE | RSZ_SCALER_BYPASS)
+
+/*
+ * writes the scaler values to the appropriate Marvin registers.
+ */
+void ci_isp_res_set_main_resize(const struct ci_isp_scale *scale,
+ enum ci_isp_conf_update_time update_time,
+ const struct ci_isp_rsz_lut *rsz_lut)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 mrsz_ctrl = REG_READ(mrv_reg->mrsz_ctrl);
+ u32 i;
+ int upscaling = false;
+
+ /* flags must be "outside" scaler value */
+ WARN_ON(!((RSZ_FLAGS_MASK & MRV_RSZ_SCALE_MASK) == 0));
+ WARN_ON(!((scale->scale_hy & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_hcb & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_hcr & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_vy & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_vc & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+
+ /* horizontal luminance scale factor */
+ dprintk(1, "scale_hy = %d( %x )", scale->scale_hy, scale->scale_hy);
+
+ if (scale->scale_hy & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_ENABLE, DISABLE);
+ } else {
+ /* enable scaler */
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_ENABLE, ENABLE);
+ /* program scale factor and phase */
+ REG_SET_SLICE(mrv_reg->mrsz_scale_hy, MRV_MRSZ_SCALE_HY,
+ (u32) scale->scale_hy);
+ REG_SET_SLICE(mrv_reg->mrsz_phase_hy, MRV_MRSZ_PHASE_HY,
+ (u32) scale->phase_hy);
+
+ if (scale->scale_hy & RSZ_UPSCALE_ENABLE) {
+ /* enable upscaling mode */
+ dprintk(1, "enable up scale");
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_UP,
+ MRV_MRSZ_SCALE_HY_UP_UPSCALE);
+ /* scaler and upscaling enabled */
+ upscaling = true;
+ } else
+ /* disable upscaling mode */
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_UP,
+ MRV_MRSZ_SCALE_HY_UP_DOWNSCALE);
+ }
+
+ /* horizontal chrominance scale factors */
+ WARN_ON(!((scale->scale_hcb & RSZ_FLAGS_MASK) == (scale->scale_hcr &
+ RSZ_FLAGS_MASK)));
+ dprintk(1, "scale_hcb = %d( %x )", scale->scale_hcb, scale->scale_hcb);
+
+ if (scale->scale_hcb & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_ENABLE, DISABLE);
+ } else {
+ /* enable scaler */
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_ENABLE, ENABLE);
+ /* program scale factor and phase */
+ REG_SET_SLICE(mrv_reg->mrsz_scale_hcb, MRV_MRSZ_SCALE_HCB,
+ (u32) scale->scale_hcb);
+ REG_SET_SLICE(mrv_reg->mrsz_scale_hcr, MRV_MRSZ_SCALE_HCB,
+ (u32) scale->scale_hcr);
+ REG_SET_SLICE(mrv_reg->mrsz_phase_hc, MRV_MRSZ_PHASE_HC,
+ (u32) scale->phase_hc);
+
+ if (scale->scale_hcb & RSZ_UPSCALE_ENABLE) {
+ /* enable upscaling mode */
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_UP,
+ MRV_MRSZ_SCALE_HC_UP_UPSCALE);
+ /* scaler and upscaling enabled */
+ upscaling = true;
+ } else {
+ /* disable upscaling mode */
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_UP,
+ MRV_MRSZ_SCALE_HC_UP_DOWNSCALE);
+ }
+ }
+
+ /* vertical luminance scale factor */
+ dprintk(1, "scale_vy = %d ( %x )", scale->scale_vy, scale->scale_vy);
+
+ if (scale->scale_vy & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VY_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VY_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->mrsz_scale_vy, MRV_MRSZ_SCALE_VY,
+ (u32) scale->scale_vy);
+ REG_SET_SLICE(mrv_reg->mrsz_phase_vy, MRV_MRSZ_PHASE_VY,
+ (u32) scale->phase_vy);
+
+ if (scale->scale_vy & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VY_UP,
+ MRV_MRSZ_SCALE_VY_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VY_UP,
+ MRV_MRSZ_SCALE_VY_UP_DOWNSCALE);
+ }
+ }
+
+ /* vertical chrominance scale factor */
+ dprintk(1, "scale_vc = %d( %x )", scale->scale_vc, scale->scale_vc);
+
+ if (scale->scale_vc & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VC_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VC_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->mrsz_scale_vc, MRV_MRSZ_SCALE_VC,
+ (u32) scale->scale_vc);
+ REG_SET_SLICE(mrv_reg->mrsz_phase_vc, MRV_MRSZ_PHASE_VC,
+ (u32) scale->phase_vc);
+
+ if (scale->scale_vc & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VC_UP,
+ MRV_MRSZ_SCALE_VC_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_VC_UP,
+ MRV_MRSZ_SCALE_VC_UP_DOWNSCALE);
+ }
+ }
+
+ /* apply upscaling lookup table */
+ if (rsz_lut) {
+ for (i = 0; i <= MRV_MRSZ_SCALE_LUT_ADDR_MASK; i++) {
+ REG_SET_SLICE(mrv_reg->mrsz_scale_lut_addr,
+ MRV_MRSZ_SCALE_LUT_ADDR, i);
+ REG_SET_SLICE(mrv_reg->mrsz_scale_lut,
+ MRV_MRSZ_SCALE_LUT,
+ rsz_lut->rsz_lut[i]);
+ }
+ } else if (upscaling) {
+ eprintk("Upscaling requires lookup table!");
+ WARN_ON(1);
+ }
+
+ /* handle immediate update flag and write mrsz_ctrl */
+ switch (update_time) {
+ case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+ /* frame synchronous update of shadow registers */
+ REG_WRITE(mrv_reg->mrsz_ctrl, mrsz_ctrl);
+ 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(mrsz_ctrl, MRV_MRSZ_CFG_UPD, ON);
+ REG_WRITE(mrv_reg->mrsz_ctrl, mrsz_ctrl);
+ break;
+ case CI_ISP_CFG_UPDATE_LATER:
+ default:
+ /* no update from within this function */
+ REG_WRITE(mrv_reg->mrsz_ctrl, mrsz_ctrl);
+ break;
+ }
+}
+
+/*
+ * writes the scaler values to the appropriate Marvin registers.
+ */
+void ci_isp_res_set_self_resize(const struct ci_isp_scale *scale,
+ enum ci_isp_conf_update_time update_time,
+ const struct ci_isp_rsz_lut *rsz_lut)
+{
+ struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+ u32 srsz_ctrl = REG_READ(mrv_reg->srsz_ctrl);
+ u32 i;
+ int upscaling = false;
+
+ /* flags must be "outside" scaler value */
+ WARN_ON(!((RSZ_FLAGS_MASK & MRV_RSZ_SCALE_MASK) == 0));
+ WARN_ON(!((scale->scale_hy & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_hcb & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_hcr & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_vy & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+ WARN_ON(!((scale->scale_vc & ~RSZ_FLAGS_MASK) <= MRV_RSZ_SCALE_MAX));
+
+ /* horizontal luminance scale factor */
+ dprintk(1, "scale_hy = %d,%x", scale->scale_hy, scale->scale_hy);
+
+ if (scale->scale_hy & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HY_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HY_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->srsz_scale_hy, MRV_SRSZ_SCALE_HY,
+ (u32) scale->scale_hy);
+ REG_SET_SLICE(mrv_reg->srsz_phase_hy, MRV_SRSZ_PHASE_HY,
+ (u32) scale->phase_hy);
+
+ if (scale->scale_hy & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HY_UP,
+ MRV_SRSZ_SCALE_HY_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HY_UP,
+ MRV_SRSZ_SCALE_HY_UP_DOWNSCALE);
+ }
+ }
+
+ /* horizontal chrominance scale factors */
+ WARN_ON(!((scale->scale_hcb & RSZ_FLAGS_MASK) == (scale->scale_hcr &
+ RSZ_FLAGS_MASK)));
+
+ dprintk(1, "scale_hcb = %d,%x", scale->scale_hcb, scale->scale_hcb);
+
+ if (scale->scale_hcb & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HC_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HC_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->srsz_scale_hcb, MRV_SRSZ_SCALE_HCB,
+ (u32) scale->scale_hcb);
+ REG_SET_SLICE(mrv_reg->srsz_scale_hcr, MRV_SRSZ_SCALE_HCB,
+ (u32) scale->scale_hcr);
+
+ REG_SET_SLICE(mrv_reg->srsz_phase_hc, MRV_SRSZ_PHASE_HC,
+ (u32) scale->phase_hc);
+
+ if (scale->scale_hcb & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HC_UP,
+ MRV_SRSZ_SCALE_HC_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HC_UP,
+ MRV_SRSZ_SCALE_HC_UP_DOWNSCALE);
+ }
+ }
+
+ /* vertical luminance scale factor */
+ dprintk(1, "scale_vy = %d,%x", scale->scale_vy, scale->scale_vy);
+
+ if (scale->scale_vy & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->srsz_scale_vy, MRV_SRSZ_SCALE_VY,
+ (u32) scale->scale_vy);
+ REG_SET_SLICE(mrv_reg->srsz_phase_vy, MRV_SRSZ_PHASE_VY,
+ (u32) scale->phase_vy);
+
+ if (scale->scale_vy & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_UP,
+ MRV_SRSZ_SCALE_VY_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_UP,
+ MRV_SRSZ_SCALE_VY_UP_DOWNSCALE);
+ }
+ }
+
+ /* vertical chrominance scale factor */
+ dprintk(1, "scale_vc = %d,%x", scale->scale_vc, scale->scale_vc);
+
+ if (scale->scale_vc & RSZ_SCALER_BYPASS) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VC_ENABLE,
+ DISABLE);
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VC_ENABLE, ENABLE);
+ REG_SET_SLICE(mrv_reg->srsz_scale_vc, MRV_SRSZ_SCALE_VC,
+ (u32) scale->scale_vc);
+ REG_SET_SLICE(mrv_reg->srsz_phase_vc, MRV_SRSZ_PHASE_VC,
+ (u32) scale->phase_vc);
+
+ if (scale->scale_vc & RSZ_UPSCALE_ENABLE) {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VC_UP,
+ MRV_SRSZ_SCALE_VC_UP_UPSCALE);
+ upscaling = true;
+ } else {
+ REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VC_UP,
+ MRV_SRSZ_SCALE_VC_UP_DOWNSCALE);
+ }
+ }
+
+ /* apply upscaling lookup table */
+ if (rsz_lut) {
+ for (i = 0; i <= MRV_SRSZ_SCALE_LUT_ADDR_MASK; i++) {
+ REG_SET_SLICE(mrv_reg->srsz_scale_lut_addr,
+ MRV_SRSZ_SCALE_LUT_ADDR, i);
+ REG_SET_SLICE(mrv_reg->srsz_scale_lut,
+ MRV_SRSZ_SCALE_LUT,
+ rsz_lut->rsz_lut[i]);
+ }
+ } else if (upscaling) {
+ eprintk("Upscaling requires lookup table!");
+ WARN_ON(1);
+ }
+
+ /* handle immediate update flag and write mrsz_ctrl */
+ switch (update_time) {
+ case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+ /* frame synchronous update of shadow registers */
+ REG_WRITE(mrv_reg->srsz_ctrl, srsz_ctrl);
+ 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(srsz_ctrl, MRV_SRSZ_CFG_UPD, ON);
+ REG_WRITE(mrv_reg->srsz_ctrl, srsz_ctrl);
+ break;
+ case CI_ISP_CFG_UPDATE_LATER:
+ default:
+ /* no update from within this function */
+ REG_WRITE(mrv_reg->srsz_ctrl, srsz_ctrl);
+ break;
+ }
+}
+
+/* bad pixel table */
+static struct ci_sensor_bp_table bp_table = { 0 };
+
+/*
+ * Initialization of the Bad Pixel Detection and Correction.
+ */
+int ci_bp_init(const struct ci_isp_bp_corr_config *bp_corr_config,
+ const struct ci_isp_bp_det_config *bp_det_config)
+{
+ int error = CI_STATUS_SUCCESS;
+
+ #define MRVSLS_BPINIT_MAX_TABLE 2048
+
+ /* check the parameters */
+ if (!bp_corr_config || !bp_det_config)
+ return CI_STATUS_NULL_POINTER;
+
+ if (bp_corr_config->bp_corr_type == CI_ISP_BP_CORR_TABLE) {
+ error |= ci_isp_set_bp_correction(bp_corr_config);
+ error |= ci_isp_set_bp_detection(bp_det_config);
+ bp_table.bp_number = 0;
+ if (!bp_table.bp_table_elem) {
+ bp_table.bp_table_elem =
+ (struct ci_sensor_bp_table_elem *)
+ kmalloc((sizeof(struct ci_sensor_bp_table_elem)*
+ MRVSLS_BPINIT_MAX_TABLE), GFP_KERNEL);
+ if (!bp_table.bp_table_elem)
+ error |= CI_STATUS_FAILURE;
+ }
+
+ bp_table.bp_table_elem_num = MRVSLS_BPINIT_MAX_TABLE;
+ error |= ci_isp_clear_bp_int();
+ } else {
+ if (bp_corr_config->bp_corr_type == CI_ISP_BP_CORR_DIRECT) {
+ error |= ci_isp_set_bp_correction(bp_corr_config);
+ error |= ci_isp_set_bp_detection(NULL);
+ } else {
+ return CI_STATUS_NOTSUPP;
+ }
+ }
+ return error;
+}
+
+/*
+ * Disable the Bad Pixel Detection and Correction.
+ */
+int ci_bp_end(const struct ci_isp_bp_corr_config *bp_corr_config)
+{
+ int result = CI_STATUS_SUCCESS;
+
+ /* check the parameter */
+ if (!bp_corr_config)
+ return CI_STATUS_NULL_POINTER;
+
+ result |= ci_isp_set_bp_correction(NULL);
+ result |= ci_isp_set_bp_detection(NULL);
+
+ if (bp_corr_config->bp_corr_type == CI_ISP_BP_CORR_TABLE) {
+ result |= ci_isp_clear_bp_int();
+ /* deallocate BP Table */
+ kfree(bp_table.bp_table_elem);
+ bp_table.bp_table_elem = NULL;
+ }
+ return result;
+}