From patchwork Mon May 4 11:00:24 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Zhang, Xiaolin" X-Patchwork-Id: 979 Return-path: Envelope-to: mchehab@infradead.org Delivery-date: Mon, 04 May 2009 11:01:03 +0000 Received: from bombadil.infradead.org [18.85.46.34] by pedra.chehab.org with IMAP (fetchmail-6.3.6) for (single-drop); Mon, 04 May 2009 08:13:31 -0300 (BRT) Received: from vger.kernel.org ([209.132.176.167]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1M0vuv-0004nA-E6; Mon, 04 May 2009 11:01:03 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752375AbZEDLA6 (ORCPT + 1 other); Mon, 4 May 2009 07:00:58 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752264AbZEDLA6 (ORCPT ); Mon, 4 May 2009 07:00:58 -0400 Received: from mga11.intel.com ([192.55.52.93]:46623 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752133AbZEDLAv convert rfc822-to-8bit (ORCPT ); Mon, 4 May 2009 07:00:51 -0400 Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 04 May 2009 03:55:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.40,291,1239001200"; d="scan'208,223";a="453866714" Received: from pgsmsx602.gar.corp.intel.com ([10.221.43.81]) by fmsmga002.fm.intel.com with ESMTP; 04 May 2009 03:55:25 -0700 Received: from pgsmsx601.gar.corp.intel.com (10.221.43.69) by pgsmsx602.gar.corp.intel.com (10.221.43.81) with Microsoft SMTP Server (TLS) id 8.1.340.0; Mon, 4 May 2009 19:00:36 +0800 Received: from pdsmsx602.ccr.corp.intel.com (172.16.12.184) by pgsmsx601.gar.corp.intel.com (10.221.43.69) with Microsoft SMTP Server (TLS) id 8.1.340.0; Mon, 4 May 2009 19:00:34 +0800 Received: from pdsmsx502.ccr.corp.intel.com ([172.16.12.96]) by pdsmsx602.ccr.corp.intel.com ([172.16.12.184]) with mapi; Mon, 4 May 2009 19:00:32 +0800 From: "Zhang, Xiaolin" To: "linux-media@vger.kernel.org" CC: "xlzhang76@gmail.com" Date: Mon, 4 May 2009 19:00:24 +0800 Subject: [PATCH 1/5 - part 2] V4L2 patches for Intel Moorestown Camera Imaging Drivers Thread-Topic: [PATCH 1/5 - part 2] V4L2 patches for Intel Moorestown Camera Imaging Drivers Thread-Index: AcnMl1a1ljdDCFhuRoupv9yLwTYdxAACRtKQAAG9NOA= Message-ID: <0A882F4D99BBF6449D58E61AAFD7EDD613810F55@pdsmsx502.ccr.corp.intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-cr-puzzleid: {22F2CE69-09A2-4848-B7D7-700515D71C53} x-cr-hashedpuzzle: qwY= CH2W C52K HLV3 Haia IpP0 JKbL JRCx Jaz0 KPOz M2c8 RDOR Rvwq SvG7 VleJ WLFg; 2; bABpAG4AdQB4AC0AbQBlAGQAaQBhAEAAdgBnAGUAcgAuAGsAZQByAG4AZQBsAC4AbwByAGcAOwB4AGwAegBoAGEAbgBnADcANgBAAGcAbQBhAGkAbAAuAGMAbwBtAA==; Sosha1_v1; 7; {22F2CE69-09A2-4848-B7D7-700515D71C53}; eABpAGEAbwBsAGkAbgAuAHoAaABhAG4AZwBAAGkAbgB0AGUAbAAuAGMAbwBtAA==; Mon, 04 May 2009 11:00:24 GMT; WwBQAEEAVABDAEgAIAAxAC8ANQAgAC0AIABwAGEAcgB0ACAAMgBdACAAVgA0AEwAMgAgAHAAYQB0AGMAaABlAHMAIABmAG8AcgAgAEkAbgB0AGUAbAAgAE0AbwBvAHIAZQBzAHQAbwB3AG4AIABDAGEAbQBlAHIAYQAgAEkAbQBhAGcAaQBuAGcAIABEAHIAaQB2AGUAcgBzAA== acceptlanguage: en-US MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From c9523cb1e81f6229c47c244896fd5772a7e9e702 Mon Sep 17 00:00:00 2001 From: Xiaolin Zhang Date: Mon, 4 May 2009 16:54:56 +0800 Subject: [PATCH] [Part 2] c files - camera imaging ISP driver on Intel Moorestown platform under v4l2 driver framework. Signed-off-by: Xiaolin Zhang --- drivers/media/video/mrstci/include/ci_isp_common.h | 58 +- drivers/media/video/mrstci/mrstisp/Makefile | 9 + drivers/media/video/mrstci/mrstisp/intel_v4l2.c | 1965 ++++++++++++++++++++ drivers/media/video/mrstci/mrstisp/mrv.c | 442 +++++ drivers/media/video/mrstci/mrstisp/mrv_col.c | 66 + drivers/media/video/mrstci/mrstisp/mrv_ie.c | 237 +++ drivers/media/video/mrstci/mrstisp/mrv_is.c | 66 + drivers/media/video/mrstci/mrstisp/mrv_isp.c | 1433 ++++++++++++++ drivers/media/video/mrstci/mrstisp/mrv_isp_bls.c | 174 ++ drivers/media/video/mrstci/mrstisp/mrv_isp_gamma.c | 87 + drivers/media/video/mrstci/mrstisp/mrv_jpe.c | 447 +++++ drivers/media/video/mrstci/mrstisp/mrv_mif.c | 677 +++++++ drivers/media/video/mrstci/mrstisp/mrv_res.c | 350 ++++ drivers/media/video/mrstci/mrstisp/mrv_sls_bp.c | 83 + drivers/media/video/mrstci/mrstisp/mrv_sls_dp.c | 1146 ++++++++++++ drivers/media/video/mrstci/mrstisp/mrv_sls_jpe.c | 53 + 16 files changed, 7237 insertions(+), 56 deletions(-) mode change 100755 => 100644 drivers/media/video/mrstci/mrstisp/Kconfig create mode 100644 drivers/media/video/mrstci/mrstisp/Makefile create mode 100644 drivers/media/video/mrstci/mrstisp/intel_v4l2.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_col.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_ie.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_is.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_isp.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_isp_bls.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_isp_gamma.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_jpe.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_mif.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_res.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_sls_bp.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_sls_dp.c create mode 100644 drivers/media/video/mrstci/mrstisp/mrv_sls_jpe.c -- 1.5.5 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/media/video/mrstci/include/ci_isp_common.h b/drivers/media/video/mrstci/include/ci_isp_common.h index 090021d..121100b 100644 --- a/drivers/media/video/mrstci/include/ci_isp_common.h +++ b/drivers/media/video/mrstci/include/ci_isp_common.h @@ -63,10 +63,6 @@ /* JPEG encoding */ enum ci_isp_jpe_enc_mode { -#if (MARVIN_FEATURE_JPE_CFG == MARVIN_FEATURE_JPE_CFG_V2) - /*single snapshot with Scalado encoding*/ - CI_ISP_JPE_SCALADO_MODE = 0x08, -#endif /* motion JPEG with header generation */ CI_ISP_JPE_LARGE_CONT_MODE = 0x04, /* motion JPEG only first frame with header */ @@ -106,14 +102,9 @@ struct ci_isp_rsz_lut{ u8 rsz_lut[64]; }; -#if (MARVIN_FEATURE_SCALE_FACTORWIDTH == MARVIN_FEATURE_16BITS) -/* flag to set in scalefactor values to enable upscaling */ -#define RSZ_UPSCALE_ENABLE 0x20000 -#else /* flag to set in scalefactor values to enable upscaling */ #define RSZ_UPSCALE_ENABLE 0x8000 -/* #if (MARVIN_FEATURE_SCALE_FACTORWIDTH == MARVIN_FEATURE_16BITS) */ -#endif + /* * Flag to set in scalefactor values to bypass the scaler block. @@ -122,13 +113,8 @@ struct ci_isp_rsz_lut{ * words: * RSZ_SCALER_BYPASS = max. scalefactor value> + 1 */ -#if (MARVIN_FEATURE_SCALE_FACTORWIDTH == MARVIN_FEATURE_12BITS) -#define RSZ_SCALER_BYPASS 0x1000 -#elif (MARVIN_FEATURE_SCALE_FACTORWIDTH == MARVIN_FEATURE_14BITS) #define RSZ_SCALER_BYPASS 0x4000 -#elif (MARVIN_FEATURE_SCALE_FACTORWIDTH == MARVIN_FEATURE_16BITS) -#define RSZ_SCALER_BYPASS 0x10000 -#endif + #define RSZ_FLAGS_MASK (RSZ_UPSCALE_ENABLE | RSZ_SCALER_BYPASS) @@ -1124,46 +1110,6 @@ struct ci_isp_cac_config { }; -/* - * register values of chromatic aberration correction block (delivered by - * the CAC driver) - */ -struct ci_isp_cac_reg_values { - /* maximum red/blue pixel shift in horizontal */ - u8 hclip_mode; - /* and vertival direction, range 0..2 */ - u8 vclip_mode; - /* TRUE=enabled, FALSE=disabled */ - int cac_enabled; - /* - * preload value of the horizontal CAC pixel - * counter, range 1..4095 - */ - u16 hcount_start; - /* - * preload value of the vertical CAC pixel - * counter, range 1..4095 - */ - u16 vcount_start; - /* parameters for radial shift calculation, */ - u16 ablue; - /* 9 bit twos complement with 4 fractional */ - u16 ared; - /* digits, valid range -16..15.9375 */ - u16 bblue; - u16 bred; - u16 cblue; - u16 cred; - /* horizontal normalization shift, range 0..7 */ - u8 xnorm_shift; - /* horizontal normalization factor, range 16..31 */ - u8 xnorm_factor; - /* vertical normalization shift, range 0..7 */ - u8 ynorm_shift; - /* vertical normalization factor, range 16..31 */ - u8 ynorm_factor; -}; - struct ci_snapshot_config { /* snapshot flags */ u32 flags; diff --git a/drivers/media/video/mrstci/mrstisp/Kconfig b/drivers/media/video/mrstci/mrstisp/Kconfig old mode 100755 new mode 100644 diff --git a/drivers/media/video/mrstci/mrstisp/Makefile b/drivers/media/video/mrstci/mrstisp/Makefile new file mode 100644 index 0000000..663e2ba --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/Makefile @@ -0,0 +1,9 @@ +mrstisp-objs := mrv_is.o mrv_ie.o mrv_jpe.o \ + mrv_isp.o mrv_sls_bp.o mrv_mif.o \ + mrv_sls_dp.o mrv_isp_bls.o mrv_isp_gamma.o \ + mrv_sls_jpe.o mrv.o mrv_isp.o \ + mrv_col.o mrv_is.o mrv_res.o intel_v4l2.o + +obj-$(CONFIG_VIDEO_MRST_ISP) += mrstisp.o + +EXTRA_CFLAGS += -I$(src)/../include -I$(src)/include \ No newline at end of file diff --git a/drivers/media/video/mrstci/mrstisp/intel_v4l2.c b/drivers/media/video/mrstci/mrstisp/intel_v4l2.c new file mode 100644 index 0000000..041da05 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/intel_v4l2.c @@ -0,0 +1,1965 @@ +/* + * Support for Moorestown Langwell Camera Imaging ISP subsystem. + * + * Copyright (c) 2009 Intel Corporation. All Rights Reserved. + * + * 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 + */ + +#include +#include "stdinc.h" +#include "ci_isp_fmts_common.h" +#include +#include + +static int video_nr = -1; +int km_debug; + +static int pci_driver_loaded; +static struct intel_isp_device intel_isp_v4l_device; +struct intel_isp_device *g_intel; + +/* !initialized struct to hold the specific configuration */ +static struct ci_sensor_config isi_config; +static struct ci_sensor_caps isi_caps; + +static struct ci_isp_config s_config; + +struct ci_isp_dbg_status { + u32 isp_imsc; + u32 mi_imsc; + u32 jpe_error_imsc; + u32 jpe_status_imsc; +}; + +/* g45-th20-b5 gamma out curve with enhanced black level */ +static struct ci_isp_gamma_out_curve g45_th20_b5 = { + { + 0x0000, 0x0014, 0x003C, 0x0064, + 0x00A0, 0x0118, 0x0171, 0x01A7, + 0x01D8, 0x0230, 0x027A, 0x02BB, + 0x0323, 0x0371, 0x03AD, 0x03DB, + 0x03FF} + , + 0 +}; + +static unsigned long jiffies_start; +void intel_timer_start(void) +{ + jiffies_start = jiffies; + +} +void intel_timer_stop(void) +{ + jiffies_start = 0; +} +unsigned long intel_get_micro_sec(void) +{ + unsigned long time_diff = 0; + + time_diff = jiffies - jiffies_start; + + return jiffies_to_msecs(time_diff); + + +} +void intel_sleep_micro_sec(unsigned long micro_sec) +{ + mdelay(micro_sec); +} + +void intel_dbg_dd_out(u32 category, const char *pszFormat, ...) +{ + va_list arglist; + va_start(arglist, pszFormat); + + if (km_debug >= 1) { + printk(KERN_INFO "intel_v4l: "); + printk(pszFormat, arglist); + } + va_end(arglist); +} + +static int intel_mrvisp_set_colorconversion_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; + +} + +static unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE - 1); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static int intel_defcfg_all_load(struct ci_isp_config *isp_config, + struct ci_sensor_config *isi_config) +{ + + if (isp_config == NULL) { + DBG_DD(("isp_config is null\n")); + return CI_STATUS_NULL_POINTER; + } + + if (isi_config == NULL) { + DBG_DD(("isi_config is null\n")); + return CI_STATUS_NULL_POINTER; + } + isp_config->demosaic_mode = CI_ISP_DEMOSAIC_ENHANCED; + /* bpc */ + isp_config->bpc_cfg.bp_corr_type = CI_ISP_BP_CORR_DIRECT; + isp_config->bpc_cfg.bp_corr_rep = CI_ISP_BP_CORR_REP_NB; + isp_config->bpc_cfg.bp_corr_mode = CI_ISP_BP_CORR_HOT_DEAD_EN; + isp_config->bpc_cfg.bp_abs_hot_thres = 496; + isp_config->bpc_cfg.bp_abs_dead_thres = 20; + isp_config->bpc_cfg.bp_dev_hot_thres = 328; + isp_config->bpc_cfg.bp_dev_dead_thres = 328; + isp_config->bpd_cfg.bp_dead_thres = 1; + + /* WB */ + isp_config->wb_config.mrv_wb_mode = CI_ISP_AWB_AUTO; + isp_config->wb_config.mrv_wb_sub_mode = CI_ISP_AWB_AUTO_ON; + isp_config->wb_config.awb_pca_damping = 16; + isp_config->wb_config.awb_prior_exp_damping = 12; + isp_config->wb_config.awb_pca_push_damping = 16; + isp_config->wb_config.awb_prior_exp_push_damping = 12; + isp_config->wb_config.awb_auto_max_y = 254; + isp_config->wb_config.awb_push_max_y = 250; + isp_config->wb_config.awb_measure_max_y = 200; + isp_config->wb_config.awb_underexp_det = 10; + isp_config->wb_config.awb_push_underexp_det = 170; + + /* CAC */ + isp_config->cac_config.hsize = 2048; + isp_config->cac_config.vsize = 1536; + isp_config->cac_config.hcenter_offset = 0; + isp_config->cac_config.vcenter_offset = 0; + isp_config->cac_config.hclip_mode = 1; + isp_config->cac_config.vclip_mode = 2; + isp_config->cac_config.ablue = 24; + isp_config->cac_config.ared = 489; + isp_config->cac_config.bblue = 450; + isp_config->cac_config.bred = 53; + isp_config->cac_config.cblue = 40; + isp_config->cac_config.cred = 479; + isp_config->cac_config.aspect_ratio = 0.000000; + + /* BLS */ + isp_config->bls_cfg.enable_automatic = 0; + isp_config->bls_cfg.disable_h = 0; + isp_config->bls_cfg.disable_v = 0; + isp_config->bls_cfg.isp_bls_window1.enable_window = 0; + isp_config->bls_cfg.isp_bls_window1.start_h = 0; + isp_config->bls_cfg.isp_bls_window1.stop_h = 0; + isp_config->bls_cfg.isp_bls_window1.start_v = 0; + isp_config->bls_cfg.isp_bls_window1.stop_v = 0; + isp_config->bls_cfg.isp_bls_window2.enable_window = 0; + isp_config->bls_cfg.isp_bls_window2.start_h = 0; + isp_config->bls_cfg.isp_bls_window2.stop_h = 0; + isp_config->bls_cfg.isp_bls_window2.start_v = 0; + isp_config->bls_cfg.isp_bls_window2.stop_v = 0; + isp_config->bls_cfg.bls_samples = 5; + isp_config->bls_cfg.bls_subtraction.fixed_a = 0x100; + isp_config->bls_cfg.bls_subtraction.fixed_b = 0x100; + isp_config->bls_cfg.bls_subtraction.fixed_c = 0x100; + isp_config->bls_cfg.bls_subtraction.fixed_d = 0x100; + + /* AF */ + isp_config->af_cfg.wnd_pos_a.hoffs = 874; + isp_config->af_cfg.wnd_pos_a.voffs = 618; + isp_config->af_cfg.wnd_pos_a.hsize = 300; + isp_config->af_cfg.wnd_pos_a.vsize = 300; + + /* color */ + isp_config->color.contrast = 128; + isp_config->color.brightness = 0; + isp_config->color.saturation = 128; + isp_config->color.hue = 0; + + /* Img Effect */ + isp_config->img_eff_cfg.mode = CI_ISP_IE_MODE_OFF; + isp_config->img_eff_cfg.color_sel = 4; + isp_config->img_eff_cfg.color_thres = 128; + isp_config->img_eff_cfg.tint_cb = 108; + isp_config->img_eff_cfg.tint_cr = 141; + isp_config->img_eff_cfg.mat_emboss.coeff_11 = 2; + isp_config->img_eff_cfg.mat_emboss.coeff_12 = 1; + isp_config->img_eff_cfg.mat_emboss.coeff_13 = 0; + isp_config->img_eff_cfg.mat_emboss.coeff_21 = 1; + isp_config->img_eff_cfg.mat_emboss.coeff_22 = 0; + isp_config->img_eff_cfg.mat_emboss.coeff_23 = -1; + isp_config->img_eff_cfg.mat_emboss.coeff_31 = 0; + isp_config->img_eff_cfg.mat_emboss.coeff_32 = -1; + isp_config->img_eff_cfg.mat_emboss.coeff_33 = -2; + + isp_config->img_eff_cfg.mat_sketch.coeff_11 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_12 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_13 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_21 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_22 = 8; + isp_config->img_eff_cfg.mat_sketch.coeff_23 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_31 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_32 = -1; + isp_config->img_eff_cfg.mat_sketch.coeff_33 = -1; + + /* Framefun */ + isp_config->flags.bls = 0; + isp_config->flags.bls_man = 0; + isp_config->flags.bls_smia = 0; + isp_config->flags.blsprint = 0; + isp_config->flags.bls_dis = 0; + isp_config->flags.lsc = 0; + isp_config->flags.lscprint = 0; + isp_config->flags.lsc_dis = 0; + isp_config->flags.bpc = 0; + isp_config->flags.bpcprint = 0; + isp_config->flags.bpc_dis = 0; + isp_config->flags.awb = 0; + isp_config->flags.awbprint = 0; + isp_config->flags.awbprint2 = 0; + isp_config->flags.awb_dis = 1; + isp_config->flags.aec = 0; + isp_config->flags.aecprint = 0; + isp_config->flags.aec_dis = 0; + isp_config->flags.af = 0; + isp_config->flags.afprint = 0; + isp_config->flags.af_dis = 0; + isp_config->flags.cp = 0; + isp_config->flags.gamma = 0; + isp_config->flags.cconv = 0; + isp_config->flags.demosaic = 0; + isp_config->flags.gamma2 = 0; + isp_config->flags.isp_filters = 0; + isp_config->flags.cac = 0; + isp_config->flags.cp_sat_loop = 0; + isp_config->flags.cp_contr_loop = 0; + isp_config->flags.cp_bright_loop = 0; + isp_config->flags.scaler_loop = 0; + isp_config->flags.cconv_basic = 0; + isp_config->flags.continous_af = 0; + isp_config->flags.bad_pixel_generation = 0; + isp_config->demosaic_th = 4; + isp_config->exposure = 80; + isp_config->advanced_aec_mode = 0; + isp_config->report_details = 0xffffffff; + + /* flags = 0x00024010*/ + isp_config->view_finder.flags = VFFLAG_HWRGB; + isp_config->view_finder.zoom = 0; + isp_config->view_finder.lcd_contrast = 77; + isp_config->view_finder.x = 0; + isp_config->view_finder.y = 0; + isp_config->view_finder.w = 100; + isp_config->view_finder.h = 75; + isp_config->view_finder.keep_aspect = 1; + + isp_config->snapshot_a.flags = 0x00010000; + isp_config->snapshot_a.user_zoom = 0; + isp_config->snapshot_a.user_w = 640; + isp_config->snapshot_a.user_h = 480; + isp_config->snapshot_a.compression_ratio = 1; + + isp_config->afm_mode = 1; + isp_config->afss_mode = 3; + isp_config->filter_level_noise_reduc = 4; + isp_config->filter_level_sharp = 4; + + isp_config->snapshot_b.flags = 0x00000007; + isp_config->snapshot_b.user_zoom = 0; + isp_config->snapshot_b.user_w = 640; + isp_config->snapshot_b.user_h = 480; + isp_config->snapshot_b.compression_ratio = 1; + return 0; +} + +static void intel_update_marvinvfaddr(struct intel_isp_device *intel) +{ + struct ci_isp_mi_path_conf isp_mi_path_conf; + u32 bufsize = 0; + u32 w; + u32 h; + u32 offset = 0; + + memset(&isp_mi_path_conf, 0, sizeof(struct ci_isp_mi_path_conf)); + + w = isp_mi_path_conf.llength = intel->bufwidth; + h = isp_mi_path_conf.ypic_height = intel->bufheight; + isp_mi_path_conf.ypic_width = intel->bufwidth; + + if (intel->pixelformat == V4L2_PIX_FMT_YUV420 || + intel->pixelformat == V4L2_PIX_FMT_YVU420 || + intel->pixelformat == V4L2_PIX_FMT_YUV422P || + intel->pixelformat == V4L2_PIX_FMT_NV12) { + bufsize = w*h; + } else + bufsize = intel->frame_size; + offset = intel->cap_frame * PAGE_ALIGN(intel->frame_size); + intel->capbuf = intel->mb1_va + offset; + intel->capbuf_pa = intel->mb1 + offset; + DBG_DD(("UpdateMarvinAddr:\n")); + DBG_DD(("buf w:%d, h:%d, cap id=%d, Fsize:%d, Bsize: %d\n", + w, h, intel->cap_frame, intel->frame_size, bufsize)); + DBG_DD(("cap buf va 0x%p, pa 0x%x\n", intel->capbuf, intel->capbuf_pa)); + + /* buffer size in bytes */ + if (intel->pixelformat == V4L2_PIX_FMT_YUV420 || + intel->pixelformat == V4L2_PIX_FMT_YVU420) { + DBG_DD(("yuv420 fmt\n")); + isp_mi_path_conf.ybuffer.size = bufsize; + isp_mi_path_conf.cb_buffer.size = bufsize/4; + isp_mi_path_conf.cr_buffer.size = bufsize/4; + } else if (intel->pixelformat == V4L2_PIX_FMT_YUV422P) { + DBG_DD(("yuv422 fmt\n")); + isp_mi_path_conf.ybuffer.size = bufsize; + isp_mi_path_conf.cb_buffer.size = bufsize/2; + isp_mi_path_conf.cr_buffer.size = bufsize/2; + } else if (intel->pixelformat == V4L2_PIX_FMT_NV12) { + DBG_DD(("nv12 fmt\n")); + isp_mi_path_conf.ybuffer.size = bufsize; + isp_mi_path_conf.cb_buffer.size = bufsize/2; + isp_mi_path_conf.cr_buffer.size = 0; + } else { + /* JPEG fmt and RGB and Bayer pattern fmt */ + DBG_DD(("jpeg and rgb fmt\n")); + isp_mi_path_conf.ybuffer.size = bufsize; + isp_mi_path_conf.cb_buffer.size = 0; + isp_mi_path_conf.cr_buffer.size = 0; + } + + if (isp_mi_path_conf.ybuffer.size != 0) { + /* buffer start address */ + isp_mi_path_conf.ybuffer.pucbuffer = (u8 *)(unsigned long) + intel->capbuf_pa; + } + + if (isp_mi_path_conf.cb_buffer.size != 0) { + /* buffer start address */ + isp_mi_path_conf.cb_buffer.pucbuffer = + isp_mi_path_conf.ybuffer.pucbuffer + + isp_mi_path_conf.ybuffer.size; + } + + if (isp_mi_path_conf.cr_buffer.size != 0) { + isp_mi_path_conf.cr_buffer.pucbuffer = + isp_mi_path_conf.cb_buffer.pucbuffer + + isp_mi_path_conf.cb_buffer.size; + } + if (intel->pixelformat == V4L2_PIX_FMT_YVU420) { + isp_mi_path_conf.cr_buffer.pucbuffer = + isp_mi_path_conf.ybuffer.pucbuffer + + isp_mi_path_conf.ybuffer.size; + isp_mi_path_conf.cb_buffer.pucbuffer = + isp_mi_path_conf.cr_buffer.pucbuffer + + isp_mi_path_conf.cr_buffer.size; + } + if (intel->sys_conf.isp_cfg->view_finder.flags & + VFFLAG_USE_MAINPATH) { + ci_isp_mif__set_main_buffer(&isp_mi_path_conf, + CI_ISP_CFG_UPDATE_FRAME_SYNC); + } else { + ci_isp_mif__set_self_buffer(&isp_mi_path_conf, + CI_ISP_CFG_UPDATE_FRAME_SYNC); + } +} + +static void init_frame_queue(struct fifo *queue) +{ + int i; + for (i = 0; i < INTEL_CAPTURE_BUFFERS; i++) { + queue->data[i] = -1; + queue->info[i].state = S_UNUSED; + queue->info[i].flags = 0; + } + queue->front = 0; + queue->back = 0; +} + +static void add_frame_to_queue(struct fifo *queue, int frame) +{ + queue->data[queue->back] = frame; + queue->back = (queue->back + 1) % (INTEL_CAPTURE_BUFFERS + 1); +} + +static int frame_queue_empty(struct fifo *queue) +{ + return queue->front == queue->back; +} + +static int remove_frame_from_queue(struct fifo *queue) +{ + int frame; + + if (frame_queue_empty(queue)) + return -1; + + frame = queue->data[queue->front]; + queue->front = (queue->front + 1) % (INTEL_CAPTURE_BUFFERS + 1); + return frame; +} + +static int intel_setup_viewfinder_path( + struct intel_isp_device *intel, + int zoom) +{ + int error = CI_STATUS_SUCCESS; + struct ci_isp_datapath_desc DpMain; + struct ci_isp_datapath_desc DpSelf; + struct ci_isp_rect self_rect; + u16 isi_hsize; + u16 isi_vsize; + u32 dp_mode; + int jpe_scale; + struct ci_pl_system_config *sys_conf = &intel->sys_conf; + struct ci_isp_config *config = sys_conf->isp_cfg; + + if (sys_conf->isp_cfg->flags.fYCbCrFullRange) + jpe_scale = false; + else + jpe_scale = true; + + memset(&DpMain, 0, sizeof(struct ci_isp_datapath_desc)); + memset(&DpSelf, 0, sizeof(struct ci_isp_datapath_desc)); + + DBG_DD(("view_finder.flags = %x\n", config->view_finder.flags)); + + self_rect.x = 0; + self_rect.y = 0; + self_rect.w = intel->bufwidth; /* 640 */ + self_rect.h = intel->bufheight; /* 480 */ + + if (intel->pixelformat == V4L2_PIX_FMT_JPEG) { + DBG_DD(("jpeg fmt\n")); + DpMain.flags = CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPJPEG; + config->view_finder.flags |= VFFLAG_USE_MAINPATH; + DpMain.out_w = (u16) intel->bufwidth; + DpMain.out_h = (u16) intel->bufheight; + } else if (intel->pixelformat == INTEL_PIX_FMT_RAW08) { + DpMain.flags = CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPRAW; + config->view_finder.flags |= VFFLAG_USE_MAINPATH; + /*just take the output of the sensor without any resizing*/ + DpMain.flags |= CI_ISP_DPD_NORESIZE; + (void)ci_sensor_res2size(sys_conf->isi_config->res, + &(DpMain.out_w), &(DpMain.out_h)); + } else if (intel->pixelformat == INTEL_PIX_FMT_RAW10 || + intel->pixelformat == INTEL_PIX_FMT_RAW12) { + DpMain.flags = (CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPRAW_16B); + config->view_finder.flags |= VFFLAG_USE_MAINPATH; + /*just take the output of the sensor without any resizing*/ + DpMain.flags |= CI_ISP_DPD_NORESIZE; + (void)ci_sensor_res2size(sys_conf->isi_config->res, + &(DpMain.out_w), &(DpMain.out_h)); + } else if (intel->bufwidth > 640 && intel->bufheight >= 480) { + DpMain.flags = (CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPYC); + DpMain.out_w = (u16) intel->bufwidth; + DpMain.out_h = (u16) intel->bufheight; + config->view_finder.flags |= VFFLAG_USE_MAINPATH; + if (intel->pixelformat == V4L2_PIX_FMT_YUV420 || + intel->pixelformat == V4L2_PIX_FMT_YVU420) + DpMain.flags |= CI_ISP_DPD_YUV_420 | CI_ISP_DPD_CSS_V2; + else if (intel->pixelformat == V4L2_PIX_FMT_YUV422P) + DpMain.flags |= CI_ISP_DPD_YUV_422; + else if (intel->pixelformat == V4L2_PIX_FMT_NV12) + DpMain.flags |= CI_ISP_DPD_YUV_NV12 | CI_ISP_DPD_CSS_V2; + else if (intel->pixelformat == V4L2_PIX_FMT_YUYV) + DpMain.flags |= CI_ISP_DPD_YUV_YUYV; + else + DBG_DD(("dpMain.flags is 0x%x\n", DpMain.flags)); + } else if (intel->bufwidth <= 640 && intel->bufheight <= 480) { + DpSelf.flags = (CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPYC); + if (intel->pixelformat == V4L2_PIX_FMT_YUV420 || + intel->pixelformat == V4L2_PIX_FMT_YVU420) + DpSelf.flags |= CI_ISP_DPD_YUV_420 | CI_ISP_DPD_CSS_V2; + else if (intel->pixelformat == V4L2_PIX_FMT_YUV422P) + DpSelf.flags |= CI_ISP_DPD_YUV_422; + else if (intel->pixelformat == V4L2_PIX_FMT_NV12) + DpSelf.flags |= CI_ISP_DPD_YUV_NV12 | CI_ISP_DPD_CSS_V2; + else if (intel->pixelformat == V4L2_PIX_FMT_YUYV) + DpSelf.flags |= CI_ISP_DPD_YUV_YUYV; + else if (intel->pixelformat == V4L2_PIX_FMT_RGB565) + DpSelf.flags |= CI_ISP_DPD_HWRGB_565; + else if (intel->pixelformat == V4L2_PIX_FMT_BGR32) + DpSelf.flags |= CI_ISP_DPD_HWRGB_888; + else + DBG_DD(("DpSelf.flags is 0x%x\n", DpSelf.flags)); + } + DBG_DD(("sensor_res = %x\n", sys_conf->isi_config->res)); + (void)ci_sensor_res2size(sys_conf->isi_config->res, &isi_hsize, + &isi_vsize); + + DBG_DD(("self path: w:%d, h:%d; sensor: w:%d, h:%d\n", + self_rect.w, self_rect.h, isi_hsize, isi_vsize)); + DBG_DD(("main path: out_w:%d, out_h:%d \n", + DpMain.out_w, DpMain.out_h)); + + DpSelf.out_w = (u16) self_rect.w; + DpSelf.out_h = (u16) self_rect.h; + + if (sys_conf->isp_cfg->view_finder.flags & VFFLAG_HWRGB) { + if (intel->pixelformat == V4L2_PIX_FMT_RGB565) + DpSelf.flags |= CI_ISP_DPD_HWRGB_565; + if (intel->pixelformat == V4L2_PIX_FMT_BGR32) + DpSelf.flags |= CI_ISP_DPD_HWRGB_888; + + } else { + DBG_DD(("don't use the HWRGB conversion\n")); + + } + + if (sys_conf->isp_cfg->view_finder.flags & VFFLAG_MIRROR) + DpSelf.flags |= CI_ISP_DPD_H_FLIP; + + if (sys_conf->isp_cfg->view_finder.flags & VFFLAG_V_FLIP) + DpSelf.flags |= CI_ISP_DPD_V_FLIP; + + if (sys_conf->isp_cfg->view_finder.flags & VFFLAG_ROT90_CCW) + DpSelf.flags |= CI_ISP_DPD_90DEG_CCW; + + if (!sys_conf->isp_cfg->flags.af_dis && + (sys_conf->isp_cfg->afm_mode != CI_ISP_AFM_HW)) { + if (sys_conf->isp_cfg->view_finder. + flags & VFFLAG_USE_MAINPATH) { + DBG_DD(("ERR: main path configured to do both" + "viewfinding and software AF mesurement\n")); + return CI_STATUS_NOTSUPP; + } + + DpMain.flags |= CI_ISP_DPD_ENABLE; + } + /* setup self & main path with zoom */ + if (zoom < 0) + zoom = sys_conf->isp_cfg->view_finder.zoom; + if (sys_conf->isp_cfg->view_finder.flags & VFFLAG_USE_MAINPATH) { + DBG_DD(("view finder in mail path\n")); + dp_mode = DpMain.flags & CI_ISP_DPD_MODE_MASK; + if ((dp_mode == CI_ISP_DPD_MODE_ISPRAW) || + (dp_mode == CI_ISP_DPD_MODE_ISPRAW_16B)) { + struct ci_sensor_config isi_conf; + isi_conf = *sys_conf->isi_config; + isi_conf.mode = SENSOR_MODE_PICT; + error = ci_isp_set_input_aquisition(&isi_conf); + if (error != CI_STATUS_SUCCESS) { + DBG_OUT((DERR, "ERR: ci_do_snapshot: failed" + "to re-init ISP input aquisition\n")); + } + } + error = ci_datapath_isp(sys_conf, &DpMain, + NULL, zoom); + + } else { + DBG_DD(("view finder in selfpath\n")); + error = + ci_datapath_isp(sys_conf, &DpMain, + &DpSelf, zoom); + } + + if (error != CI_STATUS_SUCCESS) { + DBG_DD((" ERR: failed to setup marvins datapaths\n")); + return error; + } + + intel_update_marvinvfaddr(intel); + return error; +} + +static int intel_init_mrv_image_effects( + const struct ci_pl_system_config *sys_conf, + int enable) +{ + int res; + if ((enable) && + (sys_conf->isp_cfg->img_eff_cfg.mode != CI_ISP_IE_MODE_OFF)) { + res = ci_isp_ie_set_config(&(sys_conf->isp_cfg->img_eff_cfg)); + if (res != CI_STATUS_SUCCESS) { + DBG_OUT((DWARN, "WARN: failed to configure image " + "effects, code(%d)", res)); + } + } else { + (void)ci_isp_ie_set_config(NULL); + res = CI_STATUS_SUCCESS; + } + return res; +} + +static int intel_init_mrvisp_lensshade( + const struct ci_pl_system_config *sys_conf, + int enable) +{ + if ((enable) && (sys_conf->isp_cfg->flags.lsc)) { + ci_isp_set_ls_correction(&(sys_conf->isp_cfg->lsc_cfg)); + ci_isp_ls_correction_on_off(true); + } else + (void)ci_isp_ls_correction_on_off(false); + + return CI_STATUS_SUCCESS; +} + +static int intel_init_mrvisp_badpixel( + const struct ci_pl_system_config *sys_conf, + int enable) +{ + if ((enable) && (sys_conf->isp_cfg->flags.bpc)) { + (void)ci_bp_init(&sys_conf->isp_cfg->bpc_cfg, + &sys_conf->isp_cfg->bpd_cfg); + } else { + (void)ci_bp_end(&sys_conf->isp_cfg->bpc_cfg); + (void)ci_isp_set_bp_correction(NULL); + (void)ci_isp_set_bp_detection(NULL); + } + return CI_STATUS_SUCCESS; +} + +static int intel_init_mrv_ispfilter(const struct ci_pl_system_config *sys_conf, + int enable) +{ + int res; + if ((enable) && (sys_conf->isp_cfg->flags.isp_filters)) { + (void)ci_isp_activate_filter(true); + res = + ci_isp_set_filter_params(sys_conf->isp_cfg-> + filter_level_noise_reduc, + sys_conf->isp_cfg-> + filter_level_sharp); + if (res != CI_STATUS_SUCCESS) { + DBG_OUT((DWARN, "WARN: failed to configure isp " + "filter, code(%d)", res)); + } + } else { + (void)ci_isp_activate_filter(false); + res = CI_STATUS_SUCCESS; + } + return res; +} + +static int intel_initbls(const struct ci_pl_system_config *sys_conf) +{ + struct ci_isp_bls_config *bls_config = + (struct ci_isp_bls_config *)&sys_conf->isp_cfg->bls_cfg; + return ci_isp_bls_set_config(bls_config); +} + + +static void intel_dpinitisi(struct ci_sensor_config *isi_config, + struct ci_sensor_caps *isi_caps) +{ + int error = CI_STATUS_SUCCESS; + DBG_DD(("intel_dpinitisi\n")); + ci_sensor_get_caps(isi_caps); + ci_sensor_get_config(isi_config); + + if (error != CI_STATUS_SUCCESS) { + DBG_DD(("IsiGetSelectedSensorDefaultConfig() failed.\n")); + /* unable to get the default configuration */ + ASSERT(false); + } +} + +static void intel_enable_interrupt(void) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + u32 bit_mask = 0x00000001; + REG_SET_SLICE(mrv_reg->isp_imsc, MRV_ISP_IMSC_ALL, ON); + REG_WRITE(mrv_reg->mi_imsc, bit_mask); + 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); + ci_isp_reset_interrupt_status(); +} + +static int intel_dpinitmrv(const struct ci_pl_system_config *sys_conf) +{ + int error; + u8 words_per_pixel; + struct ci_isp_config *ptcfg; + ptcfg = sys_conf->isp_cfg; + DBG_DD(("entering intel_dpinitmrv\n")); + + ci_isp_init(); + intel_enable_interrupt(); + + /* setup input acquisition according to image sensor settings */ + error = ci_isp_set_input_aquisition(sys_conf->isi_config); + if (error) { + DBG_DD(("ERR: () failed to configure input aquisition," + "code(%d)\n", error)); + return error; + } + + /* setup functional blocks for Bayer pattern processing */ + if (ci_isp_select_path(sys_conf->isi_config, &words_per_pixel) == + CI_ISP_PATH_BAYER) { + if (sys_conf->isp_cfg->flags.bls_dis) { + ci_isp_bls_set_config(NULL); + } else { + error = intel_initbls(sys_conf); + if (error != CI_STATUS_SUCCESS) + return error; + } + DBG_DD(("finished ci_isp_bls_set_config\n")); + + if (sys_conf->isp_cfg->flags.gamma2) + ci_isp_set_gamma2(&g45_th20_b5); + else + ci_isp_set_gamma2(NULL); + + DBG_DD(("finished ci_isp_set_gamma2\n")); + + ci_isp_set_demosaic(sys_conf->isp_cfg->demosaic_mode, + sys_conf->isp_cfg->demosaic_th); + DBG_DD(("finished ci_isp_set_demosaic\n")); + + if (sys_conf->isp_cfg->flags.cconv) { + if (sys_conf->isp_cfg->flags.cconv_basic) { + if (error != CI_STATUS_SUCCESS) + return error; + } else { + intel_mrvisp_set_colorconversion_ex(); + + if (error != CI_STATUS_SUCCESS) + return error; + } + } + + if (sys_conf->isp_cfg->flags.af_dis) + (void)ci_isp_set_auto_focus(NULL); + else + (void)ci_isp_set_auto_focus(&sys_conf->isp_cfg->af_cfg); + intel_init_mrv_ispfilter(sys_conf, true); + } + + ci_isp_col_set_color_processing(NULL); + intel_init_mrv_image_effects(sys_conf, true); + (void)intel_init_mrvisp_lensshade(sys_conf, true); + (void)intel_init_mrvisp_badpixel(sys_conf, true); + return CI_STATUS_SUCCESS; +} + +/* ------------------------- V4L2 interface --------------------- */ +static int intel_open(struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + DBG_DD(("intel_open\n")); + + if (!intel) { + DBG_DD(("Internal error, camera_data not found!\n")); + return -ENODEV; + } + + if (intel->open) { + ++intel->open; + DBG_DD(("device has opened already - %d\n", intel->open)); + return 0; + } + + file->private_data = dev; + /* increment our usage count for the driver */ + ++intel->open; + DBG_DD(("intel_open is %d\n", intel->open)); + + memset(&intel->sys_conf, 0, sizeof(struct ci_pl_system_config)); + memset(&isi_config, 0, sizeof(isi_config)); + memset(&isi_caps, 0, sizeof(isi_caps)); + memset(&s_config, 0, sizeof(s_config)); + + intel->sys_conf.isi_config = &isi_config; + intel->sys_conf.isi_caps = &isi_caps; + intel->sys_conf.isp_cfg = &s_config; + s_config.jpeg_enc_ratio = 1; + + intel->frame_size_used = 0; + + /* default buf size and type*/ + intel->bufwidth = 0; + intel->bufheight = 0; + intel->depth = 0; + intel->pixelformat = 0; + return 0; +} + +static int intel_close(struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + DBG_DD(("intel_close,release resources\n")); + + --intel->open; + if (intel->open) { + DBG_DD(("not the last close %d\n", intel->open)); + return 0; + } + + if (!intel->sys_conf.isp_hal_enable) + ci_sensor_stop(); + + intel->fbuffer = NULL; + intel->capbuf = NULL; + return 0; +} + +static ssize_t intel_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return 0; + +} + +static void intel_vma_open(struct vm_area_struct *vma) +{ + struct video_device *dev = vma->vm_private_data; + struct intel_isp_device *intel = video_get_drvdata(dev); + DBG_DD(("intel_vma_open %d\n", intel->vmas)); + intel->vmas++; +} + +static void intel_vma_close(struct vm_area_struct *vma) +{ + struct video_device *dev = vma->vm_private_data; + struct intel_isp_device *intel = video_get_drvdata(dev); + int i = 0; + + DBG_DD(("intel_vma_close %d\n", intel->vmas)); + intel->vmas--; + + /* docs say we should stop I/O too... */ + if (intel->vmas == 0) { + DBG_DD(("clear the ~V4L2_BUF_FLAG_MAPPED flag\n")); + DBG_DD(("i %d, num_frame is %d\n", i, intel->num_frames)); + for (i = 0; i < intel->num_frames; i++) { + intel->frame_queue.info[i].flags &= + ~V4L2_BUF_FLAG_MAPPED; + DBG_DD(("%d frame queue flags %d\n", i, + intel->frame_queue.info[i].flags)); + } + } +} + +static struct vm_operations_struct intel_vm_ops = { + .open = intel_vma_open, + .close = intel_vma_close +}; + +static int km_mmap(struct video_device *dev, struct vm_area_struct *vma) +{ + const char *adr = (const char *)vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long start = (unsigned long)adr; + unsigned long pos, page = 0; + unsigned long vsize; + struct intel_isp_device *intel = video_get_drvdata(dev); + u32 i; + + /* check the size */ + vsize = (intel->num_frames) * PAGE_ALIGN(intel->frame_size); + + if (!(vma->vm_flags & (VM_WRITE | VM_READ))) + return -EACCES; + + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + for (i = 0; i < intel->num_frames; i++) { + if (((PAGE_ALIGN(intel->frame_size)*i) >> PAGE_SHIFT) == + vma->vm_pgoff) + break; + } + + if (i == intel->num_frames) { + DBG_DD(("mmap: mapping address is out of range\n")); + return -EINVAL; + } + + if (size != PAGE_ALIGN(intel->frame_size)) { + DBG_DD((" failed to check Capture buffer size\n")); + return -EINVAL; + } + + /* VM_IO is eventually going to replace PageReserved altogether */ + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + + pos = (unsigned long)(intel->mb1_va+ + (intel->cap_frame * PAGE_ALIGN(intel->frame_size))); + + page = kvirt_to_pa(pos); + page = page >> PAGE_SHIFT; + if (remap_pfn_range(vma, start, page, size, PAGE_SHARED)) { + DBG_DD(("failed to put MMAP buffer to user space\n")); + return -EAGAIN; + } + return 0; +} + +/* FIXME */ +/* ------------------------------------------------------------------ */ +static int intel_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = file->private_data; + struct intel_isp_device *intel = video_get_drvdata(dev); + int i = 0; + int retval; + retval = km_mmap(dev, vma); + if (retval) + return retval; + vma->vm_ops = &intel_vm_ops; + vma->vm_flags |= VM_DONTEXPAND; + for (i = 0; i < intel->num_frames; i++) { + intel->frame_queue.info[i].flags = V4L2_BUF_FLAG_MAPPED; + DBG_DD(("frame queue flags %d\n", + intel->frame_queue.info[i].flags)); + } + vma->vm_private_data = file->private_data; + intel_vma_open(vma); + return retval; +} + + +static int intel_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + int ret; + + DBG_DD(("intel_g_fmt_cap\n")); + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + f->fmt.pix.width = intel->bufwidth; + f->fmt.pix.height = intel->bufheight; + f->fmt.pix.pixelformat = intel->pixelformat; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * intel->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + ret = 0; + } else { + ret = -EINVAL; + } + return ret; + +} + +static struct intel_fmt *fmt_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) + if (fmts[i].fourcc == fourcc) + return fmts+i; + return NULL; +} + +static int intel_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct intel_fmt *fmt; + int w, h; + unsigned short sw, sh; + int ret; + struct ci_sensor_config *snr_cfg; + + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + snr_cfg = intel->sys_conf.isi_config; + DBG_DD(("intel_try_fmt_cap\n")); + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + fmt = fmt_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) { + DBG_DD(("fmt not found\n")); + return -EINVAL; + } + + w = f->fmt.pix.width; + h = f->fmt.pix.height; + + DBG_DD(("TRY_FMT: try before buf :w%d, h%d\n", w, h)); + if (intel->sys_conf.isp_hal_enable && + snr_cfg->type == SENSOR_TYPE_RAW) { + ci_sensor_res2size(snr_cfg->res, &sw, &sh); + DBG_DD(("libCI/raw sensor create frame, %dx%d\n", sw, sh)); + if (w > sw) + w = sw; + if (h > sh) + h = sh; + } else { + DBG_DD(("v4l2 paht or SoC sensor create frame\n")); + if (ci_sensor_try_mode(&w, &h)) + return -EINVAL; + } + + /* RBG on self path */ + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 || + f->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) { + if (w < INTEL_MIN_WIDTH) + w = INTEL_MIN_WIDTH; + if (w > INTEL_MAX_WIDTH) + w = INTEL_MAX_WIDTH; + if (h < INTEL_MIN_HEIGHT) + h = INTEL_MIN_HEIGHT; + if (h > INTEL_MAX_HEIGHT) + h = INTEL_MAX_HEIGHT; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + } else { + /* YUV and JPEG formats*/ + if (w < INTEL_MIN_WIDTH) + w = INTEL_MIN_WIDTH; + if (w > INTEL_MAX_WIDTH_MP/*2048*/) + w = INTEL_MAX_WIDTH_MP; + if (h < INTEL_MIN_HEIGHT) + h = INTEL_MIN_HEIGHT; + if (h > INTEL_MAX_HEIGHT_MP/*1536*/) + h = INTEL_MAX_HEIGHT_MP; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + } + /* Deal with the raw data bayer pattern */ + if (f->fmt.pix.pixelformat == INTEL_PIX_FMT_RAW08 || + f->fmt.pix.pixelformat == INTEL_PIX_FMT_RAW10 || + f->fmt.pix.pixelformat == INTEL_PIX_FMT_RAW12) + ret = 0; + f->fmt.pix.width = w; + f->fmt.pix.height = h; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = (w * h)/8; + f->fmt.pix.sizeimage = (w * h * fmt->depth)/8; + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + ret = 0; + + DBG_DD(("TRY_FMT: try after buf :w%d, h%d\n", w, h)); + return ret; +} + + +static int intel_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + struct intel_fmt *fmt; + int err; + + DBG_DD(("intel_s_fmt_cap\n")); + + if (!intel->sys_conf.isp_hal_enable) { + DBG_DD(("v4l2 path intel_s_fmt_cap, sensor_start\n")); + ci_sensor_start(); + } else + DBG_DD(("isp hal path in intel_s_fmt_cap\n")); + + err = intel_try_fmt_cap(file, priv, f); + if (0 != err) { + DBG_DD(("set format failed\n")); + return err; + } + + fmt = fmt_by_fourcc(f->fmt.pix.pixelformat); + /* + * save the format into the driver + */ + intel->pixelformat = fmt->fourcc; + intel->depth = fmt->depth; + intel->bufwidth = f->fmt.pix.width; + intel->bufheight = f->fmt.pix.height; + DBG_DD(("set fmt: w %d, h%d, fourcc: %lx\n", intel->bufwidth, + intel->bufheight, fmt->fourcc)); + return 0; +} + +static int intel_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + DBG_DD(("intel_queryctrl\n")); + + if ((c->id < V4L2_CID_BASE) || (c->id >= V4L2_CID_PRIVATE_BASE)) + return -EINVAL; + + if (ci_sensor_queryctrl(c)) + return -EINVAL; + return 0; +} + +static int intel_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +{ + DBG_DD(("intel_g_ctrl\n")); + return ci_sensor_get_ctrl(c); +} + +static int intel_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + int ret = 0; + struct ci_sensor_config *isi_config; + DBG_DD(("intel_s_ctrl\n")); + ret = ci_sensor_set_ctrl(c); + if ((!ret) && (c->id == V4L2_CID_HFLIP)) { + isi_config = kzalloc(sizeof(struct ci_sensor_config), + GFP_KERNEL); + if (isi_config == NULL) + return -ENOMEM; + ci_sensor_get_config(isi_config); + ci_isp_set_input_aquisition(isi_config); + } + return ret; +} + +static int intel_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + int ret; + + if (input->index != 0) { + ret = -EINVAL; + } else { + strlcpy(input->name, "mrst isp", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->audioset = 0; + input->tuner = 0; + input->std = V4L2_STD_UNKNOWN; + input->status = 0; + memset(input->reserved, 0, sizeof(input->reserved)); + ret = 0; + } + return ret; +} + +static int intel_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int intel_s_input(struct file *file, void *priv, unsigned int i) +{ + return 0; +} + +static int intel_s_std(struct file *filp, void *priv, v4l2_std_id *a) +{ + return 0; +} + +static int intel_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct video_device *dev = video_devdata(file); + memset(cap, 0, sizeof(struct v4l2_capability)); + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); + strlcpy(cap->card, dev->name, sizeof(cap->card)); + memset(cap->bus_info, 0, sizeof(cap->bus_info)); + cap->version = INTEL_VERSION(0, 5, 0); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + + return 0; +} + +static int intel_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cap->bounds.left = 0; + cap->bounds.top = 0; + cap->bounds.width = intel->bufwidth; + cap->bounds.height = intel->bufheight; + cap->defrect = cap->bounds; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + return 0; +} + +static int intel_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + struct ci_sensor_config *snrcfg; + + int ret; + unsigned int index; + + DBG_DD(("intel_enum_fmt_cap\n")); + snrcfg = intel->sys_conf.isi_config; + index = f->index; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + ret = -EINVAL; + else { + if (snrcfg->type == SENSOR_TYPE_SOC) + if (index >= 8) + return -EINVAL; + if (index >= sizeof(fmts) / sizeof(*fmts)) + return -EINVAL; + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strlcpy(f->description, fmts[index].name, + sizeof(f->description)); + f->pixelformat = fmts[index].fourcc; + if (fmts[index].fourcc == V4L2_PIX_FMT_JPEG) + f->flags = V4L2_FMT_FLAG_COMPRESSED; + ret = 0; + } + return ret; + +} + +#define ALIGN4(x) ((((long)(x)) & 0x3) == 0) + +static int intel_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *req) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + u32 w; + u32 h; + u32 depth; + u32 fourcc; + unsigned long vsize; + + if (req->memory != V4L2_MEMORY_MMAP || + req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + req->count < 0) { + return -EINVAL; + } + + if (req->count == 0) { + /* free the buffers */ + intel->fbuffer = NULL; + intel->capbuf = NULL; + intel->frame_size_used = 0; + return 0; + } + + DBG_DD(("REQBUFS requested:%d max:%d, \n", + req->count, INTEL_CAPTURE_BUFFERS)); + + if (req->count > INTEL_CAPTURE_BUFFERS) + req->count = INTEL_CAPTURE_BUFFERS; + + w = intel->bufwidth; + h = intel->bufheight; + depth = intel->depth; + fourcc = intel->pixelformat; + + if (fourcc == V4L2_PIX_FMT_JPEG) { + DBG_DD(("JPEG\n")); + intel->frame_size = + PAGE_ALIGN(intel->mb1_size/req->count) - PAGE_SIZE; + } else if (fourcc == INTEL_PIX_FMT_RAW08 || + fourcc == INTEL_PIX_FMT_RAW10 || + fourcc == INTEL_PIX_FMT_RAW12) { + DBG_DD(("Bayer Pattern\n")); + intel->frame_size = (w * h * depth)/8; + } else { + DBG_DD(("YUV or RGB ")); + intel->frame_size = (w * h * depth)/8; + } + + DBG_DD(("frame size is %d\n", intel->frame_size)); + intel->num_frames = req->count; + + /* allocate the memory */ + if (intel->fbuffer) { + DBG_DD(("mem allocated, please free it first\n")); + return -EINVAL; + } + vsize = intel->num_frames * PAGE_ALIGN(intel->frame_size); + DBG_DD(("requested frame size is %ld, total is %ld\n", vsize, + intel->mb1_size)); + + DBG_DD(("PCI space path\n")); + if (vsize > intel->mb1_size) + intel->fbuffer = NULL; + else + intel->fbuffer = intel->mb1_va; + + if (intel->fbuffer) { + DBG_DD(("for QA to test mmap: kernel address 0x%p\n", + intel->fbuffer)); + } else { + DBG_DD(("failed to allocate fbuffer\n")); + return -ENOMEM; + } + + if (!intel->capbuf) { + if (vsize > intel->mb1_size) + intel->capbuf = NULL; + else { + + intel->capbuf = intel->mb1_va; + intel->capbuf_pa = intel->mb1; + } + + if (!intel->capbuf || !ALIGN4(intel->capbuf)) { + DBG_DD(("failed to allocate cap buf\n")); + return -ENOMEM; + } + } + + intel->vmas = 0; + init_frame_queue(&intel->frame_queue); + return 0; + + +} + +static int intel_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + if (buf->memory != V4L2_MEMORY_MMAP || + buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->index >= intel->num_frames || buf->index < 0) + return -EINVAL; + + buf->m.offset = PAGE_ALIGN(intel->frame_size) * buf->index; + buf->length = PAGE_ALIGN(intel->frame_size); + buf->flags = 0; + buf->flags |= intel->frame_queue.info[buf->index].flags; + DBG_DD(("buf flags is %x\n", buf->flags)); + + if (intel->frame_queue.info[buf->index].state == S_DONE) + buf->flags |= V4L2_BUF_FLAG_DONE; + else if (intel->frame_queue.info[buf->index].state == S_UNUSED) + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->field = V4L2_FIELD_NONE; + /* we know which one to map */ + intel->cap_frame = buf->index; + return 0; + +} + +static int intel_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + DBG_DD(("+++ intel_qbuf, ")); + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->memory != V4L2_MEMORY_MMAP || + buf->index >= intel->num_frames || buf->index < 0) + return -EINVAL; + + if (intel->frame_queue.info[buf->index].state == S_QUEUED) { + DBG_DD(("%d buf is already queued\n", buf->index)); + return -EINVAL; + } + + DBG_DD(("bufid %d enqueue\n", buf->index)); + buf->flags = 0; + intel->frame_queue.info[buf->index].state = S_QUEUED; + add_frame_to_queue(&intel->frame_queue, buf->index); + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; + buf->flags |= intel->frame_queue.info[buf->index].flags; + + return 0; + +} + +static int intel_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + char *bufbase; + u16 vsize = 0; + u16 hsize = 0; + int ret; + struct ci_sensor_config *isi_sensorcfg; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (b->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + isi_sensorcfg = intel->sys_conf.isi_config; + (void)ci_sensor_res2size(isi_sensorcfg->res, &hsize, &vsize); + intel->cap_frame = remove_frame_from_queue(&intel->frame_queue); + b->index = intel->cap_frame; + + if (intel->cap_frame < 0) { + if (file->f_flags & O_NONBLOCK) {; + return -EAGAIN; + } + intel->cap_frame = 0; + } + + if (intel->frame_queue.info[b->index].state != S_QUEUED) { + DBG_DD(("%d buf sate is not queued\n", b->index)); + return -EINVAL; + } + + DBG_DD(("bufid %d dequeue\n", intel->cap_frame)); + bufbase = (char *)(intel->fbuffer+ + intel->cap_frame * PAGE_ALIGN(intel->frame_size)); + + intel_update_marvinvfaddr(intel); + ci_isp_reset_interrupt_status(); + ci_isp_mif_reset_offsets(CI_ISP_CFG_UPDATE_IMMEDIATE); + + if (intel->pixelformat == V4L2_PIX_FMT_JPEG) { + DBG_DD(("jpeg path\n")); + ret = ci_isp_jpe_init_ex(intel->bufwidth, intel->bufheight, + s_config.jpeg_enc_ratio, true); + if (ret != CI_STATUS_SUCCESS) + return -EAGAIN; + if (ci_jpe_capture(CI_ISP_CFG_UPDATE_FRAME_SYNC) == 0) + return -EINVAL; + intel->frame_size_used = ci_isp_mif_get_byte_cnt(); + } else if (intel->pixelformat == INTEL_PIX_FMT_RAW08 || + intel->pixelformat == INTEL_PIX_FMT_RAW10 || + intel->pixelformat == INTEL_PIX_FMT_RAW12) { + DBG_DD(("raw path in dqbuf\n")); + ci_isp_start(1, CI_ISP_CFG_UPDATE_FRAME_SYNC); + ret = ci_isp_wait_for_frame_end(); + if (ret != CI_STATUS_SUCCESS) + return -EINVAL; + intel->frame_size_used = ci_isp_mif_get_byte_cnt(); + + } else { + /* reset interrupts and start Marvin for only one frame */ + DBG_DD(("yuv/rgb path in dqbuf\n")); + ci_isp_start(1, CI_ISP_CFG_UPDATE_FRAME_SYNC); + DBG_DD(("finished ci_isp_start\n")); + (void)ci_isp_wait_for_frame_end(); + intel->frame_size_used = ci_isp_mif_get_byte_cnt(); + } + + DBG_DD(("buffer in dqbuf, dst 0x%p, src 0x%p, size%dk\n", + bufbase, intel->capbuf, intel->frame_size_used/1024)); + + do_gettimeofday(&b->timestamp); + + intel->frame_queue.info[b->index].state = S_DONE; + b->flags = V4L2_BUF_FLAG_MAPPED; + b->flags &= ~V4L2_BUF_FLAG_DONE; + + if (intel->frame_size_used) + b->bytesused = intel->frame_size_used; + else + b->bytesused = intel->frame_size; + b->memory = V4L2_MEMORY_MMAP; + b->m.offset = intel->cap_frame * PAGE_ALIGN(intel->frame_size); + b->length = PAGE_ALIGN(intel->frame_size); + b->index = intel->cap_frame; + b->sequence = intel->field_count; + + return 0; + +} + +static int intel_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || !intel->fbuffer) + return -EINVAL; + + intel->cap_frame = 0; + intel->state = S_STREAMING; + if (!intel->sys_conf.isp_hal_enable) { + DBG_DD(("v4l2 path enabled\n")); + ci_sensor_set_mode(intel->bufwidth, intel->bufheight); + intel_dpinitisi(&isi_config, &isi_caps); + intel_defcfg_all_load(&s_config, &isi_config); + } else + DBG_DD(("isp hal path enabled\n")); + + intel_dpinitmrv(&intel->sys_conf); + intel_setup_viewfinder_path(intel, -1); + return 0; + +} + +static int intel_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + if (!intel->sys_conf.isp_hal_enable && + (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || !intel->fbuffer)) + return -EINVAL; + intel->state = S_IDLE; + ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC); + init_frame_queue(&intel->frame_queue); + return 0; +} + +static u32 +copy_sensor_config_from_user(struct ci_sensor_config *des, + struct ci_sensor_config *src) +{ + u32 ret = 0; + ret = copy_from_user((void *)des, (const void *)src, + sizeof(struct ci_sensor_config)); + if (ret) + return -EFAULT; + return ret; +} + +static u32 +copy_sensor_caps_from_user(struct ci_sensor_caps *des, + struct ci_sensor_caps *src) +{ + u32 ret = 0; + ret = copy_from_user((void *)des, (const void *)src, + sizeof(struct ci_sensor_caps)); + if (ret) + return -EFAULT; + return ret; +} + +static u32 +copy_isp_config_from_user(struct ci_isp_config *des, + struct ci_isp_config *src) +{ + u32 ret = 0; + ret = copy_from_user((void *)des, (const void *)src, + sizeof(struct ci_isp_config)); + if (ret) + return -EFAULT; + return ret; +} + +static int intel_set_cfg(struct file *file, void *priv, + struct ci_pl_system_config *arg) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + if (arg == NULL) { + printk(KERN_WARNING "NULL pointer in intel_set_cfg\n"); + return 0; + } + + DBG_DD(("intel_set_cfg ioctl,%d\n", arg->isp_hal_enable)); + + intel->sys_conf.isp_hal_enable = arg->isp_hal_enable; + + if (intel->sys_conf.isp_hal_enable) + DBG_DD(("isp hal path\n")); + + if (arg->isi_config != NULL) { + copy_sensor_config_from_user(intel->sys_conf.isi_config, + arg->isi_config); + } else { + printk(KERN_WARNING "NULL sensor config pointer\n"); + return CI_STATUS_NULL_POINTER; + } + + if (arg->isi_caps != NULL) { + DBG_DD((" sync isi caps\n")); + copy_sensor_caps_from_user(intel->sys_conf.isi_caps, + arg->isi_caps); + } else { + printk(KERN_WARNING "NULL sensor caps pointer\n"); + return CI_STATUS_NULL_POINTER; + } + + if (arg->isp_cfg != NULL) { + DBG_DD(("sync isp cfg\n")); + copy_isp_config_from_user(intel->sys_conf.isp_cfg, + arg->isp_cfg); + } else { + printk(KERN_WARNING "NULL isp config pointer\n"); + return CI_STATUS_NULL_POINTER; + } + + return 0; +} + +/* for buffer sharing between CI and VA */ +static int intel_get_frame_info(struct file *file, void *priv, + struct ci_frame_info *arg) +{ + struct video_device *dev = video_devdata(file); + struct intel_isp_device *intel = video_get_drvdata(dev); + + arg->width = intel->bufwidth; + arg->height = intel->bufheight; + arg->fourcc = intel->pixelformat; + arg->stride = intel->bufwidth; /* should be 64 bit alignment*/ + arg->offset = arg->frame_id * PAGE_ALIGN(intel->frame_size); + DBG_DD(("w=%d, h=%d, 4cc =%x, stride=%d, offset=%d,fsize=%d\n", + arg->width, arg->height, arg->fourcc, arg->stride, + arg->offset, intel->frame_size)); + return 0; + +} + +static int intel_set_jpg_enc_ratio(struct file *file, void *priv, + int *arg) +{ + DBG_DD(("set jpg compression ratio is %d\n", *arg)); + s_config.jpeg_enc_ratio = *arg; + return 0; +} + +/* intel private ioctl for libci */ +static int intel_v4l2p_ioctl(struct file *file, + unsigned int cmd, void __user *arg) +{ + void *priv = file->private_data; + + switch (cmd) { + + case VIDIOC_SET_SYS_CFG: + return intel_set_cfg(file, priv, + (struct ci_pl_system_config *)arg); + + case VIDIOC_SET_JPG_ENC_RATIO: + return intel_set_jpg_enc_ratio(file, priv, (int *)arg); + + case ISP_IOCTL_GET_FRAME_INFO: + return intel_get_frame_info(file, priv, + (struct ci_frame_info *)arg); + + default: + return -EINVAL; + } +} + +static long intel_ioctl_v4l2(struct file *file, + unsigned int cmd, void __user *arg) +{ + void *priv = file->private_data; + + switch (cmd) { + + case VIDIOC_QUERYCAP: + return intel_querycap(file, priv, arg); + + case VIDIOC_ENUMINPUT: + return intel_enum_input(file, priv, arg); + + case VIDIOC_G_INPUT: + return intel_g_input(file, priv, arg); + + case VIDIOC_S_INPUT: + return 0; + + case VIDIOC_QUERYCTRL: + return intel_queryctrl(file, priv, arg); + + case VIDIOC_G_CTRL: + return intel_g_ctrl(file, priv, arg); + + case VIDIOC_S_CTRL: + return intel_s_ctrl(file, priv, arg); + + case VIDIOC_CROPCAP: + return intel_cropcap(file, priv, arg); + + case VIDIOC_G_CROP: + return -EINVAL; + + case VIDIOC_S_CROP: + return -EINVAL; + + case VIDIOC_ENUM_FMT: + return intel_enum_fmt_cap(file, priv, arg); + + case VIDIOC_G_FMT: + return intel_g_fmt_cap(file, priv, arg); + + case VIDIOC_TRY_FMT: + return intel_try_fmt_cap(file, priv, arg); + + case VIDIOC_S_FMT: + return intel_s_fmt_cap(file, priv, arg); + + case VIDIOC_REQBUFS: + return intel_reqbufs(file, priv, arg); + + case VIDIOC_QUERYBUF: + return intel_querybuf(file, priv, arg); + + case VIDIOC_QBUF: + return intel_qbuf(file, priv, arg); + + case VIDIOC_DQBUF: + return intel_dqbuf(file, priv, arg); + + case VIDIOC_STREAMON: + return intel_streamon(file, priv, *(int *)arg); + + case VIDIOC_STREAMOFF: + return intel_streamoff(file, priv, *(int *)arg); + + case VIDIOC_S_STD: + return intel_s_std(file, priv, arg); + + case VIDIOC_G_STD: + case VIDIOC_QUERYSTD: + case VIDIOC_ENUMSTD: + case VIDIOC_QUERYMENU: + case VIDIOC_ENUM_FRAMEINTERVALS: + return -EINVAL; + + default: + return intel_v4l2p_ioctl(file, cmd, arg); + } +} + +static long intel_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + + return video_usercopy(file, cmd, arg, intel_ioctl_v4l2); +} + + +static const struct v4l2_file_operations intel_fops = { + .owner = THIS_MODULE, + .open = intel_open, + .release = intel_close, + .read = intel_read, + .mmap = intel_mmap, + .ioctl = intel_ioctl, +}; + +static const struct v4l2_ioctl_ops intel_ioctl_ops = { + .vidioc_querycap = intel_querycap, + .vidioc_enum_fmt_vid_cap = intel_enum_fmt_cap, + .vidioc_g_fmt_vid_cap = intel_g_fmt_cap, + .vidioc_try_fmt_vid_cap = intel_try_fmt_cap, + .vidioc_s_fmt_vid_cap = intel_s_fmt_cap, + .vidioc_cropcap = intel_cropcap, + .vidioc_reqbufs = intel_reqbufs, + .vidioc_querybuf = intel_querybuf, + .vidioc_qbuf = intel_qbuf, + .vidioc_dqbuf = intel_dqbuf, + .vidioc_enum_input = intel_enum_input, + .vidioc_g_input = intel_g_input, + .vidioc_s_input = intel_s_input, + .vidioc_s_std = intel_s_std, + .vidioc_queryctrl = intel_queryctrl, + .vidioc_streamon = intel_streamon, + .vidioc_streamoff = intel_streamoff, + .vidioc_g_ctrl = intel_g_ctrl, + .vidioc_s_ctrl = intel_s_ctrl, +}; + +static struct video_device intel_template = { + .name = "Moorestown Camera Imaging", + .minor = -1, + .fops = &intel_fops, + .ioctl_ops = &intel_ioctl_ops, + .release = video_device_release, +}; + +static void __devexit intel_pci_remove(struct pci_dev *pci_dev) +{ + struct intel_isp_device *intel = NULL; + + if (pci_driver_loaded) + intel = &intel_isp_v4l_device; + + pci_driver_loaded = 0; + + if (intel->fbuffer) + vfree(intel->fbuffer); + intel->fbuffer = NULL; + + if (intel->capbuf) { + if (intel->frame_size <= MAX_KMALLOC_MEM) + kfree(intel->capbuf); + else + iounmap(intel->capbuf); + } + + intel->capbuf = NULL; + + if (intel->regs) + iounmap(intel->regs); + + intel->regs = NULL; + + if (intel->mb1_va) + iounmap(intel->mb1_va); + + intel->mb1_va = NULL; + + video_unregister_device(intel->vdev); + DBG_DD((" Remove v4l device. interrupt_count=%ld\n", + intel->interrupt_count)); + pci_release_regions(pci_dev); + if (!pci_driver_loaded) + pci_set_drvdata(pci_dev, NULL); + +} + +static int __devinit intel_pci_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + struct intel_isp_device *intel; + int ret = 0; + unsigned int start = 0; + unsigned int len = 0; + intel = &intel_isp_v4l_device; + g_intel = &intel_isp_v4l_device; + intel->pci_dev = dev; + intel->interrupt_count = 0; + + if (pci_enable_device(dev) < 0) { + printk(KERN_INFO " can't enable device.\n"); + return -EIO; + } + + ret = pci_request_regions(dev, "intel_isp"); + if (ret) { + DBG_DD(("failed to request I/O memory\n")); + return -EIO; + } + + /* Determine the address of the I2C area */ + start = intel->mb0 = pci_resource_start(dev, 0); + len = intel->mb0_size = pci_resource_len(dev, 0); + + intel->regs = ioremap_nocache(start, len); + if (intel->regs == NULL) { + DBG_DD(("failed to ioremap\n")); + return -ENXIO; + } + DBG_DD((" mmio address: 0x%p, lenght=0x%lx\n", + intel->regs, intel->mb0_size)); + + /* mem base 1*/ + start = intel->mb1 = pci_resource_start(dev, 1); + len = intel->mb1_size = pci_resource_len(dev, 1); + intel->mb1_va = ioremap_nocache(start, len); + if (intel->mb1_va == NULL) { + DBG_DD(("failed to ioremap\n")); + return -ENXIO; + } + + DBG_DD((" mmio address: 0x%p, lenght=0x%lx\n", + intel->mb1_va, intel->mb1_size)); + + pci_read_config_word(dev, PCI_VENDOR_ID, &intel->vendorID); + pci_read_config_word(dev, PCI_DEVICE_ID, &intel->deviceID); + + + if (!pci_driver_loaded) { + pci_driver_loaded = 1; + pci_set_master(dev); + pci_set_drvdata(dev, intel); + } + + g_intel->vdev = kmalloc(sizeof(struct video_device), GFP_KERNEL); + memcpy(intel->vdev, &intel_template, sizeof(intel_template)); + + intel->vdev->parent = &dev->dev; + + printk(KERN_INFO "reset ISP hardware ...\n"); + ci_isp_init(); + printk(KERN_INFO "reset ISP hardware - done\n"); + /* register v4l device */ + video_set_drvdata(g_intel->vdev, g_intel); + if (video_register_device(intel->vdev, VFL_TYPE_GRABBER, video_nr) + == -1) { + printk(KERN_INFO "video_register_device failed\n"); + return -1; + } + + return 0; + +} + +static struct pci_device_id intel_isp_pci_tbl[] __devinitdata = { + { PCI_DEVICE(0x8086, 0x080B) }, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, intel_isp_pci_tbl); + +static struct pci_driver intel_isp_pci_driver = { + .name = "mrstisp", + .id_table = intel_isp_pci_tbl, + .probe = intel_pci_probe, + .remove = intel_pci_remove, +}; + +static int __init intel_pci_init(void) +{ + int ret = 0; + ret = pci_register_driver(&intel_isp_pci_driver); + if (ret) { + printk(KERN_ERR "Unable to register intel_isp_pci driver\n"); + return ret; + } + return ret; +} + +static void __exit intel_pci_exit(void) +{ + struct intel_isp_device *intel = NULL; + intel = &intel_isp_v4l_device; + + DBG_DD((" v4l module cleanup.\n")); + pci_unregister_driver(&intel_isp_pci_driver); +} + +module_init(intel_pci_init); +module_exit(intel_pci_exit); + +MODULE_DESCRIPTION("mrstisp.ko - CI/V4L2 driver for Moorestown"); +MODULE_AUTHOR("Xiaolin Zhang "); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("video"); + +module_param(km_debug, int, 0); +MODULE_PARM_DESC(km_debug, "debug level (default: 0)"); diff --git a/drivers/media/video/mrstci/mrstisp/mrv.c b/drivers/media/video/mrstci/mrstisp/mrv.c new file mode 100644 index 0000000..4665a78 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv.c @@ -0,0 +1,442 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +#define CI_ISP_DELAY_AFTER_RESET 15 + +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; +} + +static int ci_isp_verify_chip_id(void) +{ + u32 mrv_id = ci_isp_get_ci_isp_id(); + if (mrv_id != MARVIN_FEATURE_CHIP_ID) { + DBG_DD(("WARNING: Marvin HW-Id does not match! " + "read:0x%08X, expected:0x%08X\n", + mrv_id, MARVIN_FEATURE_CHIP_ID)); + return CI_STATUS_FAILURE; + } + return CI_STATUS_SUCCESS; +} + +void ci_isp_init(void) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + + (void)ci_isp_verify_chip_id(); + + REG_SET_SLICE(mrv_reg->vi_ccl, MRV_VI_CCLFDIS, + MRV_VI_CCLFDIS_ENABLE); + 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); + intel_sleep_micro_sec(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); +} + +static 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; + } + } + } + +} + +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 */ + ASSERT(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); + + 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); + DBG_DD(("xiaolin ISP_CTRL = 0x%08X\n", mrv_reg->isp_ctrl)); +} + +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); + /* disable output formatter */ + 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); +} + +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; + + 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: + DBG_DD(("ci_isp_set_data_path: unknown value for " + "enum ci_isp_ycs_chn_mode\n")); + return CI_STATUS_NOTSUPP; + } + + if (vi_chan_mode & + ~(MRV_VI_CHAN_MODE_MASK >> MRV_VI_CHAN_MODE_SHIFT)) + return CI_STATUS_NOTSUPP; + + 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: + DBG_DD((" unknown value for teDpSwitch\n")); + return CI_STATUS_NOTSUPP; + } + + if (vi_mp_mux & ~MRV_VI_MP_MUX_MASK) + return CI_STATUS_NOTSUPP; + + 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; +} + +int ci_isp_set_mipi_smia(u32 mode) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + u32 if_select; + + switch (mode) { + 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: + return CI_STATUS_NOTSUPP; + } + + /* program settings into MARVIN vi_dpcl register */ + REG_SET_SLICE(mrv_reg->vi_dpcl, MRV_IF_SELECT, if_select); + return CI_STATUS_SUCCESS; +} + +static int ci_isp_wait_for_mi(u32 bit_mask) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + + intel_timer_start(); + + while ((mrv_reg->mi_ris & bit_mask) != bit_mask) { + if (intel_get_micro_sec() > 2000000) { + intel_timer_stop(); + 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); + intel_sleep_micro_sec(CI_ISP_DELAY_AFTER_RESET); + REG_SET_SLICE(mrv_reg->isp_ctrl, + MRV_ISP_ISP_CFG_UPD, ON); + return CI_STATUS_FAILURE; + } + } + + intel_timer_stop(); + + if (REG_GET_SLICE(mrv_reg->isp_ris, MRV_ISP_RIS_DATA_LOSS)) { + DBG_DD(("WARN: *** no failure, " + "but MRV_ISPINT_DATA_LOSS *** \n")); + } + + return CI_STATUS_SUCCESS; +} + +int ci_isp_wait_for_frame_end(void) +{ + return ci_isp_wait_for_mi(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); +} + +void ci_isp_set_dma_read_mode(enum ci_isp_dma_read_mode mode, + enum ci_isp_conf_update_time update_time) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + u32 vi_dma_switch = 0; + u32 vi_dma_spmux = 0; + u32 vi_dma_iemux = 0; + int dma_jpeg_select = false; + +#define DMA_READ_MODE_PROGRAMMING_VI_DPCL 1 + ASSERT((mode == CI_ISP_DMA_RD_OFF) || + (mode == CI_ISP_DMA_RD_SELF_PATH) || + (mode == CI_ISP_DMA_RD_IE_PATH) || + (mode == CI_ISP_DMA_RD_SUPERIMPOSE)); + + switch (mode) { + case CI_ISP_DMA_RD_OFF: + vi_dma_switch = MRV_VI_DMA_SWITCH_SELF; + vi_dma_spmux = MRV_VI_DMA_SPMUX_CAM; + vi_dma_iemux = MRV_VI_DMA_IEMUX_CAM; + dma_jpeg_select = false; + break; + case CI_ISP_DMA_RD_SELF_PATH: + vi_dma_switch = MRV_VI_DMA_SWITCH_SELF; + vi_dma_spmux = MRV_VI_DMA_SPMUX_DMA; + vi_dma_iemux = MRV_VI_DMA_IEMUX_CAM; + dma_jpeg_select = false; + break; + case CI_ISP_DMA_RD_IE_PATH: + vi_dma_switch = MRV_VI_DMA_SWITCH_IE; + vi_dma_spmux = MRV_VI_DMA_SPMUX_CAM; + vi_dma_iemux = MRV_VI_DMA_IEMUX_DMA; + dma_jpeg_select = false; + break; + case CI_ISP_DMA_RD_JPG_ENC: + vi_dma_switch = MRV_VI_DMA_SWITCH_JPG; + vi_dma_spmux = MRV_VI_DMA_SPMUX_CAM; + vi_dma_iemux = MRV_VI_DMA_IEMUX_CAM; + dma_jpeg_select = true; + break; + case CI_ISP_DMA_RD_SUPERIMPOSE: + vi_dma_switch = MRV_VI_DMA_SWITCH_SI; + vi_dma_spmux = MRV_VI_DMA_SPMUX_CAM; + vi_dma_iemux = MRV_VI_DMA_IEMUX_CAM; + dma_jpeg_select = false; + break; + default: + ASSERT(0); + + } + + { + u32 vi_dpcl = REG_READ(mrv_reg->vi_dpcl); + + REG_SET_SLICE(vi_dpcl, MRV_VI_DMA_SWITCH, vi_dma_switch); + REG_SET_SLICE(vi_dpcl, MRV_VI_DMA_SPMUX, vi_dma_spmux); + REG_SET_SLICE(vi_dpcl, MRV_VI_DMA_IEMUX, vi_dma_iemux); +#if ((MRV_VI_MP_MUX_JPGDIRECT & \ + ~(MRV_VI_MP_MUX_MASK >> MRV_VI_MP_MUX_SHIFT)) == 0) + if (dma_jpeg_select) { + REG_SET_SLICE(vi_dpcl, MRV_VI_MP_MUX, + MRV_VI_MP_MUX_JPGDIRECT); + } +#else + UNUSED_PARAM(dma_jpeg_select); +#endif + REG_WRITE(mrv_reg->vi_dpcl, vi_dpcl); + } +} + + +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); +} diff --git a/drivers/media/video/mrstci/mrstisp/mrv_col.c b/drivers/media/video/mrstci/mrstisp/mrv_col.c new file mode 100644 index 0000000..63bb40e --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_col.c @@ -0,0 +1,66 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "mrv_priv.h" + +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) { + /* disable color processing (bypass) */ + 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; + + /* modify color processing registers */ + 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; + } + } +} + diff --git a/drivers/media/video/mrstci/mrstisp/mrv_ie.c b/drivers/media/video/mrstci/mrstisp/mrv_ie.c new file mode 100644 index 0000000..5cb45fa --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_ie.c @@ -0,0 +1,237 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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; +} + +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; + } +} + +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) { + /* just disable the module, i.e. put it in bypass mode */ + REG_SET_SLICE(mrv_reg->img_eff_ctrl, + MRV_IMGEFF_BYPASS_MODE, + MRV_IMGEFF_BYPASS_MODE_BYPASS); + } else { + 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; +} + diff --git a/drivers/media/video/mrstci/mrstisp/mrv_is.c b/drivers/media/video/mrstci/mrstisp/mrv_is.c new file mode 100644 index 0000000..0414b03 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_is.c @@ -0,0 +1,66 @@ +/* + * 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 + */ +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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) { + DBG_OUT((DERR, "ci_isp_is_set_config: is_config == NULL\n")); + return CI_STATUS_NULL_POINTER; + } + 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)); + } + + 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; +} + + diff --git a/drivers/media/video/mrstci/mrstisp/mrv_isp.c b/drivers/media/video/mrstci/mrstisp/mrv_isp.c new file mode 100644 index 0000000..989cd8d --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_isp.c @@ -0,0 +1,1433 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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_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; +} + +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) { + DBG_DD(("failed to select path\n")); + 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; + + default: + return CI_STATUS_NOTSUPP; + } + + switch (isi_cfg->bus_width) { + case SENSOR_BUSWIDTH_12BIT: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION, + MRV_ISP_INPUT_SELECTION_12EXT); + break; + case SENSOR_BUSWIDTH_10BIT_ZZ: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION, + MRV_ISP_INPUT_SELECTION_10ZERO); + break; + case SENSOR_BUSWIDTH_10BIT_EX: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION, + MRV_ISP_INPUT_SELECTION_10MSB); + break; + case SENSOR_BUSWIDTH_8BIT_ZZ: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION, + MRV_ISP_INPUT_SELECTION_8ZERO); + break; + case SENSOR_BUSWIDTH_8BIT_EX: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_INPUT_SELECTION, + MRV_ISP_INPUT_SELECTION_8MSB); + break; + + 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) { + case SENSOR_HPOL_SYNCPOS: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 1); + break; + case SENSOR_HPOL_SYNCNEG: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 0); + break; + case SENSOR_HPOL_REFPOS: + REG_SET_SLICE(isp_acq_prop, MRV_ISP_HSYNC_POL, 0); + break; + case SENSOR_HPOL_REFNEG: + 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; + } + + /* now write values to registers */ + REG_WRITE(mrv_reg->isp_ctrl, isp_ctrl); + REG_WRITE(mrv_reg->isp_acq_prop, isp_acq_prop); + + 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); + + 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; + default: + return CI_STATUS_NOTSUPP; + } + + return CI_STATUS_SUCCESS; +} + +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: + 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->isp_ctrl, + MRV_ISP_ISP_CFG_UPD, ON); + break; + case CI_ISP_CFG_UPDATE_LATER: + break; + default: + break; + } + } +} + +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: + ASSERT(false); + } + + REG_SET_SLICE(isp_demosaic, MRV_ISP_DEMOSAIC_TH, demosaic_th); + REG_WRITE(mrv_reg->isp_demosaic, isp_demosaic); +} + +static int ci_isp_afm_wnd2_regs(const struct ci_isp_window *wnd, u32 *lt, + u32 *rb) +{ + ASSERT((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; + } + + 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; + + 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), + <, &rb); + if (result != CI_STATUS_SUCCESS) + return result; + + REG_WRITE(mrv_reg->isp_afm_lt_a, lt); + REG_WRITE(mrv_reg->isp_afm_rb_a, rb); + + result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_b), + <, &rb); + + if (result != CI_STATUS_SUCCESS) + return result; + + REG_WRITE(mrv_reg->isp_afm_lt_b, lt); + REG_WRITE(mrv_reg->isp_afm_rb_b, rb); + + result = ci_isp_afm_wnd2_regs(&(af_config->wnd_pos_c), + <, &rb); + + if (result != CI_STATUS_SUCCESS) + return result; + + REG_WRITE(mrv_reg->isp_afm_lt_c, lt); + REG_WRITE(mrv_reg->isp_afm_rb_c, rb); + + 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)); + REG_SET_SLICE(mrv_reg->isp_afm_ctrl, MRV_AFM_AFM_EN, ENABLE); + } + + return result; + +} + +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) { + /* disable lens shading module */ + 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); + intel_sleep_micro_sec(1000); + enabled = true; + } + + 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); + + ASSERT(((CI_ISP_MAX_LSC_SECTORS + 1) * + ((CI_ISP_MAX_LSC_SECTORS + 2) / 2)) == + (MRV_LSC_R_RAM_ADDR_MAX + 1)); + 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); + } + + 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]); + + 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]); + + 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]); + + 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) { + 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; + +} + +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) { + 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); + + ASSERT(!REG_GET_SLICE(mrv_reg->isp_bp_ctrl, + MRV_BP_BP_DET_EN)); + + 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 { + ASSERT(REG_GET_SLICE(mrv_reg->isp_bp_ctrl, MRV_BP_COR_TYPE) + == MRV_BP_COR_TYPE_TABLE); + REG_SET_SLICE(mrv_reg->isp_bp_cfg1, MRV_BP_DEAD_THRES, + bp_det_config->bp_dead_thres); + + 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; + + 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; + + retval = ci_isp_initialize_filter_registers(); + if (retval != CI_STATUS_SUCCESS) + return retval; + + 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 + /* MRV_FILT_STAGE1_SELECT_MAX_BLUR */); + 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 + /* MRV_FILT_STAGE1_SELECT_DEFAULT */); + 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 + /* MRV_FILT_STAGE1_SELECT_DEFAULT */); + 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) { + /* SharpLevel = 0; no sharp enhancement */ + 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); + REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0, + MRV_FILT_FILT_FAC_BL0, + (filt_fac_bl0) >> 1); + 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); + REG_SET_SLICE(mrv_reg->isp_filt_fac_bl0, + MRV_FILT_FILT_FAC_BL0, + (filt_fac_bl0 * 3) >> 2); + REG_SET_SLICE(mrv_reg->isp_filt_fac_bl1, + MRV_FILT_FILT_FAC_BL1, + (filt_fac_bl1) >> 1); + } + } + + REG_SET_SLICE(isp_filt_mode, MRV_FILT_FILT_MODE, + MRV_FILT_FILT_MODE_DYNAMIC); + 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 + + return CI_STATUS_OUTOFRANGE; +} diff --git a/drivers/media/video/mrstci/mrstisp/mrv_isp_bls.c b/drivers/media/video/mrstci/mrstisp/mrv_isp_bls.c new file mode 100644 index 0000000..6f79e89 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_isp_bls.c @@ -0,0 +1,174 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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 { + /* we are in this path */ + 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) { + /* disable the BLS module */ + 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)); + + /* set Mode */ + 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; +} diff --git a/drivers/media/video/mrstci/mrstisp/mrv_isp_gamma.c b/drivers/media/video/mrstci/mrstisp/mrv_isp_gamma.c new file mode 100644 index 0000000..870bd90 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_isp_gamma.c @@ -0,0 +1,87 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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 = 4; + 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); + } +} + +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) { + ASSERT(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/mrv_jpe.c b/drivers/media/video/mrstci/mrstisp/mrv_jpe.c new file mode 100644 index 0000000..cb270c9 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_jpe.c @@ -0,0 +1,447 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" +#include "mrv_jpe.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; + + 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); + intel_sleep_micro_sec(15); + ci_isp_jpe_set_tables(compression_ratio); + ci_isp_jpe_select_tables(); + + return CI_STATUS_SUCCESS; +} + +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: + hsize = BP1_SIZE_H; + vsize = BP1_SIZE_V; + break; + case SENSOR_RES_S_AFM: + hsize = S_AFM_SIZE_H; + vsize = S_AFM_SIZE_V; + break; + case SENSOR_RES_M_AFM: + hsize = M_AFM_SIZE_H; + vsize = M_AFM_SIZE_V; + break; + case SENSOR_RES_L_AFM: + hsize = L_AFM_SIZE_H; + vsize = L_AFM_SIZE_V; + break; + case SENSOR_RES_QQCIF: + hsize = QQCIF_SIZE_H; + vsize = QQCIF_SIZE_V; + break; + case SENSOR_RES_QQVGA: + hsize = QQVGA_SIZE_H; + vsize = QQVGA_SIZE_V; + break; + case SENSOR_RES_QCIF: + hsize = QCIF_SIZE_H; + vsize = QCIF_SIZE_V; + break; + case SENSOR_RES_QVGA: + hsize = QVGA_SIZE_H; + vsize = QVGA_SIZE_V; + break; + case SENSOR_RES_CIF: + hsize = CIF_SIZE_H; + vsize = CIF_SIZE_V; + break; + case SENSOR_RES_VGA: + hsize = VGA_SIZE_H; + vsize = VGA_SIZE_V; + break; + case SENSOR_RES_SVGA: + hsize = SVGA_SIZE_H; + vsize = SVGA_SIZE_V; + break; + case SENSOR_RES_XGA: + hsize = XGA_SIZE_H; + vsize = XGA_SIZE_V; + break; + case SENSOR_RES_XGA_PLUS: + hsize = XGA_PLUS_SIZE_H; + vsize = XGA_PLUS_SIZE_V; + break; + case SENSOR_RES_SXGA: + hsize = SXGA_SIZE_H; + vsize = SXGA_SIZE_V; + break; + case SENSOR_RES_UXGA: + hsize = UXGA_SIZE_H; + vsize = UXGA_SIZE_V; + break; + case SENSOR_RES_QXGA: + hsize = QXGA_SIZE_H; + vsize = QXGA_SIZE_V; + break; + case SENSOR_RES_QSXGA: + hsize = QSXGA_SIZE_H; + vsize = QSXGA_SIZE_V; + break; + case SENSOR_RES_QSXGA_PLUS: + hsize = QSXGA_PLUS_SIZE_H; + vsize = QSXGA_PLUS_SIZE_V; + break; + case SENSOR_RES_QSXGA_PLUS2: + hsize = QSXGA_PLUS2_SIZE_H; + vsize = QSXGA_PLUS2_SIZE_V; + break; + case SENSOR_RES_QSXGA_PLUS3: + hsize = QSXGA_PLUS3_SIZE_H; + vsize = QSXGA_PLUS3_SIZE_V; + break; + case SENSOR_RES_WQSXGA: + hsize = WQSXGA_SIZE_H; + vsize = WQSXGA_SIZE_V; + break; + case SENSOR_RES_QUXGA: + hsize = QUXGA_SIZE_H; + vsize = QUXGA_SIZE_V; + break; + case SENSOR_RES_WQUXGA: + hsize = WQUXGA_SIZE_H; + vsize = WQUXGA_SIZE_V; + break; + case SENSOR_RES_HXGA: + hsize = HXGA_SIZE_H; + vsize = HXGA_SIZE_V; + break; + default: + DBG_OUT((DERR, + "ci_isp_jpe_init: resolution not supported\n")); + 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; + 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: + 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]); + 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; + + REG_SET_SLICE(mrv_reg->jpe_tq_y_select, MRV_JPE_TQ0_SELECT, + MRV_JPE_TQ_SELECT_TAB0); + REG_SET_SLICE(mrv_reg->jpe_tq_u_select, MRV_JPE_TQ1_SELECT, + MRV_JPE_TQ_SELECT_TAB1); + REG_SET_SLICE(mrv_reg->jpe_tq_v_select, MRV_JPE_TQ2_SELECT, + MRV_JPE_TQ_SELECT_TAB1); + 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); + 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) { + 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 { + 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); + } + + 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(u8 header_mode) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + + ASSERT((header_mode == MRV_JPE_HEADER_MODE_JFIF) + || (header_mode == MRV_JPE_HEADER_MODE_NO)); + + 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); + REG_SET_SLICE(mrv_reg->jpe_gen_header, MRV_JPE_GEN_HEADER, ON); + return ci_isp_jpe_wait_for_header_gen_done(); +} + +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); + + 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: + REG_SET_SLICE(jpe_encode, MRV_JPE_CONT_MODE, + MRV_JPE_CONT_MODE_HEADER); + break; + case CI_ISP_JPE_SHORT_CONT_MODE: + REG_SET_SLICE(jpe_encode, MRV_JPE_CONT_MODE, + MRV_JPE_CONT_MODE_NEXT); + break; + default: + 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); +} + +int ci_isp_jpe_wait_for_header_gen_done(void) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + + intel_timer_start(); + + while (!REG_GET_SLICE + (mrv_reg->jpe_status_ris, MRV_JPE_GEN_HEADER_DONE)) { + if (intel_get_micro_sec() > 2000000) { + intel_timer_stop(); + return CI_STATUS_FAILURE; + } + } + intel_timer_stop(); + return CI_STATUS_SUCCESS; +} + +int ci_isp_jpe_wait_for_encode_done(void) +{ + struct isp_register *mrv_reg = + (struct isp_register *) MEM_MRV_REG_BASE; + + intel_timer_start(); + while (!REG_GET_SLICE + (mrv_reg->jpe_status_ris, MRV_JPE_ENCODE_DONE)) { + if (intel_get_micro_sec() > 200000) { + intel_timer_stop(); + return CI_STATUS_FAILURE; + } + } + intel_timer_stop(); + 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/mrv_mif.c b/drivers/media/video/mrstci/mrstisp/mrv_mif.c new file mode 100644 index 0000000..c682c21 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_mif.c @@ -0,0 +1,677 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +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; + } + +} + +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); +} + +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: + 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: + 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) { + DBG_OUT((DERR, + "ci_isp_mif_check_mi_path_conf(): isp_mi_path_conf is" + " NULL\n")); + return CI_STATUS_NULL_POINTER; + } + + if (!isp_mi_path_conf->ybuffer.pucbuffer) + 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; +} + +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); + } + + 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; +} + +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; + + 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); + + 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); + + 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; +} + +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) + return CI_STATUS_NULL_POINTER; + + if ((mrv_mi_ctrl-> + irq_offs_init & ~(MRV_MI_MP_Y_IRQ_OFFS_INIT_VALID_MASK)) != + 0) + 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); + + 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: + return error; + } + + 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: + return error; + } + + 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: + return error; + } + + error = CI_STATUS_SUCCESS; + + 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) + return error; + + if (mrv_mi_ctrl->main_path == CI_ISP_PATH_ON) { + + 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) + return error; + switch (mrv_mi_ctrl->burst_length_chrom) { + case CI_ISP_MIF_BURST_LENGTH_4: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_CHROM, + MRV_MI_BURST_LEN_CHROM_4); + break; + case CI_ISP_MIF_BURST_LENGTH_8: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_CHROM, + MRV_MI_BURST_LEN_CHROM_8); + break; + case CI_ISP_MIF_BURST_LENGTH_16: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_CHROM, + MRV_MI_BURST_LEN_CHROM_16); + break; + default: + error = CI_STATUS_OUTOFRANGE; + break; + } + + if (error != CI_STATUS_SUCCESS) + return error; + switch (mrv_mi_ctrl->burst_length_lum) { + case CI_ISP_MIF_BURST_LENGTH_4: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_LUM, + MRV_MI_BURST_LEN_LUM_4); + break; + case CI_ISP_MIF_BURST_LENGTH_8: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_LUM, + MRV_MI_BURST_LEN_LUM_8); + break; + case CI_ISP_MIF_BURST_LENGTH_16: + REG_SET_SLICE(mi_ctrl, MRV_MI_BURST_LEN_LUM, + MRV_MI_BURST_LEN_LUM_16); + break; + default: + error = CI_STATUS_OUTOFRANGE; + break; + } + + if (error != CI_STATUS_SUCCESS) + 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) + return error; + + REG_SET_SLICE(mi_ctrl, MRV_MI_BYTE_SWAP, + (mrv_mi_ctrl->byte_swap_enable) ? ON : OFF); + REG_SET_SLICE(mi_ctrl, MRV_MI_LAST_PIXEL_SIG_EN, + (mrv_mi_ctrl->last_pixel_enable) ? ON : OFF); + + REG_WRITE(mrv_reg->mi_ctrl, mi_ctrl); + 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 + error = CI_STATUS_OUTOFRANGE; + + REG_SET_SLICE(mrv_reg->mi_init, MRV_MI_MI_CFG_UPD, ON); + return error; +} diff --git a/drivers/media/video/mrstci/mrstisp/mrv_res.c b/drivers/media/video/mrstci/mrstisp/mrv_res.c new file mode 100644 index 0000000..a1fab25 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_res.c @@ -0,0 +1,350 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "reg_access.h" +#include "mrv_priv.h" + +#define RSZ_FLAGS_MASK (RSZ_UPSCALE_ENABLE | RSZ_SCALER_BYPASS) + +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); + int upscaling = false; + + /* horizontal luminance scale factor */ + DBG_DD(("ci_isp_res_set_main_resize, hy %d,%x\n", 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 { + REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_ENABLE, ENABLE); + 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) { + DBG_DD(("enable up scale\n")); + REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_UP, + MRV_MRSZ_SCALE_HY_UP_UPSCALE); + upscaling = true; + } else { + REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HY_UP, + MRV_MRSZ_SCALE_HY_UP_DOWNSCALE); + } + } + + /* horizontal chrominance scale factors */ + ASSERT((scale->scale_hcb & RSZ_FLAGS_MASK) == + (scale->scale_hcr & RSZ_FLAGS_MASK)); + DBG_DD(("ci_isp_res_set_main_resize, hcb %d,%x\n", 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 { + 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) { + REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_UP, + MRV_MRSZ_SCALE_HC_UP_UPSCALE); + /* scaler and upscaling enabled */ + upscaling = true; + } else { + REG_SET_SLICE(mrsz_ctrl, MRV_MRSZ_SCALE_HC_UP, + MRV_MRSZ_SCALE_HC_UP_DOWNSCALE); + } + } + + /* vertical luminance scale factor */ + DBG_DD(("ci_isp_res_set_main_resize, Vy %d,%x\n", 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 */ + DBG_DD(("ci_isp_res_set_main_resize, Vc %d,%x\n", + 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) { + u32 i; + 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) { + ASSERT("ci_isp_res_set_main_resize()" == + "Upscaling requires lookup table!"); + } + + /* handle immediate update flag and write mrsz_ctrl */ + switch (update_time) { + case CI_ISP_CFG_UPDATE_FRAME_SYNC: + 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: + 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: + 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); + int upscaling = false; + + /* flags must be "outside" scaler value */ + ASSERT((RSZ_FLAGS_MASK & MRV_RSZ_SCALE_MASK) == 0); + ASSERT((scale->scale_hy & ~RSZ_FLAGS_MASK) <= + MRV_RSZ_SCALE_MAX); + ASSERT((scale->scale_hcb & ~RSZ_FLAGS_MASK) <= + MRV_RSZ_SCALE_MAX); + ASSERT((scale->scale_hcr & ~RSZ_FLAGS_MASK) <= + MRV_RSZ_SCALE_MAX); + ASSERT((scale->scale_vy & ~RSZ_FLAGS_MASK) <= + MRV_RSZ_SCALE_MAX); + ASSERT((scale->scale_vc & ~RSZ_FLAGS_MASK) <= + MRV_RSZ_SCALE_MAX); + + /* horizontal luminance scale factor */ + DBG_DD(("ci_isp_res_set_self_resize, hy %d,%x\n", scale->scale_hy, + scale->scale_hy)); + + if (scale->scale_hy & RSZ_SCALER_BYPASS) { + /* disable (bypass) scaler */ + 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 */ + ASSERT((scale->scale_hcb & RSZ_FLAGS_MASK) == + (scale->scale_hcr & RSZ_FLAGS_MASK)); + + DBG_DD(("ci_isp_res_set_self_resize, hcb %d,%x\n", 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); + /* program scale factor and phase */ + + 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); + /* scaler and upscaling enabled */ + upscaling = true; + } else { + REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_HC_UP, + MRV_SRSZ_SCALE_HC_UP_DOWNSCALE); + } + } + + /* vertical luminance scale factor */ + DBG_DD(("ci_isp_res_set_self_resize, vy %d,%x\n", 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); + /* program scale factor and phase */ + + 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) + /* enable upscaling mode */ + { + REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_UP, + MRV_SRSZ_SCALE_VY_UP_UPSCALE); + /* scaler and upscaling enabled */ + upscaling = true; + } else + /* disable upscaling mode */ + { + REG_SET_SLICE(srsz_ctrl, MRV_SRSZ_SCALE_VY_UP, + MRV_SRSZ_SCALE_VY_UP_DOWNSCALE); + } + + } + + /* vertical chrominance scale factor */ + DBG_DD(("ci_isp_res_set_self_resize, vc %d,%x\n", 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); + /* program scale factor and phase */ + + 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); + /* scaler and upscaling enabled */ + 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) { + u32 i; + 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) { + ASSERT("ci_isp_res_set_self_resize()" == + "Upscaling requires lookup table!"); + } + + + /* handle immediate update flag and write mrsz_ctrl */ + switch (update_time) { + case CI_ISP_CFG_UPDATE_FRAME_SYNC: + 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: + 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: + REG_WRITE(mrv_reg->srsz_ctrl, srsz_ctrl); + break; + } +} diff --git a/drivers/media/video/mrstci/mrstisp/mrv_sls_bp.c b/drivers/media/video/mrstci/mrstisp/mrv_sls_bp.c new file mode 100644 index 0000000..8681dce --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_sls_bp.c @@ -0,0 +1,83 @@ +/* + * 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 + */ + +#include "stdinc.h" +static struct ci_sensor_bp_table bp_table = { 0 }; + +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 + 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; +} + +int ci_bp_end(const struct ci_isp_bp_corr_config *bp_corr_config) +{ + int uiResult = CI_STATUS_SUCCESS; + + if (!bp_corr_config) + return CI_STATUS_NULL_POINTER; + + uiResult |= ci_isp_set_bp_correction(NULL); + uiResult |= ci_isp_set_bp_detection(NULL); + + if (bp_corr_config->bp_corr_type == CI_ISP_BP_CORR_TABLE) { + uiResult |= ci_isp_clear_bp_int(); + kfree(bp_table.bp_table_elem); + bp_table.bp_table_elem = NULL; + } + return uiResult; +} + diff --git a/drivers/media/video/mrstci/mrstisp/mrv_sls_dp.c b/drivers/media/video/mrstci/mrstisp/mrv_sls_dp.c new file mode 100644 index 0000000..4a800d3 --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_sls_dp.c @@ -0,0 +1,1146 @@ +/* + * 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 + */ + +#include "stdinc.h" +#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 +#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 + +/* 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 + } +}; + +/* 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; + +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); + + } + return RSZ_SCALER_BYPASS; +} + +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_inW; + u16 chroma_inH; + u16 chroma_outWCR; + u16 chroma_outWCB; + u16 chroma_outH; + + memset(scale, 0, sizeof(struct ci_isp_scale)); + 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; + } + + if (implementation == MARVIN_FEATURE_SCALEFACTOR_SEPARATED_UV) { + switch (scaler_input_format) { + case CI_ISP_DPD_DMA_IN_422: + chroma_inW = source->out_w / 2; + chroma_inH = source->out_h; + chroma_outWCR = path->out_w / 2; + chroma_outWCB = (path->out_w + 1) / 2; + chroma_outH = path->out_h; + break; + case CI_ISP_DPD_DMA_IN_420: + chroma_inW = source->out_w / 2; + chroma_inH = source->out_h / 2; + chroma_outWCR = path->out_w / 2; + chroma_outWCB = (path->out_w + 1) / 2; + chroma_outH = path->out_h / 2; + break; + case CI_ISP_DPD_DMA_IN_411: + chroma_inW = source->out_w / 4; + chroma_inH = source->out_h; + chroma_outWCR = path->out_w / 4; + chroma_outWCB = (path->out_w + 2) / 4; + chroma_outH = path->out_h; + break; + case CI_ISP_DPD_DMA_IN_444: + default: + chroma_inW = source->out_w; + chroma_inH = source->out_h; + chroma_outWCB = chroma_outWCR = path->out_w; + chroma_outH = path->out_h; + break; + } + } else { + ASSERT(implementation == + MARVIN_FEATURE_SCALEFACTOR_COMBINED_UV); + ASSERT(scaler_input_format == CI_ISP_DPD_DMA_IN_422); + chroma_inW = source->out_w; + chroma_inH = source->out_h; + chroma_outWCB = chroma_outWCR = path->out_w; + chroma_outH = path->out_h; + } + + /* calculate chrominance scale factors */ + switch (path->flags & CI_ISP_DPD_CSS_H_MASK) { + case CI_ISP_DPD_CSS_H2: + chroma_outWCB /= 2; + chroma_outWCR /= 2; + break; + case CI_ISP_DPD_CSS_H4: + chroma_outWCB /= 4; + chroma_outWCR /= 4; + break; + case CI_ISP_DPD_CSS_HUP2: + chroma_outWCB *= 2; + chroma_outWCR *= 2; + break; + case CI_ISP_DPD_CSS_HUP4: + chroma_outWCB *= 4; + chroma_outWCR *= 4; + break; + default: + /*leave chroma_outW untouched*/ + break; + } + scale->scale_hcr = ci_get_scale_reg(chroma_inW, chroma_outWCR); + scale->scale_hcb = ci_get_scale_reg(chroma_inW, chroma_outWCB); + scale->scale_hcb = scale->scale_hcr; + switch (path->flags & CI_ISP_DPD_CSS_V_MASK) { + case CI_ISP_DPD_CSS_V2: + chroma_outH /= 2; + break; + case CI_ISP_DPD_CSS_V4: + chroma_outH /= 4; + break; + case CI_ISP_DPD_CSS_VUP2: + chroma_outH *= 2; + break; + case CI_ISP_DPD_CSS_VUP4: + chroma_outH *= 4; + break; + default: + /* leave chroma_outH untouched */ + break; + } + scale->scale_vc = ci_get_scale_reg(chroma_inH, chroma_outH); + + /* 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)) + scaler_output_format = scaler_input_format; + else { + /* 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; +} + +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; +} + +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; + + PRE_CONDITION(source != NULL); + PRE_CONDITION(scale_main != NULL); + PRE_CONDITION(mrv_mi_ctrl != NULL); + + /* assume datapath deactivation if no selfpath pointer is given) */ + if (main) + main_flag = main->flags; + else + main_flag = 0; + + 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: + DBG_OUT((DERR, + "ERR: unsupported mode for main path\n")); + return CI_STATUS_NOTSUPP; + } + if (0 /* main_flag & CI_ISP_DPD_HWRGB_MASK*/) { + DBG_OUT((DERR, + "ERR: not supported for main path\n")); + return CI_STATUS_NOTSUPP; + } + if (main_flag & (CI_ISP_DPD_H_FLIP | CI_ISP_DPD_V_FLIP | + CI_ISP_DPD_90DEG_CCW)) { + DBG_OUT((DERR, + "ERR: not supported for main path\n")); + return CI_STATUS_NOTSUPP; + } + if (main_flag & CI_ISP_DPD_NORESIZE) { + if (main_flag & CI_ISP_DPD_CSS_MASK) { + DBG_OUT((DERR, + "ERR: main path needs rezizer\n")); + return CI_STATUS_NOTSUPP; + } + if (main_flag & + (CI_ISP_DPD_LUMA_HSHIFT | CI_ISP_DPD_LUMA_VSHIFT)) { + DBG_OUT((DERR, + "ERR: main path needs rezizer\n")); + return CI_STATUS_NOTSUPP; + } + } else { + if ((mrv_mi_ctrl->main_path == CI_ISP_PATH_RAW8) + || (mrv_mi_ctrl->main_path == CI_ISP_PATH_RAW8)) { + DBG_OUT((DERR, + "ERR: scaler not in RAW mode\n")); + return CI_STATUS_NOTSUPP; + } + if (main != NULL) { + DBG_DD(("xiaolin, here to main resize\n")); + if ((((u32) (source->out_w) * + MAIN_UPSCALE_FACTOR_MAX) < main->out_w) + || + (((u32) (source->out_h) * + MAIN_UPSCALE_FACTOR_MAX) < + main->out_h)) { + DBG_OUT((DERR, + "ERR: : main upscaling exceeded\n")); + return CI_STATUS_NOTSUPP; + } + if ((main->out_w > + MAIN_SCALER_WIDTH_MAX) + || (main->out_w < SCALER_MIN) + || (main->out_h < SCALER_MIN)) { + DBG_OUT((DERR, + "ERR: : main scaler ange exceeded\n")); + return CI_STATUS_NOTSUPP; + } + } else { + ASSERT(main != NULL); + } + + if (source->out_w & 0x01) { + DBG_OUT((DERR, + "ERR: input width must be even!(is %hu)\n", + source->out_w)); + return CI_STATUS_NOTSUPP; + } + + /* calculate scale factors. */ + DBG_DD(("ci_calc_main_path_settings\n")); + (void)ci_calc_scale_factors(source, main, + scale_main, + MARVIN_FEATURE_MSCALE_FACTORCALC); + } + } else { + mrv_mi_ctrl->main_path = CI_ISP_PATH_OFF; + } + + /* hardcoded MI settings */ + DBG_DD(("*** main_flag is 0x%x\n", 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; + + PRE_CONDITION(source != NULL); + PRE_CONDITION(scale_flag != NULL); + PRE_CONDITION(mrv_mi_ctrl != NULL); + + /* assume datapath deactivation if no selfpath pointer is given) */ + if (self) + self_flag = self->flags; + else + self_flag = 0; + 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: + DBG_OUT((DERR, + "ERR: unsupported mode for self path\n")); + return CI_STATUS_NOTSUPP; + } + + if (self_flag & CI_ISP_DPD_NORESIZE) { + if (self_flag & CI_ISP_DPD_CSS_MASK) { + DBG_OUT((DERR, + "ERR: in self path needs rezizer\n")); + return CI_STATUS_NOTSUPP; + } + if (self_flag & + (CI_ISP_DPD_LUMA_HSHIFT | CI_ISP_DPD_LUMA_VSHIFT)) { + DBG_OUT((DERR, + "ERR: n self path needs rezizer\n")); + return CI_STATUS_NOTSUPP; + } + if (self != NULL) { + if ((source->out_w != self->out_w) || + (source->out_h != self->out_h)) { + DBG_OUT((DERR, + "ERR: sizes needs resizer\n")); + return CI_STATUS_NOTSUPP; + } + } else { + ASSERT(self != NULL); + } + } else { + if (self != NULL) { + if ((((u32) (source->out_w) * + SELF_UPSCALE_FACTOR_MAX) < + self->out_w) + || + (((u32) (source->out_h) * + SELF_UPSCALE_FACTOR_MAX) < + self->out_h)) { + DBG_OUT((DERR, + "ERR: apability exceeded\n")); + return CI_STATUS_NOTSUPP; + } + if ((self->out_w > + SELF_SCALER_WIDTH_MAX) + || (self->out_w < SCALER_MIN) + || (self->out_h < SCALER_MIN)) { + DBG_OUT((DERR, + "ERR: out range exceeded\n")); + return CI_STATUS_NOTSUPP; + } + } else { + ASSERT(self != NULL); + } + + if (source->out_w & 0x01) { + DBG_OUT((DERR, + "ERR: width must be even! (is %hu)\n", + source->out_w)); + return CI_STATUS_NOTSUPP; + } + + /* calculate scale factors. */ + scaler_out_col_format = + ci_calc_scale_factors(source, self, scale_flag, + 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; + /* no break, does not seem to be supported by HW */ + case CI_ISP_DPD_DMA_IN_411: + default: + DBG_OUT((DERR, + "ERR: input color format not supported\n")); + return CI_STATUS_NOTSUPP; + } + + 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; + DBG_DD(("CI_ISP_MIF_COL_FORMAT_RGB_888\n")); + 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: + DBG_OUT((DERR, + "ERR: output color format not supported\n")); + return CI_STATUS_NOTSUPP; + } + + 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; +} + +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) { + DBG_OUT((DERR, + "ERR: ombined with RAW mode of main path\n")); + 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: + ASSERT(0); + + } + + return CI_STATUS_SUCCESS; +} + +#define ISPWND_COMBINE_WNDS 0x00000001 +#define ISPWND_APPLY_OUTFORM 0x00000002 +#define ISPWND_APPLY_ISCONF 0x00000004 +#define ISPWND_NO_CROPPING 0x00000008 + +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; +} + +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)); + + isp_path = ci_isp_select_path(isi_sensor_config, NULL); + if (isp_path == CI_ISP_PATH_UNKNOWN) { + DBG_OUT((DERR, + "failed to detect marvin ISP path to use\n")); + return CI_STATUS_NOTSUPP; + } + + wnd_style = ci_get_isp_wnd_style(isp_path); + if (wnd_style & ISPWND_NO_CROPPING) { + u16 isiX; + u16 isiY; + (void)ci_sensor_res2size(isi_sensor_config->res, &isiX, + &isiY); + if ((wnd_zoom_crop->hsize != isiX) + || (wnd_zoom_crop->vsize != isiY) + || (wnd_zoom_crop->hoffs != 0) + || (wnd_zoom_crop->voffs != 0)) { + DBG_OUT((DERR, + "not supported in selected ISP data path\n")); + return CI_STATUS_NOTSUPP; + } + if ((wnd_blackline->hsize != isiX) || + (wnd_blackline->vsize != isiY) || + (wnd_blackline->hoffs != 0) || + (wnd_blackline->voffs != 0)) { + DBG_OUT((DERR, + " not supported in selected ISP data path\n")); + return CI_STATUS_NOTSUPP; + } + } + + 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) { + /* combine both blackline and zoom/crop window */ + 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) { + is_conf.mrv_is_window.hoffs = 0; + is_conf.mrv_is_window.voffs = 0; + } + } else { + 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) { + DBG_OUT((DERR, + "ERR: set image stabilization config\n")); + 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; +} + +static int ci_ext_ycb_cr_mode(const struct ci_isp_datapath_desc *path) +{ + + u32 main_flag; + + PRE_CONDITION(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_isp_datapath_desc *main, + const struct ci_isp_datapath_desc *self, int zoom) +{ + /* return value of several sub-functions called from here */ + int res; + u32 main_flag; + u32 self_flag; + /* resolution from sensor configuration */ + u16 isiX; + u16 isiY; + const struct ci_isp_datapath_desc *target = NULL; + + /* things to apply to MARVIN */ + 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; + /* ISP windowing because of cutting away blacklines from the sensor */ + struct ci_isp_window wnd_blackline; + /* ISP windowing because of aspect ratio change and/or zoom */ + struct ci_isp_window wnd_zoom_crop; + + /* assume dapapath deactivation for not provided descriptors */ + main_flag = 0; + self_flag = 0; + if (main) + main_flag = main->flags; /* 0x012 */ + + if (self) + self_flag = self->flags; /* 0x10015 */ + + /* initialize variables on the stack */ + res = CI_STATUS_SUCCESS; + (void)ci_sensor_res2size(sys_conf->isi_config->res, &isiX, &isiY); + 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)); + + wnd_blackline.hsize = isiX; + wnd_blackline.vsize = isiY; + wnd_zoom_crop = wnd_blackline; + + 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) { + DBG_OUT((DERR, + "ERR: only allowed for one path\n")); + return CI_STATUS_NOTSUPP; + } + target = self; + } + + /* if so, calculate the cropping */ + if (target) { + u32 aspect_cam = + (0x1000 * ((u32) isiX)) / isiY; + u32 aspect_target = + (0x1000 * ((u32) (target->out_w))) / + target->out_h; + if (aspect_cam < aspect_target) { + wnd_zoom_crop.vsize = + (u16) (((u32) isiX * + (u32) (target-> + out_h)) / + target->out_w); + } else { + wnd_zoom_crop.hsize = + (u16) (((u32) isiY * + (u32) (target-> + out_w)) / + target->out_h); + } + } + + 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)); + } + + wnd_zoom_crop.hsize &= ~0x01; + wnd_zoom_crop.hoffs = (isiX - wnd_zoom_crop.hsize) / 2; + wnd_zoom_crop.voffs = (isiY - wnd_zoom_crop.vsize) / 2; + + switch (sys_conf->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: + DBG_OUT((DERR, + "black sensor config\n")); + return CI_STATUS_NOTSUPP; + } + + if (sys_conf->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))) { + DBG_OUT((DERR, + "in main and self path\n")); + 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; + + 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: + DBG_OUT((DERR, + "supported for data coming from the ISP\n")); + return CI_STATUS_NOTSUPP; + } + } + + 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.fYCbCrNonCosited) + mrv_mi_ctrl.mrv_mif_spInPhase = mrv_mif_col_Phase_Non_Cosited; + else + mrv_mi_ctrl.mrv_mif_spInPhase = mrv_mif_col_Phase_Cosited; + if (sys_conf->isp_cfg->flags.fYCbCrFullRange) + mrv_mi_ctrl.mrv_mif_spInRange = mrv_mif_col_Range_Full; + else + mrv_mi_ctrl.mrv_mif_spInRange = 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: + /* only allowed case, just proceed */ + break; + default: + DBG_OUT((DERR, + "supported for data coming from the ISP\n")); + 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; + + mrv_mi_ctrl.byte_swap_enable = false; + mrv_mi_ctrl.init_vals = CI_ISP_MIF_INIT_OFFSAndBase; + + res = ci_set_isp_windows(sys_conf->isi_config, &wnd_blackline, + &wnd_zoom_crop); + if (res != CI_STATUS_SUCCESS) { + DBG_OUT((DERR, + "ERR: failed to set ISP window configuration\n")); + 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(sys_conf->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)); + + ci_isp_set_dma_read_mode(CI_ISP_DMA_RD_OFF, + CI_ISP_CFG_UPDATE_IMMEDIATE); + + res = ci_isp_mif__set_path_and_orientation(&mrv_mi_ctrl); + if (res != CI_STATUS_SUCCESS) { + DBG_OUT((DERR, + "ERR: failed to set MI path and orientation\n")); + return res; + } + + /* here the extended YCbCr mode is configured */ + if (sys_conf->isp_cfg->flags.fYCbCrFullRange) + res = ci_ext_ycb_cr_mode(main); + else + (void)ci_isp_set_yc_mode(); + + if (res != CI_STATUS_SUCCESS) { + DBG_OUT((DERR, + "ERR: failed to set ISP YCbCr extended mode\n")); + return res; + } + return CI_STATUS_SUCCESS; +} + diff --git a/drivers/media/video/mrstci/mrstisp/mrv_sls_jpe.c b/drivers/media/video/mrstci/mrstisp/mrv_sls_jpe.c new file mode 100644 index 0000000..6bb0d4b --- /dev/null +++ b/drivers/media/video/mrstci/mrstisp/mrv_sls_jpe.c @@ -0,0 +1,53 @@ +/* + * 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 + */ + +#include "stdinc.h" +#include "mrv_priv.h" + +u32 ci_jpe_capture(enum ci_isp_conf_update_time update_time) +{ + int retval = CI_STATUS_SUCCESS; + + /* generate header */ + retval = ci_isp_jpe_generate_header(MRV_JPE_HEADER_MODE_JFIF); + if (retval != CI_STATUS_SUCCESS) + return 0; + + /* now encode JPEG */ + retval = ci_jpe_encode(update_time, CI_ISP_JPE_SINGLE_SHOT); + if (retval != CI_STATUS_SUCCESS) + return 0; + return ci_isp_mif_get_byte_cnt(); +} + +int ci_jpe_encode(enum ci_isp_conf_update_time update_time, + enum ci_isp_jpe_enc_mode mrv_jpe_encMode) +{ + ci_isp_jpe_prep_enc(mrv_jpe_encMode); + /* start Marvin for 1 frame to capture */ + ci_isp_start(1, update_time); + return ci_isp_jpe_wait_for_encode_done(); +} +