From c23dffa7b8b8e5f68c569a0b770aaba1a1c52d0e Mon Sep 17 00:00:00 2001 From: Sunmi Lee Date: Tue, 3 Jul 2018 09:31:28 +0900 Subject: [PATCH] [COMMON] fimc-is2: Added new file and functions to support cac 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 --- .../exynos/fimc-is2/hardware/Makefile | 1 + .../hardware/api/fimc-is-hw-api-mcscaler-v2.h | 5 + .../api/fimc-is-hw-api-mcscaler-v5_0.c | 44 ++++ .../hardware/fimc-is-hw-mcscaler-v2.c | 1 + .../hardware/fimc-is-hw-mcscaler-v2.h | 8 +- .../fimc-is2/hardware/fimc-is-hw-uvsp-cac.c | 211 ++++++++++++++++++ .../fimc-is2/hardware/fimc-is-hw-uvsp-cac.h | 4 +- 7 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.c diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/Makefile b/drivers/media/platform/exynos/fimc-is2/hardware/Makefile index 92b77c52137e..1062b9c8dbe6 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/hardware/Makefile @@ -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 diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v2.h b/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v2.h index 9cb77345d479..06ee3d14e7cc 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v2.h +++ b/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v2.h @@ -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); diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v5_0.c b/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v5_0.c index 1fb339c87dcd..ed166e773f62 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v5_0.c +++ b/drivers/media/platform/exynos/fimc-is2/hardware/api/fimc-is-hw-api-mcscaler-v5_0.c @@ -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) { diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.c b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.c index a7550ae4fbbf..2144192817b7 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.c +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.c @@ -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); diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.h b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.h index 76a6299ceeff..93ab9636f25c 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.h +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-mcscaler-v2.h @@ -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 index 000000000000..1b768e7853e1 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.c @@ -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; +} diff --git a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.h b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.h index 773f32fb25f9..5b8d816d75e7 100644 --- a/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.h +++ b/drivers/media/platform/exynos/fimc-is2/hardware/fimc-is-hw-uvsp-cac.h @@ -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 { -- 2.20.1