[PATCH v2 2/10] V4L2 patches for Intel Moorestown Camera Imaging Drivers - part 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From a40f7d1da1cd78f2614c19610fe14bb3af2b55f4 Mon Sep 17 00:00:00 2001
From: Xiaolin Zhang <xiaolin.zhang@xxxxxxxxx>
Date: Sun, 28 Mar 2010 21:34:04 +0800
Subject: [PATCH 2/10] This patch is second part of intel moorestown isp driver and c files collection which is hardware componnet functionality.

Signed-off-by: Xiaolin Zhang <xiaolin.zhang@xxxxxxxxx>
---
 drivers/media/video/mrstci/mrstisp/mrstisp_dp.c  | 1224 ++++++++++++++
 drivers/media/video/mrstci/mrstisp/mrstisp_hw.c  | 1360 +++++++++++++++
 drivers/media/video/mrstci/mrstisp/mrstisp_isp.c | 1913 ++++++++++++++++++++++
 drivers/media/video/mrstci/mrstisp/mrstisp_jpe.c |  569 +++++++
 drivers/media/video/mrstci/mrstisp/mrstisp_mif.c |  703 ++++++++
 5 files changed, 5769 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/mrstci/mrstisp/mrstisp_dp.c
 create mode 100644 drivers/media/video/mrstci/mrstisp/mrstisp_hw.c
 create mode 100644 drivers/media/video/mrstci/mrstisp/mrstisp_isp.c
 create mode 100644 drivers/media/video/mrstci/mrstisp/mrstisp_jpe.c
 create mode 100644 drivers/media/video/mrstci/mrstisp/mrstisp_mif.c

