[COMMON] fimc-is2: Added new file and functions to support cac
authorSunmi Lee <carrotsm.lee@samsung.com>
Tue, 3 Jul 2018 00:31:28 +0000 (09:31 +0900)
committerSunyoung Kang <sy0816.kang@samsung.com>
Mon, 23 Jul 2018 08:06:09 +0000 (17:06 +0900)
CAC function is controlled by noise_index (this value from ISP).
So it is needed to calculate the proper value with using linear interpolation by noise_index.
To support uvsp and cac function, new source file was added.
Of course, the Makefile and Kconfig is also modified.

PR JIRA ID: CPR-25

Change-Id: Iafe7e6631d2ba2a42942e9d4f0370ea571ae70c8
Signed-off-by: Sunmi Lee <carrotsm.lee@samsung.com>
drivers/media/platform/exynos/fimc-is2/hardware/Makefile
drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v2.h
drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v5_0.c
drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.c
drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.h
drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.c [new file with mode: 0644]
drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.h

index 92b77c52137e818e55e9fdbe14c6f55fce4b55e0..1062b9c8dbe635036d599333c0bfe52addfacd44 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_CAMERA_FIMC_SCALER_USE) += fimc-is-hw-scp.o
 obj-$(CONFIG_CAMERA_MC_SCALER_VER1_USE) += fimc-is-hw-mcscaler-v1.o
 obj-$(CONFIG_CAMERA_MC_SCALER_VER2_USE) += fimc-is-hw-mcscaler-v2.o
 obj-$(CONFIG_CAMERA_MC_SCALER_VER2_USE) += fimc-is-hw-djag.o
+obj-$(CONFIG_CAMERA_MC_SCALER_VER2_USE) += fimc-is-hw-uvsp-cac.o
 ifeq ($(CONFIG_CAMERA_MC_SCALER_VER2_USE),y)
 obj-$(CONFIG_CAMERA_TDNR_VER1_USE) += fimc-is-hw-tdnr-v1.o
 obj-$(CONFIG_CAMERA_TDNR_VER2_USE) += fimc-is-hw-tdnr-v2.o
index 9cb77345d479d4e0af78830f5aea10ccb1807f66..06ee3d14e7cc8f37422200ca0b850a088af015b7 100644 (file)
@@ -226,6 +226,11 @@ void fimc_is_scaler_set_djag_init_phase_offset(void __iomem *base_addr, u32 h_of
 void fimc_is_scaler_set_djag_round_mode(void __iomem *base_addr, u32 round_enable);
 void fimc_is_scaler_set_djag_tunning_param(void __iomem *base_addr, const struct djag_setfile_contents *djag_tune);
 
+/* cac */
+void fimc_is_scaler_set_cac_enable(void __iomem *base_addr, u32 en);
+void fimc_is_scaler_set_cac_input_source(void __iomem *base_addr, u32 in);
+void fimc_is_scaler_set_cac_map_crt_thr(void __iomem *base_addr, struct cac_cfg_by_ni *cfg);
+
 /* ysum */
 void fimc_is_scaler_set_ysum_input_sourece_enable(void __iomem *base_addr, u32 output_id, bool ysum_enable);
 void fimc_is_scaler_set_ysum_enable(void __iomem *base_addr, bool ysum_enable);
index 1fb339c87dcdda512290121192ffb09c18e4e865..ed166e773f620bc24ae65f3b104e0dda50c9a312 100644 (file)
@@ -3499,6 +3499,50 @@ void fimc_is_scaler_set_djag_tunning_param(void __iomem *base_addr, const struct
        fimc_is_hw_set_reg(base_addr, &mcsc_regs[MCSC_R_DJAG_CP_ARBI], reg_val);
 }
 
+/* for CAC */
+void fimc_is_scaler_set_cac_enable(void __iomem *base_addr, u32 en)
+{
+       u32 reg_val = 0;
+
+       reg_val = fimc_is_hw_get_reg(base_addr, &mcsc_regs[MCSC_R_CAC_CTRL]);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_ENABLE], en);
+       fimc_is_hw_set_reg(base_addr, &mcsc_regs[MCSC_R_CAC_CTRL], reg_val);
+}
+
+void fimc_is_scaler_set_cac_input_source(void __iomem *base_addr, u32 in)
+{
+       u32 reg_val = 0;
+
+       reg_val = fimc_is_hw_get_reg(base_addr, &mcsc_regs[MCSC_R_CAC_CTRL]);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_INPUT_SEL], in);
+       fimc_is_hw_set_reg(base_addr, &mcsc_regs[MCSC_R_CAC_CTRL], reg_val);
+}
+
+void fimc_is_scaler_set_cac_map_crt_thr(void __iomem *base_addr, struct cac_cfg_by_ni *cfg)
+{
+       u32 reg_val = 0;
+
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_MAP_SPOT_THR_L],
+                       cfg->map_thr_cfg.map_spot_thr_l);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_MAP_SPOT_THR_H],
+                       cfg->map_thr_cfg.map_spot_thr_h);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_MAP_SPOT_THR],
+                       cfg->map_thr_cfg.map_spot_thr);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_MAP_SPOT_NR_STRENGTH],
+                       cfg->map_thr_cfg.map_spot_nr_strength);
+       fimc_is_hw_set_reg(base_addr, &mcsc_regs[MCSC_R_CAC_MAP_THR], reg_val);
+
+
+       reg_val = 0;
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_CRT_COLOR_THR_L_DOT],
+                       cfg->crt_thr_cfg.crt_color_thr_l_dot);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_CRT_COLOR_THR_L_LINE],
+                       cfg->crt_thr_cfg.crt_color_thr_l_line);
+       reg_val = fimc_is_hw_set_field_value(reg_val, &mcsc_fields[MCSC_F_CAC_CRT_COLOR_THR_H],
+                       cfg->crt_thr_cfg.crt_color_thr_h);
+       fimc_is_hw_set_reg(base_addr, &mcsc_regs[MCSC_R_CAC_CRT_THR], reg_val);
+}
+
 /* DS */
 void fimc_is_scaler_set_ds_enable(void __iomem *base_addr, u32 ds_enable)
 {
index a7550ae4fbbf19ae8e707e6b3c2054db2f6c27ed..2144192817b717ced4ff0d3f4318a0ee89bce364 100644 (file)
@@ -832,6 +832,7 @@ config:
 
        ret_internal = fimc_is_hw_mcsc_update_dsvra_register(hw_ip, head, mcs_param, instance, frame->shot);
        ret_internal = fimc_is_hw_mcsc_update_tdnr_register(hw_ip, frame, param, start_flag);
+       ret_internal = fimc_is_hw_mcsc_update_cac_register(hw_ip, frame, instance);
        ret_internal = fimc_is_hw_mcsc_update_ysum_register(hw_ip, head, mcs_param, instance, frame->shot);
        if (ret_internal) {
                msdbg_hw(2, "ysum cfg is failed\n", instance, hw_ip);
index 76a6299ceeff6733a6e9e199e9935ccead3ad462..93ab9636f25c6bce387b89bca34b3cbfaca674b2 100644 (file)
@@ -116,7 +116,7 @@ struct hw_mcsc_setfile {
         */
        struct djag_setfile_contents    djag[MAX_SCALINGRATIOINDEX_DEPENDED_CONFIGS];
 #endif
-#if (MCSC_USE_TUNING_PARAM_VER >= 0x14027432)
+#if defined(USE_UVSP_CAC)
        struct scaler_bchs_clamp_cfg    sc_bchs[2];     /* 0: YUV_FULL, 1: YUV_NARROW */
        struct scaler_coef_cfg          sc_coef;
        struct djag_wb_thres_cfg        djag_wb[MAX_SCALINGRATIOINDEX_DEPENDED_CONFIGS];
@@ -151,6 +151,7 @@ struct fimc_is_hw_mcsc_cap {
        bool                    enable_shared_output;
        enum mcsc_cap_enum      tdnr;
        enum mcsc_cap_enum      djag;
+       enum mcsc_cap_enum      cac;
        enum mcsc_cap_enum      ysum;
        enum mcsc_cap_enum      ds_vra;
 };
@@ -180,6 +181,9 @@ struct fimc_is_hw_mcsc {
        enum yic_mode           yic_en;
        struct tdnr_configs     tdnr_cfgs;
 
+       /* for CAC*/
+       u32                     cac_in;
+
        /* for Djag */
        u32                     djag_in;
 
@@ -244,6 +248,8 @@ void fimc_is_hw_mcsc_adjust_size_with_djag(struct fimc_is_hw_ip *hw_ip, struct p
 int fimc_is_hw_mcsc_update_djag_register(struct fimc_is_hw_ip *hw_ip,
                struct mcs_param *param,
                u32 instance);
+int fimc_is_hw_mcsc_update_cac_register(struct fimc_is_hw_ip *hw_ip,
+       struct fimc_is_frame *frame, u32 instance);
 int fimc_is_hw_mcsc_update_ysum_register(struct fimc_is_hw_ip *hw_ip,
        struct fimc_is_group *head, struct mcs_param *mcs_param,
        u32 instance, struct camera2_shot *shot);
diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.c b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.c
new file mode 100644 (file)
index 0000000..1b768e7
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Samsung EXYNOS FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#include "fimc-is-hw-mcscaler-v2.h"
+#include "api/fimc-is-hw-api-mcscaler-v2.h"
+#include "../interface/fimc-is-interface-ischain.h"
+#include "fimc-is-param.h"
+#include "fimc-is-err.h"
+
+/* NI from DDK needs to adjust scale factor (by multipling 10) */
+#define MULTIPLIED_10(value)           (10 * (value))
+#define INTRPL_SHFT_VAL                        (12)
+#define SUB(a, b)              (u32)(((a) - (b)) > 0 ? ((a) - (b)) : ((b) - (a)))
+#define LSHFT(a)               ((int)((a) << INTRPL_SHFT_VAL))
+#define RSHFT(a)               ((int)((a) >> INTRPL_SHFT_VAL))
+#define NUMERATOR(Y1, Y2, DXn)                 (((Y2) - (Y1)) * (DXn))
+#define CALC_LNR_INTRPL(Y1, Y2, X1, X2, X)     (LSHFT(NUMERATOR(Y1, Y2, SUB(X, X1))) / SUB(X2, X1) + LSHFT(Y1))
+#define GET_LNR_INTRPL(Y1, Y2, X1, X2, X)      RSHFT(CALC_LNR_INTRPL(Y1, Y2, X1, X2, X))
+
+struct ref_ni {
+       u32 min;
+       u32 max;
+};
+
+struct ref_ni hw_mcsc_find_ni_idx_for_cac(struct fimc_is_hw_ip *hw_ip,
+       struct cac_setfile_contents *cac, u32 cur_ni)
+{
+       struct ref_ni ret_idx = {0, 0};
+       struct ref_ni ni_idx_range;
+       u32 ni_idx;
+
+       for (ni_idx = 0; ni_idx < cac->ni_max - 1; ni_idx++) {
+               ni_idx_range.min = MULTIPLIED_10(cac->ni_vals[ni_idx]);
+               ni_idx_range.max = MULTIPLIED_10(cac->ni_vals[ni_idx + 1]);
+
+               if (ni_idx_range.min < cur_ni && cur_ni < ni_idx_range.max) {
+                       ret_idx.min = ni_idx;
+                       ret_idx.max = ni_idx + 1;
+                       break;
+               } else if (cur_ni == ni_idx_range.min) {
+                       ret_idx.min = ni_idx;
+                       ret_idx.max = ni_idx;
+                       break;
+               } else if (cur_ni == ni_idx_range.max) {
+                       ret_idx.min = ni_idx + 1;
+                       ret_idx.max = ni_idx + 1;
+                       break;
+               }
+       }
+
+       sdbg_hw(10, "TEST: get_lnr_intprl(11, 20, 1, 10, 3) = %d\n",
+                       hw_ip, GET_LNR_INTRPL(11, 20, 1, 10, 3));
+
+       sdbg_hw(2, "[CAC] find_ni_idx: cur_ni(%d), ni[%d, %d], idx[%d, %d]\n", hw_ip,
+               cac->ni_vals[ret_idx.min], cac->ni_vals[ret_idx.max],
+               ret_idx.min, ret_idx.max);
+
+       return ret_idx;
+}
+
+void hw_mcsc_calc_cac_map_thr(struct cac_cfg_by_ni *cac_cfg,
+       struct cac_cfg_by_ni *cfg_min, struct cac_cfg_by_ni *cfg_max,
+       struct ref_ni *ni_idx, u32 cur_ni)
+{
+       struct cac_map_thr_cfg *min, *max;
+
+       min = &cfg_min->map_thr_cfg;
+       max = &cfg_max->map_thr_cfg;
+
+       cac_cfg->map_thr_cfg.map_spot_thr_l = GET_LNR_INTRPL(
+                       min->map_spot_thr_l, max->map_spot_thr_l,
+                       ni_idx->min, ni_idx->max, cur_ni);
+       cac_cfg->map_thr_cfg.map_spot_thr_h = GET_LNR_INTRPL(
+                       min->map_spot_thr_h, max->map_spot_thr_h,
+                       ni_idx->min, ni_idx->max, cur_ni);
+       cac_cfg->map_thr_cfg.map_spot_thr = GET_LNR_INTRPL(
+                       min->map_spot_thr, max->map_spot_thr,
+                       ni_idx->min, ni_idx->max, cur_ni);
+       cac_cfg->map_thr_cfg.map_spot_nr_strength = GET_LNR_INTRPL(
+                       min->map_spot_nr_strength, max->map_spot_nr_strength,
+                       ni_idx->min, ni_idx->max, cur_ni);
+
+}
+
+void hw_mcsc_calc_cac_crt_thr(struct cac_cfg_by_ni *cac_cfg,
+       struct cac_cfg_by_ni *cfg_min, struct cac_cfg_by_ni *cfg_max,
+       struct ref_ni *ni_idx, u32 cur_ni)
+{
+       struct cac_crt_thr_cfg *min, *max;
+
+       min = &cfg_min->crt_thr_cfg;
+       max = &cfg_max->crt_thr_cfg;
+
+       cac_cfg->crt_thr_cfg.crt_color_thr_l_dot = GET_LNR_INTRPL(
+                       min->crt_color_thr_l_dot, max->crt_color_thr_l_dot,
+                       ni_idx->min, ni_idx->max, cur_ni);
+       cac_cfg->crt_thr_cfg.crt_color_thr_l_line = GET_LNR_INTRPL(
+                       min->crt_color_thr_l_line, max->crt_color_thr_l_line,
+                       ni_idx->min, ni_idx->max, cur_ni);
+       cac_cfg->crt_thr_cfg.crt_color_thr_h = GET_LNR_INTRPL(
+                       min->crt_color_thr_h, max->crt_color_thr_h,
+                       ni_idx->min, ni_idx->max, cur_ni);
+}
+
+void hw_mcsc_calc_cac_param_by_ni(struct fimc_is_hw_ip *hw_ip,
+       struct cac_setfile_contents *cac, u32 cur_ni)
+{
+       struct ref_ni ni_range, ni_idx;
+       struct cac_cfg_by_ni cac_cfg, cfg_max, cfg_min;
+
+       ni_range.min = MULTIPLIED_10(cac->ni_vals[0]);
+       ni_range.max = MULTIPLIED_10(cac->ni_vals[cac->ni_max - 1]);
+
+       if (cur_ni <= ni_range.min) {
+               sdbg_hw(2, "[CAC] cur_ni(%d) <= ni_range.min(%d)\n", hw_ip, cur_ni, ni_range.min);
+               ni_idx.min = 0;
+               ni_idx.max = 0;
+       } else if (cur_ni >= ni_range.max) {
+               sdbg_hw(2, "[CAC] cur_ni(%d) >= ni_range.max(%d)\n", hw_ip, cur_ni, ni_range.max);
+               ni_idx.min = cac->ni_max - 1;
+               ni_idx.max = cac->ni_max - 1;
+       } else {
+               ni_idx = hw_mcsc_find_ni_idx_for_cac(hw_ip, cac, cur_ni);
+       }
+
+       cfg_min = cac->cfgs[ni_idx.min];
+       cfg_max = cac->cfgs[ni_idx.max];
+       hw_mcsc_calc_cac_map_thr(&cac_cfg, &cfg_min, &cfg_max, &ni_idx, cur_ni);
+       hw_mcsc_calc_cac_crt_thr(&cac_cfg, &cfg_min, &cfg_max, &ni_idx, cur_ni);
+
+       fimc_is_scaler_set_cac_map_crt_thr(hw_ip->regs, &cac_cfg);
+       fimc_is_scaler_set_cac_enable(hw_ip->regs, 1);
+}
+
+int fimc_is_hw_mcsc_update_cac_register(struct fimc_is_hw_ip *hw_ip,
+       struct fimc_is_frame *frame, u32 instance)
+{
+       int ret = 0;
+       struct fimc_is_hw_mcsc *hw_mcsc;
+       struct fimc_is_hw_mcsc_cap *cap;
+       struct hw_mcsc_setfile *setfile;
+       struct cac_setfile_contents *cac;
+       enum exynos_sensor_position sensor_position;
+       u32 ni, backup_in;
+
+       BUG_ON(!hw_ip);
+       BUG_ON(!hw_ip->priv_info);
+
+       hw_mcsc = (struct fimc_is_hw_mcsc *)hw_ip->priv_info;
+       cap = GET_MCSC_HW_CAP(hw_ip);
+
+       if (cap->cac != MCSC_CAP_SUPPORT)
+               return ret;
+
+#ifdef LHM_ENABLE_EVT0
+       return ret;
+#endif
+
+       backup_in = hw_mcsc->cac_in;
+       if (hw_ip->hardware->video_mode)
+               hw_mcsc->cac_in = DEV_HW_MCSC0;
+       else
+               hw_mcsc->cac_in = DEV_HW_MCSC1;
+
+       if (backup_in != hw_mcsc->cac_in)
+               sdbg_hw(0, "cac input_source changed %d-> %d\n", hw_ip,
+                       backup_in - DEV_HW_MCSC0, hw_mcsc->cac_in - DEV_HW_MCSC0);
+
+       fimc_is_scaler_set_cac_input_source(hw_ip->regs, (hw_mcsc->cac_in - DEV_HW_MCSC0));
+
+       if (hw_mcsc->cac_in != hw_ip->id)
+               return ret;
+
+       sensor_position = hw_ip->hardware->sensor_position[instance];
+       setfile = hw_mcsc->cur_setfile[sensor_position];
+
+       /* calculate cac parameters */
+#ifdef FIXED_TDNR_NOISE_INDEX
+       ni = FIXED_TDNR_NOISE_INDEX_VALUE;
+#else
+       ni = frame->noise_idx;
+#endif
+       if (hw_mcsc->cur_ni == ni)
+               goto exit;
+
+#if defined(USE_UVSP_CAC)
+       cac = &setfile->cac;
+       hw_mcsc_calc_cac_param_by_ni(hw_ip, cac, ni);
+#endif
+
+exit:
+       hw_mcsc->cur_ni = ni;
+
+       return 0;
+}
+
+int fimc_is_hw_mcsc_recovery_cac_register(struct fimc_is_hw_ip *hw_ip,
+               struct is_param_region *param, u32 instance)
+{
+       int ret = 0;
+       /* TODO */
+
+       return ret;
+}
index 773f32fb25f98feedb6a53ff12db72d731b4a656..5b8d816d75e7f873319189a66274ea5e215517f7 100644 (file)
@@ -8,8 +8,8 @@
  * published by the Free Software Foundation.
  */
 
-#ifndef FIMC_IS_HW_UVSP_H
-#define FIMC_IS_HW_UVSP_H
+#ifndef FIMC_IS_HW_UVSP_CAC_H
+#define FIMC_IS_HW_UVSP_CAC_H
 
 #define CAC_MAX_NI_DEPENDED_CFG     (9)
 struct cac_map_thr_cfg {