diff --git a/drivers/media/video/mrstci/mrstisp/mrstisp_dp.c b/drivers/media/video/mrstci/mrstisp/mrstisp_dp.c
new file mode 100644
index 0000000..c0e404b
--- /dev/null
+++ b/drivers/media/video/mrstci/mrstisp/mrstisp_dp.c
@@ -0,0 +1,1224 @@
+/*
+ * 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@xxxxxxxxx>
+ */
+
+#include "mrstisp_stdinc.h"
+
+/* mask for all chroma subsampling settings */
+#define CI_ISP_DPD_CSS_MASK  (CI_ISP_DPD_CSS_H_MASK | CI_ISP_DPD_CSS_V_MASK)
+#define SCALER_COFFS_COSITED 0x400
+#define FIXEDPOINT_ONE 0x1000
+
+/* limitations of main and self scaler */
+#define MAIN_SCALER_WIDTH_MAX 2600
+#define SELF_SCALER_WIDTH_MAX 640
+#define SCALER_MIN 16
+
+#define SELF_UPSCALE_FACTOR_MAX 5
+#define MAIN_UPSCALE_FACTOR_MAX 5
+
+/*
+ * upscale lookup table for smooth edges
+ * (linear interpolation between pixels)
+ */
+
+/* smooth edges */
+static const struct ci_isp_rsz_lut isp_rsz_lut_smooth_lin = {
+       {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+       0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+       0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
+       }
+};
+
+/*
+ * upscale lookup table for sharp edges
+ * (no interpolation, just duplicate pixels)
+ */
+
+/* sharp edges */
+static const struct ci_isp_rsz_lut isp_rsz_lut_sharp = {
+       {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
+       }
+};
+
+/* structure combining virtual ISP windows settings */
+struct ci_isp_virtual_isp_wnds {
+       struct ci_isp_window wnd_blacklines;
+       struct ci_isp_window wnd_zoom_crop;
+};
+
+/* static storage to remember last applied virtual ISP window settings */
+static struct ci_isp_virtual_isp_wnds last_isp_wnds;
+
+/*
+ * Calculates the value to program into the struct ci_isp_scale or
+ * tsMrvSScale structures to scale from in pixels to out pixels.
+ *
+ * The formulas are taken from the MARVIN / MARVIN3PLUS user
+ * manuals (fixed-point calculation using 32 bit during
+ * processing, will overflow at an output size of 1048575 pixels).
+ */
+static u32 ci_get_scale_reg(u16 in, u16 out)
+{
+       if (in > out) {
+               /* downscaling */
+               return (u32) (((((u32) out - 1) * RSZ_SCALER_BYPASS) /
+                                 (u32) (in - 1)) + 1);
+       } else if (in < out) {
+               /* upscaling */
+               return (u32) (((((u32) in - 1) * RSZ_SCALER_BYPASS) /
+                                 (u32) (out - 1)) | (u32) RSZ_UPSCALE_ENABLE);
+       }
+
+       /* no scaling */
+       return RSZ_SCALER_BYPASS;
+}
+
+/*
+ * Calculates the values of the ci_isp_scale structure for the
+ * given input size and data path descriptor.
+ */
+static u32 ci_calc_scale_factors(const struct ci_isp_datapath_desc *source,
+                                const struct ci_isp_datapath_desc *path,
+                                struct ci_isp_scale *scale, int implementation)
+{
+       u32 scaler_output_format;
+       u32 cssflags;
+       u32 scaler_input_format;
+
+       u16 chroma_in_w;
+       u16 chroma_in_h;
+       u16 chroma_out_wcr;
+       u16 chroma_out_wcb;
+       u16 chroma_out_h;
+
+       memset(scale, 0, sizeof(struct ci_isp_scale));
+       dprintk(1, "srcw %d, srch %d;", source->out_w, source->out_h);
+       dprintk(1, "dstw %d, dsth %d", path->out_w, path->out_h);
+
+       /* calculate Y scale factors */
+       scale->scale_hy = ci_get_scale_reg(source->out_w, path->out_w);
+       scale->scale_vy = ci_get_scale_reg(source->out_h, path->out_h);
+
+       /* figure out the color input format of the scaler */
+       switch (path->flags & CI_ISP_DPD_MODE_MASK) {
+       case CI_ISP_DPD_MODE_DMAYC_DIRECT:
+       case CI_ISP_DPD_MODE_DMAYC_ISP:
+       case CI_ISP_DPD_MODE_DMAJPEG_DIRECT:
+       case CI_ISP_DPD_MODE_DMAJPEG_ISP:
+               scaler_input_format = path->flags & CI_ISP_DPD_DMA_IN_MASK;
+               break;
+       default:
+               scaler_input_format = CI_ISP_DPD_DMA_IN_422;
+               break;
+       }
+
+       dprintk(1, "scaler_input_format is 0x%x", scaler_input_format);
+
+       switch (scaler_input_format) {
+       case CI_ISP_DPD_DMA_IN_422:
+               chroma_in_w = source->out_w / 2;
+               chroma_in_h = source->out_h;
+               chroma_out_wcr = path->out_w / 2;
+               chroma_out_wcb = (path->out_w + 1) / 2;
+               chroma_out_h = path->out_h;
+               break;
+       case CI_ISP_DPD_DMA_IN_420:
+               chroma_in_w = source->out_w / 2;
+               chroma_in_h = source->out_h / 2;
+               chroma_out_wcr = path->out_w / 2;
+               chroma_out_wcb = (path->out_w + 1) / 2;
+               chroma_out_h = path->out_h / 2;
+               break;
+       case CI_ISP_DPD_DMA_IN_411:
+               chroma_in_w = source->out_w / 4;
+               chroma_in_h = source->out_h;
+               chroma_out_wcr = path->out_w / 4;
+               chroma_out_wcb = (path->out_w + 2) / 4;
+               chroma_out_h = path->out_h;
+               break;
+       case CI_ISP_DPD_DMA_IN_444:
+       default:
+               chroma_in_w = source->out_w;
+               chroma_in_h = source->out_h;
+               chroma_out_wcb = chroma_out_wcr = path->out_w;
+               chroma_out_h = path->out_h;
+               break;
+       }
+
+       /* calculate chrominance scale factors */
+       switch (path->flags & CI_ISP_DPD_CSS_H_MASK) {
+       case CI_ISP_DPD_CSS_H2:
+               chroma_out_wcb /= 2;
+               chroma_out_wcr /= 2;
+               break;
+       case CI_ISP_DPD_CSS_H4:
+               chroma_out_wcb /= 4;
+               chroma_out_wcr /= 4;
+               break;
+       case CI_ISP_DPD_CSS_HUP2:
+               chroma_out_wcb *= 2;
+               chroma_out_wcr *= 2;
+               break;
+       case CI_ISP_DPD_CSS_HUP4:
+               chroma_out_wcb *= 4;
+               chroma_out_wcr *= 4;
+               break;
+       default:
+               break;
+       }
+
+       scale->scale_hcr = ci_get_scale_reg(chroma_in_w, chroma_out_wcr);
+       scale->scale_hcb = ci_get_scale_reg(chroma_in_w, chroma_out_wcb);
+       scale->scale_hcb = scale->scale_hcr;
+
+       switch (path->flags & CI_ISP_DPD_CSS_V_MASK) {
+       case CI_ISP_DPD_CSS_V2:
+               chroma_out_h /= 2;
+               break;
+       case CI_ISP_DPD_CSS_V4:
+               chroma_out_h /= 4;
+               break;
+       case CI_ISP_DPD_CSS_VUP2:
+               chroma_out_h *= 2;
+               break;
+       case CI_ISP_DPD_CSS_VUP4:
+               chroma_out_h *= 4;
+               break;
+       default:
+               break;
+       }
+
+       scale->scale_vc = ci_get_scale_reg(chroma_in_h, chroma_out_h);
+
+       /* additional chrominance phase shifts */
+       if (path->flags & CI_ISP_DPD_CSS_HSHIFT)
+               scale->phase_hc = SCALER_COFFS_COSITED;
+       if (path->flags & CI_ISP_DPD_CSS_VSHIFT)
+               scale->phase_vc = SCALER_COFFS_COSITED;
+
+       /* additional luminance phase shifts */
+       if (path->flags & CI_ISP_DPD_LUMA_HSHIFT)
+               scale->phase_hy = SCALER_COFFS_COSITED;
+       if (path->flags & CI_ISP_DPD_LUMA_VSHIFT)
+               scale->phase_vy = SCALER_COFFS_COSITED;
+
+       /* try to figure out the outcoming YCbCr format */
+       cssflags = path->flags & CI_ISP_DPD_CSS_MASK;
+       if (cssflags == (CI_ISP_DPD_CSS_H_OFF | CI_ISP_DPD_CSS_V_OFF)) {
+               /* trivial case: the output format is not changed */
+               scaler_output_format = scaler_input_format;
+       } else {
+               /* output format gets changed by the scaler setting */
+               /* assume invalid format by default */
+               scaler_output_format = (u32) (-1);
+               switch (scaler_input_format) {
+               case CI_ISP_DPD_DMA_IN_444:
+                       if (cssflags == (CI_ISP_DPD_CSS_H2
+                                        | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 444 -> 422 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_422;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H4
+                                               | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 444 -> 411 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_411;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H2
+                                               | CI_ISP_DPD_CSS_V2)) {
+                               /* conversion 444 -> 420 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_420;
+                       }
+                       break;
+
+               case CI_ISP_DPD_DMA_IN_422:
+                       if (cssflags == (CI_ISP_DPD_CSS_HUP2
+                                        | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 422 -> 444 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_444;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H2
+                                               | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 422 -> 411 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_411;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H_OFF
+                                               | CI_ISP_DPD_CSS_V2)) {
+                               /* conversion 422 -> 420 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_420;
+                       }
+                       break;
+
+               case CI_ISP_DPD_DMA_IN_420:
+                       if (cssflags == (CI_ISP_DPD_CSS_HUP2
+                                        | CI_ISP_DPD_CSS_VUP2)) {
+                               /* conversion 420 -> 444 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_444;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H2
+                                               | CI_ISP_DPD_CSS_VUP2)) {
+                               /* conversion 420 -> 411 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_411;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_H_OFF
+                                               | CI_ISP_DPD_CSS_VUP2)) {
+                               /* conversion 420 -> 422 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_422;
+                       }
+                       break;
+
+               case CI_ISP_DPD_DMA_IN_411:
+                       if (cssflags == (CI_ISP_DPD_CSS_HUP4
+                                        | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 411 -> 444 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_444;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_HUP2
+                                               | CI_ISP_DPD_CSS_V_OFF)) {
+                               /* conversion 411 -> 422 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_422;
+                       } else if (cssflags == (CI_ISP_DPD_CSS_HUP2
+                                               | CI_ISP_DPD_CSS_V2)) {
+                               /* conversion 411 -> 420 */
+                               scaler_output_format = CI_ISP_DPD_DMA_IN_420;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return scaler_output_format;
+}
+
+/*
+ * Returns the address of up-scaling lookup table to use for
+ * the given data path flags.
+ */
+static const struct ci_isp_rsz_lut *ci_get_rsz_lut(u32 flags)
+{
+       const struct ci_isp_rsz_lut *ret_val;
+       switch (flags & CI_ISP_DPD_UPSCALE_MASK) {
+       case CI_ISP_DPD_UPSCALE_SHARP:
+               ret_val = &isp_rsz_lut_sharp;
+               break;
+       default:
+               ret_val = &isp_rsz_lut_smooth_lin;
+               break;
+       }
+       return ret_val;
+}
+
+/*
+ * Fills in scale factors and MI configuration for the main path.
+ * Note that only self path related settings will be written into
+ * the MI configuration struct, so this routine can be used for
+ * both ISP and DMA originated data path setups.
+ *
+ * Following fields are being filled in:
+ * scale_main: [all fields]
+ * mrv_mi_ctrl: mrv_mif_mp_pic_form main_path
+ */
+static int ci_calc_main_path_settings(const struct ci_isp_datapath_desc *source,
+                                     const struct ci_isp_datapath_desc  *main,
+                                     struct ci_isp_scale *scale_main,
+                                     struct ci_isp_mi_ctrl *mrv_mi_ctrl)
+{
+       u32 main_flag;
+
+       WARN_ON(!(source != NULL));
+       WARN_ON(!(scale_main != NULL));
+       WARN_ON(!(mrv_mi_ctrl != NULL));
+
+       /* assume datapath deactivation if no selfpath pointer is given) */
+       if (main)
+               main_flag = main->flags;
+       else
+               main_flag = 0;
+
+       /* initialize the given parameters */
+       memset(scale_main, 0, sizeof(struct ci_isp_scale));
+       scale_main->scale_hy = RSZ_SCALER_BYPASS;
+       scale_main->scale_hcb = RSZ_SCALER_BYPASS;
+       scale_main->scale_hcr = RSZ_SCALER_BYPASS;
+       scale_main->scale_vy = RSZ_SCALER_BYPASS;
+       scale_main->scale_vc = RSZ_SCALER_BYPASS;
+
+       if (main_flag & CI_ISP_DPD_ENABLE) {
+               switch (main_flag & CI_ISP_DPD_MODE_MASK) {
+               case CI_ISP_DPD_MODE_ISPYC:
+               case CI_ISP_DPD_MODE_DMAYC_ISP:
+                       mrv_mi_ctrl->main_path = CI_ISP_PATH_ON;
+                       break;
+               case CI_ISP_DPD_MODE_ISPJPEG:
+               case CI_ISP_DPD_MODE_DMAJPEG_DIRECT:
+               case CI_ISP_DPD_MODE_DMAJPEG_ISP:
+                       mrv_mi_ctrl->main_path = CI_ISP_PATH_JPE;
+                       break;
+               case CI_ISP_DPD_MODE_ISPRAW:
+                       mrv_mi_ctrl->main_path = CI_ISP_PATH_RAW8;
+                       break;
+               case CI_ISP_DPD_MODE_ISPRAW_16B:
+                       mrv_mi_ctrl->main_path = CI_ISP_PATH_RAW816;
+                       break;
+               default:
+                       eprintk("unsupported mode for main path");
+                       return CI_STATUS_NOTSUPP;
+               }
+               if (main_flag & (CI_ISP_DPD_H_FLIP | CI_ISP_DPD_V_FLIP |
+                       CI_ISP_DPD_90DEG_CCW)) {
+                       eprintk("not supported for main path");
+                       return CI_STATUS_NOTSUPP;
+               }
+               if (main_flag & CI_ISP_DPD_NORESIZE) {
+                       if (main_flag & CI_ISP_DPD_CSS_MASK) {
+                               eprintk("main path needs rezizer");
+                               return CI_STATUS_NOTSUPP;
+                       }
+                       if (main_flag &
+                           (CI_ISP_DPD_LUMA_HSHIFT | CI_ISP_DPD_LUMA_VSHIFT)) {
+                               eprintk("main path needs rezizer");
+                               return CI_STATUS_NOTSUPP;
+                       }
+               } else {
+                       if ((mrv_mi_ctrl->main_path == CI_ISP_PATH_RAW8)
+                           || (mrv_mi_ctrl->main_path == CI_ISP_PATH_RAW8)) {
+                               eprintk("scaler not in RAW mode");
+                               return CI_STATUS_NOTSUPP;
+                       }
+                       /* changed to avoid LINT warnings (Warning 613) */
+                       if (main != NULL) {
+                               if ((((u32) (source->out_w) *
+                                     MAIN_UPSCALE_FACTOR_MAX) < main->out_w)
+                                   ||
+                                   (((u32) (source->out_h) *
+                                     MAIN_UPSCALE_FACTOR_MAX) <
+                                    main->out_h)) {
+                                       eprintk("main upscaling exceeded");
+                                       return CI_STATUS_NOTSUPP;
+                               }
+                               if ((main->out_w >
+                                    MAIN_SCALER_WIDTH_MAX)
+                                   || (main->out_w < SCALER_MIN)
+                                   || (main->out_h < SCALER_MIN)) {
+                                       eprintk("main scaler ange exceeded");
+                                       return CI_STATUS_NOTSUPP;
+                               }
+                       } else {
+                               WARN_ON(main == NULL);
+                       }
+
+                       if (source->out_w & 0x01) {
+                               eprintk("input width must be even!");
+                               return CI_STATUS_NOTSUPP;
+                       }
+
+                       /* calculate scale factors. */
+                       (void)ci_calc_scale_factors(source, main, scale_main,
+                                                   3 /*MARVIN_FEATURE_MSCALE_FACTORCALC*/);
+               }
+       } else {
+               mrv_mi_ctrl->main_path = CI_ISP_PATH_OFF;
+       }
+
+       /* hardcoded MI settings */
+       dprintk(1, "main_flag is 0x%x", main_flag);
+       if (main_flag & CI_ISP_DPD_HWRGB_MASK) {
+               switch (main_flag & CI_ISP_DPD_HWRGB_MASK) {
+               case CI_ISP_DPD_YUV_420:
+               case CI_ISP_DPD_YUV_422:
+                       mrv_mi_ctrl->mrv_mif_mp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       break;
+               case CI_ISP_DPD_YUV_NV12:
+                       mrv_mi_ctrl->mrv_mif_mp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_SEMI_PLANAR;
+                       break;
+               case CI_ISP_DPD_YUV_YUYV:
+                       mrv_mi_ctrl->mrv_mif_mp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_INTERLEAVED;
+                       break;
+               default:
+                       mrv_mi_ctrl->mrv_mif_mp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+               }
+       }
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Fills in scale factors and MI configuration for the self
+ * path.  Note that only self path related settings will be written into
+ * the MI config struct, so this routine can be used for both ISP and DMA
+ * originated datapath setups.
+ *
+ * Following fields are being filled in:
+ *           scale_flag :
+ *              [all fields]
+ *           mrv_mi_ctrl :
+ *              mrv_mif_sp_out_form
+ *              mrv_mif_sp_in_form
+ *              mrv_mif_sp_pic_form
+ *              mrv_mif_sp_mode
+ *              self_path
+ */
+static int ci_calc_self_path_settings(const struct ci_isp_datapath_desc *source,
+                                     const struct ci_isp_datapath_desc *self,
+                                     struct ci_isp_scale *scale_flag,
+                                     struct ci_isp_mi_ctrl *mrv_mi_ctrl)
+{
+       u32 scaler_out_col_format;
+       u32 self_flag;
+
+       WARN_ON(!(source != NULL));
+       WARN_ON(!(scale_flag != NULL));
+       WARN_ON(!(mrv_mi_ctrl != NULL));
+
+       /* assume datapath deactivation if no selfpath pointer is given) */
+       if (self)
+               self_flag = self->flags;
+       else
+               self_flag = 0;
+
+       /* initialize the given parameters */
+       memset(scale_flag, 0, sizeof(struct ci_isp_scale));
+       scale_flag->scale_hy = RSZ_SCALER_BYPASS;
+       scale_flag->scale_hcb = RSZ_SCALER_BYPASS;
+       scale_flag->scale_hcr = RSZ_SCALER_BYPASS;
+       scale_flag->scale_vy = RSZ_SCALER_BYPASS;
+       scale_flag->scale_vc = RSZ_SCALER_BYPASS;
+
+       if (self_flag & CI_ISP_DPD_ENABLE) {
+               switch (self_flag & CI_ISP_DPD_MODE_MASK) {
+               case CI_ISP_DPD_MODE_ISPYC:
+                       mrv_mi_ctrl->self_path = CI_ISP_PATH_ON;
+                       scaler_out_col_format = CI_ISP_DPD_DMA_IN_422;
+                       break;
+               case CI_ISP_DPD_MODE_DMAYC_ISP:
+               case CI_ISP_DPD_MODE_DMAYC_DIRECT:
+                       mrv_mi_ctrl->self_path = CI_ISP_PATH_ON;
+                       scaler_out_col_format =
+                           self_flag & CI_ISP_DPD_DMA_IN_MASK;
+                       break;
+               default:
+                       eprintk("unsupported mode for self path");
+                       return CI_STATUS_NOTSUPP;
+               }
+
+               if (self_flag & CI_ISP_DPD_NORESIZE) {
+                       if (self_flag & CI_ISP_DPD_CSS_MASK) {
+                               eprintk("in self path needs rezizer");
+                               return CI_STATUS_NOTSUPP;
+                       }
+                       if (self_flag &
+                           (CI_ISP_DPD_LUMA_HSHIFT | CI_ISP_DPD_LUMA_VSHIFT)) {
+                               eprintk("n self path needs rezizer");
+                               return CI_STATUS_NOTSUPP;
+                       }
+                       /* changed to avoid LINT warnings (Warning 613) */
+                       if (self != NULL) {
+                               if ((source->out_w != self->out_w) ||
+                                   (source->out_h != self->out_h)) {
+                                       eprintk("sizes needs resizer");
+                                       return CI_STATUS_NOTSUPP;
+                               }
+                       } else {
+                               WARN_ON(self == NULL);
+                       }
+               } else {
+                       /* changed to avoid LINT warnings (Warning 613) */
+                       if (self != NULL) {
+                               /* upscaling only to factor
+                                * SELF_UPSCALE_FACTOR_MAX possible
+                                */
+                               if ((((u32) (source->out_w) *
+                                     SELF_UPSCALE_FACTOR_MAX) <
+                                    self->out_w)
+                                   ||
+                                   (((u32) (source->out_h) *
+                                     SELF_UPSCALE_FACTOR_MAX) <
+                                    self->out_h)) {
+                                       eprintk("apability exceeded");
+                                       return CI_STATUS_NOTSUPP;
+                               }
+                               if ((self->out_w >
+                                    SELF_SCALER_WIDTH_MAX)
+                                   || (self->out_w < SCALER_MIN)
+                                   || (self->out_h < SCALER_MIN)) {
+                                       eprintk("out range exceeded");
+                                       return CI_STATUS_NOTSUPP;
+                               }
+                       } else {
+                               WARN_ON(self == NULL);
+                       }
+
+                       /*
+                        * Remember that the input picture width should be
+                        * even if the scaler is used otherwise the scaler may
+                        * show unexpected behaviour in some rare cases)
+                        */
+                       if (source->out_w & 0x01) {
+                               eprintk("width must be even!");
+                               return CI_STATUS_NOTSUPP;
+                       }
+
+                       /* calculate scale factors. */
+                       scaler_out_col_format =
+                           ci_calc_scale_factors(source, self, scale_flag,
+                                                 3 /*MARVIN_FEATURE_SSCALE_FACTORCALC*/);
+               }
+
+               /* figure out the input format setting */
+               switch (scaler_out_col_format) {
+               case CI_ISP_DPD_DMA_IN_444:
+                       mrv_mi_ctrl->mrv_mif_sp_in_form =
+                           CI_ISP_MIF_COL_FORMAT_YCBCR_444;
+                       break;
+               case CI_ISP_DPD_DMA_IN_422:
+                       mrv_mi_ctrl->mrv_mif_sp_in_form =
+                           CI_ISP_MIF_COL_FORMAT_YCBCR_422;
+                       break;
+               case CI_ISP_DPD_DMA_IN_420:
+                       mrv_mi_ctrl->mrv_mif_sp_in_form =
+                           CI_ISP_MIF_COL_FORMAT_YCBCR_420;
+                       break;
+               case CI_ISP_DPD_DMA_IN_411:
+               default:
+                       eprintk("input color format not supported");
+                       return CI_STATUS_NOTSUPP;
+               }
+
+               /* figure out the output format setting */
+               dprintk(2, "step2, self_flag is 0x%x", self_flag);
+
+               switch (self_flag & CI_ISP_DPD_HWRGB_MASK) {
+               case CI_ISP_DPD_HWRGB_565:
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                           CI_ISP_MIF_COL_FORMAT_RGB_565;
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       break;
+               case CI_ISP_DPD_HWRGB_666:
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                           CI_ISP_MIF_COL_FORMAT_RGB_666;
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       break;
+               case CI_ISP_DPD_HWRGB_888:
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                           CI_ISP_MIF_COL_FORMAT_RGB_888;
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       break;
+               case CI_ISP_DPD_YUV_420:
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                               CI_ISP_MIF_COL_FORMAT_YCBCR_420;
+                       break;
+               case CI_ISP_DPD_YUV_422:
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                               CI_ISP_MIF_COL_FORMAT_YCBCR_422;
+                       break;
+               case CI_ISP_DPD_YUV_NV12:
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_SEMI_PLANAR;
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                               CI_ISP_MIF_COL_FORMAT_YCBCR_420;
+                       break;
+               case CI_ISP_DPD_YUV_YUYV:
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_INTERLEAVED;
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                               CI_ISP_MIF_COL_FORMAT_YCBCR_422;
+                       break;
+
+               case CI_ISP_DPD_HWRGB_OFF:
+                       mrv_mi_ctrl->mrv_mif_sp_out_form =
+                           mrv_mi_ctrl->mrv_mif_sp_in_form;
+                       mrv_mi_ctrl->mrv_mif_sp_pic_form =
+                               CI_ISP_MIF_PIC_FORM_PLANAR;
+                       break;
+               default:
+                       eprintk("output color format not supported");
+                       return CI_STATUS_NOTSUPP;
+               }
+
+               /* picture flipping / rotation */
+               dprintk(2, "step3");
+
+               switch (self_flag &
+                       (CI_ISP_DPD_90DEG_CCW | CI_ISP_DPD_V_FLIP |
+                        CI_ISP_DPD_H_FLIP)) {
+               case (CI_ISP_DPD_H_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_HORIZONTAL_FLIP;
+                       break;
+               case (CI_ISP_DPD_V_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_VERTICAL_FLIP;
+                       break;
+               case (CI_ISP_DPD_V_FLIP | CI_ISP_DPD_H_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_ROTATION_180_DEG;
+                       break;
+               case (CI_ISP_DPD_90DEG_CCW):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_ROTATION_090_DEG;
+                       break;
+               case (CI_ISP_DPD_90DEG_CCW | CI_ISP_DPD_H_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_ROT_270_V_FLIP;
+                       break;
+               case (CI_ISP_DPD_90DEG_CCW | CI_ISP_DPD_V_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_ROT_090_V_FLIP;
+                       break;
+               case (CI_ISP_DPD_90DEG_CCW | CI_ISP_DPD_V_FLIP |
+                       CI_ISP_DPD_H_FLIP):
+                       mrv_mi_ctrl->mrv_mif_sp_mode =
+                       CI_ISP_MIF_SP_ROTATION_270_DEG;
+                       break;
+               default:
+                       mrv_mi_ctrl->mrv_mif_sp_mode = CI_ISP_MIF_SP_ORIGINAL;
+                       break;
+               }
+
+       } else {
+               mrv_mi_ctrl->self_path = CI_ISP_PATH_OFF;
+       }
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Translates the given memory interface configuration struct
+ * into appropriate values to program the data path multiplexers.
+ */
+static int ci_calc_dp_mux_settings(const struct ci_isp_mi_ctrl *mi_ctrl,
+                                  enum ci_isp_ycs_chn_mode *peYcsChnMode,
+                                  enum ci_isp_dp_switch *peDpSwitch)
+{
+       switch (mi_ctrl->main_path) {
+       case CI_ISP_PATH_RAW8:
+       case CI_ISP_PATH_RAW816:
+               *peDpSwitch = CI_ISP_DP_RAW;
+               *peYcsChnMode = CI_ISP_YCS_MVRaw;
+               if (mi_ctrl->self_path != CI_ISP_PATH_OFF) {
+                       eprintk("ombined with RAW mode of main path");
+                       return CI_STATUS_NOTSUPP;
+               }
+               break;
+
+       case CI_ISP_PATH_JPE:
+               *peDpSwitch = CI_ISP_DP_JPEG;
+               if (mi_ctrl->self_path != CI_ISP_PATH_OFF)
+                       *peYcsChnMode = CI_ISP_YCS_MV_SP;
+               else
+                       *peYcsChnMode = CI_ISP_YCS_MV;
+               break;
+
+       case CI_ISP_PATH_ON:
+               *peDpSwitch = CI_ISP_DP_MV;
+               if (mi_ctrl->self_path != CI_ISP_PATH_OFF)
+                       *peYcsChnMode = CI_ISP_YCS_MV_SP;
+               else
+                       *peYcsChnMode = CI_ISP_YCS_MV;
+               break;
+
+       case CI_ISP_PATH_OFF:
+               *peDpSwitch = CI_ISP_DP_MV;
+               if (mi_ctrl->self_path != CI_ISP_PATH_OFF)
+                       *peYcsChnMode = CI_ISP_YCS_SP;
+               else
+                       *peYcsChnMode = CI_ISP_YCS_OFF;
+               break;
+
+       default:
+               return CI_STATUS_NOTSUPP;
+       }
+
+       return CI_STATUS_SUCCESS;
+}
+
+#define ISPWND_COMBINE_WNDS    0x00000001
+#define ISPWND_APPLY_OUTFORM   0x00000002
+#define ISPWND_APPLY_ISCONF    0x00000004
+#define ISPWND_NO_CROPPING     0x00000008
+
+/*
+ * Returns information about how to combine black pixel and
+ * zoom/crop windows for programming the ISP output formatter and the image
+ * stabilization unit for the given marvin derivative and ISP path.
+ */
+static u32 ci_get_isp_wnd_style(enum ci_isp_path isp_path)
+{
+       u32 res = 0;
+
+       /* image stabilization in both bayer and YCbCr paths */
+       if ((isp_path == CI_ISP_PATH_BAYER) ||
+           (isp_path == CI_ISP_PATH_YCBCR))
+               res = ISPWND_APPLY_OUTFORM | ISPWND_APPLY_ISCONF;
+       else
+               res = ISPWND_COMBINE_WNDS | ISPWND_APPLY_OUTFORM;
+
+       return res;
+}
+
+/*
+ *  the given windows for cutting away blacklines coming from
+ *  the image sensor and further cropping of the image for other
+ *  purposes like e.g. digital zoom to the output formatter and/or
+ *  image stabilisation modules of Marvins ISP.
+ */
+static int ci_set_isp_windows(const struct ci_sensor_config *isi_sensor_config,
+                             const struct ci_isp_window *wnd_blackline,
+                             const struct ci_isp_window *wnd_zoom_crop)
+{
+       struct ci_isp_window wnd_out_form;
+       struct ci_isp_is_config is_conf;
+       enum ci_isp_path isp_path;
+       u32 wnd_style;
+
+       memset(&wnd_out_form, 0, sizeof(wnd_out_form));
+       memset(&is_conf, 0, sizeof(is_conf));
+
+       /*
+        * figure out the path through the ISP to process the data from the
+        * image sensor
+        */
+       isp_path = ci_isp_select_path(isi_sensor_config, NULL);
+       if (isp_path == CI_ISP_PATH_UNKNOWN) {
+               eprintk("detect marvin ISP path to use");
+               return CI_STATUS_NOTSUPP;
+       }
+
+       /*
+        * get the recommended way to configure output formatter and/or
+        * image stabilization
+        */
+       wnd_style = ci_get_isp_wnd_style(isp_path);
+       if (wnd_style & ISPWND_NO_CROPPING) {
+               /*
+                * cropping not possible -> make sure that it is *not*
+                * supposed to be used
+                */
+               u16 isi_x;
+               u16 isi_y;
+               ci_sensor_res2size(isi_sensor_config->res, &isi_x, &isi_y);
+               if ((wnd_zoom_crop->hsize != isi_x)
+                   || (wnd_zoom_crop->vsize != isi_y)
+                   || (wnd_zoom_crop->hoffs != 0)
+                   || (wnd_zoom_crop->voffs != 0)) {
+                       eprintk("in selected ISP data path");
+                       return CI_STATUS_NOTSUPP;
+               }
+               if ((wnd_blackline->hsize != isi_x) ||
+                   (wnd_blackline->vsize != isi_y) ||
+                   (wnd_blackline->hoffs != 0) ||
+                   (wnd_blackline->voffs != 0)) {
+                       eprintk("supported in selected ISP data path");
+                       return CI_STATUS_NOTSUPP;
+               }
+       }
+
+       /*
+        * The image stabilization is allowed to move the window in both
+        * directions by the same amount of pixels we have calculated for
+        * the offsets. The initial image stabilization window is equal to
+        * the zoom/crop window
+        */
+       is_conf.max_dx = wnd_zoom_crop->hoffs;
+       is_conf.max_dy = wnd_zoom_crop->voffs;
+       is_conf.mrv_is_window = *wnd_zoom_crop;
+
+       /* combine both blackline and zoom/crop window */
+       if (wnd_style & ISPWND_COMBINE_WNDS) {
+               wnd_out_form = *wnd_zoom_crop;
+               wnd_out_form.voffs += wnd_blackline->voffs;
+               wnd_out_form.hoffs += wnd_blackline->hoffs;
+               is_conf.mrv_is_window = wnd_out_form;
+               if (wnd_style & ISPWND_APPLY_OUTFORM) {
+                       /*
+                        * if the output formatter is to be used, offsets
+                        * are cut away there, so
+                        * we don't need additional ones in the imags
+                        * stabilization unit
+                        */
+                       is_conf.mrv_is_window.hoffs = 0;
+                       is_conf.mrv_is_window.voffs = 0;
+               }
+       } else {
+               /*
+                * do not combine windows --> blacklines done with output
+                * formatter, zoom/cropping done with image stabilization
+                */
+               wnd_out_form = *wnd_blackline;
+               is_conf.mrv_is_window = *wnd_zoom_crop;
+       }
+
+       /* finally, apply the settings to marvin */
+       if (wnd_style & ISPWND_APPLY_OUTFORM) {
+               ci_isp_set_output_formatter(&wnd_out_form,
+                                           CI_ISP_CFG_UPDATE_IMMEDIATE);
+       }
+       if (wnd_style & ISPWND_APPLY_ISCONF) {
+               int res = ci_isp_is_set_config(&is_conf);
+               if (res != CI_STATUS_SUCCESS) {
+                       eprintk("set image stabilization config");
+                       return res;
+               }
+       }
+
+       /* success - remember our virtual settings */
+       last_isp_wnds.wnd_blacklines = *wnd_blackline;
+       last_isp_wnds.wnd_zoom_crop = *wnd_zoom_crop;
+
+       return CI_STATUS_SUCCESS;
+}
+
+/* sets extended YCbCr mode */
+static int ci_ext_ycb_cr_mode(const struct ci_isp_datapath_desc *path)
+{
+       u32 main_flag;
+
+       WARN_ON(!(path != NULL));
+
+       /* assume datapath deactivation if no selfpath pointer is given) */
+       if (path)
+               main_flag = path->flags;
+       else
+               main_flag = 0;
+
+       /* if flag CI_ISP_DPD_YCBCREXT is set set extended YCbCr mode */
+       if (main_flag & CI_ISP_DPD_ENABLE) {
+               if (main_flag & CI_ISP_DPD_YCBCREXT)
+                       ci_isp_set_ext_ycmode();
+       }
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Configures main and self data pathes and scaler for data coming from the ISP.
+ *
+ * Following MARVIN subsystems are programmed:
+ * - ISP output formatter
+ * - Image stabilization module
+ * - YC-Splitter
+ * - Self path DMA-read multiplexer
+ * - Main path multiplexer
+ * - Main & Self path resizer
+ * - Small output unit
+ * - Memory Interface (MI) input source, en/disable and data format
+ *
+ * Following MARVIN subsystems are *NOT* programmed:
+ * - All ISP functionality but the output formatter & image stabilization module
+ * - color Processing block
+ * - JPEG encode subsystem (quantisation tables etc.)
+ * - Memory Interface (MI) output buffer addresses and sizes
+ */
+int ci_datapath_isp(const struct ci_pl_system_config *sys_conf,
+                   const struct ci_sensor_config *isi_config,
+                   const struct ci_isp_datapath_desc *main,
+                   const struct ci_isp_datapath_desc *self, int zoom)
+{
+       int res;
+
+       u32 main_flag;
+       u32 self_flag;
+       u16 isi_x;
+       u16 isi_y;
+       struct ci_isp_scale scale_main;
+       struct ci_isp_scale scale_flag;
+       enum ci_isp_ycs_chn_mode chn_mode = 0;
+       enum ci_isp_dp_switch dp_switch = 0;
+       struct ci_isp_mi_ctrl mrv_mi_ctrl;
+       struct ci_isp_datapath_desc source;
+       struct ci_isp_window wnd_blackline;
+       struct ci_isp_window wnd_zoom_crop;
+
+       const struct ci_isp_datapath_desc *target = NULL;
+
+       /* assume dapapath deactivation for not provided descriptors */
+       main_flag = 0;
+       self_flag = 0;
+       if (main)
+               main_flag = main->flags;
+
+       if (self)
+               self_flag = self->flags;
+
+       /* initialize variables on the stack */
+       res = CI_STATUS_SUCCESS;
+       (void)ci_sensor_res2size(isi_config->res, &isi_x, &isi_y);
+       memset(&mrv_mi_ctrl, 0, sizeof(struct ci_isp_mi_ctrl));
+       memset(&wnd_blackline, 0, sizeof(wnd_blackline));
+       memset(&wnd_zoom_crop, 0, sizeof(wnd_zoom_crop));
+
+       /* no cropping, no offset */
+       wnd_blackline.hsize = isi_x;
+       wnd_blackline.vsize = isi_y;
+       wnd_zoom_crop = wnd_blackline;
+
+       /* output channel */
+       if ((main_flag & CI_ISP_DPD_ENABLE) &&
+           (main_flag & CI_ISP_DPD_KEEPRATIO)) {
+               target = main;
+       }
+       if ((self_flag & CI_ISP_DPD_ENABLE) &&
+           (self_flag & CI_ISP_DPD_KEEPRATIO)) {
+               if (target) {
+                       eprintk("only allowed for one path");
+                       return CI_STATUS_NOTSUPP;
+               }
+               target = self;
+       }
+
+       /* if so, calculate the cropping */
+       if (target) {
+               u32 aspect_cam = (0x1000 * ((u32) isi_x)) / isi_y;
+               u32 aspect_target = (0x1000 * ((u32) (target->out_w))) /
+                   target->out_h;
+               if (aspect_cam < aspect_target) {
+                       /*
+                        * camera aspect is more 'portrait-like' as
+                        * target aspect. We have to crop the
+                        * camera picture by cutting off a bit of
+                        * the top & bottom changed to avoid LINT
+                        * warnings (Info 734)
+                        */
+                       wnd_zoom_crop.vsize = (u16) (((u32) isi_x *
+                                      (u32) (target->out_h)) / target->out_w);
+               } else  {
+                       /* camera aspect is more 'landscape-like'
+                        * as target aspect. We have to crop the
+                        * camera picture by cutting off a bit of
+                        * the left and right changed to avoid LINT
+                        * warnings (Info 734) */
+                       wnd_zoom_crop.hsize = (u16) (((u32) isi_y *
+                                      (u32) (target->out_w)) / target->out_h);
+               }
+       }
+
+       /*
+        * now, we may also want to do digital zoom. If so, we need
+        * to shrink the ISP window by the desired zoom factor.
+        */
+       if (zoom > 0) {
+               wnd_zoom_crop.vsize = (u16) (((u32) (wnd_zoom_crop.vsize) *
+                              1024) / (1024 + (u32) zoom));
+               wnd_zoom_crop.hsize = (u16) (((u32) (wnd_zoom_crop.hsize) *
+                              1024) / (1024 + (u32) zoom));
+       }
+
+       /*
+        * Remember that the output formatter h_size should be
+        * even if the scaler is used
+        * (otherwise the scaler may show unexpected behaviour in
+        * some rare cases)
+        */
+       wnd_zoom_crop.hsize &= ~0x01;
+
+       /*
+        * At last, we care about the offset of the ISP window. We
+        * want it centered on the image data delivered by the
+        * sensor (not counting possible black lines)
+        */
+       wnd_zoom_crop.hoffs = (isi_x - wnd_zoom_crop.hsize) / 2;
+       wnd_zoom_crop.voffs = (isi_y - wnd_zoom_crop.vsize) / 2;
+
+       /*
+        * If the image sensor delivers blacklines, we cut them
+        * away with moving wnd_blackline window by the given
+        * amount of lines
+        */
+       switch (isi_config->bls) {
+       case SENSOR_BLS_OFF:
+               break;
+       case SENSOR_BLS_TWO_LINES:
+               wnd_blackline.voffs += 2;
+               break;
+       case SENSOR_BLS_FOUR_LINES:
+               wnd_blackline.voffs += 2;
+               break;
+       default:
+               eprintk("config");
+               return CI_STATUS_NOTSUPP;
+       }
+       /*
+        * if we are instructed to show the blacklines and the
+        * sensor generates them,
+        * we have to move the ISP windows to the upper border of
+        * the whole sensor, and deny the image stabilization to
+        * move around the window in vertical direction.
+        */
+       if (isi_config->bls != SENSOR_BLS_OFF) {
+               if (((main_flag & CI_ISP_DPD_ENABLE)
+                    && (main_flag & CI_ISP_DPD_BLACKLINES_TOP))
+                   || ((self_flag & CI_ISP_DPD_ENABLE)
+                       && (self_flag & CI_ISP_DPD_BLACKLINES_TOP))) {
+                       if ((main_flag & CI_ISP_DPD_ENABLE)
+                           && (self_flag & CI_ISP_DPD_ENABLE)
+                           && ((main_flag & CI_ISP_DPD_BLACKLINES_TOP)
+                               != (self_flag & CI_ISP_DPD_BLACKLINES_TOP))) {
+                               eprintk("and self path");
+                               return CI_STATUS_NOTSUPP;
+                       }
+                       wnd_blackline.voffs = 0;
+                       wnd_zoom_crop.voffs = 0;
+               }
+       }
+
+       source.out_w = wnd_zoom_crop.hsize;
+       source.out_h = wnd_zoom_crop.vsize;
+       source.flags = CI_ISP_DPD_DMA_IN_422;
+
+       /*to use crop set crop_flag first*/
+       if (crop_flag) {
+               wnd_zoom_crop.hsize = main->out_w;
+               wnd_zoom_crop.vsize = main->out_h;
+       }
+
+       dprintk(1, "source.out_w %d, source.out_h %d",
+               source.out_w, source.out_h);
+       if (main)
+               dprintk(1, "main.out_w %d, main.out_h %d",
+                       main->out_w, main->out_h);
+       if (self)
+               dprintk(1, "self.out_w %d, self.out_h %d",
+                       self->out_w, self->out_h);
+
+       res = ci_calc_main_path_settings(&source, main, &scale_main,
+                                        &mrv_mi_ctrl);
+       if (res != CI_STATUS_SUCCESS)
+               return res;
+
+       /* additional settings specific for main path fed from ISP */
+       if (main_flag & CI_ISP_DPD_ENABLE) {
+               switch (main_flag & CI_ISP_DPD_MODE_MASK) {
+               case CI_ISP_DPD_MODE_ISPYC:
+               case CI_ISP_DPD_MODE_ISPRAW:
+               case CI_ISP_DPD_MODE_ISPRAW_16B:
+               case CI_ISP_DPD_MODE_ISPJPEG:
+                       break;
+               default:
+                       eprintk("data coming from the ISP");
+                       return CI_STATUS_NOTSUPP;
+               }
+       }
+
+       /* basic selfpath settings */
+       res = ci_calc_self_path_settings(&source, self, &scale_flag,
+                                        &mrv_mi_ctrl);
+       if (res != CI_STATUS_SUCCESS)
+               return res;
+
+       if (sys_conf->isp_cfg.flags.ycbcr_non_cosited)
+               mrv_mi_ctrl.mrv_mif_sp_in_phase = mrv_mif_col_phase_non_cosited;
+       else
+               mrv_mi_ctrl.mrv_mif_sp_in_phase = mrv_mif_col_phase_cosited;
+       if (sys_conf->isp_cfg.flags.ycbcr_full_range)
+               mrv_mi_ctrl.mrv_mif_sp_in_range = mrv_mif_col_range_full;
+       else
+               mrv_mi_ctrl.mrv_mif_sp_in_range = mrv_mif_col_range_std;
+       if (self_flag & CI_ISP_DPD_ENABLE) {
+               switch (self_flag & CI_ISP_DPD_MODE_MASK) {
+               case CI_ISP_DPD_MODE_ISPYC:
+                       break;
+               default:
+                       return CI_STATUS_NOTSUPP;
+               }
+       }
+
+       /* Datapath multiplexers */
+       res = ci_calc_dp_mux_settings(&mrv_mi_ctrl, &chn_mode, &dp_switch);
+       if (res != CI_STATUS_SUCCESS)
+               return res;
+
+       /* hardcoded global settings of the memory interface */
+       mrv_mi_ctrl.byte_swap_enable = false;
+
+       mrv_mi_ctrl.init_vals = CI_ISP_MIF_INIT_OFFSAndBase;
+
+       /*to use crop set crop_flag first*/
+       if (crop_flag) {
+               wnd_blackline.hsize = main->out_w;
+               wnd_blackline.vsize = main->out_h;
+       }
+
+       res = ci_set_isp_windows(isi_config, &wnd_blackline,
+                                &wnd_zoom_crop);
+       if (res != CI_STATUS_SUCCESS) {
+               eprintk("failed to set ISP window configuration");
+               return res;
+       }
+       res = ci_isp_set_data_path(chn_mode, dp_switch);
+       if (res != CI_STATUS_SUCCESS)
+               return res;
+
+       res = ci_isp_set_mipi_smia(isi_config->mode);
+       if (res != CI_STATUS_SUCCESS)
+               return res;
+
+       if (mrv_mi_ctrl.self_path != CI_ISP_PATH_OFF)
+               ci_isp_res_set_self_resize(&scale_flag,
+                                          CI_ISP_CFG_UPDATE_IMMEDIATE,
+                                          ci_get_rsz_lut(self_flag));
+
+       if (mrv_mi_ctrl.main_path != CI_ISP_PATH_OFF)
+               ci_isp_res_set_main_resize(&scale_main,
+                                          CI_ISP_CFG_UPDATE_IMMEDIATE,
+                                          ci_get_rsz_lut(main_flag));
+
+       res = ci_isp_mif_set_path_and_orientation(&mrv_mi_ctrl);
+       if (res != CI_STATUS_SUCCESS) {
+               eprintk("failed to set MI path and orientation");
+               return res;
+       }
+
+       /* here the extended YCbCr mode is configured */
+       if (sys_conf->isp_cfg.flags.ycbcr_full_range)
+               res = ci_ext_ycb_cr_mode(main);
+       else
+               (void)ci_isp_set_yc_mode();
+
+       if (res != CI_STATUS_SUCCESS) {
+               eprintk("failed to set ISP YCbCr extended mode");
+               return res;
+       }
+
+       return CI_STATUS_SUCCESS;
+}
diff --git a/drivers/media/video/mrstci/mrstisp/mrstisp_hw.c b/drivers/media/video/mrstci/mrstisp/mrstisp_hw.c
new file mode 100644
index 0000000..ece0145
--- /dev/null
+++ b/drivers/media/video/mrstci/mrstisp/mrstisp_hw.c
@@ -0,0 +1,1360 @@
+/*
+ * 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@xxxxxxxxx>
+ */
+
+#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;
+
+       (void)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)
+{
+       if (dec <= (-6)) {
+               /* equivlent to -8 */
+               return 0x0f;
+       } else if (dec <= (-3)) {
+               /* equivlent to -4 */
+               return 0x0e;
+       } else if (dec == (-2)) {
+               /* equivlent to -2 */
+               return 0x0d;
+       } else if (dec == (-1)) {
+               /* equivlent to -1 */
+               return 0x0c;
+       } else if (dec == 0) {
+               /* equivlent to 0 (entry not used) */
+               return 0x00;
+       } else if (dec == 1) {
+               /* equivlent to 1 */
+               return 0x08;
+       } else if (dec == 2) {
+               /* equivlent to 2 */
+               return 0x09;
+       } else if (dec < 6) {
+               /* equivlent to 4 */
+               return 0x0a;
+       } else {
+               /* equivlent to 8 */
+               return 0x0b;
+       }
+}
+
+/*
+ * 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;
+}
diff --git a/drivers/media/video/mrstci/mrstisp/mrstisp_isp.c b/drivers/media/video/mrstci/mrstisp/mrstisp_isp.c
new file mode 100644
index 0000000..6c13115
--- /dev/null
+++ b/drivers/media/video/mrstci/mrstisp/mrstisp_isp.c
@@ -0,0 +1,1913 @@
+/*
+ * 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@xxxxxxxxx>
+ */
+
+#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;
+
+       /* disable measurement module */
+       REG_SET_SLICE(mrv_reg->isp_afm_ctrl, MRV_AFM_AFM_EN, DISABLE);
+
+       if (af_config) {
+               u32 lt;
+               u32 rb;
+               result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_a),
+                                             &lt, &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),
+                                             &lt, &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),
+                                             &lt, &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);
+       } else {
+               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.
+ */
+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 (((noise_reduc_level <= 10) || (noise_reduc_level == 99))
+           && (sharp_level <= 10)) {
+               switch (noise_reduc_level) {
+               case 99:
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 0x000003FF);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 0x000003FF);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 0x000003FF);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 0x000003FF);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 0);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_BYPASS);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_BYPASS);
+                       break;
+
+               case 0:
+                       /* NoiseReductionLevel = 0 */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 0x000000);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 0x000000);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 0x000000);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 0x000000);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 6);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC8);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_BYPASS);
+                       break;
+
+               case 1:
+                       /* NoiseReductionLevel = 1; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 33);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 18);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 8);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 2);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 6);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 2:
+                       /* NoiseReductionLevel = 2; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 44);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 26);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 13);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 5);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 4);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 3:
+                       /* NoiseReductionLevel = 3; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 51);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 36);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 23);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 10);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 4);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 4:
+                       /* NoiseReductionLevel = 4; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 67);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 41);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 26);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 15);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 3);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 5:
+                       /* NoiseReductionLevel = 5; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 100);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 75);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 50);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 20);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 3);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 6:
+                       /* NoiseReductionLevel = 6; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 120);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 90);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 60);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 26);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 2);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 7:
+                       /* NoiseReductionLevel = 7; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 150);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 120);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 80);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 51);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 2);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 8:
+                       /* NoiseReductionLevel = 8; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 200);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 170);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 140);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 100);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT, 2);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 9:
+                       /* NoiseReductionLevel = 9; */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 300);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 250);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 180);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 150);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+                                     (sharp_level > 3) ? 2 : 1);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               case 10:
+                       /* NoiseReductionLevel = 10; extrem noise */
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh1,
+                                     MRV_FILT_FILT_THRESH_SH1, 1023);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_sh0,
+                                     MRV_FILT_FILT_THRESH_SH0, 1023);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl0,
+                                     MRV_FILT_FILT_THRESH_BL0, 1023);
+                       REG_SET_SLICE(mrv_reg->isp_filt_thresh_bl1,
+                                     MRV_FILT_FILT_THRESH_BL1, 1023);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_STAGE1_SELECT,
+                                     (sharp_level > 5) ? 2 :
+                                     ((sharp_level > 3) ? 1 : 0));
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_V_MODE,
+                                     MRV_FILT_FILT_CHR_V_MODE_STATIC12);
+                       REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_CHR_H_MODE,
+                                     MRV_FILT_FILT_CHR_H_MODE_DYN_2);
+                       break;
+
+               default:
+                       return CI_STATUS_OUTOFRANGE;
+               }
+
+               switch (sharp_level) {
+               case 0:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000004);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x00000004);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000004);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000002);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000000);
+                       break;
+
+               /* SharpLevel = 1; */
+               case 1:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000008);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x00000007);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000006);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000002);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000000);
+                       break;
+
+               /* SharpLevel = 2; */
+               case 2:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x0000000C);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x0000000A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000008);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000004);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000000);
+                       break;
+
+               /* SharpLevel = 3; */
+               case 3:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000010);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x0000000C);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x0000000A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000006);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000002);
+                       break;
+
+               /* SharpLevel = 4; */
+               case 4:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000016);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x00000010);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x0000000C);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000008);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000004);
+                       break;
+
+               /* SharpLevel = 5; */
+               case 5:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x0000001B);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x00000014);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000010);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x0000000A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000004);
+                       break;
+
+               /* SharpLevel = 6; */
+               case 6:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000020);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x0000001A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000013);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x0000000C);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000006);
+                       break;
+
+               /* SharpLevel = 7; */
+               case 7:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x00000026);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x0000001E);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000017);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000010);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000008);
+                       break;
+
+               /* SharpLevel = 8; */
+               case 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);
+                       }
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                                     MRV_FILT_FILT_FAC_SH1, 0x0000002C);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x00000024);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x0000001D);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x00000015);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x0000000D);
+                       break;
+
+               /* SharpLevel = 9; */
+               case 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, 0x00000030);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                                     MRV_FILT_FILT_FAC_SH0, 0x0000002A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                                     MRV_FILT_FILT_FAC_MID, 0x00000022);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                                     MRV_FILT_FILT_FAC_BL0, 0x0000001A);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                                     MRV_FILT_FILT_FAC_BL1, 0x00000014);
+                       break;
+
+               /* SharpLevel = 10; */
+               case 10:
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh1,
+                               MRV_FILT_FILT_FAC_SH1, 0x0000003F);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_sh0,
+                               MRV_FILT_FILT_FAC_SH0, 0x00000030);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_mid,
+                               MRV_FILT_FILT_FAC_MID, 0x00000028);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0,
+                               MRV_FILT_FILT_FAC_BL0, 0x00000024);
+                       REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1,
+                               MRV_FILT_FILT_FAC_BL1, 0x00000020);
+                       break;
+
+               default:
+                       return CI_STATUS_OUTOFRANGE;
+               }
+
+               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;
+       } else {
+               /* At least one function parameter is out of range */
+               return CI_STATUS_OUTOFRANGE;
+       }
+}
+
+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);
+       }
+
+}
diff --git a/drivers/media/video/mrstci/mrstisp/mrstisp_jpe.c b/drivers/media/video/mrstci/mrstisp/mrstisp_jpe.c
new file mode 100644
index 0000000..c042e06
--- /dev/null
+++ b/drivers/media/video/mrstci/mrstisp/mrstisp_jpe.c
@@ -0,0 +1,569 @@
+/*
+ * 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@xxxxxxxxx>
+ */
+
+#include "mrstisp_stdinc.h"
+
+int ci_isp_jpe_init_ex(u16 hsize, u16 vsize, u8 compression_ratio, u8 jpe_scale)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       /*
+        * Reset JPEG-Encoder. In contrast to other software resets
+        * this triggers the modules asynchronous reset resulting
+        * in loss of all data.
+        */
+
+       REG_SET_SLICE(mrv_reg->vi_ircl, MRV_VI_JPEG_SOFT_RST, ON);
+       REG_SET_SLICE(mrv_reg->vi_ircl, MRV_VI_JPEG_SOFT_RST, OFF);
+
+       /* set configuration for the Jpeg capturing */
+       ci_isp_jpe_set_config(hsize, vsize, jpe_scale);
+
+       /*
+        * Sleep a while before setting up tables because of the 400
+        * clock cycles required to initialize the table RAM after a
+        * reset was issued. On FPGA we are running with only 30MHz,
+        * so at least 13us are required.
+        */
+
+
+       /*
+        * Note: this func is called when holding spin lock,
+        * so can not change to msleep.
+        */
+       mdelay(15);
+
+       /* program tables */
+       ci_isp_jpe_set_tables(compression_ratio);
+
+       /* choose tables */
+       ci_isp_jpe_select_tables();
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * initialization of JPEG encoder
+ */
+int ci_isp_jpe_init(u32 resolution, u8 compression_ratio, int jpe_scale)
+{
+       u16 hsize = 0;
+       u16 vsize = 0;
+
+       switch (resolution) {
+       case SENSOR_RES_BP1:
+               /* 352; */
+               hsize = BP1_SIZE_H;
+               /* 240; */
+               vsize = BP1_SIZE_V;
+               break;
+       case SENSOR_RES_S_AFM:
+               /* 64; */
+               hsize = S_AFM_SIZE_H;
+               /* 32; */
+               vsize = S_AFM_SIZE_V;
+               break;
+       case SENSOR_RES_M_AFM:
+               /* 128; */
+               hsize = M_AFM_SIZE_H;
+               /* 96; */
+               vsize = M_AFM_SIZE_V;
+               break;
+       case SENSOR_RES_L_AFM:
+               /* 720; */
+               hsize = L_AFM_SIZE_H;
+               /* 480; */
+               vsize = L_AFM_SIZE_V;
+               break;
+       case SENSOR_RES_QQCIF:
+               /* 88; */
+               hsize = QQCIF_SIZE_H;
+               /* 72; */
+               vsize = QQCIF_SIZE_V;
+               break;
+       case SENSOR_RES_QQVGA:
+               /* 160; */
+               hsize = QQVGA_SIZE_H;
+               /* 120; */
+               vsize = QQVGA_SIZE_V;
+               break;
+       case SENSOR_RES_QCIF:
+               /* 176; */
+               hsize = QCIF_SIZE_H;
+               /* 144; */
+               vsize = QCIF_SIZE_V;
+               break;
+       case SENSOR_RES_QVGA:
+               /* 320; */
+               hsize = QVGA_SIZE_H;
+               /* 240; */
+               vsize = QVGA_SIZE_V;
+               break;
+       case SENSOR_RES_CIF:
+               /* 352; */
+               hsize = CIF_SIZE_H;
+               /* 288; */
+               vsize = CIF_SIZE_V;
+               break;
+       case SENSOR_RES_VGA:
+               /* 640; */
+               hsize = VGA_SIZE_H;
+               /* 480; */
+               vsize = VGA_SIZE_V;
+               break;
+       case SENSOR_RES_SVGA:
+               /* 800; */
+               hsize = SVGA_SIZE_H;
+               /* 600; */
+               vsize = SVGA_SIZE_V;
+               break;
+       case SENSOR_RES_XGA:
+               /* 1024; */
+               hsize = XGA_SIZE_H;
+               /* 768; */
+               vsize = XGA_SIZE_V;
+               break;
+       case SENSOR_RES_XGA_PLUS:
+               /* 1280; */
+               hsize = XGA_PLUS_SIZE_H;
+               /* 960; */
+               vsize = XGA_PLUS_SIZE_V;
+               break;
+       case SENSOR_RES_SXGA:
+               /* 1280; */
+               hsize = SXGA_SIZE_H;
+               /* 1024; */
+               vsize = SXGA_SIZE_V;
+               break;
+       case SENSOR_RES_UXGA:
+               /* 1600; */
+               hsize = UXGA_SIZE_H;
+               /* 1200; */
+               vsize = UXGA_SIZE_V;
+               break;
+       case SENSOR_RES_QXGA:
+               /* 2048; */
+               hsize = QXGA_SIZE_H;
+               /* 1536; */
+               vsize = QXGA_SIZE_V;
+               break;
+       case SENSOR_RES_QSXGA:
+               /* 2586; */
+               hsize = QSXGA_SIZE_H;
+               /* 2048; */
+               vsize = QSXGA_SIZE_V;
+               break;
+       case SENSOR_RES_QSXGA_PLUS:
+               /* 2600; */
+               hsize = QSXGA_PLUS_SIZE_H;
+               /* 2048; */
+               vsize = QSXGA_PLUS_SIZE_V;
+               break;
+       case SENSOR_RES_QSXGA_PLUS2:
+               /* 2600; */
+               hsize = QSXGA_PLUS2_SIZE_H;
+               /* 1950; */
+               vsize = QSXGA_PLUS2_SIZE_V;
+               break;
+       case SENSOR_RES_QSXGA_PLUS3:
+               /* 2686; */
+               hsize = QSXGA_PLUS3_SIZE_H;
+               /* 2048; */
+               vsize = QSXGA_PLUS3_SIZE_V;
+               break;
+       case SENSOR_RES_WQSXGA:
+               /* 3200 */
+               hsize = WQSXGA_SIZE_H;
+               /* 2048 */
+               vsize = WQSXGA_SIZE_V;
+               break;
+       case SENSOR_RES_QUXGA:
+               /* 3200 */
+               hsize = QUXGA_SIZE_H;
+               /* 2400 */
+               vsize = QUXGA_SIZE_V;
+               break;
+       case SENSOR_RES_WQUXGA:
+               /* 3840 */
+               hsize = WQUXGA_SIZE_H;
+               /* 2400 */
+               vsize = WQUXGA_SIZE_V;
+               break;
+       case SENSOR_RES_HXGA:
+               /* 4096 */
+               hsize = HXGA_SIZE_H;
+               /* 3072 */
+               vsize = HXGA_SIZE_V;
+               break;
+       default:
+               eprintk("resolution not supported");
+               return CI_STATUS_NOTSUPP;
+       }
+
+       return ci_isp_jpe_init_ex(hsize, vsize, compression_ratio, jpe_scale);
+}
+
+void ci_isp_jpe_set_tables(u8 compression_ratio)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       /* required because auto-increment register */
+       u32 jpe_table_data = 0;
+
+       u8 idx, size;
+       const u8 *yqtable = NULL;
+       const u8 *uvqtable = NULL;
+
+       switch (compression_ratio) {
+       case CI_ISP_JPEG_LOW_COMPRESSION:
+               yqtable = ci_isp_yq_table_low_comp1;
+               uvqtable = ci_isp_uv_qtable_low_comp1;
+               break;
+       case CI_ISP_JPEG_01_PERCENT:
+               yqtable = ci_isp_yq_table01_per_cent;
+               uvqtable = ci_isp_uv_qtable01_per_cent;
+               break;
+       case CI_ISP_JPEG_20_PERCENT:
+               yqtable = ci_isp_yq_table20_per_cent;
+               uvqtable = ci_isp_uv_qtable20_per_cent;
+               break;
+       case CI_ISP_JPEG_30_PERCENT:
+               yqtable = ci_isp_yq_table30_per_cent;
+               uvqtable = ci_isp_uv_qtable30_per_cent;
+               break;
+       case CI_ISP_JPEG_40_PERCENT:
+               yqtable = ci_isp_yq_table40_per_cent;
+               uvqtable = ci_isp_uv_qtable40_per_cent;
+               break;
+       case CI_ISP_JPEG_50_PERCENT:
+               yqtable = ci_isp_yq_table50_per_cent;
+               uvqtable = ci_isp_uv_qtable50_per_cent;
+               break;
+       case CI_ISP_JPEG_60_PERCENT:
+               yqtable = ci_isp_yq_table60_per_cent;
+               uvqtable = ci_isp_uv_qtable60_per_cent;
+               break;
+       case CI_ISP_JPEG_70_PERCENT:
+               yqtable = ci_isp_yq_table70_per_cent;
+               uvqtable = ci_isp_uv_qtable70_per_cent;
+               break;
+       case CI_ISP_JPEG_80_PERCENT:
+               yqtable = ci_isp_yq_table80_per_cent;
+               uvqtable = ci_isp_uv_qtable80_per_cent;
+               break;
+       case CI_ISP_JPEG_90_PERCENT:
+               yqtable = ci_isp_yq_table90_per_cent;
+               uvqtable = ci_isp_uv_qtable90_per_cent;
+               break;
+       case CI_ISP_JPEG_99_PERCENT:
+               yqtable = ci_isp_yq_table99_per_cent;
+               uvqtable = ci_isp_uv_qtable99_per_cent;
+               break;
+       case CI_ISP_JPEG_HIGH_COMPRESSION:
+       default:
+               /*
+                * in the case an unknown value is set,
+                * use CI_JPEG_HIGH_COMPRESSION
+                */
+               yqtable = ci_isp_yq_table75_per_cent;
+               uvqtable = ci_isp_uv_qtable75_per_cent;
+               break;
+       }
+
+       /* Y q-table 0 programming */
+
+       /* all possible assigned tables have same size */
+       size = sizeof(ci_isp_yq_table75_per_cent)/
+               sizeof(ci_isp_yq_table75_per_cent[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_QUANT0);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             yqtable[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             yqtable[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+
+       /* U/V q-table 0 programming */
+
+       /* all possible assigned tables have same size */
+       size = sizeof(ci_isp_uv_qtable75_per_cent) /
+               sizeof(ci_isp_uv_qtable75_per_cent[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_QUANT1);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             uvqtable[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             uvqtable[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+
+       /* Y AC-table 0 programming */
+
+       size = sizeof(ci_isp_ac_luma_table_annex_k) /
+               sizeof(ci_isp_ac_luma_table_annex_k[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_VLC_AC0);
+       REG_SET_SLICE(mrv_reg->jpe_tac0_len, MRV_JPE_TAC0_LEN, size);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             ci_isp_ac_luma_table_annex_k[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             ci_isp_ac_luma_table_annex_k[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+
+       /* U/V AC-table 1 programming */
+
+       size = sizeof(ci_isp_ac_chroma_table_annex_k) /
+               sizeof(ci_isp_ac_chroma_table_annex_k[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_VLC_AC1);
+       REG_SET_SLICE(mrv_reg->jpe_tac1_len, MRV_JPE_TAC1_LEN, size);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             ci_isp_ac_chroma_table_annex_k[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             ci_isp_ac_chroma_table_annex_k[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+
+       /* Y DC-table 0 programming */
+
+       size = sizeof(ci_isp_dc_luma_table_annex_k) /
+               sizeof(ci_isp_dc_luma_table_annex_k[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_VLC_DC0);
+       REG_SET_SLICE(mrv_reg->jpe_tdc0_len, MRV_JPE_TDC0_LEN, size);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             ci_isp_dc_luma_table_annex_k[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             ci_isp_dc_luma_table_annex_k[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+
+       /* U/V DC-table 1 programming */
+
+       size = sizeof(ci_isp_dc_chroma_table_annex_k) /
+               sizeof(ci_isp_dc_chroma_table_annex_k[0]);
+       REG_SET_SLICE(mrv_reg->jpe_table_id, MRV_JPE_TABLE_ID,
+                     MRV_JPE_TABLE_ID_VLC_DC1);
+       REG_SET_SLICE(mrv_reg->jpe_tdc1_len, MRV_JPE_TDC1_LEN, size);
+       for (idx = 0; idx < (size - 1); idx += 2) {
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_H,
+                             ci_isp_dc_chroma_table_annex_k[idx]);
+               REG_SET_SLICE(jpe_table_data, MRV_JPE_TABLE_WDATA_L,
+                             ci_isp_dc_chroma_table_annex_k[idx + 1]);
+               /* auto-increment register! */
+               REG_WRITE(mrv_reg->jpe_table_data, jpe_table_data);
+       }
+}
+
+/*
+ * selects tables to be used by encoder
+ */
+void ci_isp_jpe_select_tables(void)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       /* selects quantization table for Y */
+       REG_SET_SLICE(mrv_reg->jpe_tq_y_select, MRV_JPE_TQ0_SELECT,
+                     MRV_JPE_TQ_SELECT_TAB0);
+       /* selects quantization table for U */
+       REG_SET_SLICE(mrv_reg->jpe_tq_u_select, MRV_JPE_TQ1_SELECT,
+                     MRV_JPE_TQ_SELECT_TAB1);
+       /* selects quantization table for V */
+       REG_SET_SLICE(mrv_reg->jpe_tq_v_select, MRV_JPE_TQ2_SELECT,
+                     MRV_JPE_TQ_SELECT_TAB1);
+       /* selects Huffman DC table */
+       REG_SET_SLICE(mrv_reg->jpe_dc_table_select,
+                     MRV_JPE_DC_TABLE_SELECT_Y, 0);
+       REG_SET_SLICE(mrv_reg->jpe_dc_table_select,
+                     MRV_JPE_DC_TABLE_SELECT_U, 1);
+       REG_SET_SLICE(mrv_reg->jpe_dc_table_select,
+                     MRV_JPE_DC_TABLE_SELECT_V, 1);
+       /* selects Huffman AC table */
+       REG_SET_SLICE(mrv_reg->jpe_ac_table_select,
+                     MRV_JPE_AC_TABLE_SELECT_Y, 0);
+       REG_SET_SLICE(mrv_reg->jpe_ac_table_select,
+                     MRV_JPE_AC_TABLE_SELECT_U, 1);
+       REG_SET_SLICE(mrv_reg->jpe_ac_table_select,
+                     MRV_JPE_AC_TABLE_SELECT_V, 1);
+}
+
+/*
+ * configure JPEG encoder
+ */
+void ci_isp_jpe_set_config(u16 hsize, u16 vsize, int jpe_scale)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       /* JPEG image size */
+
+       REG_SET_SLICE(mrv_reg->jpe_enc_hsize, MRV_JPE_ENC_HSIZE, hsize);
+       REG_SET_SLICE(mrv_reg->jpe_enc_vsize, MRV_JPE_ENC_VSIZE, vsize);
+
+       if (jpe_scale) {
+               /* upscaling of BT601 color space to full range 0..255 */
+               REG_SET_SLICE(mrv_reg->jpe_y_scale_en, MRV_JPE_Y_SCALE_EN,
+                             ENABLE);
+               REG_SET_SLICE(mrv_reg->jpe_cbcr_scale_en,
+                             MRV_JPE_CBCR_SCALE_EN, ENABLE);
+       } else {
+               /* bypass scaler */
+               REG_SET_SLICE(mrv_reg->jpe_y_scale_en,
+                             MRV_JPE_Y_SCALE_EN, DISABLE);
+               REG_SET_SLICE(mrv_reg->jpe_cbcr_scale_en,
+                             MRV_JPE_CBCR_SCALE_EN, DISABLE);
+       }
+
+       /* picture format YUV 422 */
+       REG_SET_SLICE(mrv_reg->jpe_pic_format, MRV_JPE_ENC_PIC_FORMAT,
+                     MRV_JPE_ENC_PIC_FORMAT_422);
+       REG_SET_SLICE(mrv_reg->jpe_table_flush, MRV_JPE_TABLE_FLUSH, 0);
+}
+
+int ci_isp_jpe_generate_header(struct mrst_isp_device *intel, u8 header_mode)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       WARN_ON(!((header_mode == MRV_JPE_HEADER_MODE_JFIF)
+           || (header_mode == MRV_JPE_HEADER_MODE_NO)));
+
+       /* clear jpeg gen_header_done interrupt */
+       /* since we poll them later to detect command completion */
+
+       REG_SET_SLICE(mrv_reg->jpe_status_icr, MRV_JPE_GEN_HEADER_DONE, 1);
+       REG_SET_SLICE(mrv_reg->jpe_header_mode, MRV_JPE_HEADER_MODE,
+                     header_mode);
+
+       /* start header generation */
+       REG_SET_SLICE(mrv_reg->jpe_gen_header, MRV_JPE_GEN_HEADER, ON);
+
+       return ci_isp_jpe_wait_for_header_gen_done(intel);
+}
+
+void ci_isp_jpe_prep_enc(enum ci_isp_jpe_enc_mode jpe_enc_mode)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       u32 jpe_encode = REG_READ(mrv_reg->jpe_encode);
+
+       /* clear jpeg encode_done interrupt */
+       /* since we poll them later to detect command completion */
+
+       REG_SET_SLICE(mrv_reg->jpe_status_icr, MRV_JPE_ENCODE_DONE, 1);
+       REG_SET_SLICE(jpe_encode, MRV_JPE_ENCODE, ON);
+
+       switch (jpe_enc_mode) {
+       case CI_ISP_JPE_LARGE_CONT_MODE:
+               /* motion JPEG with header generation */
+               REG_SET_SLICE(jpe_encode, MRV_JPE_CONT_MODE,
+                   MRV_JPE_CONT_MODE_HEADER);
+               break;
+       case CI_ISP_JPE_SHORT_CONT_MODE:
+               /* motion JPEG only first frame with header */
+               REG_SET_SLICE(jpe_encode, MRV_JPE_CONT_MODE,
+                   MRV_JPE_CONT_MODE_NEXT);
+               break;
+       default:
+               /* single shot JPEG */
+               REG_SET_SLICE(jpe_encode, MRV_JPE_CONT_MODE,
+                   MRV_JPE_CONT_MODE_STOP);
+               break;
+       }
+
+       REG_WRITE(mrv_reg->jpe_encode, jpe_encode);
+       REG_SET_SLICE(mrv_reg->jpe_init, MRV_JPE_JP_INIT, 1);
+}
+
+/*
+ * wait until JPG Header is generated (MRV_JPGINT_GEN_HEADER_DONE
+ *              interrupt occurs)
+ *              waiting for JPG Header to be generated
+ */
+int ci_isp_jpe_wait_for_header_gen_done(struct mrst_isp_device *intel)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       mrst_timer_start();
+
+       while (!REG_GET_SLICE(mrv_reg->jpe_status_ris,
+                              MRV_JPE_GEN_HEADER_DONE)) {
+               if (mrst_get_micro_sec() > 2000000) {
+                       mrst_timer_stop();
+                       eprintk("timeout");
+                       return CI_STATUS_FAILURE;
+               }
+       }
+
+       mrst_timer_stop();
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * wait until JPG Encoder is done  (MRV_JPGINT_ENCODE_DONE
+ * interrupt occurs) waiting for the JPG Encoder to be done
+ */
+int ci_isp_jpe_wait_for_encode_done(struct mrst_isp_device *intel)
+{
+#if 0
+       int ret = 0;
+       INIT_COMPLETION(intel->jpe_complete);
+       ret = wait_for_completion_interruptible_timeout(&intel->jpe_complete,
+                                                       100 * HZ);
+       if ((ret == 0) | (intel->irq_stat == IRQ_JPE_ERROR)) {
+               eprintk("timeout");
+               return CI_STATUS_FAILURE;
+       }
+
+       return CI_STATUS_SUCCESS;
+#endif
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       mrst_timer_start();
+
+       while (!REG_GET_SLICE(mrv_reg->jpe_status_ris,
+                             MRV_JPE_ENCODE_DONE)) {
+               if (mrst_get_micro_sec() > 200000) {
+                       mrst_timer_stop();
+                       eprintk("timeout");
+                       return CI_STATUS_FAILURE;
+               }
+       }
+
+       mrst_timer_stop();
+
+       /* clear jpeg encode_done interrupt */
+       REG_SET_SLICE(mrv_reg->jpe_status_icr, MRV_JPE_ENCODE_DONE, 1);
+
+       return CI_STATUS_SUCCESS;
+}
diff --git a/drivers/media/video/mrstci/mrstisp/mrstisp_mif.c b/drivers/media/video/mrstci/mrstisp/mrstisp_mif.c
new file mode 100644
index 0000000..e88ffbc
--- /dev/null
+++ b/drivers/media/video/mrstci/mrstisp/mrstisp_mif.c
@@ -0,0 +1,703 @@
+/*
+ * 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@xxxxxxxxx>
+ */
+
+#include "mrstisp_stdinc.h"
+
+/*
+ * sets all main picture and self picture buffer offsets back to 0
+ */
+void ci_isp_mif_reset_offsets(enum ci_isp_conf_update_time update_time)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       REG_SET_SLICE(mrv_reg->mi_mp_y_offs_cnt_init,
+                     MRV_MI_MP_Y_OFFS_CNT_INIT, 0);
+       REG_SET_SLICE(mrv_reg->mi_mp_cb_offs_cnt_init,
+                     MRV_MI_MP_CB_OFFS_CNT_INIT, 0);
+       REG_SET_SLICE(mrv_reg->mi_mp_cr_offs_cnt_init,
+                     MRV_MI_MP_CR_OFFS_CNT_INIT, 0);
+
+       REG_SET_SLICE(mrv_reg->mi_sp_y_offs_cnt_init,
+                     MRV_MI_SP_Y_OFFS_CNT_INIT, 0);
+       REG_SET_SLICE(mrv_reg->mi_sp_cb_offs_cnt_init,
+                     MRV_MI_SP_CB_OFFS_CNT_INIT, 0);
+       REG_SET_SLICE(mrv_reg->mi_sp_cr_offs_cnt_init,
+                     MRV_MI_SP_CR_OFFS_CNT_INIT, 0);
+
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_OFFSET_EN, ON);
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_BASE_EN, ON);
+
+       switch (update_time) {
+       case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+               break;
+       case CI_ISP_CFG_UPDATE_IMMEDIATE:
+               REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON);
+               break;
+       case CI_ISP_CFG_UPDATE_LATER:
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * This function get the byte count from the last JPEG or raw data transfer
+ */
+u32 ci_isp_mif_get_byte_cnt(void)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+
+       return (u32) REG_GET_SLICE(mrv_reg->mi_byte_cnt, MRV_MI_BYTE_CNT);
+}
+
+/*
+ * Sets the desired self picture orientation, if possible.
+ */
+static int ci_isp_mif_set_self_pic_orientation(enum ci_isp_mif_sp_mode
+                                               mrv_mif_sp_mode,
+                                               int activate_self_path)
+{
+
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       u32 mi_ctrl = REG_READ(mrv_reg->mi_ctrl);
+
+       u32 output_format = REG_GET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT);
+
+       switch (mrv_mif_sp_mode) {
+       case CI_ISP_MIF_SP_ORIGINAL:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP, 0);
+               break;
+
+       case CI_ISP_MIF_SP_HORIZONTAL_FLIP:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_H_FLIP);
+               break;
+
+       case CI_ISP_MIF_SP_VERTICAL_FLIP:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_V_FLIP);
+               break;
+
+       case CI_ISP_MIF_SP_ROTATION_090_DEG:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_ROTATE);
+               break;
+
+       case CI_ISP_MIF_SP_ROTATION_180_DEG:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_H_FLIP |
+                             MRV_MI_ROT_AND_FLIP_V_FLIP);
+               break;
+
+       case CI_ISP_MIF_SP_ROTATION_270_DEG:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_H_FLIP |
+                             MRV_MI_ROT_AND_FLIP_V_FLIP |
+                             MRV_MI_ROT_AND_FLIP_ROTATE);
+               break;
+
+       case CI_ISP_MIF_SP_ROT_090_V_FLIP:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_V_FLIP |
+                             MRV_MI_ROT_AND_FLIP_ROTATE);
+               break;
+
+       case CI_ISP_MIF_SP_ROT_270_V_FLIP:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP,
+                             MRV_MI_ROT_AND_FLIP_H_FLIP |
+                             MRV_MI_ROT_AND_FLIP_ROTATE);
+               break;
+
+       default:
+               eprintk("unknown value for mrv_mif_sp_mode");
+               return CI_STATUS_NOTSUPP;
+       }
+
+       if (REG_GET_SLICE(mi_ctrl, MRV_MI_ROT_AND_FLIP) &
+           MRV_MI_ROT_AND_FLIP_ROTATE) {
+               switch (output_format) {
+               case MRV_MI_SP_OUTPUT_FORMAT_RGB888:
+               case MRV_MI_SP_OUTPUT_FORMAT_RGB666:
+               case MRV_MI_SP_OUTPUT_FORMAT_RGB565:
+                       break;
+               default:
+                       eprintk("rotation is only allowed for RGB modes.");
+                       return CI_STATUS_NOTSUPP;
+               }
+       }
+
+       REG_SET_SLICE(mi_ctrl, MRV_MI_SP_ENABLE,
+                     (activate_self_path) ? ENABLE : DISABLE);
+       REG_WRITE(mrv_reg->mi_ctrl, mi_ctrl);
+       REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON);
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Checks the main or self picture path buffer structure.
+ */
+static int ci_isp_mif_check_mi_path_conf(const struct ci_isp_mi_path_conf
+                                        *isp_mi_path_conf, int main_buffer)
+{
+       if (!isp_mi_path_conf) {
+               eprintk("isp_mi_path_conf is NULL");
+               return CI_STATUS_NULL_POINTER;
+       }
+
+       if (!isp_mi_path_conf->ybuffer.pucbuffer) {
+               eprintk("isp_mi_path_conf->ybuffer.pucbuffer is NULL");
+               return CI_STATUS_NULL_POINTER;
+       }
+
+       if (main_buffer) {
+               if ((((unsigned long)(isp_mi_path_conf->ybuffer.pucbuffer)
+                     & ~(MRV_MI_MP_Y_BASE_AD_INIT_VALID_MASK)) != 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.size
+                       & ~(MRV_MI_MP_Y_SIZE_INIT_VALID_MASK)) != 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.size
+                       & (MRV_MI_MP_Y_SIZE_INIT_VALID_MASK)) == 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.offs
+                       & ~(MRV_MI_MP_Y_OFFS_CNT_INIT_VALID_MASK)) != 0)) {
+                               return CI_STATUS_OUTOFRANGE;
+               }
+       } else {
+               if ((((unsigned long) isp_mi_path_conf->ybuffer.pucbuffer
+                       & ~(MRV_MI_SP_Y_BASE_AD_INIT_VALID_MASK)) != 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.size &
+                       ~(MRV_MI_SP_Y_SIZE_INIT_VALID_MASK)) != 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.size &
+                       (MRV_MI_SP_Y_SIZE_INIT_VALID_MASK)) == 0)
+                       ||
+                       ((isp_mi_path_conf->ybuffer.offs &
+                       ~(MRV_MI_SP_Y_OFFS_CNT_INIT_VALID_MASK)) !=
+                       0)
+                       ||
+                       ((isp_mi_path_conf->llength &
+                       ~(MRV_MI_SP_Y_LLENGTH_VALID_MASK)) != 0)
+                       ||
+                       ((isp_mi_path_conf->
+                       llength & (MRV_MI_SP_Y_LLENGTH_VALID_MASK)) == 0)) {
+                       return CI_STATUS_OUTOFRANGE;
+               }
+       }
+
+       if (isp_mi_path_conf->cb_buffer.pucbuffer != 0) {
+               if (main_buffer) {
+                       if ((((unsigned long)
+                               isp_mi_path_conf->cb_buffer.pucbuffer
+                               & ~(MRV_MI_MP_CB_BASE_AD_INIT_VALID_MASK)) !=
+                               0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.size &
+                               ~(MRV_MI_MP_CB_SIZE_INIT_VALID_MASK)) != 0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.size &
+                               (MRV_MI_MP_CB_SIZE_INIT_VALID_MASK)) == 0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.offs &
+                               ~(MRV_MI_MP_CB_OFFS_CNT_INIT_VALID_MASK)) !=
+                               0)) {
+                                       return CI_STATUS_OUTOFRANGE;
+                       }
+               } else {
+                       if ((((unsigned long)
+                               isp_mi_path_conf->cb_buffer.pucbuffer
+                               & ~(MRV_MI_SP_CB_BASE_AD_INIT_VALID_MASK)) !=
+                               0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.size &
+                               ~(MRV_MI_SP_CB_SIZE_INIT_VALID_MASK)) != 0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.size &
+                               (MRV_MI_SP_CB_SIZE_INIT_VALID_MASK)) == 0)
+                               ||
+                               ((isp_mi_path_conf->cb_buffer.offs &
+                               ~(MRV_MI_SP_CB_OFFS_CNT_INIT_VALID_MASK)) !=
+                               0)) {
+                                       return CI_STATUS_OUTOFRANGE;
+                       }
+               }
+       }
+
+       if (isp_mi_path_conf->cr_buffer.pucbuffer != 0) {
+               if (main_buffer) {
+                       if ((((unsigned long)
+                               isp_mi_path_conf->cr_buffer.pucbuffer
+                               & ~(MRV_MI_MP_CR_BASE_AD_INIT_VALID_MASK)) !=
+                               0)
+                               ||
+                               ((isp_mi_path_conf->cr_buffer.size &
+                               ~(MRV_MI_MP_CR_SIZE_INIT_VALID_MASK)) != 0)
+                               ||
+                               ((isp_mi_path_conf->cr_buffer.size &
+                               (MRV_MI_MP_CR_SIZE_INIT_VALID_MASK)) == 0)
+                               ||
+                               ((isp_mi_path_conf->cr_buffer.offs &
+                               ~(MRV_MI_MP_CR_OFFS_CNT_INIT_VALID_MASK)) !=
+                               0)){
+                                       return CI_STATUS_OUTOFRANGE;
+                       }
+               } else {
+                       if ((((unsigned long)
+                               isp_mi_path_conf->cr_buffer.pucbuffer
+                               & ~(MRV_MI_SP_CR_BASE_AD_INIT_VALID_MASK))
+                               != 0)
+                           ||
+                           ((isp_mi_path_conf->cr_buffer.size &
+                             ~(MRV_MI_SP_CR_SIZE_INIT_VALID_MASK)) != 0)
+                           ||
+                           ((isp_mi_path_conf->cr_buffer.size &
+                           (MRV_MI_SP_CR_SIZE_INIT_VALID_MASK)) == 0)
+                           ||
+                           ((isp_mi_path_conf->cr_buffer.offs &
+                           ~(MRV_MI_SP_CR_OFFS_CNT_INIT_VALID_MASK)) != 0)) {
+                               return CI_STATUS_OUTOFRANGE;
+                       }
+               }
+       }
+
+       return CI_STATUS_SUCCESS;
+}
+
+/*
+ * Configures the main picture path buffers of the MI.
+ */
+int ci_isp_mif_set_main_buffer(const struct ci_isp_mi_path_conf
+                              *isp_mi_path_conf,
+                              enum ci_isp_conf_update_time update_time)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       int error = CI_STATUS_FAILURE;
+
+       error = ci_isp_mif_check_mi_path_conf(isp_mi_path_conf, true);
+       if (error != CI_STATUS_SUCCESS)
+               return error;
+
+       /* set register values */
+       REG_SET_SLICE(mrv_reg->mi_mp_y_base_ad_init,
+                     MRV_MI_MP_Y_BASE_AD_INIT,
+                     (u32)(unsigned long)isp_mi_path_conf->ybuffer.pucbuffer);
+       REG_SET_SLICE(mrv_reg->mi_mp_y_size_init, MRV_MI_MP_Y_SIZE_INIT,
+                     isp_mi_path_conf->ybuffer.size);
+       REG_SET_SLICE(mrv_reg->mi_mp_y_offs_cnt_init,
+                     MRV_MI_MP_Y_OFFS_CNT_INIT,
+                     isp_mi_path_conf->ybuffer.offs);
+
+       if (isp_mi_path_conf->cb_buffer.pucbuffer != 0) {
+               REG_SET_SLICE(mrv_reg->mi_mp_cb_base_ad_init,
+                             MRV_MI_MP_CB_BASE_AD_INIT,
+                             (u32)(unsigned long) isp_mi_path_conf->cb_buffer.
+                             pucbuffer);
+               REG_SET_SLICE(mrv_reg->mi_mp_cb_size_init,
+                             MRV_MI_MP_CB_SIZE_INIT,
+                             isp_mi_path_conf->cb_buffer.size);
+               REG_SET_SLICE(mrv_reg->mi_mp_cb_offs_cnt_init,
+                             MRV_MI_MP_CB_OFFS_CNT_INIT,
+                             isp_mi_path_conf->cb_buffer.offs);
+       }
+
+       if (isp_mi_path_conf->cr_buffer.pucbuffer != 0) {
+               REG_SET_SLICE(mrv_reg->mi_mp_cr_base_ad_init,
+                             MRV_MI_MP_CR_BASE_AD_INIT,
+                             (u32)(unsigned long) isp_mi_path_conf->cr_buffer.
+                             pucbuffer);
+               REG_SET_SLICE(mrv_reg->mi_mp_cr_size_init,
+                             MRV_MI_MP_CR_SIZE_INIT,
+                             isp_mi_path_conf->cr_buffer.size);
+               REG_SET_SLICE(mrv_reg->mi_mp_cr_offs_cnt_init,
+                             MRV_MI_MP_CR_OFFS_CNT_INIT,
+                             isp_mi_path_conf->cr_buffer.offs);
+       }
+
+       /*
+        * update base and offset registers during next immediate or
+        * automatic update request
+        */
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_OFFSET_EN, ENABLE);
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_BASE_EN, ENABLE);
+
+       switch (update_time) {
+       case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+               REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD, ON);
+               break;
+       case CI_ISP_CFG_UPDATE_IMMEDIATE:
+               REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON);
+               break;
+       case CI_ISP_CFG_UPDATE_LATER:
+               break;
+       default:
+               break;
+       }
+
+       return error;
+}
+
+/*
+ * Configures the self picture path buffers of the MI.
+ *
+ */
+int ci_isp_mif_set_self_buffer(const struct ci_isp_mi_path_conf
+                               *isp_mi_path_conf,
+                               enum ci_isp_conf_update_time update_time)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       int error = CI_STATUS_FAILURE;
+
+       error = ci_isp_mif_check_mi_path_conf(isp_mi_path_conf, false);
+       if (error != CI_STATUS_SUCCESS)
+               return error;
+
+       /* set register values */
+       REG_SET_SLICE(mrv_reg->mi_sp_y_base_ad_init,
+                     MRV_MI_SP_Y_BASE_AD_INIT,
+                     (u32)(unsigned long)isp_mi_path_conf->ybuffer.pucbuffer);
+       REG_SET_SLICE(mrv_reg->mi_sp_y_size_init, MRV_MI_SP_Y_SIZE_INIT,
+                     isp_mi_path_conf->ybuffer.size);
+       REG_SET_SLICE(mrv_reg->mi_sp_y_offs_cnt_init,
+                     MRV_MI_SP_Y_OFFS_CNT_INIT,
+                     isp_mi_path_conf->ybuffer.offs);
+
+       /*
+        * llength is counted in pixels and this value could be stored
+        * directly into the register
+        */
+       REG_SET_SLICE(mrv_reg->mi_sp_y_llength, MRV_MI_SP_Y_LLENGTH,
+                     isp_mi_path_conf->llength);
+
+       if (isp_mi_path_conf->cb_buffer.pucbuffer) {
+               REG_SET_SLICE(mrv_reg->mi_sp_cb_base_ad_init,
+                             MRV_MI_SP_CB_BASE_AD_INIT,
+                             (u32) (unsigned long)isp_mi_path_conf->cb_buffer.
+                             pucbuffer);
+               REG_SET_SLICE(mrv_reg->mi_sp_cb_size_init,
+                             MRV_MI_SP_CB_SIZE_INIT,
+                             isp_mi_path_conf->cb_buffer.size);
+               REG_SET_SLICE(mrv_reg->mi_sp_cb_offs_cnt_init,
+                             MRV_MI_SP_CB_OFFS_CNT_INIT,
+                             isp_mi_path_conf->cb_buffer.offs);
+       }
+
+       if (isp_mi_path_conf->cr_buffer.pucbuffer) {
+               REG_SET_SLICE(mrv_reg->mi_sp_cr_base_ad_init,
+                             MRV_MI_SP_CR_BASE_AD_INIT,
+                             (u32) (unsigned long)isp_mi_path_conf->cr_buffer.
+                             pucbuffer);
+               REG_SET_SLICE(mrv_reg->mi_sp_cr_size_init,
+                             MRV_MI_SP_CR_SIZE_INIT,
+                             isp_mi_path_conf->cr_buffer.size);
+               REG_SET_SLICE(mrv_reg->mi_sp_cr_offs_cnt_init,
+                             MRV_MI_SP_CR_OFFS_CNT_INIT,
+                             isp_mi_path_conf->cr_buffer.offs);
+       }
+
+       if ((!isp_mi_path_conf->ypic_width)
+           || (!isp_mi_path_conf->ypic_height)) {
+               return CI_STATUS_FAILURE;
+       }
+
+       REG_SET_SLICE(mrv_reg->mi_sp_y_pic_width, MRV_MI_SP_Y_PIC_WIDTH,
+                     isp_mi_path_conf->ypic_width);
+       REG_SET_SLICE(mrv_reg->mi_sp_y_pic_height, MRV_MI_SP_Y_PIC_HEIGHT,
+                     isp_mi_path_conf->ypic_height);
+       REG_SET_SLICE(mrv_reg->mi_sp_y_pic_size, MRV_MI_SP_Y_PIC_SIZE,
+                     isp_mi_path_conf->ypic_height *
+                     isp_mi_path_conf->llength);
+
+       /*
+        * update base and offset registers during next immediate or
+        * automatic update request
+        */
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_OFFSET_EN, ENABLE);
+       REG_SET_SLICE(mrv_reg->mi_ctrl, MRV_MI_INIT_BASE_EN, ENABLE);
+
+       switch (update_time) {
+       case CI_ISP_CFG_UPDATE_FRAME_SYNC:
+               REG_SET_SLICE(mrv_reg->isp_ctrl, MRV_ISP_ISP_GEN_CFG_UPD,
+                             ON);
+               break;
+       case CI_ISP_CFG_UPDATE_IMMEDIATE:
+               REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON);
+               break;
+       case CI_ISP_CFG_UPDATE_LATER:
+               break;
+       default:
+               break;
+       }
+
+       return error;
+}
+
+/*
+ * Configures the DMA path of the MI.
+ *
+ */
+int ci_isp_mif_set_path_and_orientation(const struct ci_isp_mi_ctrl
+                                       *mrv_mi_ctrl)
+{
+       struct isp_register *mrv_reg = (struct isp_register *) MEM_MRV_REG_BASE;
+       int error = CI_STATUS_OUTOFRANGE;
+       u32 mi_ctrl = 0;
+
+       if (!mrv_mi_ctrl) {
+               eprintk("mrv_mi_ctrl is NULL");
+               return CI_STATUS_NULL_POINTER;
+       }
+
+       if ((mrv_mi_ctrl->irq_offs_init &
+            ~(MRV_MI_MP_Y_IRQ_OFFS_INIT_VALID_MASK)) != 0) {
+               eprintk("bad mrv_mi_ctrl->irq_offs_init value");
+               return error;
+       }
+
+       REG_SET_SLICE(mrv_reg->mi_mp_y_irq_offs_init,
+                     MRV_MI_MP_Y_IRQ_OFFS_INIT, mrv_mi_ctrl->irq_offs_init);
+
+       /* main picture path */
+       switch (mrv_mi_ctrl->main_path) {
+       case CI_ISP_PATH_OFF:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_MP_ENABLE, OFF);
+               break;
+       case CI_ISP_PATH_ON:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_MP_ENABLE, ON);
+               break;
+       case CI_ISP_PATH_JPE:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_JPEG_ENABLE, ON);
+               break;
+       case CI_ISP_PATH_RAW8:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, ON);
+               break;
+       case CI_ISP_PATH_RAW816:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_RAW_ENABLE, ON);
+               REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
+                             MRV_MI_MP_WRITE_FORMAT_INTERLEAVED);
+               break;
+       default:
+               eprintk("bad mrv_mi_ctrl->main_path value");
+               return error;
+       }
+
+       /* self picture path output format */
+       switch (mrv_mi_ctrl->mrv_mif_sp_out_form) {
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_422:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_YUV422);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_444:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_YUV444);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_420:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_YUV420);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_400:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_YUV400);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_RGB_565:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_RGB565);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_RGB_888:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_RGB888);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_RGB_666:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_OUTPUT_FORMAT,
+                             MRV_MI_SP_OUTPUT_FORMAT_RGB666);
+               break;
+
+       default:
+               eprintk("bad mrv_mi_ctrl->mrv_mif_sp_out_form value");
+               return error;
+       }
+
+       /* self picture path input format */
+       switch (mrv_mi_ctrl->mrv_mif_sp_in_form) {
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_422:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_INPUT_FORMAT,
+                             MRV_MI_SP_INPUT_FORMAT_YUV422);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_444:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_INPUT_FORMAT,
+                             MRV_MI_SP_INPUT_FORMAT_YUV444);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_420:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_INPUT_FORMAT,
+                             MRV_MI_SP_INPUT_FORMAT_YUV420);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_YCBCR_400:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_INPUT_FORMAT,
+                             MRV_MI_SP_INPUT_FORMAT_YUV400);
+               break;
+       case CI_ISP_MIF_COL_FORMAT_RGB_565:
+       case CI_ISP_MIF_COL_FORMAT_RGB_666:
+       case CI_ISP_MIF_COL_FORMAT_RGB_888:
+       default:
+               eprintk("bad mrv_mi_ctrl->mrv_mif_sp_in_form value");
+               return error;
+       }
+
+       error = CI_STATUS_SUCCESS;
+
+       /* self picture path write format */
+       switch (mrv_mi_ctrl->mrv_mif_sp_pic_form) {
+       case CI_ISP_MIF_PIC_FORM_PLANAR:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
+                             MRV_MI_SP_WRITE_FORMAT_PLANAR);
+               break;
+       case CI_ISP_MIF_PIC_FORM_SEMI_PLANAR:
+               if ((mrv_mi_ctrl->mrv_mif_sp_out_form ==
+                   CI_ISP_MIF_COL_FORMAT_YCBCR_422)
+                   || (mrv_mi_ctrl->mrv_mif_sp_out_form ==
+                   CI_ISP_MIF_COL_FORMAT_YCBCR_420)) {
+                       REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
+                                     MRV_MI_SP_WRITE_FORMAT_SEMIPLANAR);
+               } else {
+                       error = CI_STATUS_NOTSUPP;
+               }
+               break;
+       case CI_ISP_MIF_PIC_FORM_INTERLEAVED:
+               if (mrv_mi_ctrl->mrv_mif_sp_out_form ==
+                   CI_ISP_MIF_COL_FORMAT_YCBCR_422) {
+                       REG_SET_SLICE(mi_ctrl, MRV_MI_SP_WRITE_FORMAT,
+                                     MRV_MI_SP_WRITE_FORMAT_INTERLEAVED);
+               } else {
+                       error = CI_STATUS_NOTSUPP;
+               }
+               break;
+       default:
+               error = CI_STATUS_OUTOFRANGE;
+               break;
+
+       }
+
+       if (error != CI_STATUS_SUCCESS) {
+               eprintk("bad mrv_mi_ctrl->mrv_mif_sp_pic_form value");
+               return error;
+       }
+
+       if (mrv_mi_ctrl->main_path == CI_ISP_PATH_ON) {
+               /* for YCbCr mode only, permitted for raw mode */
+               /* main picture path write format */
+               switch (mrv_mi_ctrl->mrv_mif_mp_pic_form) {
+               case CI_ISP_MIF_PIC_FORM_PLANAR:
+                       REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
+                                     MRV_MI_MP_WRITE_FORMAT_PLANAR);
+                       break;
+               case CI_ISP_MIF_PIC_FORM_SEMI_PLANAR:
+                       REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
+                                     MRV_MI_MP_WRITE_FORMAT_SEMIPLANAR);
+                       break;
+               case CI_ISP_MIF_PIC_FORM_INTERLEAVED:
+                       REG_SET_SLICE(mi_ctrl, MRV_MI_MP_WRITE_FORMAT,
+                                     MRV_MI_MP_WRITE_FORMAT_INTERLEAVED);
+                       break;
+               default:
+                       error = CI_STATUS_OUTOFRANGE;
+                       break;
+               }
+       }
+
+       if (error != CI_STATUS_SUCCESS) {
+               eprintk("bad mrv_mi_ctrl->mrv_mif_mp_pic_form value");
+               return error;
+       }
+
+       REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_CHROM,
+           MRV_MI_BURST_LEN_CHROM_16);
+
+       if (error != CI_STATUS_SUCCESS) {
+               eprintk("bad mrv_mi_ctrl->burst_length_chrom value");
+               return error;
+       }
+
+       REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_LUM,
+           MRV_MI_BURST_LEN_LUM_16);
+
+       if (error != CI_STATUS_SUCCESS) {
+               eprintk("bad mrv_mi_ctrl->burst_length_lum value");
+               return error;
+       }
+
+       switch (mrv_mi_ctrl->init_vals) {
+       case CI_ISP_MIF_NO_INIT_VALS:
+               break;
+       case CI_ISP_MIF_INIT_OFFS:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_INIT_OFFSET_EN, ENABLE);
+               break;
+       case CI_ISP_MIF_INIT_BASE:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_INIT_BASE_EN, ENABLE);
+               break;
+       case CI_ISP_MIF_INIT_OFFSAndBase:
+               REG_SET_SLICE(mi_ctrl, MRV_MI_INIT_OFFSET_EN, ENABLE);
+               REG_SET_SLICE(mi_ctrl, MRV_MI_INIT_BASE_EN, ENABLE);
+               break;
+       default:
+               error = CI_STATUS_OUTOFRANGE;
+               break;
+       }
+
+       if (error != CI_STATUS_SUCCESS) {
+               eprintk("bad mrv_mi_ctrl->init_vals value");
+               return error;
+       }
+
+       /* enable change of byte order for write port */
+       REG_SET_SLICE(mi_ctrl, MRV_MI_BYTE_SWAP,
+           (mrv_mi_ctrl->byte_swap_enable) ? ON : OFF);
+
+       /* enable or disable the last pixel signalization */
+       REG_SET_SLICE(mi_ctrl, MRV_MI_LAST_PIXEL_SIG_EN,
+           (mrv_mi_ctrl->last_pixel_enable) ? ON : OFF);
+
+       /* now write settings into register */
+       REG_WRITE(mrv_reg->mi_ctrl, mi_ctrl);
+
+       dprintk(2, "mi_ctrl = 0x%x", mi_ctrl);
+
+       /* self picture path operating mode */
+       if ((mrv_mi_ctrl->self_path == CI_ISP_PATH_ON) ||
+           (mrv_mi_ctrl->self_path == CI_ISP_PATH_OFF)) {
+
+               error = ci_isp_mif_set_self_pic_orientation(
+                                   mrv_mi_ctrl->mrv_mif_sp_mode,
+                                   (int) (mrv_mi_ctrl->self_path
+                                          == CI_ISP_PATH_ON));
+       } else {
+               eprintk("bad mrv_mi_ctrl->self_path value");
+               error = CI_STATUS_OUTOFRANGE;
+       }
+
+       REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON);
+
+       return error;
+}
--
1.6.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux