[PATCH v6 3/5] media: add V4L2 vendor specific control handlers

From: Yuji Ishikawa
Date: Tue Jun 20 2023 - 00:07:36 EST


Add support to Image Signal Processors of Visconti's Video Input Interface.
This patch adds vendor specific compound controls
to configure the image signal processor.

Signed-off-by: Yuji Ishikawa <yuji2.ishikawa@xxxxxxxxxxxxx>
---
Changelog v2:
- Resend v1 because a patch exceeds size limit.

Changelog v3:
- Adapted to media control framework
- Introduced ISP subdevice, capture device
- Remove private IOCTLs and add vendor specific V4L2 controls
- Change function name avoiding camelcase and uppercase letters

Changelog v4:
- Split patches because the v3 patch exceeds size limit
- Stop using ID number to identify driver instance:
- Use dynamically allocated structure to hold HW specific context,
instead of static one.
- Call HW layer functions with the context structure instead of ID number

Changelog v5:
- no change

Changelog v6:
- remove unused macros
- removed hwd_ and HWD_ prefix
- update source code documentation
- Suggestion from Hans Verkuil
- pointer to userland memory is removed from uAPI arguments
- style of structure is now "nested" instead of "chained by pointer";
- use div64_u64 for 64bit division
- vendor specific controls support TRY_EXT_CTRLS
- add READ_ONLY flag to GET_CALIBRATION_STATUS control and similar ones
- human friendry control names for vendor specific controls
- add initial value to each vendor specific control
- GET_LAST_CAPTURE_STATUS control is updated asyncnously from workqueue
- remove EXECUTE_ON_WRITE flag of vendor specific control
- uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes
- applied v4l2-compliance
- Suggestion from Sakari Ailus
- use div64_u64 for 64bit division
- update copyright's year
- remove redandunt cast
- use bool instead of HWD_VIIF_ENABLE/DISABLE
- simplify comparison to 0
- simplify statements with trigram operator
- remove redundant local variables
- use general integer types instead of u32/s32
- Suggestion from Laurent Pinchart
- moved VIIF driver to driver/platform/toshiba/visconti
- change register access: struct-style to macro-style
- remove unused type definitions
- define enums instead of successive macro constants
- remove redundant parenthesis of macro constant
- embed struct hwd_res into struct viif_device
- use xxx_dma instead of xxx_paddr for variable names of IOVA
- literal value: just 0 instead of 0x0
- use literal 1 or 0 instead of HWD_VIIF_ENABLE, DISABLE for register access
- use true or false instead of HWD_VIIF_ENABLE, DISABLE for function calls
- uAPI: return value of GET_CALIBRATION_STATUS follows common rules of error codes

.../media/platform/toshiba/visconti/Makefile | 2 +-
.../media/platform/toshiba/visconti/viif.c | 10 +-
.../platform/toshiba/visconti/viif_controls.c | 3411 +++++++++++++++++
.../platform/toshiba/visconti/viif_controls.h | 18 +
.../platform/toshiba/visconti/viif_isp.c | 15 +-
5 files changed, 3439 insertions(+), 17 deletions(-)
create mode 100644 drivers/media/platform/toshiba/visconti/viif_controls.c
create mode 100644 drivers/media/platform/toshiba/visconti/viif_controls.h

diff --git a/drivers/media/platform/toshiba/visconti/Makefile b/drivers/media/platform/toshiba/visconti/Makefile
index 5f2f9199c..a28e6fa84 100644
--- a/drivers/media/platform/toshiba/visconti/Makefile
+++ b/drivers/media/platform/toshiba/visconti/Makefile
@@ -3,6 +3,6 @@
# Makefile for the Visconti video input device driver
#

-visconti-viif-objs = viif.o viif_capture.o viif_isp.o viif_csi2rx.o viif_common.o
+visconti-viif-objs = viif.o viif_capture.o viif_controls.o viif_isp.o viif_csi2rx.o viif_common.o

obj-$(CONFIG_VIDEO_VISCONTI_VIIF) += visconti-viif.o
diff --git a/drivers/media/platform/toshiba/visconti/viif.c b/drivers/media/platform/toshiba/visconti/viif.c
index 345dc457a..de2a1e165 100644
--- a/drivers/media/platform/toshiba/visconti/viif.c
+++ b/drivers/media/platform/toshiba/visconti/viif.c
@@ -17,6 +17,7 @@

#include "viif.h"
#include "viif_capture.h"
+#include "viif_controls.h"
#include "viif_csi2rx.h"
#include "viif_common.h"
#include "viif_isp.h"
@@ -208,12 +209,9 @@ static struct viif_subdev *to_viif_subdev(struct v4l2_async_subdev *asd)
/* before a userland capture application is trigered by vb2_buffer_done() */
static void visconti_viif_wthread_l1info(struct work_struct *work)
{
- /* called function is implemented by the next patch */
-/*
- * struct viif_device *viif_dev = container_of(work, struct viif_device, work);
- *
- * visconti_viif_save_l1_info(viif_dev);
- */
+ struct viif_device *viif_dev = container_of(work, struct viif_device, work);
+
+ visconti_viif_save_l1_info(viif_dev);
}

static void viif_vsync_irq_handler_w_isp(struct viif_device *viif_dev)
diff --git a/drivers/media/platform/toshiba/visconti/viif_controls.c b/drivers/media/platform/toshiba/visconti/viif_controls.c
new file mode 100644
index 000000000..e5e5f1084
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_controls.c
@@ -0,0 +1,3411 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+
+#include "viif.h"
+#include "viif_controls.h"
+#include "viif_csi2rx.h"
+#include "viif_isp.h"
+#include "viif_common.h"
+#include "viif_regs.h"
+
+/*=============================================*/
+/* parameters */
+/*=============================================*/
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE */
+#define VIIF_L1_INPUT_DEPTH_MIN 8U
+#define VIIF_L1_INPUT_DEPTH_MAX 24U
+#define VIIF_L1_INPUT_DEPTH_PWL_MAX 14U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF */
+#define VIIF_L1_COEF_MIN 256U
+#define VIIF_L1_COEF_MAX 65024U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE */
+#define VIIF_L1_AG_ID_NUM 4U
+#define VIIF_L1_SENSITIVITY_IMAGE_NUM 3U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE */
+#define VIIF_L1_HDRE_MAX_KNEEPOINT_VAL 0x3fffU
+#define VIIF_L1_HDRE_MAX_HDRE_SIG_VAL 0xffffffU
+#define VIIF_L1_HDRE_MAX_OUT_PIXEL_RATIO 0x400000U
+#define VIIF_L1_HDRE_MAX_OUT_PIXEL_VAL 0xffffffU
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION */
+#define VIIF_L1_IMG_EXTRACT_MAX_BLACK_LEVEL_VAL 0xffffffU
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC */
+#define VIIF_L1_DPC_MAX_RATIO_LIMIT_VAL 1023U
+#define VIIF_L1_DPC_MIN_LUMA_ADJ_VAL 1U
+#define VIIF_L1_DPC_MAX_LUMA_ADJ_VAL 31U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE */
+#define VIIF_L1_PWHB_MAX_OUT_PIXEL_VAL 4095U
+#define VIIF_L1_PWHB_MAX_GAIN_VAL 0x80000U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION */
+#define VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL 63U
+#define VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL 31U
+#define VIIF_L1_RCNR_MAX_ADJUSTMENT_GAIN_VAL 3U
+#define VIIF_L1_RCNR_MAX_ZERO_CLIP_VAL 256U
+#define VIIF_L1_RCNR_MAX_BLEND_VAL 16U
+#define VIIF_L1_RCNR_MAX_BLACK_LEVEL_VAL 64U
+#define VIIF_L1_RCNR_MIN_0DIV_GUARD_VAL 4U
+#define VIIF_L1_RCNR_MAX_0DIV_GUARD_VAL 16U
+#define VIIF_L1_RCNR_MAX_CALC_MSF_NOISE_MULTI_VAL 32U
+#define VIIF_L1_RCNR_MAX_GEN_LUMA_SIG_BLEND_VAL 2U
+#define VIIF_L1_RCNR_MAX_UP_LIMIT_GRGB_SENS_RATIO 15U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS */
+#define VIIF_L1_HDRS_MIN_BLEND_RATIO 0x400U
+#define VIIF_L1_HDRS_MAX_BLEND_RATIO 0x400000U
+#define VIIF_L1_HDRS_MAX_DIGITAL_GAIN_VAL 0x400000U
+#define VIIF_L1_HDRS_MAX_DST_MAX_VAL 0xffffffU
+#define VIIF_L1_HDRS_MAX_BLEND_PIX_VAL 4095U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION */
+#define VIIF_L1_BLACK_LEVEL_MAX_VAL 0xffffffU
+#define VIIF_L1_BLACK_LEVEL_MAX_GAIN_VAL 0x100000U
+#define VIIF_L1_BLACK_LEVEL_MAX_DST_VAL 0xffffffU
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC */
+#define VIIF_L1_LSC_MIN_GAIN -4096
+#define VIIF_L1_LSC_MAX_GAIN 4096
+#define VIIF_L1_LSC_GRID_MIN_COORDINATE 1U
+#define VIIF_L1_LSC_PWB_MAX_COEF_VAL 0x800U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS */
+#define VIIF_DAMP_MAX_LSBSEL 15U
+#define VIIF_MAIN_PROCESS_MAX_OUT_PIXEL_VAL 0xffffffU
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB */
+#define VIIF_L1_AWB_MIN_GAIN 64U
+#define VIIF_L1_AWB_MAX_GAIN 1024U
+#define VIIF_L1_AWB_GATE_LOWER -127
+#define VIIF_L1_AWB_GATE_UPPER 127
+#define VIIF_L1_AWB_UNSIGNED_GATE_UPPER 127U
+#define VIIF_L1_AWB_MAX_UV_CONVERGENCE_SPEED 15U
+#define VIIF_L1_AWB_MAX_UV_CONVERGENCE_LEVEL 31U
+#define VIIF_L1_AWB_INTEGRATION_STOP_TH 1023U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC */
+#define VIIF_L1_HDRC_MAX_THROUGH_SHIFT_VAL 8U
+#define VIIF_L1_HDRC_MIN_INPUT_DATA_WIDTH 10U
+#define VIIF_L1_HDRC_MAX_INPUT_DATA_WIDTH 24U
+#define VIIF_L1_HDRC_MAX_PT_SLOPE 13U
+#define VIIF_L1_HDRC_MAX_BLEND_RATIO 256U
+#define VIIF_L1_HDRC_MAX_FLARE_VAL 0xffffffU
+#define VIIF_L1_HDRC_MAX_BLEND_LUMA 16U
+#define VIIF_L1_HDRC_RATIO_OFFSET 10U
+#define VIIF_REGBUF_ACCESS_TIME 15360UL
+#define VIIF_L1_DELAY_W_HDRC 31U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM */
+#define VIIF_L1_HDRC_MAX_LTM_TONE_BLEND_RATIO 0x400000U
+#define VIIF_L1_HDRC_MAX_LTM_MAGNIFICATION 0x4000U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA */
+#define VIIF_L1_GAMMA_MAX_VAL 8191U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT */
+#define VIIF_L1_SUPPRESSION_MAX_VAL 0x4000U
+#define VIIF_L1_EDGE_SUPPRESSION_MAX_LIMIT 15U
+#define VIIF_L1_COLOR_LEVEL_MAX_GAIN 0x1000U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION */
+#define VIIF_L1_AEXP_MAX_WEIGHT 3U
+#define VIIF_L1_AEXP_MAX_BLOCK_TH 256U
+#define VIIF_L1_AEXP_MAX_SATURATION_PIXEL_TH 0xffffffU
+#define VIIF_L1_AEXP_MIN_BLOCK_WIDTH 64U
+#define VIIF_L1_AEXP_MIN_BLOCK_HEIGHT 64U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST */
+#define VIIF_L2_UNDIST_POLY_NUM 11U
+#define VIIF_L2_UNDIST_MIN_SENSOR_CROP_OFS_H -4296
+#define VIIF_L2_UNDIST_MAX_SENSOR_CROP_OFS_H 4296
+#define VIIF_L2_UNDIST_MIN_SENSOR_CROP_OFS_V -2360
+#define VIIF_L2_UNDIST_MAX_SENSOR_CROP_OFS_V 2360
+#define VIIF_L2_UNDIST_MAX_NORM_SCALE 1677721U
+#define VIIF_L2_UNDIST_MAX_VALID_R_NORM2 0x4000000U
+#define VIIF_L2_UNDIST_MAX_ROI_WRITE_AREA_DELTA 0x800U
+#define VIIF_L2_UNDIST_MIN_POLY_COEF -2147352576
+#define VIIF_L2_UNDIST_MAX_POLY_COEF 2147352576
+#define VIIF_L2_UNDIST_MIN_GRID_NUM 16U
+#define VIIF_L2_UNDIST_MAX_GRID_NUM 64U
+#define VIIF_L2_UNDIST_MAX_GRID_TOTAL_NUM 2048U
+#define VIIF_L2_UNDIST_MAX_GRID_PATCH_SIZE_INV 0x800000U
+#define VIIF_L2_UNDIST_MIN_TABLE_SIZE 0x400U
+#define VIIF_L2_UNDIST_MAX_TABLE_SIZE 0x2000U
+#define VIIF_L2_UNDIST_MAX_GRID_TOTAL_NUM 2048U
+#define VIIF_L2_UNDIST_MAX_GRID_PATCH_SIZE_INV 0x800000U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI */
+#define VIIF_L2_ROI_MIN_SCALE 32768U
+#define VIIF_L2_ROI_MAX_SCALE 131072U
+#define VIIF_L2_ROI_MIN_SCALE_INV 32768U
+#define VIIF_L2_ROI_MAX_SCALE_INV 131072U
+#define VIIF_L2_ROI_MIN_CORRECTED_WO_SCALE_HSIZE 128U
+#define VIIF_L2_ROI_MAX_CORRECTED_WO_SCALE_HSIZE 8190U
+#define VIIF_L2_ROI_MIN_CORRECTED_WO_SCALE_VSIZE 128U
+#define VIIF_L2_ROI_MAX_CORRECTED_WO_SCALE_VSIZE 4094U
+#define VIIF_L2_ROI_MIN_CORRECTED_HSIZE 128U
+#define VIIF_L2_ROI_MAX_CORRECTED_HSIZE 8190U
+#define VIIF_L2_ROI_MIN_CORRECTED_VSIZE 128U
+#define VIIF_L2_ROI_MAX_CORRECTED_VSIZE 4094U
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA */
+#define VIIF_GAMMA_MAX_VSPLIT 4094U
+
+/* v4l2 controls vendor specific type */
+#define COMPOUND_TYPE_SAMPLE01 0x0280
+
+/*=============================================*/
+/* Table Transmission (Memory -> ISP) */
+/*=============================================*/
+static void viif_config_vdm_tgroup(struct viif_device *viif_dev, int idx)
+{
+ const struct {
+ u32 cfg;
+ u32 sram_base;
+ u32 sram_size;
+ } conf[] = {
+ /* T01: L1_SET_DPC, L1_SET_LSC */
+ { VAL_TGROUP_CFG_64BIT_RD, 0x600, 0x20 },
+ /* T02: L2_UNDIST grid table */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x620, 0x20 },
+ /* T02: L2_GAMMA (path0) */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x640, 0x20 },
+ /* T03: L2 GAMMA (path1) */
+ { VAL_TGROUP_CFG_32BIT_RD, 0x660, 0x20 },
+ };
+
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_CFG(idx), conf[idx].cfg);
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_BASE(idx), conf[idx].sram_base);
+ viif_capture_write(viif_dev, REG_VDM_TGROUP_X_SRAM_SIZE(idx), conf[idx].sram_size);
+}
+
+/*=============================================*/
+/* vendor specific ISP request handlers */
+/*=============================================*/
+/* V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE */
+static int viif_main_set_rawpack_mode_try(struct viif_device *viif_dev, u32 *rawpack)
+{
+ if (!rawpack)
+ return -EINVAL;
+ if ((*rawpack != VIIF_RAWPACK_DISABLE) && (*rawpack != VIIF_RAWPACK_MSBFIRST) &&
+ (*rawpack != VIIF_RAWPACK_LSBFIRST))
+ return -EINVAL;
+ return 0;
+}
+
+static int viif_main_set_rawpack_mode(struct viif_device *viif_dev, u32 *rawpack)
+{
+ if (vb2_is_streaming(&viif_dev->cap_dev0.vb2_vq))
+ return -EBUSY;
+
+ /* value is already tested in _try*/
+ viif_dev->rawpack_mode = *rawpack;
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE */
+static int viif_l1_set_input_mode_try(struct viif_device *viif_dev,
+ struct viif_l1_input_mode_config *arg)
+{
+ u32 filter = arg->raw_color_filter;
+ u32 depth = arg->depth;
+ u32 mode = arg->mode;
+ u32 depth_max;
+
+ /* SDR input is not supported by this driver*/
+ if (mode != VIIF_L1_INPUT_HDR && mode != VIIF_L1_INPUT_PWL &&
+ mode != VIIF_L1_INPUT_HDR_IMG_CORRECT && mode != VIIF_L1_INPUT_PWL_IMG_CORRECT)
+ return -EINVAL;
+
+ if (filter != VIIF_L1_RAW_GR_R_B_GB && filter != VIIF_L1_RAW_R_GR_GB_B &&
+ filter != VIIF_L1_RAW_B_GB_GR_R && filter != VIIF_L1_RAW_GB_B_R_GR)
+ return -EINVAL;
+
+ if (mode == VIIF_L1_INPUT_PWL || mode == VIIF_L1_INPUT_PWL_IMG_CORRECT)
+ depth_max = VIIF_L1_INPUT_DEPTH_PWL_MAX;
+ else
+ depth_max = VIIF_L1_INPUT_DEPTH_MAX;
+
+ if (depth < VIIF_L1_INPUT_DEPTH_MIN || depth > depth_max || depth % 2U)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int viif_l1_set_input_mode(struct viif_device *viif_dev,
+ struct viif_l1_input_mode_config *arg)
+{
+ unsigned long irqflags;
+
+ /* values are already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_INPUT_MODE, (u32)arg->mode);
+ viif_capture_write(viif_dev, REG_L1_IBUF_DEPTH, (u32)arg->depth);
+ viif_capture_write(viif_dev, REG_L1_SYSM_START_COLOR, (u32)arg->raw_color_filter);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF */
+static int viif_l1_set_rgb_to_y_coef_try(struct viif_device *viif_dev,
+ struct viif_l1_rgb_to_y_coef_config *arg)
+{
+ u16 coef_r = arg->coef_r;
+ u16 coef_g = arg->coef_g;
+ u16 coef_b = arg->coef_b;
+
+ if (coef_r < VIIF_L1_COEF_MIN || coef_r > VIIF_L1_COEF_MAX || coef_g < VIIF_L1_COEF_MIN ||
+ coef_g > VIIF_L1_COEF_MAX || coef_b < VIIF_L1_COEF_MIN || coef_b > VIIF_L1_COEF_MAX) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_rgb_to_y_coef(struct viif_device *viif_dev,
+ struct viif_l1_rgb_to_y_coef_config *arg)
+{
+ unsigned long irqflags;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_R, (u32)arg->coef_r);
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_G, (u32)arg->coef_g);
+ viif_capture_write(viif_dev, REG_L1_SYSM_YCOEF_B, (u32)arg->coef_b);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE */
+static int viif_l1_set_ag_mode_try(struct viif_device *viif_dev, struct viif_l1_ag_mode_config *arg)
+{
+ if (arg->sysm_ag_psel_hobc_high >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_hobc_middle_led >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_hobc_low >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_abpc_high >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_abpc_middle_led >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_abpc_low >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_rcnr_high >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_rcnr_middle_led >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_psel_rcnr_low >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_ssel_lssc >= VIIF_L1_SENSITIVITY_IMAGE_NUM ||
+ arg->sysm_ag_psel_lssc >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_ssel_mpro >= VIIF_L1_SENSITIVITY_IMAGE_NUM ||
+ arg->sysm_ag_psel_mpro >= VIIF_L1_AG_ID_NUM ||
+ arg->sysm_ag_ssel_vpro >= VIIF_L1_SENSITIVITY_IMAGE_NUM ||
+ arg->sysm_ag_psel_vpro >= VIIF_L1_AG_ID_NUM) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_ag_mode(struct viif_device *viif_dev, struct viif_l1_ag_mode_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* SYSM_AG_PARAM */
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_A,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[0], arg->sysm_ag_ofst[0]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_B,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[1], arg->sysm_ag_ofst[1]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_C,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[2], arg->sysm_ag_ofst[2]));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_PARAM_D,
+ PACK_L1_SYSM_AG_PARAM(arg->sysm_ag_grad[3], arg->sysm_ag_ofst[3]));
+
+ /* SYSM_AG_SEL */
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_HOBC,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_hobc_high,
+ arg->sysm_ag_psel_hobc_middle_led,
+ arg->sysm_ag_psel_hobc_low));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_ABPC,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_abpc_high,
+ arg->sysm_ag_psel_abpc_middle_led,
+ arg->sysm_ag_psel_abpc_low));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_RCNR,
+ PACK_L1_SYSM_AG_SEL_HML(arg->sysm_ag_psel_rcnr_high,
+ arg->sysm_ag_psel_rcnr_middle_led,
+ arg->sysm_ag_psel_rcnr_low));
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_LSSC,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_lssc, arg->sysm_ag_psel_lssc));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_MPRO,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_mpro, arg->sysm_ag_psel_mpro));
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_SEL_VPRO,
+ PACK_L1_SYSM_AG_SEL_SP(arg->sysm_ag_ssel_vpro, arg->sysm_ag_psel_vpro));
+
+ /* SYSM_AG_CONT */
+ val = arg->sysm_ag_cont_hobc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_hobc_test_middle_led);
+ val |= arg->sysm_ag_cont_hobc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_hobc_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC01_EN, val);
+
+ val = arg->sysm_ag_cont_hobc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_hobc_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_HOBC2_EN, val);
+
+ val = arg->sysm_ag_cont_abpc_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_abpc_test_middle_led);
+ val |= arg->sysm_ag_cont_abpc_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_abpc_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC01_EN, val);
+
+ val = arg->sysm_ag_cont_abpc_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_abpc_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_ABPC2_EN, val);
+
+ val = arg->sysm_ag_cont_rcnr_en_middle_led ? MASK_L1_SYSM_AG_CONT_M_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_M_VAL, arg->sysm_ag_cont_rcnr_test_middle_led);
+ val |= arg->sysm_ag_cont_rcnr_en_high ? MASK_L1_SYSM_AG_CONT_H_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_H_VAL, arg->sysm_ag_cont_rcnr_test_high);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR01_EN, val);
+
+ val = arg->sysm_ag_cont_rcnr_en_low ? MASK_L1_SYSM_AG_CONT_L_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_L_VAL, arg->sysm_ag_cont_rcnr_test_low);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_RCNR2_EN, val);
+
+ val = arg->sysm_ag_cont_lssc_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_lssc_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_LSSC_EN, val);
+
+ val = arg->sysm_ag_cont_mpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_mpro_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_MPRO_EN, val);
+
+ val = arg->sysm_ag_cont_vpro_en ? MASK_L1_SYSM_AG_CONT_EN : 0;
+ val |= FIELD_PREP(MASK_L1_SYSM_AG_CONT_VAL, arg->sysm_ag_cont_vpro_test);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_CONT_VPRO_EN, val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG */
+static int viif_l1_set_ag(struct viif_device *viif_dev, struct viif_l1_ag_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_H, (u32)arg->gain_h);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_M, (u32)arg->gain_m);
+ viif_capture_write(viif_dev, REG_L1_SYSM_AG_L, (u32)arg->gain_l);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE */
+static int viif_l1_set_hdre_try(struct viif_device *viif_dev, struct viif_l1_hdre_config *arg)
+{
+ u32 idx;
+
+ for (idx = 0; idx < 16U; idx++) {
+ if (arg->hdre_src_point[idx] > VIIF_L1_HDRE_MAX_KNEEPOINT_VAL)
+ return -EINVAL;
+ }
+
+ for (idx = 0; idx < 17U; idx++) {
+ if (arg->hdre_dst_base[idx] > VIIF_L1_HDRE_MAX_HDRE_SIG_VAL ||
+ arg->hdre_ratio[idx] >= VIIF_L1_HDRE_MAX_OUT_PIXEL_RATIO) {
+ return -EINVAL;
+ }
+ }
+
+ if (arg->hdre_dst_max_val > VIIF_L1_HDRE_MAX_OUT_PIXEL_VAL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int viif_l1_set_hdre(struct viif_device *viif_dev, struct viif_l1_hdre_config *arg)
+{
+ unsigned long irqflags;
+ int i;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ for (i = 0; i < LEN_L1_HDRE_SRCPOINT; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCPOINT(i), arg->hdre_src_point[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(0), 0);
+ for (i = 1; i < LEN_L1_HDRE_SRCBASE; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_SRCBASE(i), arg->hdre_src_point[i - 1]);
+
+ for (i = 0; i < LEN_L1_HDRE_DSTBASE; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_DSTBASE(i), arg->hdre_dst_base[i]);
+
+ for (i = 0; i < LEN_L1_HDRE_RATIO; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRE_RATIO(i), arg->hdre_ratio[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRE_DSTMAXVAL, arg->hdre_dst_max_val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION */
+static int viif_l1_set_img_extraction_try(struct viif_device *viif_dev,
+ struct viif_l1_img_extraction_config *arg)
+{
+ if (arg->input_black_gr > VIIF_L1_IMG_EXTRACT_MAX_BLACK_LEVEL_VAL ||
+ arg->input_black_r > VIIF_L1_IMG_EXTRACT_MAX_BLACK_LEVEL_VAL ||
+ arg->input_black_b > VIIF_L1_IMG_EXTRACT_MAX_BLACK_LEVEL_VAL ||
+ arg->input_black_gb > VIIF_L1_IMG_EXTRACT_MAX_BLACK_LEVEL_VAL) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_img_extraction(struct viif_device *viif_dev,
+ struct viif_l1_img_extraction_config *arg)
+{
+ unsigned long irqflags;
+
+ /* value is already tested in _try*/
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GR, arg->input_black_gr);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_R, arg->input_black_r);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_B, arg->input_black_b);
+ viif_capture_write(viif_dev, REG_L1_SLIC_SRCBLACKLEVEL_GB, arg->input_black_gb);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC */
+static int viif_l1_set_dpc_try(struct viif_device *viif_dev, struct viif_l1_dpc_config *arg)
+{
+ const struct viif_l1_dpc *params[] = {
+ &arg->param_h,
+ &arg->param_m,
+ &arg->param_l,
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(params); i++) {
+ const struct viif_l1_dpc *param = params[i];
+
+ if (!param->abpc_dyn_en)
+ continue;
+
+ if (param->abpc_ratio_limit > VIIF_L1_DPC_MAX_RATIO_LIMIT_VAL ||
+ param->abpc_dark_limit > VIIF_L1_DPC_MAX_RATIO_LIMIT_VAL ||
+ param->abpc_sn_coef_w_ag_min < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_ag_min > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_ag_mid < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_ag_mid > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_ag_max < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_ag_max > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_min < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_min > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_mid < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_mid > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_max < VIIF_L1_DPC_MIN_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_b_ag_max > VIIF_L1_DPC_MAX_LUMA_ADJ_VAL ||
+ param->abpc_sn_coef_w_th_min >= param->abpc_sn_coef_w_th_max ||
+ param->abpc_sn_coef_b_th_min >= param->abpc_sn_coef_b_th_max) {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void dpc_table_transmission(struct viif_device *viif_dev, uintptr_t table_h,
+ uintptr_t table_m, uintptr_t table_l)
+{
+ u32 val = 0x0U;
+
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+ if (table_h) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_H),
+ (u32)table_h);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_H),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_H;
+ }
+
+ if (table_m) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_M),
+ (u32)table_m);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_M),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_M;
+ }
+
+ if (table_l) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_DPC_L),
+ (u32)table_l);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_DPC_L),
+ VIIF_DPC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_DPC_L;
+ }
+
+ val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_DPC);
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static int viif_l1_set_dpc(struct viif_device *viif_dev, struct viif_l1_dpc_config *arg)
+{
+ const struct viif_l1_dpc *param_h, *param_m, *param_l;
+ dma_addr_t table_h = 0;
+ dma_addr_t table_m = 0;
+ dma_addr_t table_l = 0;
+ unsigned long irqflags;
+ u32 val;
+
+ if (arg->param_h.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_h, arg->table_h, VIIF_DPC_TABLE_BYTES);
+ table_h = (dma_addr_t)viif_dev->tables_dma->dpc_table_h;
+ }
+ if (arg->param_m.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_m, arg->table_m, VIIF_DPC_TABLE_BYTES);
+ table_m = (dma_addr_t)viif_dev->tables_dma->dpc_table_m;
+ }
+ if (arg->param_l.abpc_sta_en) {
+ memcpy(viif_dev->tables->dpc_table_l, arg->table_l, VIIF_DPC_TABLE_BYTES);
+ table_l = (dma_addr_t)viif_dev->tables_dma->dpc_table_l;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ dpc_table_transmission(viif_dev, table_h, table_m, table_l);
+
+ param_h = &arg->param_h;
+ param_m = &arg->param_m;
+ param_l = &arg->param_l;
+
+ val = (param_h->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_H :
+ 0 | (param_m->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_M :
+ 0 | (param_l->abpc_sta_en) ? MASK_L1_ABPC_ENABLE_L :
+ 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_STA_EN, val);
+
+ val = (param_h->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_H :
+ 0 | (param_m->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_M :
+ 0 | (param_l->abpc_dyn_en) ? MASK_L1_ABPC_ENABLE_L :
+ 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_EN, val);
+
+ val = (param_h->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_H :
+ 0 | (param_m->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_M :
+ 0 | (param_l->abpc_dyn_mode == VIIF_L1_DPC_2PIXEL) ? MASK_L1_ABPC_DYN_MODE_2PIXEL_L :
+ 0;
+ viif_capture_write(viif_dev, REG_L1_ABPC012_DYN_MODE, val);
+
+ /* setup param_h */
+ viif_capture_write(viif_dev, REG_L1_ABPC0_RATIO_LIMIT, param_h->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_DARK_LIMIT, param_h->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MIN, param_h->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MID, param_h->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_AG_MAX, param_h->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MIN, param_h->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MID, param_h->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_AG_MAX, param_h->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MIN, param_h->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_W_TH_MAX, param_h->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MIN, param_h->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC0_SN_COEF_B_TH_MAX, param_h->abpc_sn_coef_b_th_max);
+
+ /* setup param_m */
+ viif_capture_write(viif_dev, REG_L1_ABPC1_RATIO_LIMIT, param_m->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_DARK_LIMIT, param_m->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MIN, param_m->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MID, param_m->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_AG_MAX, param_m->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MIN, param_m->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MID, param_m->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_AG_MAX, param_m->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MIN, param_m->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_W_TH_MAX, param_m->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MIN, param_m->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC1_SN_COEF_B_TH_MAX, param_m->abpc_sn_coef_b_th_max);
+
+ /* setup param_l */
+ viif_capture_write(viif_dev, REG_L1_ABPC2_RATIO_LIMIT, param_l->abpc_ratio_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_DARK_LIMIT, param_l->abpc_dark_limit);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MIN, param_l->abpc_sn_coef_w_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MID, param_l->abpc_sn_coef_w_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_AG_MAX, param_l->abpc_sn_coef_w_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MIN, param_l->abpc_sn_coef_b_ag_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MID, param_l->abpc_sn_coef_b_ag_mid);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_AG_MAX, param_l->abpc_sn_coef_b_ag_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MIN, param_l->abpc_sn_coef_w_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_W_TH_MAX, param_l->abpc_sn_coef_w_th_max);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MIN, param_l->abpc_sn_coef_b_th_min);
+ viif_capture_write(viif_dev, REG_L1_ABPC2_SN_COEF_B_TH_MAX, param_l->abpc_sn_coef_b_th_max);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE */
+static int viif_l1_set_preset_white_balance_try(struct viif_device *viif_dev,
+ struct viif_l1_preset_white_balance_config *arg)
+{
+ const struct viif_l1_preset_wb *param_h, *param_m, *param_l;
+
+ param_h = &arg->param_h;
+ param_m = &arg->param_m;
+ param_l = &arg->param_l;
+
+ if (arg->dstmaxval > VIIF_L1_PWHB_MAX_OUT_PIXEL_VAL)
+ return -EINVAL;
+
+ if (param_h->gain_gr >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_h->gain_r >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_h->gain_b >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_h->gain_gb >= VIIF_L1_PWHB_MAX_GAIN_VAL) {
+ return -EINVAL;
+ }
+
+ if (param_m->gain_gr >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_m->gain_r >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_m->gain_b >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_m->gain_gb >= VIIF_L1_PWHB_MAX_GAIN_VAL) {
+ return -EINVAL;
+ }
+
+ if (param_l->gain_gr >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_l->gain_r >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_l->gain_b >= VIIF_L1_PWHB_MAX_GAIN_VAL ||
+ param_l->gain_gb >= VIIF_L1_PWHB_MAX_GAIN_VAL) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int viif_l1_set_preset_white_balance(struct viif_device *viif_dev,
+ struct viif_l1_preset_white_balance_config *arg)
+{
+ const struct viif_l1_preset_wb *param_h, *param_m, *param_l;
+ unsigned long irqflags;
+
+ param_h = &arg->param_h;
+ param_m = &arg->param_m;
+ param_l = &arg->param_l;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_DSTMAXVAL, arg->dstmaxval);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_H_GR, param_h->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_HR, param_h->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_HB, param_h->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_H_GB, param_h->gain_gb);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_M_GR, param_m->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_MR, param_m->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_MB, param_m->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_M_GB, param_m->gain_gb);
+
+ viif_capture_write(viif_dev, REG_L1_PWHB_L_GR, param_l->gain_gr);
+ viif_capture_write(viif_dev, REG_L1_PWHB_LR, param_l->gain_r);
+ viif_capture_write(viif_dev, REG_L1_PWHB_LB, param_l->gain_b);
+ viif_capture_write(viif_dev, REG_L1_PWHB_L_GB, param_l->gain_gb);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION */
+static int
+viif_l1_set_raw_color_noise_reduction_try(struct viif_device *viif_dev,
+ struct viif_l1_raw_color_noise_reduction_config *arg)
+{
+ const struct viif_l1_raw_color_noise_reduction *params[] = {
+ &arg->param_h,
+ &arg->param_m,
+ &arg->param_l,
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(params); i++) {
+ const struct viif_l1_raw_color_noise_reduction *param = params[i];
+
+ if (param->rcnr_cnf_dark_ag0 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_dark_ag1 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_dark_ag2 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_ratio_ag0 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_ratio_ag1 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_ratio_ag2 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_cnf_clip_gain_r > VIIF_L1_RCNR_MAX_ADJUSTMENT_GAIN_VAL ||
+ param->rcnr_cnf_clip_gain_g > VIIF_L1_RCNR_MAX_ADJUSTMENT_GAIN_VAL ||
+ param->rcnr_cnf_clip_gain_b > VIIF_L1_RCNR_MAX_ADJUSTMENT_GAIN_VAL ||
+ param->rcnr_a1l_dark_ag0 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_a1l_dark_ag1 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_a1l_dark_ag2 > VIIF_L1_RCNR_MAX_DARK_ADJUSTMENT_VAL ||
+ param->rcnr_a1l_ratio_ag0 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_a1l_ratio_ag1 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_a1l_ratio_ag2 > VIIF_L1_RCNR_MAX_LUMA_LINKAGE_ADJUSTMENT_VAL ||
+ param->rcnr_inf_zero_clip > VIIF_L1_RCNR_MAX_ZERO_CLIP_VAL ||
+ param->rcnr_merge_d2blend_ag0 > VIIF_L1_RCNR_MAX_BLEND_VAL ||
+ param->rcnr_merge_d2blend_ag1 > VIIF_L1_RCNR_MAX_BLEND_VAL ||
+ param->rcnr_merge_d2blend_ag2 > VIIF_L1_RCNR_MAX_BLEND_VAL ||
+ param->rcnr_merge_black > VIIF_L1_RCNR_MAX_BLACK_LEVEL_VAL ||
+ param->rcnr_merge_mindiv < VIIF_L1_RCNR_MIN_0DIV_GUARD_VAL ||
+ param->rcnr_merge_mindiv > VIIF_L1_RCNR_MAX_0DIV_GUARD_VAL) {
+ return -EINVAL;
+ }
+
+ switch (param->rcnr_hry_type) {
+ case VIIF_L1_RCNR_LOW_RESOLUTION:
+ case VIIF_L1_RCNR_MIDDLE_RESOLUTION:
+ case VIIF_L1_RCNR_HIGH_RESOLUTION:
+ case VIIF_L1_RCNR_ULTRA_HIGH_RESOLUTION:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (param->rcnr_anf_blend_ag0 != VIIF_L1_MSF_BLEND_RATIO_0_DIV_64 &&
+ param->rcnr_anf_blend_ag0 != VIIF_L1_MSF_BLEND_RATIO_1_DIV_64 &&
+ param->rcnr_anf_blend_ag0 != VIIF_L1_MSF_BLEND_RATIO_2_DIV_64) {
+ return -EINVAL;
+ }
+ if (param->rcnr_anf_blend_ag1 != VIIF_L1_MSF_BLEND_RATIO_0_DIV_64 &&
+ param->rcnr_anf_blend_ag1 != VIIF_L1_MSF_BLEND_RATIO_1_DIV_64 &&
+ param->rcnr_anf_blend_ag1 != VIIF_L1_MSF_BLEND_RATIO_2_DIV_64) {
+ return -EINVAL;
+ }
+ if (param->rcnr_anf_blend_ag2 != VIIF_L1_MSF_BLEND_RATIO_0_DIV_64 &&
+ param->rcnr_anf_blend_ag2 != VIIF_L1_MSF_BLEND_RATIO_1_DIV_64 &&
+ param->rcnr_anf_blend_ag2 != VIIF_L1_MSF_BLEND_RATIO_2_DIV_64) {
+ return -EINVAL;
+ }
+
+ if (param->rcnr_lpf_threshold >= VIIF_L1_RCNR_MAX_CALC_MSF_NOISE_MULTI_VAL ||
+ param->rcnr_merge_hlblend_ag0 > VIIF_L1_RCNR_MAX_GEN_LUMA_SIG_BLEND_VAL ||
+ param->rcnr_merge_hlblend_ag1 > VIIF_L1_RCNR_MAX_GEN_LUMA_SIG_BLEND_VAL ||
+ param->rcnr_merge_hlblend_ag2 > VIIF_L1_RCNR_MAX_GEN_LUMA_SIG_BLEND_VAL) {
+ return -EINVAL;
+ }
+
+ if (param->rcnr_gnr_sw) {
+ if (param->rcnr_gnr_ratio > VIIF_L1_RCNR_MAX_UP_LIMIT_GRGB_SENS_RATIO)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+viif_l1_set_raw_color_noise_reduction(struct viif_device *viif_dev,
+ struct viif_l1_raw_color_noise_reduction_config *arg)
+{
+ const struct viif_l1_raw_color_noise_reduction *params[] = {
+ &arg->param_h,
+ &arg->param_m,
+ &arg->param_l,
+ };
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ for (i = 0; i < 3; i++) {
+ const struct viif_l1_raw_color_noise_reduction *param = params[i];
+ /* param_h */
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_SW(i), param->rcnr_sw ? 1 : 0);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG0(i),
+ param->rcnr_cnf_dark_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG1(i),
+ param->rcnr_cnf_dark_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_DARK_AG2(i),
+ param->rcnr_cnf_dark_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG0(i),
+ param->rcnr_cnf_ratio_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG1(i),
+ param->rcnr_cnf_ratio_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_RATIO_AG2(i),
+ param->rcnr_cnf_ratio_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_R(i),
+ param->rcnr_cnf_clip_gain_r);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_G(i),
+ param->rcnr_cnf_clip_gain_g);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_CNF_CLIP_GAIN_B(i),
+ param->rcnr_cnf_clip_gain_b);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG0(i),
+ param->rcnr_a1l_dark_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG1(i),
+ param->rcnr_a1l_dark_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_DARK_AG2(i),
+ param->rcnr_a1l_dark_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG0(i),
+ param->rcnr_a1l_ratio_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG1(i),
+ param->rcnr_a1l_ratio_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_A1L_RATIO_AG2(i),
+ param->rcnr_a1l_ratio_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_INF_ZERO_CLIP(i),
+ param->rcnr_inf_zero_clip);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG0(i),
+ param->rcnr_merge_d2blend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG1(i),
+ param->rcnr_merge_d2blend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_D2BLEND_AG2(i),
+ param->rcnr_merge_d2blend_ag2);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_BLACK(i), param->rcnr_merge_black);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_MINDIV(i),
+ param->rcnr_merge_mindiv);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_HRY_TYPE(i), param->rcnr_hry_type);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG0(i),
+ param->rcnr_anf_blend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG1(i),
+ param->rcnr_anf_blend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_ANF_BLEND_AG2(i),
+ param->rcnr_anf_blend_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_LPF_THRESHOLD(i),
+ param->rcnr_lpf_threshold);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG0(i),
+ param->rcnr_merge_hlblend_ag0);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG1(i),
+ param->rcnr_merge_hlblend_ag1);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_MERGE_HLBLEND_AG2(i),
+ param->rcnr_merge_hlblend_ag2);
+
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_SW(i), param->rcnr_gnr_sw ? 1 : 0);
+
+ if (param->rcnr_gnr_sw) {
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_RATIO(i),
+ param->rcnr_gnr_ratio);
+ viif_capture_write(viif_dev, REG_L1_RCNR_X_GNR_WIDE_EN(i),
+ param->rcnr_gnr_wide_en ? 1 : 0);
+ }
+ }
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS */
+static int viif_l1_set_hdrs_try(struct viif_device *viif_dev, struct viif_l1_hdrs_config *arg)
+{
+ if ((arg->hdrs_hdr_mode != VIIF_L1_HDRS_NOT_USE_MIDDLE_SENS_IMAGE &&
+ arg->hdrs_hdr_mode != VIIF_L1_HDRS_USE_MIDDLE_SENS_IMAGE) ||
+ arg->hdrs_hdr_ratio_m < VIIF_L1_HDRS_MIN_BLEND_RATIO ||
+ arg->hdrs_hdr_ratio_m > VIIF_L1_HDRS_MAX_BLEND_RATIO ||
+ arg->hdrs_hdr_ratio_l < VIIF_L1_HDRS_MIN_BLEND_RATIO ||
+ arg->hdrs_hdr_ratio_l > VIIF_L1_HDRS_MAX_BLEND_RATIO ||
+ arg->hdrs_hdr_ratio_e < VIIF_L1_HDRS_MIN_BLEND_RATIO ||
+ arg->hdrs_hdr_ratio_e > VIIF_L1_HDRS_MAX_BLEND_RATIO ||
+ arg->hdrs_dg_h >= VIIF_L1_HDRS_MAX_DIGITAL_GAIN_VAL ||
+ arg->hdrs_dg_m >= VIIF_L1_HDRS_MAX_DIGITAL_GAIN_VAL ||
+ arg->hdrs_dg_l >= VIIF_L1_HDRS_MAX_DIGITAL_GAIN_VAL ||
+ arg->hdrs_dg_e >= VIIF_L1_HDRS_MAX_DIGITAL_GAIN_VAL ||
+ arg->hdrs_blendend_h > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_blendend_m > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_blendend_e > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_blendbeg_h > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_blendbeg_m > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_blendbeg_e > VIIF_L1_HDRS_MAX_BLEND_PIX_VAL ||
+ arg->hdrs_dst_max_val > VIIF_L1_HDRS_MAX_DST_MAX_VAL) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_hdrs(struct viif_device *viif_dev, struct viif_l1_hdrs_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRMODE, arg->hdrs_hdr_mode);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_M, arg->hdrs_hdr_ratio_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_L, arg->hdrs_hdr_ratio_l);
+ viif_capture_write(viif_dev, REG_L1_HDRS_HDRRATIO_E, arg->hdrs_hdr_ratio_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_H, arg->hdrs_dg_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_M, arg->hdrs_dg_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_L, arg->hdrs_dg_l);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DG_E, arg->hdrs_dg_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_H, arg->hdrs_blendend_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_M, arg->hdrs_blendend_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDEND_E, arg->hdrs_blendend_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_H, arg->hdrs_blendbeg_h);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_M, arg->hdrs_blendbeg_m);
+ viif_capture_write(viif_dev, REG_L1_HDRS_BLENDBEG_E, arg->hdrs_blendbeg_e);
+
+ viif_capture_write(viif_dev, REG_L1_HDRS_LEDMODE_ON, arg->hdrs_led_mode_on ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L1_HDRS_DSTMAXVAL, arg->hdrs_dst_max_val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION */
+static int viif_l1_set_black_level_correction_try(struct viif_device *viif_dev,
+ struct viif_l1_black_level_correction_config *arg)
+{
+ if (arg->srcblacklevel_gr > VIIF_L1_BLACK_LEVEL_MAX_VAL ||
+ arg->srcblacklevel_r > VIIF_L1_BLACK_LEVEL_MAX_VAL ||
+ arg->srcblacklevel_b > VIIF_L1_BLACK_LEVEL_MAX_VAL ||
+ arg->srcblacklevel_gb > VIIF_L1_BLACK_LEVEL_MAX_VAL ||
+ arg->mulval_gr >= VIIF_L1_BLACK_LEVEL_MAX_GAIN_VAL ||
+ arg->mulval_r >= VIIF_L1_BLACK_LEVEL_MAX_GAIN_VAL ||
+ arg->mulval_b >= VIIF_L1_BLACK_LEVEL_MAX_GAIN_VAL ||
+ arg->mulval_gb >= VIIF_L1_BLACK_LEVEL_MAX_GAIN_VAL ||
+ arg->dstmaxval > VIIF_L1_BLACK_LEVEL_MAX_DST_VAL) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_black_level_correction(struct viif_device *viif_dev,
+ struct viif_l1_black_level_correction_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_GR, arg->srcblacklevel_gr);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_R, arg->srcblacklevel_r);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVEL_B, arg->srcblacklevel_b);
+ viif_capture_write(viif_dev, REG_L1_BLVC_SRCBLACKLEVELGB, arg->srcblacklevel_gb);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GR, arg->mulval_gr);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_R, arg->mulval_r);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_B, arg->mulval_b);
+ viif_capture_write(viif_dev, REG_L1_BLVC_MULTVAL_GB, arg->mulval_gb);
+
+ viif_capture_write(viif_dev, REG_L1_BLVC_DSTMAXVAL, arg->dstmaxval);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC */
+static inline u32 gen_grid_size(u32 param)
+{
+ switch (param) {
+ case 32U:
+ return 5U;
+ case 64U:
+ return 6U;
+ case 128U:
+ return 7U;
+ case 256U:
+ return 8U;
+ case 512U:
+ return 9U;
+ default:
+ return 0;
+ }
+}
+
+static int viif_l1_set_lsc_try(struct viif_device *viif_dev, struct viif_l1_lsc_config *arg)
+{
+ struct viif_l1_lsc *param;
+ u32 sysm_width, sysm_height;
+
+ /* disable LSC */
+ if (!arg->enable)
+ return 0;
+
+ param = &arg->param;
+
+ sysm_width = viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH);
+ sysm_height = viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT);
+
+ /* enabling LSC Parabola */
+ if (arg->enable & VIIF_L1_LSC_PARABOLA_EN_MASK) {
+ struct viif_l1_lsc_parabola_param *parabola_param = &param->lssc_parabola_param;
+ unsigned int idx;
+
+ if (parabola_param->lssc_para_h_center >= sysm_width ||
+ parabola_param->lssc_para_v_center >= sysm_height ||
+ parabola_param->lssc_para_h_gain >= VIIF_L1_LSC_MAX_GAIN ||
+ parabola_param->lssc_para_v_gain >= VIIF_L1_LSC_MAX_GAIN) {
+ return -EINVAL;
+ }
+
+ switch (parabola_param->lssc_para_mgsel2) {
+ case VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_SECOND:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_FIRST:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (parabola_param->lssc_para_mgsel4) {
+ case VIIF_L1_PARA_COEF_GAIN_ONE_EIGHTH:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_FOURTH:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_SECOND:
+ case VIIF_L1_PARA_COEF_GAIN_ONE_FIRST:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (idx = 0U; idx < 8U; idx++) {
+ const struct viif_l1_lsc_parabola_ag_param *ag_param;
+
+ switch (idx) {
+ case 0U:
+ ag_param = &parabola_param->r_2d;
+ break;
+ case 1U:
+ ag_param = &parabola_param->r_4d;
+ break;
+ case 2U:
+ ag_param = &parabola_param->gr_2d;
+ break;
+ case 3U:
+ ag_param = &parabola_param->gr_4d;
+ break;
+ case 4U:
+ ag_param = &parabola_param->gb_2d;
+ break;
+ case 5U:
+ ag_param = &parabola_param->gb_4d;
+ break;
+ case 6U:
+ ag_param = &parabola_param->b_2d;
+ break;
+ default:
+ ag_param = &parabola_param->b_4d;
+ break;
+ }
+
+ if (!ag_param || ag_param->lssc_paracoef_h_l_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_h_l_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_h_l_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_h_l_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_h_l_min > ag_param->lssc_paracoef_h_l_max ||
+ ag_param->lssc_paracoef_h_r_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_h_r_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_h_r_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_h_r_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_h_r_min > ag_param->lssc_paracoef_h_r_max ||
+ ag_param->lssc_paracoef_v_u_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_v_u_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_v_u_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_v_u_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_v_u_min > ag_param->lssc_paracoef_v_u_max ||
+ ag_param->lssc_paracoef_v_d_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_v_d_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_v_d_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_v_d_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_v_d_min > ag_param->lssc_paracoef_v_d_max ||
+ ag_param->lssc_paracoef_hv_lu_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_lu_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_lu_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_lu_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_lu_min > ag_param->lssc_paracoef_hv_lu_max ||
+ ag_param->lssc_paracoef_hv_ru_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_ru_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_ru_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_ru_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_ru_min > ag_param->lssc_paracoef_hv_ru_max ||
+ ag_param->lssc_paracoef_hv_ld_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_ld_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_ld_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_ld_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_ld_min > ag_param->lssc_paracoef_hv_ld_max ||
+ ag_param->lssc_paracoef_hv_rd_max < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_rd_max >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_rd_min < VIIF_L1_LSC_MIN_GAIN ||
+ ag_param->lssc_paracoef_hv_rd_min >= VIIF_L1_LSC_MAX_GAIN ||
+ ag_param->lssc_paracoef_hv_rd_min > ag_param->lssc_paracoef_hv_rd_max) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* enabling LSC Grid */
+ if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+ struct viif_l1_lsc_grid_param *grid_param = &param->lssc_grid_param;
+ u32 grid_h_size = gen_grid_size(grid_param->lssc_grid_h_size);
+ u32 grid_v_size = gen_grid_size(grid_param->lssc_grid_v_size);
+
+ if (!grid_h_size || !grid_v_size)
+ return -EINVAL;
+
+ if (grid_param->lssc_grid_h_center < VIIF_L1_LSC_GRID_MIN_COORDINATE ||
+ grid_param->lssc_grid_h_center > grid_param->lssc_grid_h_size) {
+ return -EINVAL;
+ }
+
+ if (sysm_width >
+ (grid_param->lssc_grid_h_center + (grid_param->lssc_grid_h_size * 31U))) {
+ return -EINVAL;
+ }
+
+ if (grid_param->lssc_grid_v_center < VIIF_L1_LSC_GRID_MIN_COORDINATE ||
+ grid_param->lssc_grid_v_center > grid_param->lssc_grid_v_size) {
+ return -EINVAL;
+ }
+
+ if (sysm_height >
+ (grid_param->lssc_grid_v_center + (grid_param->lssc_grid_v_size * 23U))) {
+ return -EINVAL;
+ }
+
+ if (grid_param->lssc_grid_mgsel != VIIF_L1_GRID_COEF_GAIN_X1 &&
+ grid_param->lssc_grid_mgsel != VIIF_L1_GRID_COEF_GAIN_X2) {
+ return -EINVAL;
+ }
+ }
+
+ if (param->lssc_pwhb_r_gain_max >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_r_gain_min >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_r_gain_min > param->lssc_pwhb_r_gain_max ||
+ param->lssc_pwhb_gr_gain_max >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_gr_gain_min >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_gr_gain_min > param->lssc_pwhb_gr_gain_max ||
+ param->lssc_pwhb_gb_gain_max >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_gb_gain_min >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_gb_gain_min > param->lssc_pwhb_gb_gain_max ||
+ param->lssc_pwhb_b_gain_max >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_b_gain_min >= VIIF_L1_LSC_PWB_MAX_COEF_VAL ||
+ param->lssc_pwhb_b_gain_min > param->lssc_pwhb_b_gain_max) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void lsc_table_transmission(struct viif_device *viif_dev, dma_addr_t table_gr,
+ dma_addr_t table_r, dma_addr_t table_b, dma_addr_t table_gb)
+{
+ u32 val = 0x0U;
+
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L1_ISP);
+
+ if (table_gr) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GR),
+ (u32)table_gr);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GR),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_GR;
+ }
+
+ if (table_r) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_R),
+ (u32)table_r);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_R),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_R;
+ }
+
+ if (table_b) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_B),
+ (u32)table_b);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_B),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_B;
+ }
+
+ if (table_gb) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L1_LSSC_GB),
+ (u32)table_gb);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L1_LSSC_GB),
+ VIIF_LSC_TABLE_BYTES);
+ val |= MASK_VDM_T_ENABLE_L1_LSSC_GB;
+ }
+
+ val |= (viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L1_LSSC);
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+#define PACK_PARA_COEF(max, min) (FIELD_PREP(0x1FFF0000, (max)) | FIELD_PREP(0x1FFF, (min)))
+
+static int viif_l1_set_lsc(struct viif_device *viif_dev, struct viif_l1_lsc_config *arg)
+{
+ dma_addr_t table_gr = 0;
+ dma_addr_t table_gb = 0;
+ dma_addr_t table_r = 0;
+ dma_addr_t table_b = 0;
+ unsigned long irqflags;
+ int ret;
+ u32 val;
+
+ if (!arg->enable) {
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_EN, 0);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+ return 0;
+ }
+
+ if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+ memcpy(viif_dev->tables->lsc_table_gr, arg->table_gr, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_r, arg->table_r, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_b, arg->table_b, VIIF_LSC_TABLE_BYTES);
+ memcpy(viif_dev->tables->lsc_table_gb, arg->table_gb, VIIF_LSC_TABLE_BYTES);
+ table_gr = (dma_addr_t)viif_dev->tables_dma->lsc_table_gr;
+ table_r = (dma_addr_t)viif_dev->tables_dma->lsc_table_r;
+ table_b = (dma_addr_t)viif_dev->tables_dma->lsc_table_b;
+ table_gb = (dma_addr_t)viif_dev->tables_dma->lsc_table_gb;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+ lsc_table_transmission(viif_dev, table_gr, table_r, table_b, table_gb);
+
+ /* parabola shading */
+ if (arg->enable & VIIF_L1_LSC_PARABOLA_EN_MASK) {
+ struct viif_l1_lsc_parabola_param *parabola_param = &arg->param.lssc_parabola_param;
+ const struct viif_l1_lsc_parabola_ag_param *params[] = {
+ &parabola_param->r_2d, &parabola_param->r_4d, &parabola_param->gr_2d,
+ &parabola_param->gr_4d, &parabola_param->gb_2d, &parabola_param->gb_4d,
+ &parabola_param->b_2d, &parabola_param->b_4d,
+ };
+ int i;
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 1);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_CENTER,
+ parabola_param->lssc_para_h_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_CENTER,
+ parabola_param->lssc_para_v_center);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_H_GAIN,
+ parabola_param->lssc_para_h_gain);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_V_GAIN,
+ parabola_param->lssc_para_v_gain);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL2,
+ parabola_param->lssc_para_mgsel2);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_MGSEL4,
+ parabola_param->lssc_para_mgsel4);
+
+ for (i = 0; i < 8; i++) {
+ const struct viif_l1_lsc_parabola_ag_param *p = params[i];
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_L(i),
+ PACK_PARA_COEF(p->lssc_paracoef_h_l_max,
+ p->lssc_paracoef_h_l_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_H_R(i),
+ PACK_PARA_COEF(p->lssc_paracoef_h_r_max,
+ p->lssc_paracoef_h_r_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_U(i),
+ PACK_PARA_COEF(p->lssc_paracoef_v_u_max,
+ p->lssc_paracoef_v_u_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_V_D(i),
+ PACK_PARA_COEF(p->lssc_paracoef_v_d_max,
+ p->lssc_paracoef_v_d_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LU(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_lu_max,
+ p->lssc_paracoef_hv_lu_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RU(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_ru_max,
+ p->lssc_paracoef_hv_ru_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_LD(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_ld_max,
+ p->lssc_paracoef_hv_ld_min));
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_COEF_X_HV_RD(i),
+ PACK_PARA_COEF(p->lssc_paracoef_hv_rd_max,
+ p->lssc_paracoef_hv_rd_min));
+ }
+ } else {
+ viif_capture_write(viif_dev, REG_L1_LSSC_PARA_EN, 0);
+ }
+
+ /* grid shading */
+ if (arg->enable & VIIF_L1_LSC_GRID_EN_MASK) {
+ struct viif_l1_lsc_grid_param *grid_param = &arg->param.lssc_grid_param;
+ u32 grid_h_size = gen_grid_size(grid_param->lssc_grid_h_size);
+ u32 grid_v_size = gen_grid_size(grid_param->lssc_grid_v_size);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 1);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_SIZE, grid_h_size);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_SIZE, grid_v_size);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_H_CENTER,
+ grid_param->lssc_grid_h_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_V_CENTER,
+ grid_param->lssc_grid_v_center);
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_MGSEL, grid_param->lssc_grid_mgsel);
+
+ } else {
+ viif_capture_write(viif_dev, REG_L1_LSSC_GRID_EN, 0);
+ }
+
+ /* preset white balance */
+ val = (arg->param.lssc_pwhb_r_gain_max << 16U) | (arg->param.lssc_pwhb_r_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_R_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_gr_gain_max << 16U) | (arg->param.lssc_pwhb_gr_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GR_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_gb_gain_max << 16U) | (arg->param.lssc_pwhb_gb_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_GB_GAIN, val);
+
+ val = (arg->param.lssc_pwhb_b_gain_max << 16U) | (arg->param.lssc_pwhb_b_gain_min);
+ viif_capture_write(viif_dev, REG_L1_LSSC_PWHB_B_GAIN, val);
+
+ viif_capture_write(viif_dev, REG_L1_LSSC_EN, 1);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return ret;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS */
+static int viif_l1_set_main_process_try(struct viif_device *viif_dev,
+ struct viif_l1_main_process_config *arg)
+{
+ if (arg->demosaic_mode != VIIF_L1_DEMOSAIC_ACPI &&
+ arg->demosaic_mode != VIIF_L1_DEMOSAIC_DMG) {
+ return -EINVAL;
+ }
+
+ if (arg->damp_lsbsel > VIIF_DAMP_MAX_LSBSEL)
+ return -EINVAL;
+
+ if (arg->colormat_enable) {
+ struct viif_l1_color_matrix_correction *color_matrix = &arg->colormat_param;
+
+ if (color_matrix->coef_rmg_min > color_matrix->coef_rmg_max ||
+ color_matrix->coef_rmb_min > color_matrix->coef_rmb_max ||
+ color_matrix->coef_gmr_min > color_matrix->coef_gmr_max ||
+ color_matrix->coef_gmb_min > color_matrix->coef_gmb_max ||
+ color_matrix->coef_bmr_min > color_matrix->coef_bmr_max ||
+ color_matrix->coef_bmg_min > color_matrix->coef_bmg_max ||
+ (u32)color_matrix->dst_minval > arg->dst_maxval)
+ return -EINVAL;
+ }
+
+ if (arg->dst_maxval > VIIF_MAIN_PROCESS_MAX_OUT_PIXEL_VAL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int viif_l1_set_main_process(struct viif_device *viif_dev,
+ struct viif_l1_main_process_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_CONF, arg->damp_lsbsel << 4);
+ viif_capture_write(viif_dev, REG_L1_MPRO_LCS_MODE, arg->demosaic_mode);
+
+ if (arg->colormat_enable) {
+ const struct viif_l1_color_matrix_correction *color_matrix = &arg->colormat_param;
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_SW, 1);
+
+ val = (u32)color_matrix->coef_rmg_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MIN, val);
+
+ val = (u32)color_matrix->coef_rmg_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMG_MAX, val);
+
+ val = (u32)color_matrix->coef_rmb_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MIN, val);
+
+ val = (u32)color_matrix->coef_rmb_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_RMB_MAX, val);
+
+ val = (u32)color_matrix->coef_gmr_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MIN, val);
+
+ val = (u32)color_matrix->coef_gmr_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMR_MAX, val);
+
+ val = (u32)color_matrix->coef_gmb_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MIN, val);
+
+ val = (u32)color_matrix->coef_gmb_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_GMB_MAX, val);
+
+ val = (u32)color_matrix->coef_bmr_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MIN, val);
+
+ val = (u32)color_matrix->coef_bmr_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMR_MAX, val);
+
+ val = (u32)color_matrix->coef_bmg_min & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MIN, val);
+
+ val = (u32)color_matrix->coef_bmg_max & 0xffffU;
+ viif_capture_write(viif_dev, REG_L1_MPRO_LM0_BMG_MAX, val);
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_DST_MINVAL, (u32)color_matrix->dst_minval);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_MPRO_SW, 0);
+ }
+
+ viif_capture_write(viif_dev, REG_L1_MPRO_DST_MAXVAL, arg->dst_maxval);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB */
+static int viif_l1_set_awb_try(struct viif_device *viif_dev, struct viif_l1_awb_config *arg)
+{
+ struct viif_l1_awb *param;
+ u32 val;
+
+ if (arg->awhb_wbmrg < VIIF_L1_AWB_MIN_GAIN || arg->awhb_wbmrg >= VIIF_L1_AWB_MAX_GAIN ||
+ arg->awhb_wbmgg < VIIF_L1_AWB_MIN_GAIN || arg->awhb_wbmgg >= VIIF_L1_AWB_MAX_GAIN ||
+ arg->awhb_wbmbg < VIIF_L1_AWB_MIN_GAIN || arg->awhb_wbmbg >= VIIF_L1_AWB_MAX_GAIN) {
+ return -EINVAL;
+ }
+
+ /* disabling AWB */
+ if (!arg->enable)
+ return 0;
+
+ param = &arg->param;
+
+ if (param->awhb_ygate_data != 64U && param->awhb_ygate_data != 128U &&
+ param->awhb_ygate_data != 256U && param->awhb_ygate_data != 512U) {
+ return -EINVAL;
+ }
+
+ if (param->awhb_cgrange != VIIF_L1_AWB_ONE_SECOND &&
+ param->awhb_cgrange != VIIF_L1_AWB_X1 && param->awhb_cgrange != VIIF_L1_AWB_X2 &&
+ param->awhb_cgrange != VIIF_L1_AWB_X4) {
+ return -EINVAL;
+ }
+
+ if (param->awhb_areamode != VIIF_L1_AWB_AREA_MODE0 &&
+ param->awhb_areamode != VIIF_L1_AWB_AREA_MODE1 &&
+ param->awhb_areamode != VIIF_L1_AWB_AREA_MODE2 &&
+ param->awhb_areamode != VIIF_L1_AWB_AREA_MODE3) {
+ return -EINVAL;
+ }
+
+ val = viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH);
+ if (param->awhb_area_hsize < 1U || (param->awhb_area_hsize > ((val - 8U) / 8U)) ||
+ param->awhb_area_hofs > (val - 9U)) {
+ return -EINVAL;
+ }
+
+ val = viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT);
+ if (param->awhb_area_vsize < 1U || (param->awhb_area_vsize > ((val - 4U) / 8U)) ||
+ param->awhb_area_vofs > (val - 5U)) {
+ return -EINVAL;
+ }
+
+ if (param->awhb_bycut0p > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_bycut0n > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rycut0p > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rycut0n > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rbcut0h < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_rbcut0h > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_rbcut0l < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_rbcut0l > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_bycut_h[0] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_bycut_h[0] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_bycut_h[1] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_bycut_h[1] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_bycut_h[2] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_bycut_h[2] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_bycut_l[0] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_bycut_l[1] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_bycut_l[2] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rycut_h[0] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_rycut_h[0] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_rycut_h[1] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_rycut_h[1] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_rycut_h[2] < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_rycut_h[2] > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_rycut_l[0] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rycut_l[1] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_rycut_l[2] > VIIF_L1_AWB_UNSIGNED_GATE_UPPER ||
+ param->awhb_awbsftu < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_awbsftu > VIIF_L1_AWB_GATE_UPPER ||
+ param->awhb_awbsftv < VIIF_L1_AWB_GATE_LOWER ||
+ param->awhb_awbsftv > VIIF_L1_AWB_GATE_UPPER) {
+ return -EINVAL;
+ }
+
+ if (param->awhb_awbspd > VIIF_L1_AWB_MAX_UV_CONVERGENCE_SPEED ||
+ param->awhb_awbulv > VIIF_L1_AWB_MAX_UV_CONVERGENCE_LEVEL ||
+ param->awhb_awbvlv > VIIF_L1_AWB_MAX_UV_CONVERGENCE_LEVEL ||
+ param->awhb_awbondot > VIIF_L1_AWB_INTEGRATION_STOP_TH) {
+ return -EINVAL;
+ }
+
+ switch (param->awhb_awbfztim) {
+ case VIIF_L1_AWB_RESTART_NO:
+ case VIIF_L1_AWB_RESTART_128FRAME:
+ case VIIF_L1_AWB_RESTART_64FRAME:
+ case VIIF_L1_AWB_RESTART_32FRAME:
+ case VIIF_L1_AWB_RESTART_16FRAME:
+ case VIIF_L1_AWB_RESTART_8FRAME:
+ case VIIF_L1_AWB_RESTART_4FRAME:
+ case VIIF_L1_AWB_RESTART_2FRAME:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int viif_l1_set_awb(struct viif_device *viif_dev, struct viif_l1_awb_config *arg)
+{
+ struct viif_l1_awb *param = &arg->param;
+ unsigned long irqflags;
+ u32 val, ygate_data;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMRG, arg->awhb_wbmrg);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMGG, arg->awhb_wbmgg);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBMBG, arg->awhb_wbmbg);
+
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_EN;
+
+ /* disabling AWB */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+ goto op_done;
+ }
+
+ /* enabling AWB */
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val | MASK_L1_AWHB_SW_EN);
+
+ if (param->awhb_ygate_data == 64U)
+ ygate_data = 0U;
+ else if (param->awhb_ygate_data == 128U)
+ ygate_data = 1U;
+ else if (param->awhb_ygate_data == 256U)
+ ygate_data = 2U;
+ else
+ ygate_data = 3U;
+
+ val = param->awhb_ygate_sel ? MASK_L1_AWHB_GATE_YGATE_SEL : 0;
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_YGATE_DATA, ygate_data);
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_CGRANGE, param->awhb_cgrange);
+ viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF0, val);
+
+ val = param->awhb_ygatesw ? MASK_L1_AWHB_GATE_YGATESW : 0;
+ val |= param->awhb_hexsw ? MASK_L1_AWHB_GATE_HEXSW : 0;
+ val |= FIELD_PREP(MASK_L1_AWHB_GATE_AREAMODE, param->awhb_areamode);
+ viif_capture_write(viif_dev, REG_L1_AWHB_GATE_CONF1, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HSIZE, param->awhb_area_hsize);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VSIZE, param->awhb_area_vsize);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_HOFS, param->awhb_area_hofs);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_VOFS, param->awhb_area_vofs);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKH, param->awhb_area_maskh);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AREA_MASKL, param->awhb_area_maskl);
+
+ val = param->awhb_sq_sw[0] ? MASK_L1_AWHB_SQ_CONF_SQ1SW : 0;
+ val |= param->awhb_sq_pol[0] ? MASK_L1_AWHB_SQ_CONF_SQ1POL : 0;
+ val |= param->awhb_sq_sw[1] ? MASK_L1_AWHB_SQ_CONF_SQ2SW : 0;
+ val |= param->awhb_sq_pol[1] ? MASK_L1_AWHB_SQ_CONF_SQ2POL : 0;
+ val |= param->awhb_sq_sw[2] ? MASK_L1_AWHB_SQ_CONF_SQ3SW : 0;
+ val |= param->awhb_sq_pol[2] ? MASK_L1_AWHB_SQ_CONF_SQ3POL : 0;
+ viif_capture_write(viif_dev, REG_L1_AWHB_SQ_CONF, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_YGATEH, (u32)param->awhb_ygateh);
+ viif_capture_write(viif_dev, REG_L1_AWHB_YGATEL, (u32)param->awhb_ygatel);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0P, param->awhb_bycut0p);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT0N, param->awhb_bycut0n);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0P, param->awhb_rycut0p);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT0N, param->awhb_rycut0n);
+
+ val = (u32)param->awhb_rbcut0h & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0H, val);
+ val = (u32)param->awhb_rbcut0l & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RBCUT0L, val);
+
+ val = (u32)param->awhb_bycut_h[0] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT1L, param->awhb_bycut_l[0]);
+ val = (u32)param->awhb_bycut_h[1] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT2L, param->awhb_bycut_l[1]);
+ val = (u32)param->awhb_bycut_h[2] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_BYCUT3L, param->awhb_bycut_l[2]);
+
+ val = (u32)param->awhb_rycut_h[0] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT1L, param->awhb_rycut_l[0]);
+ val = (u32)param->awhb_rycut_h[1] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT2L, param->awhb_rycut_l[1]);
+ val = (u32)param->awhb_rycut_h[2] & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3H, val);
+ viif_capture_write(viif_dev, REG_L1_AWHB_RYCUT3L, param->awhb_rycut_l[2]);
+
+ val = (u32)param->awhb_awbsftu & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTU, val);
+ val = (u32)param->awhb_awbsftv & 0xffU;
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSFTV, val);
+
+ val = (param->awhb_awbhuecor ? MASK_L1_AWHB_AWBSPD_HUECOR : 0);
+ val |= FIELD_PREP(MASK_L1_AWHB_AWBSPD_SPD, param->awhb_awbspd);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBSPD, val);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBULV, param->awhb_awbulv);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBVLV, param->awhb_awbvlv);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBWAIT, (u32)param->awhb_awbwait);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBONDOT, param->awhb_awbondot);
+ viif_capture_write(viif_dev, REG_L1_AWHB_AWBFZTIM, param->awhb_awbfztim);
+
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMAX, (u32)param->awhb_wbgrmax);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMAX, (u32)param->awhb_wbgbmax);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGRMIN, (u32)param->awhb_wbgrmin);
+ viif_capture_write(viif_dev, REG_L1_AWHB_WBGBMIN, (u32)param->awhb_wbgbmin);
+
+op_done:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_LOCK_AWB_GAIN */
+static int viif_l1_lock_awb_gain(struct viif_device *viif_dev, u32 *enable)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_SW) & ~MASK_L1_AWHB_SW_LOCK;
+ val |= (*enable ? MASK_L1_AWHB_SW_LOCK : 0);
+ viif_capture_write(viif_dev, REG_L1_AWHB_SW, val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC */
+static int viif_l1_set_hdrc_try(struct viif_device *viif_dev, struct viif_l1_hdrc_config *arg)
+{
+ struct viif_l1_hdrc *param;
+
+ /* disabling HDRC */
+ if (!arg->enable) {
+ if (arg->hdrc_thr_sft_amt > VIIF_L1_HDRC_MAX_THROUGH_SHIFT_VAL)
+ return -EINVAL;
+ return 0;
+ }
+
+ /* enabling HDRC */
+ param = &arg->param;
+
+ if (arg->hdrc_thr_sft_amt || param->hdrc_ratio < VIIF_L1_HDRC_MIN_INPUT_DATA_WIDTH ||
+ param->hdrc_ratio > VIIF_L1_HDRC_MAX_INPUT_DATA_WIDTH ||
+ param->hdrc_pt_ratio > VIIF_L1_HDRC_MAX_PT_SLOPE ||
+ param->hdrc_pt_blend > VIIF_L1_HDRC_MAX_BLEND_RATIO ||
+ param->hdrc_pt_blend2 > VIIF_L1_HDRC_MAX_BLEND_RATIO ||
+ (param->hdrc_pt_blend + param->hdrc_pt_blend2) > VIIF_L1_HDRC_MAX_BLEND_RATIO ||
+ (param->hdrc_tn_type != VIIF_L1_HDRC_TONE_USER &&
+ param->hdrc_tn_type != VIIF_L1_HDRC_TONE_PRESET) ||
+ param->hdrc_flr_val > VIIF_L1_HDRC_MAX_FLARE_VAL ||
+ param->hdrc_orgy_blend > VIIF_L1_HDRC_MAX_BLEND_LUMA) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Convert the unit of time-period (from sysclk, to num lines in the image) */
+static u32 sysclk_to_numlines(u32 time_in_sysclk, const struct viif_img_clk *img_clk)
+{
+ u64 v1 = (u64)time_in_sysclk * img_clk->pixel_clock;
+ u64 v2 = (u64)img_clk->htotal_size * VIIF_SYS_CLK;
+
+ return (u32)div64_u64(v1, v2);
+}
+
+static int viif_l1_set_hdrc(struct viif_device *viif_dev, struct viif_l1_hdrc_config *arg)
+{
+ const struct viif_l1_hdrc *param = &arg->param;
+ unsigned long irqflags;
+ u32 val, sw_delay1;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling HDRC */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_HDRC_THR_SFT_AMT, arg->hdrc_thr_sft_amt);
+ viif_capture_write(viif_dev, REG_L1_HDRC_EN, 0);
+
+ goto done_op;
+ }
+
+ /* enabling HDRC */
+ viif_capture_write(viif_dev, REG_L1_HDRC_RATIO,
+ (param->hdrc_ratio - VIIF_L1_HDRC_RATIO_OFFSET));
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_RATIO, param->hdrc_pt_ratio);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND, param->hdrc_pt_blend);
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_BLEND2, param->hdrc_pt_blend2);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_PT_SAT, param->hdrc_pt_sat);
+ viif_capture_write(viif_dev, REG_L1_HDRC_TN_TYPE, param->hdrc_tn_type);
+
+ for (i = 0; i < LEN_L1_HDRC_UTN_TBL; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRC_UTN_TBL(i), param->hdrc_utn_tbl[i]);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_FLR_VAL, param->hdrc_flr_val);
+ viif_capture_write(viif_dev, REG_L1_HDRC_FLR_ADP, param->hdrc_flr_adp ? 1 : 0);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_YBR_OFF, param->hdrc_ybr_off ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L1_HDRC_ORGY_BLEND, param->hdrc_orgy_blend);
+
+ val = ((viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT)) % 64U) / 2U;
+ viif_capture_write(viif_dev, REG_L1_HDRC_MAR_TOP, val);
+ val = ((viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH)) % 64U) / 2U;
+ viif_capture_write(viif_dev, REG_L1_HDRC_MAR_LEFT, val);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_EN, 1);
+
+ /* update of sw_delay1 must be done when MAIN unit is NOT running. */
+ if (!viif_dev->run_flag_main) {
+ sw_delay1 = sysclk_to_numlines(VIIF_REGBUF_ACCESS_TIME, &viif_dev->img_clk) +
+ VIIF_L1_DELAY_W_HDRC + 1U;
+ val = viif_capture_read(viif_dev, REG_INT_M1_LINE) & 0xffffU;
+ val |= (sw_delay1 << 16U);
+ viif_capture_write(viif_dev, REG_INT_M1_LINE, val);
+ /* M2_LINE is the same condition as M1_LINE */
+ viif_capture_write(viif_dev, REG_INT_M2_LINE, val);
+ }
+
+done_op:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM */
+static int viif_l1_set_hdrc_ltm_try(struct viif_device *viif_dev,
+ struct viif_l1_hdrc_ltm_config *arg)
+{
+ u32 val;
+ int idx;
+
+ if (arg->tnp_max >= VIIF_L1_HDRC_MAX_LTM_TONE_BLEND_RATIO ||
+ arg->tnp_mag >= VIIF_L1_HDRC_MAX_LTM_MAGNIFICATION) {
+ return -EINVAL;
+ }
+
+ val = (u32)arg->tnp_fil[0];
+ for (idx = 1; idx < 5; idx++)
+ val += (u32)arg->tnp_fil[idx] * 2U;
+
+ if (val != 1024U)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int viif_l1_set_hdrc_ltm(struct viif_device *viif_dev, struct viif_l1_hdrc_ltm_config *arg)
+{
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAX, arg->tnp_max);
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_MAG, arg->tnp_mag);
+
+ for (i = 0; i < LEN_L1_HDRC_TNP_FIL; i++)
+ viif_capture_write(viif_dev, REG_L1_HDRC_TNP_FIL(i), (u32)arg->tnp_fil[i]);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA */
+static int viif_l1_set_gamma_try(struct viif_device *viif_dev, struct viif_l1_gamma_config *arg)
+{
+ int idx;
+
+ /* disabling L1 gamma */
+ if (!arg->enable)
+ return 0;
+
+ /* enabling L1 gamma */
+ for (idx = 0; idx < 44U; idx++) {
+ if (arg->param.gam_p[idx] > VIIF_L1_GAMMA_MAX_VAL)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int viif_l1_set_gamma(struct viif_device *viif_dev, struct viif_l1_gamma_config *arg)
+{
+ const struct viif_l1_gamma *param = &arg->param;
+ unsigned long irqflags;
+ int i;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling L1 gamma */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 0);
+ goto done_op;
+ }
+
+ /* enabling L1 gamma */
+ for (i = 0; i < 44; i++)
+ viif_capture_write(viif_dev, REG_L1_VPRO_GAMxP(i), param->gam_p[i]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLKADJ, param->blkadj);
+ viif_capture_write(viif_dev, REG_L1_VPRO_PGC_SW, 1);
+
+done_op:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT */
+static int viif_l1_set_img_quality_adjustment_try(struct viif_device *viif_dev,
+ struct viif_l1_img_quality_adjustment_config *arg)
+{
+ if (arg->enable & VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK) {
+ struct viif_l1_lum_noise_reduction *param = &arg->lum_noise_reduction;
+
+ if (param->gain_min > param->gain_max || param->lim_min > param->lim_max)
+ return -EINVAL;
+ }
+ if (arg->enable & VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK) {
+ struct viif_l1_edge_enhancement *param = &arg->edge_enhancement;
+
+ if (param->gain_min > param->gain_max || param->lim_min > param->lim_max ||
+ param->coring_min > param->coring_max)
+ return -EINVAL;
+ }
+ if (arg->enable & VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK) {
+ struct viif_l1_uv_suppression *param = &arg->uv_suppression;
+
+ if (param->bk_mp >= VIIF_L1_SUPPRESSION_MAX_VAL ||
+ param->black >= VIIF_L1_SUPPRESSION_MAX_VAL ||
+ param->wh_mp >= VIIF_L1_SUPPRESSION_MAX_VAL ||
+ param->white >= VIIF_L1_SUPPRESSION_MAX_VAL || param->bk_slv >= param->wh_slv)
+ return -EINVAL;
+ }
+ if (arg->enable & VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK) {
+ struct viif_l1_coring_suppression *param = &arg->coring_suppression;
+
+ if (param->gain_min > param->gain_max || param->lv_min > param->lv_max)
+ return -EINVAL;
+ }
+ if (arg->enable & VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK) {
+ if (arg->edge_suppression.lim > VIIF_L1_EDGE_SUPPRESSION_MAX_LIMIT)
+ return -EINVAL;
+ }
+ if (arg->enable & VIIF_L1_IQA_COLOR_LEVEL_EN_MASK) {
+ struct viif_l1_color_level *param = &arg->color_level;
+
+ if (param->cb_gain >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->cr_gain >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->cbr_mgain_min >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->cbp_gain_max >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->cbm_gain_max >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->crp_gain_max >= VIIF_L1_COLOR_LEVEL_MAX_GAIN ||
+ param->crm_gain_max >= VIIF_L1_COLOR_LEVEL_MAX_GAIN) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int viif_l1_set_img_quality_adjustment(struct viif_device *viif_dev,
+ struct viif_l1_img_quality_adjustment_config *arg)
+{
+ unsigned long irqflags;
+ u32 val;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* RGB to YUV (enabled by default, should be enabled) */
+ viif_capture_write(viif_dev, REG_L1_VPRO_YUVC_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_MAT, (u32)arg->coef_cb);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_MAT, (u32)arg->coef_cr);
+
+ /* brightness */
+ val = (u32)arg->brightness & 0xffffU;
+ if (val) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT, val);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_BRIGHT_SW, 0);
+ }
+
+ /* linear contrast */
+ if ((u32)arg->linear_contrast != 128U) {
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCONT_LEV, arg->linear_contrast);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_LCNT_SW, 0);
+ }
+
+ /* nonlinear contrast */
+ if (arg->enable & VIIF_L1_IQA_NONLINEAR_CONTRAST_EN_MASK) {
+ struct viif_l1_nonlinear_contrast *nonlinear_contrast = &arg->nonlinear_contrast;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_KNEE, nonlinear_contrast->blk_knee);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_KNEE, nonlinear_contrast->wht_knee);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT0,
+ nonlinear_contrast->blk_cont[0]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT1,
+ nonlinear_contrast->blk_cont[1]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_BLK_CONT2,
+ nonlinear_contrast->blk_cont[2]);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT0,
+ nonlinear_contrast->wht_cont[0]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT1,
+ nonlinear_contrast->wht_cont[1]);
+ viif_capture_write(viif_dev, REG_L1_VPRO_WHT_CONT2,
+ nonlinear_contrast->wht_cont[2]);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_NLCNT_SW, 0);
+ }
+
+ /* luminance noise reduction */
+ if (arg->enable & VIIF_L1_IQA_LUM_NOISE_REDUCTION_EN_MASK) {
+ struct viif_l1_lum_noise_reduction *lum_noise_reduction = &arg->lum_noise_reduction;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MIN,
+ lum_noise_reduction->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_GAIN_MAX,
+ lum_noise_reduction->gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MIN, lum_noise_reduction->lim_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_LIM_MAX, lum_noise_reduction->lim_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_YNR_SW, 0);
+ }
+
+ /* edge enhancement */
+ if (arg->enable & VIIF_L1_IQA_EDGE_ENHANCEMENT_EN_MASK) {
+ struct viif_l1_edge_enhancement *edge_enhancement = &arg->edge_enhancement;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MIN, edge_enhancement->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_GAIN_MAX, edge_enhancement->gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MIN, edge_enhancement->lim_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_LIM_MAX, edge_enhancement->lim_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MIN,
+ edge_enhancement->coring_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_CORING_MAX,
+ edge_enhancement->coring_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_ETE_SW, 0);
+ }
+
+ /* UV suppression */
+ if (arg->enable & VIIF_L1_IQA_UV_SUPPRESSION_EN_MASK) {
+ struct viif_l1_uv_suppression *uv_suppression = &arg->uv_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_SLV, uv_suppression->bk_slv);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BK_MP, uv_suppression->bk_mp);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_BLACK, uv_suppression->black);
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_SLV, uv_suppression->wh_slv);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WH_MP, uv_suppression->wh_mp);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_WHITE, uv_suppression->white);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_UVSUP_SW, 0);
+ }
+
+ /* coring suppression */
+ if (arg->enable & VIIF_L1_IQA_CORING_SUPPRESSION_EN_MASK) {
+ struct viif_l1_coring_suppression *coring_suppression = &arg->coring_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MIN,
+ coring_suppression->lv_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_LV_MAX,
+ coring_suppression->lv_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MIN,
+ coring_suppression->gain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_GAIN_MAX,
+ coring_suppression->gain_max);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_CSUP_CORING_SW, 0);
+ }
+
+ /* edge suppression */
+ if (arg->enable & VIIF_L1_IQA_EDGE_SUPPRESSION_EN_MASK) {
+ struct viif_l1_edge_suppression *edge_suppression = &arg->edge_suppression;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 1);
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_GAIN, edge_suppression->gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_LIM, edge_suppression->lim);
+ } else {
+ viif_capture_write(viif_dev, REG_L1_VPRO_EDGE_SUP_SW, 0);
+ }
+
+ /* color level */
+ if (arg->enable & VIIF_L1_IQA_COLOR_LEVEL_EN_MASK) {
+ struct viif_l1_color_level *color_level = &arg->color_level;
+
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, color_level->cb_gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, color_level->cr_gain);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, color_level->cbr_mgain_min);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, color_level->cbp_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, color_level->cbm_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, color_level->crp_gain_max);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, color_level->crm_gain_max);
+ } else {
+ /* disable */
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_GAIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_GAIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CBR_MGAIN_MIN, 1024U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_P_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CB_M_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_P_GAIN_MAX, 0U);
+ viif_capture_write(viif_dev, REG_L1_VPRO_CR_M_GAIN_MAX, 0U);
+ }
+
+ /* color noise reduction */
+ viif_capture_write(viif_dev, REG_L1_VPRO_CNR_SW,
+ arg->enable & VIIF_L1_IQA_COLOR_NOISE_REDUCTION_EN_MASK ? 1 : 0);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION */
+static int viif_l1_set_avg_lum_generation_try(struct viif_device *viif_dev,
+ struct viif_l1_avg_lum_generation_config *arg)
+{
+ u32 width, height;
+ int i, j;
+
+ if (!arg->enable)
+ return 0;
+
+ width = viif_capture_read(viif_dev, REG_L1_SYSM_WIDTH);
+ height = viif_capture_read(viif_dev, REG_L1_SYSM_HEIGHT);
+
+ if (arg->aexp_start_x > (width - 1U))
+ return -EINVAL;
+
+ if (arg->aexp_block_width < VIIF_L1_AEXP_MIN_BLOCK_WIDTH || arg->aexp_block_width > width)
+ return -EINVAL;
+
+ if (arg->aexp_block_width % 64U)
+ return -EINVAL;
+
+ if (arg->aexp_start_y > (height - 1U))
+ return -EINVAL;
+
+ if (arg->aexp_block_height < VIIF_L1_AEXP_MIN_BLOCK_HEIGHT ||
+ arg->aexp_block_height > height) {
+ return -EINVAL;
+ }
+ if (arg->aexp_block_height % 64U)
+ return -EINVAL;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ if (arg->aexp_weight[i][j] > VIIF_L1_AEXP_MAX_WEIGHT)
+ return -EINVAL;
+ }
+ }
+
+ if (arg->aexp_satur_ratio > VIIF_L1_AEXP_MAX_BLOCK_TH ||
+ arg->aexp_black_ratio > VIIF_L1_AEXP_MAX_BLOCK_TH ||
+ arg->aexp_satur_level > VIIF_L1_AEXP_MAX_SATURATION_PIXEL_TH) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (arg->aexp_ave4linesy[i] > (height - 4U))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline u32 pack_weight(u32 *vec)
+{
+ return (vec[0] << 14) | (vec[1] << 12) | (vec[2] << 10) | (vec[3] << 8) | (vec[4] << 6) |
+ (vec[5] << 4) | (vec[6] << 2U) | (vec[7]);
+}
+
+static int viif_l1_set_avg_lum_generation(struct viif_device *viif_dev,
+ struct viif_l1_avg_lum_generation_config *arg)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* disabling aggregation */
+ if (!arg->enable) {
+ viif_capture_write(viif_dev, REG_L1_AEXP_ON, 0);
+ goto op_done;
+ }
+
+ /* enabling aggregation */
+ viif_capture_write(viif_dev, REG_L1_AEXP_ON, 1);
+ viif_capture_write(viif_dev, REG_L1_AEXP_START_X, arg->aexp_start_x);
+ viif_capture_write(viif_dev, REG_L1_AEXP_START_Y, arg->aexp_start_y);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_WIDTH, arg->aexp_block_width);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLOCK_HEIGHT, arg->aexp_block_height);
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_0, pack_weight(arg->aexp_weight[0]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_1, pack_weight(arg->aexp_weight[1]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_2, pack_weight(arg->aexp_weight[2]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[3]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_3, pack_weight(arg->aexp_weight[4]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_4, pack_weight(arg->aexp_weight[5]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_5, pack_weight(arg->aexp_weight[6]));
+ viif_capture_write(viif_dev, REG_L1_AEXP_WEIGHT_7, pack_weight(arg->aexp_weight[7]));
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_RATIO, arg->aexp_satur_ratio);
+ viif_capture_write(viif_dev, REG_L1_AEXP_BLACK_RATIO, arg->aexp_black_ratio);
+ viif_capture_write(viif_dev, REG_L1_AEXP_SATUR_LEVEL, arg->aexp_satur_level);
+
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY0, arg->aexp_ave4linesy[0]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY1, arg->aexp_ave4linesy[1]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY2, arg->aexp_ave4linesy[2]);
+ viif_capture_write(viif_dev, REG_L1_AEXP_AVE4LINESY3, arg->aexp_ave4linesy[3]);
+
+op_done:
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST */
+static void undist_table_transmission(struct viif_device *viif_dev, dma_addr_t write_g,
+ dma_addr_t read_b, dma_addr_t read_g, dma_addr_t read_r,
+ u32 size)
+{
+ u32 val = 0U;
+
+ if (read_b) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_B),
+ (u32)read_b);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_B), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_B;
+ }
+ if (read_g) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_G),
+ (u32)read_g);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_G), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_G;
+ }
+ if (read_r) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_RD_R),
+ (u32)read_r);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_RD_R), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_RD_R;
+ }
+ if (write_g) {
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(IDX_TPORT_L2_UNDIST_WR_G),
+ (u32)write_g);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(IDX_TPORT_L2_UNDIST_WR_G), size);
+ val |= MASK_VDM_T_ENABLE_L2_UNDIST_WR_G;
+ }
+
+ if (val)
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_UNDIST);
+
+ val |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) & ~MASK_VDM_T_ENABLE_L2_UNDIST;
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, val);
+}
+
+static int viif_l2_set_undist_try(struct viif_device *viif_dev, struct viif_l2_undist_config *arg)
+{
+ struct viif_l2_undist *param = &arg->param;
+ u32 grid_num_h = param->grid_node_num_h;
+ u32 grid_num_v = param->grid_node_num_v;
+ u32 size = arg->size;
+ bool transfer;
+ u32 val;
+ int i;
+
+ if ((size && size < VIIF_L2_UNDIST_MIN_TABLE_SIZE) ||
+ size > VIIF_L2_UNDIST_MAX_TABLE_SIZE) {
+ return -EINVAL;
+ }
+
+ if (size % 4U)
+ return -EINVAL;
+
+ transfer = ((param->roi_mode[0] != VIIF_L2_UNDIST_POLY) ||
+ (param->roi_mode[1] != VIIF_L2_UNDIST_POLY));
+ if ((transfer && !size) || (!transfer && size))
+ return -EINVAL;
+
+ for (i = 0; i < 2; i++) {
+ if (param->roi_mode[i] != VIIF_L2_UNDIST_POLY &&
+ param->roi_mode[i] != VIIF_L2_UNDIST_GRID &&
+ param->roi_mode[i] != VIIF_L2_UNDIST_POLY_TO_GRID &&
+ param->roi_mode[i] != VIIF_L2_UNDIST_GRID_TO_POLY) {
+ return -EINVAL;
+ }
+ }
+ if (param->roi_write_area_delta[0] >= VIIF_L2_UNDIST_MAX_ROI_WRITE_AREA_DELTA ||
+ param->roi_write_area_delta[1] >= VIIF_L2_UNDIST_MAX_ROI_WRITE_AREA_DELTA ||
+ param->sensor_crop_ofs_h < VIIF_L2_UNDIST_MIN_SENSOR_CROP_OFS_H ||
+ param->sensor_crop_ofs_h > VIIF_L2_UNDIST_MAX_SENSOR_CROP_OFS_H ||
+ param->sensor_crop_ofs_v < VIIF_L2_UNDIST_MIN_SENSOR_CROP_OFS_V ||
+ param->sensor_crop_ofs_v > VIIF_L2_UNDIST_MAX_SENSOR_CROP_OFS_V ||
+ param->norm_scale > VIIF_L2_UNDIST_MAX_NORM_SCALE ||
+ param->valid_r_norm2_poly >= VIIF_L2_UNDIST_MAX_VALID_R_NORM2 ||
+ param->valid_r_norm2_grid >= VIIF_L2_UNDIST_MAX_VALID_R_NORM2) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < (int)VIIF_L2_UNDIST_POLY_NUM; i++) {
+ if (param->poly_write_g_coef[i] < VIIF_L2_UNDIST_MIN_POLY_COEF ||
+ param->poly_write_g_coef[i] > VIIF_L2_UNDIST_MAX_POLY_COEF ||
+ param->poly_read_b_coef[i] < VIIF_L2_UNDIST_MIN_POLY_COEF ||
+ param->poly_read_b_coef[i] > VIIF_L2_UNDIST_MAX_POLY_COEF ||
+ param->poly_read_g_coef[i] < VIIF_L2_UNDIST_MIN_POLY_COEF ||
+ param->poly_read_g_coef[i] > VIIF_L2_UNDIST_MAX_POLY_COEF ||
+ param->poly_read_r_coef[i] < VIIF_L2_UNDIST_MIN_POLY_COEF ||
+ param->poly_read_r_coef[i] > VIIF_L2_UNDIST_MAX_POLY_COEF) {
+ return -EINVAL;
+ }
+ }
+
+ if (grid_num_h < VIIF_L2_UNDIST_MIN_GRID_NUM || grid_num_h > VIIF_L2_UNDIST_MAX_GRID_NUM ||
+ grid_num_v < VIIF_L2_UNDIST_MIN_GRID_NUM || grid_num_v > VIIF_L2_UNDIST_MAX_GRID_NUM) {
+ return -EINVAL;
+ }
+
+ if (grid_num_h % 2U)
+ grid_num_h += 1U;
+
+ if (grid_num_v % 2U)
+ grid_num_v += 1U;
+
+ if ((grid_num_v * grid_num_h) > VIIF_L2_UNDIST_MAX_GRID_TOTAL_NUM ||
+ param->grid_patch_hsize_inv >= VIIF_L2_UNDIST_MAX_GRID_PATCH_SIZE_INV ||
+ param->grid_patch_vsize_inv >= VIIF_L2_UNDIST_MAX_GRID_PATCH_SIZE_INV) {
+ return -EINVAL;
+ }
+
+ val = viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE) & GENMASK(12, 0);
+ if (((param->sensor_crop_ofs_h / 2) + ((s16)val)) > 4095)
+ return -EINVAL;
+
+ val = viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE) & GENMASK(11, 0);
+ if (((param->sensor_crop_ofs_v / 2) + ((s16)val)) > 2047)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void undist_setup(struct viif_device *viif_dev, struct viif_l2_undist *param)
+{
+ u32 val;
+ unsigned int i;
+
+ /* Undist through mode */
+ if (param->through_mode) {
+ /* Enable through mode */
+ viif_capture_write(viif_dev, REG_L2_MODE, 1);
+ return;
+ }
+
+ /* Undist operation */
+ val = (param->roi_mode[0] << 1U) | (param->roi_mode[1] << 3U);
+ viif_capture_write(viif_dev, REG_L2_MODE, val);
+ val = (u32)param->sensor_crop_ofs_h & GENMASK(13, 0);
+ viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_H, val);
+ val = (u32)param->sensor_crop_ofs_v & GENMASK(12, 0);
+ viif_capture_write(viif_dev, REG_L2_SENSOR_CROP_OFS_V, val);
+ viif_capture_write(viif_dev, REG_L2_NORM_SCALE, param->norm_scale);
+ viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_POLY, param->valid_r_norm2_poly);
+ viif_capture_write(viif_dev, REG_L2_VALID_R_NORM2_GRID, param->valid_r_norm2_grid);
+ viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(0),
+ param->roi_write_area_delta[0]);
+ viif_capture_write(viif_dev, REG_L2_ROI_WRITE_AREA_DELTA(1),
+ param->roi_write_area_delta[1]);
+
+ for (i = 0; i < VIIF_L2_UNDIST_POLY_NUM; i++) {
+ val = (u32)param->poly_write_g_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_WRITE_G_COEF(i), val);
+ val = (u32)param->poly_read_b_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_B_COEF(i), val);
+ val = (u32)param->poly_read_g_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_G_COEF(i), val);
+ val = (u32)param->poly_read_r_coef[i];
+ viif_capture_write(viif_dev, REG_L2_POLY10_READ_R_COEF(i), val);
+ }
+ viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_H, param->grid_node_num_h);
+ viif_capture_write(viif_dev, REG_L2_GRID_NODE_NUM_V, param->grid_node_num_v);
+ viif_capture_write(viif_dev, REG_L2_GRID_PATCH_HSIZE_INV, param->grid_patch_hsize_inv);
+ viif_capture_write(viif_dev, REG_L2_GRID_PATCH_VSIZE_INV, param->grid_patch_vsize_inv);
+}
+
+static int viif_l2_set_undist(struct viif_device *viif_dev, struct viif_l2_undist_config *arg)
+{
+ dma_addr_t table_write_g = 0;
+ dma_addr_t table_read_b = 0;
+ dma_addr_t table_read_g = 0;
+ dma_addr_t table_read_r = 0;
+ unsigned long irqflags;
+
+ if (arg->param.roi_mode[0] != VIIF_L2_UNDIST_POLY ||
+ arg->param.roi_mode[1] != VIIF_L2_UNDIST_POLY) {
+ memcpy(viif_dev->tables->undist_write_g, arg->write_g, arg->size);
+ memcpy(viif_dev->tables->undist_read_b, arg->read_b, arg->size);
+ memcpy(viif_dev->tables->undist_read_g, arg->read_g, arg->size);
+ memcpy(viif_dev->tables->undist_read_r, arg->read_r, arg->size);
+
+ table_write_g = (uintptr_t)viif_dev->tables_dma->undist_write_g;
+ table_read_b = (uintptr_t)viif_dev->tables_dma->undist_read_b;
+ table_read_g = (uintptr_t)viif_dev->tables_dma->undist_read_g;
+ table_read_r = (uintptr_t)viif_dev->tables_dma->undist_read_r;
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ undist_table_transmission(viif_dev, table_write_g, table_read_b, table_read_g, table_read_r,
+ arg->size);
+
+ undist_setup(viif_dev, &arg->param);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+ return 0;
+}
+
+int visconti_viif_l2_undist_through(struct viif_device *viif_dev)
+{
+ struct viif_l2_undist undist = { 0 };
+
+ undist.through_mode = VIIF_ENABLE;
+ undist.sensor_crop_ofs_h =
+ 1 - FIELD_GET(0x1FFF, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_HSIZE));
+ undist.sensor_crop_ofs_v =
+ 1 - FIELD_GET(0x0FFF, viif_capture_read(viif_dev, REG_L2_SENSOR_CROP_VSIZE));
+ undist.grid_node_num_h = 16;
+ undist.grid_node_num_v = 16;
+
+ undist_setup(viif_dev, &undist);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI */
+static int viif_l2_set_roi_try(struct viif_device *viif_dev, struct viif_l2_roi_config *param)
+{
+ int i;
+
+ if (!param)
+ return -EINVAL;
+
+ if (param->roi_num != 1 && param->roi_num != 2)
+ return -EINVAL;
+
+ for (i = 0; i < 2; i++) {
+ if (param->roi_scale[i] < VIIF_L2_ROI_MIN_SCALE ||
+ param->roi_scale[i] > VIIF_L2_ROI_MAX_SCALE ||
+ param->roi_scale_inv[i] < VIIF_L2_ROI_MIN_SCALE_INV ||
+ param->roi_scale_inv[i] > VIIF_L2_ROI_MAX_SCALE_INV ||
+ param->corrected_wo_scale_hsize[i] < VIIF_L2_ROI_MIN_CORRECTED_WO_SCALE_HSIZE ||
+ param->corrected_wo_scale_hsize[i] > VIIF_L2_ROI_MAX_CORRECTED_WO_SCALE_HSIZE ||
+ param->corrected_wo_scale_vsize[i] < VIIF_L2_ROI_MIN_CORRECTED_WO_SCALE_VSIZE ||
+ param->corrected_wo_scale_vsize[i] > VIIF_L2_ROI_MAX_CORRECTED_WO_SCALE_VSIZE ||
+ param->corrected_hsize[i] < VIIF_L2_ROI_MIN_CORRECTED_HSIZE ||
+ param->corrected_hsize[i] > VIIF_L2_ROI_MAX_CORRECTED_HSIZE ||
+ param->corrected_vsize[i] < VIIF_L2_ROI_MIN_CORRECTED_VSIZE ||
+ param->corrected_vsize[i] > VIIF_L2_ROI_MAX_CORRECTED_VSIZE) {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int viif_l2_set_roi_wrap(struct viif_device *viif_dev, struct viif_l2_roi_config *roi)
+{
+ unsigned long irqflags;
+
+ /* update ROI parameter */
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+ visconti_viif_l2_set_roi(viif_dev, roi);
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ /* reflect change to pad::compose_rect */
+ visconti_viif_isp_set_compose_rect(viif_dev, roi);
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA */
+struct viif_l2_gamma_table {
+ dma_addr_t table[VIIF_L2_GAMMA_TABLE_CH_NUM];
+};
+
+static void l2_gamma_table_transmission(struct viif_device *viif_dev, u32 post_id,
+ const struct viif_l2_gamma_table *gamma_table)
+{
+ u32 vdm_enable = 0U;
+ u32 i;
+
+ /* 0: LUT0-G/Y, 1: LUT1-G/Y, 2: LUT0-B/U, 3: LUT1-B/U, 4: LUT0-R/V, 5: LUT1-R/V */
+ for (i = 0; i < VIIF_L2_GAMMA_TABLE_CH_NUM; i++) {
+ if (gamma_table->table[i]) {
+ int idx = IDX_TPORT_L2_GAMMA_LUT(post_id, i);
+
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_STADR(idx),
+ (u32)gamma_table->table[i]);
+ viif_capture_write(viif_dev, REG_VDM_TPORT_X_SIZE(idx),
+ VIIF_L2_GAMMA_TABLE_BYTES);
+ vdm_enable |= MASK_VDM_T_ENABLE_L2_GAMMA(post_id, i);
+ }
+ }
+ if (vdm_enable)
+ viif_config_vdm_tgroup(viif_dev, IDX_TGROUP_L2_GAMMA_LUT(post_id));
+
+ vdm_enable |= viif_capture_read(viif_dev, REG_VDM_T_ENABLE) &
+ ~MASK_VDM_T_ENABLE_L2_GAMMA_ALL(post_id);
+
+ viif_capture_write(viif_dev, REG_VDM_T_ENABLE, vdm_enable);
+}
+
+static int viif_l2_set_gamma_try(struct viif_device *viif_dev,
+ struct viif_l2_gamma_config *l2_gamma)
+{
+ u32 vsplit, mode;
+ bool enable;
+
+ if (!l2_gamma)
+ return -EINVAL;
+
+ enable = (l2_gamma->table_en != 0);
+ vsplit = l2_gamma->vsplit;
+ mode = l2_gamma->mode;
+
+ if (l2_gamma->pathid != CAPTURE_PATH_MAIN_POST0 &&
+ l2_gamma->pathid != CAPTURE_PATH_MAIN_POST1)
+ return -EINVAL;
+
+ if (vsplit > VIIF_GAMMA_MAX_VSPLIT ||
+ (mode != VIIF_GAMMA_COMPRESSED && mode != VIIF_GAMMA_LINEAR) || (!enable && vsplit) ||
+ (!enable && mode != VIIF_GAMMA_COMPRESSED)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int viif_l2_set_gamma(struct viif_device *viif_dev, struct viif_l2_gamma_config *l2_gamma)
+{
+ struct viif_l2_gamma_table dma_table = { 0 };
+ int pathid = l2_gamma->pathid;
+ unsigned long irqflags;
+ int table_en;
+ int postid;
+ u32 val;
+ int i;
+
+ postid = (pathid == CAPTURE_PATH_MAIN_POST0) ? VIIF_L2ISP_POST_0 : VIIF_L2ISP_POST_1;
+
+ table_en = l2_gamma->table_en;
+ for (i = 0; i < 6; i++) {
+ if (table_en & BIT(i)) {
+ memcpy(viif_dev->tables->l2_gamma_table[pathid][i], l2_gamma->table[i],
+ VIIF_L2_GAMMA_TABLE_BYTES);
+ dma_table.table[i] =
+ (dma_addr_t)viif_dev->tables_dma->l2_gamma_table[pathid][i];
+ }
+ }
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ l2_gamma_table_transmission(viif_dev, postid, &dma_table);
+
+ val = (l2_gamma->vsplit << 16U) | (l2_gamma->mode << 4U) | (table_en != 0 ? 1 : 0);
+ viif_capture_write(viif_dev, REG_L2_POST_X_GAMMA_M(postid), val);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_CALIBRATION_STATUS */
+static const struct viif_csi2rx_dphy_calibration_status calib_status_not_streaming = {
+ .term_cal_with_rext = -EAGAIN,
+ .clock_lane_offset_cal = -EAGAIN,
+ .data_lane0_offset_cal = -EAGAIN,
+ .data_lane1_offset_cal = -EAGAIN,
+ .data_lane2_offset_cal = -EAGAIN,
+ .data_lane3_offset_cal = -EAGAIN,
+ .data_lane0_ddl_tuning_cal = -EAGAIN,
+ .data_lane1_ddl_tuning_cal = -EAGAIN,
+ .data_lane2_ddl_tuning_cal = -EAGAIN,
+ .data_lane3_ddl_tuning_cal = -EAGAIN,
+};
+
+static int
+viif_csi2rx_get_calibration_status(struct viif_device *viif_dev,
+ struct viif_csi2rx_dphy_calibration_status *calibration_status)
+{
+ if (!vb2_start_streaming_called(&viif_dev->cap_dev0.vb2_vq)) {
+ *calibration_status = calib_status_not_streaming;
+ return 0;
+ }
+ visconti_viif_csi2rx_get_calibration_status(viif_dev, calibration_status);
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_ERR_STATUS */
+static const struct viif_csi2rx_err_status csi_err_not_streaming;
+
+static int viif_csi2rx_get_err_status(struct viif_device *viif_dev,
+ struct viif_csi2rx_err_status *csi_err)
+{
+ if (!vb2_is_streaming(&viif_dev->cap_dev0.vb2_vq)) {
+ *csi_err = csi_err_not_streaming;
+ return 0;
+ }
+ visconti_viif_csi2rx_get_err_status(viif_dev, csi_err);
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS */
+static int viif_isp_get_last_capture_status(struct viif_device *viif_dev,
+ struct viif_isp_capture_status *status)
+{
+ return 0;
+}
+
+/* V4L2_CID_VISCONTI_VIIF_GET_REPORTED_ERRORS */
+static int viif_isp_get_reported_errors(struct viif_device *viif_dev,
+ struct viif_reported_errors *status)
+{
+ status->main = viif_dev->reported_err_main;
+ status->sub = viif_dev->reported_err_sub;
+ status->csi2rx = viif_dev->reported_err_csi2rx;
+ viif_dev->reported_err_main = 0;
+ viif_dev->reported_err_sub = 0;
+ viif_dev->reported_err_csi2rx = 0;
+
+ return 0;
+}
+
+void visconti_viif_save_l1_info(struct viif_device *viif_dev)
+{
+ struct viif_isp_capture_status status;
+ struct viif_l1_info *l1_info = &status.l1_info;
+ unsigned long irqflags;
+ int i, j;
+ u32 val;
+
+ if (!viif_dev->isp_subdev.ctrl_last_capture_status)
+ return;
+
+ spin_lock_irqsave(&viif_dev->regbuf_lock, irqflags);
+ hwd_viif_isp_guard_start(viif_dev);
+
+ /* change register buffer to regbuf0 where driver gets information */
+ viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BUFFER0);
+
+ /* get AWB info */
+ l1_info->awb_ave_u = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_USIG);
+ l1_info->awb_ave_v = viif_capture_read(viif_dev, REG_L1_AWHB_AVE_VSIG);
+ l1_info->awb_accumulated_pixel = viif_capture_read(viif_dev, REG_L1_AWHB_NUM_UVON);
+ l1_info->awb_gain_r = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINR);
+ l1_info->awb_gain_g = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAING);
+ l1_info->awb_gain_b = viif_capture_read(viif_dev, REG_L1_AWHB_AWBGAINB);
+ val = viif_capture_read(viif_dev, REG_L1_AWHB_R_CTR_STOP);
+ l1_info->awb_status_u = (FIELD_GET(BIT(1), val) != 0);
+ l1_info->awb_status_v = (FIELD_GET(BIT(0), val) != 0);
+
+ /* get average luminance info */
+ l1_info->avg_lum_weight = viif_capture_read(viif_dev, REG_L1_AEXP_RESULT_AVE);
+ val = viif_capture_read(viif_dev, REG_L1_AEXP_SATUR_BLACK_PIXNUM);
+ l1_info->avg_satur_pixnum = FIELD_GET(GENMASK(31, 16), val);
+ l1_info->avg_black_pixnum = FIELD_GET(GENMASK(15, 0), val);
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ l1_info->avg_lum_block[i][j] =
+ viif_capture_read(viif_dev, REG_L1_AEXP_AVE(i, j));
+ }
+ }
+ l1_info->avg_lum_four_line_lum[0] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES0);
+ l1_info->avg_lum_four_line_lum[1] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES1);
+ l1_info->avg_lum_four_line_lum[2] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES2);
+ l1_info->avg_lum_four_line_lum[3] = viif_capture_read(viif_dev, REG_L1_AEXP_AVE4LINES3);
+
+ /* revert to register access from register buffer access */
+ viif_capture_write(viif_dev, REG_L1_CRGBF_ACC_CONF, VAL_L1_CRGBF_ACC_CONF_MODE_BYPASS);
+
+ hwd_viif_isp_guard_end(viif_dev);
+ spin_unlock_irqrestore(&viif_dev->regbuf_lock, irqflags);
+
+ v4l2_ctrl_s_ctrl_compound(viif_dev->isp_subdev.ctrl_last_capture_status,
+ viif_dev->isp_subdev.ctrl_last_capture_status->type, &status);
+}
+
+/* ===== v4l2 subdevice control handlers ===== */
+static int isp_set_ctrl(struct viif_device *viif_dev, struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE:
+ return viif_main_set_rawpack_mode(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE:
+ return viif_l1_set_input_mode(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF:
+ return viif_l1_set_rgb_to_y_coef(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE:
+ return viif_l1_set_ag_mode(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG:
+ return viif_l1_set_ag(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE:
+ return viif_l1_set_hdre(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION:
+ return viif_l1_set_img_extraction(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC:
+ return viif_l1_set_dpc(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE:
+ return viif_l1_set_preset_white_balance(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION:
+ return viif_l1_set_raw_color_noise_reduction(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS:
+ return viif_l1_set_hdrs(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION:
+ return viif_l1_set_black_level_correction(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC:
+ return viif_l1_set_lsc(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS:
+ return viif_l1_set_main_process(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB:
+ return viif_l1_set_awb(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_LOCK_AWB_GAIN:
+ return viif_l1_lock_awb_gain(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC:
+ return viif_l1_set_hdrc(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM:
+ return viif_l1_set_hdrc_ltm(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA:
+ return viif_l1_set_gamma(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT:
+ return viif_l1_set_img_quality_adjustment(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION:
+ return viif_l1_set_avg_lum_generation(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST:
+ return viif_l2_set_undist(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI:
+ return viif_l2_set_roi_wrap(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA:
+ return viif_l2_set_gamma(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS:
+ return 0;
+ default:
+ pr_info("unknown_ctrl:s: id=%08X val=%d", ctrl->id, ctrl->val);
+ break;
+ }
+ return -EINVAL;
+}
+
+static int isp_get_ctrl(struct viif_device *viif_dev, struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_CALIBRATION_STATUS:
+ return viif_csi2rx_get_calibration_status(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_ERR_STATUS:
+ return viif_csi2rx_get_err_status(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS:
+ return viif_isp_get_last_capture_status(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_GET_REPORTED_ERRORS:
+ return viif_isp_get_reported_errors(viif_dev, ctrl->p_new.p);
+ default:
+ pr_info("unknown_ctrl:g: id=%08X val=%d", ctrl->id, ctrl->val);
+ break;
+ }
+ return -EINVAL;
+}
+
+static int visconti_viif_isp_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct viif_device *viif_dev = ctrl->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE:
+ return viif_main_set_rawpack_mode_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE:
+ return viif_l1_set_input_mode_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF:
+ return viif_l1_set_rgb_to_y_coef_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE:
+ return viif_l1_set_ag_mode_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG:
+ return 0; //no need to check
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE:
+ return viif_l1_set_hdre_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION:
+ return viif_l1_set_img_extraction_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC:
+ return viif_l1_set_dpc_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE:
+ return viif_l1_set_preset_white_balance_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION:
+ return viif_l1_set_raw_color_noise_reduction_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS:
+ return viif_l1_set_hdrs_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION:
+ return viif_l1_set_black_level_correction_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC:
+ return viif_l1_set_lsc_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS:
+ return viif_l1_set_main_process_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB:
+ return viif_l1_set_awb_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_LOCK_AWB_GAIN:
+ return 0;
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC:
+ return viif_l1_set_hdrc_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM:
+ return viif_l1_set_hdrc_ltm_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA:
+ return viif_l1_set_gamma_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT:
+ return viif_l1_set_img_quality_adjustment_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION:
+ return viif_l1_set_avg_lum_generation_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST:
+ return viif_l2_set_undist_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI:
+ return viif_l2_set_roi_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA:
+ return viif_l2_set_gamma_try(viif_dev, ctrl->p_new.p);
+ case V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS:
+ return 0;
+ default:
+ pr_info("unknown_ctrl:t: id=%08X val=%d", ctrl->id, ctrl->val);
+ break;
+ }
+ return -EINVAL;
+}
+
+static int visconti_viif_isp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct viif_device *viif_dev = ctrl->priv;
+ int ret;
+
+ pr_info("isp_set_ctrl: %s", ctrl->name);
+ if (pm_runtime_status_suspended(viif_dev->dev)) {
+ pr_info("warning: visconti viif HW is not powered");
+ return -EIO;
+ }
+
+ mutex_lock(&viif_dev->isp_subdev.ops_lock);
+ ret = isp_set_ctrl(viif_dev, ctrl);
+ mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+ return ret;
+}
+
+static int visconti_viif_isp_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct viif_device *viif_dev = ctrl->priv;
+ int ret;
+
+ pr_info("isp_get_ctrl: %s", ctrl->name);
+ if (pm_runtime_status_suspended(viif_dev->dev)) {
+ pr_info("warning: visconti viif HW is not powered");
+ return -EIO;
+ }
+
+ mutex_lock(&viif_dev->isp_subdev.ops_lock);
+ ret = isp_get_ctrl(viif_dev, ctrl);
+ mutex_unlock(&viif_dev->isp_subdev.ops_lock);
+ return ret;
+}
+
+/* ===== register v4l2 subdevice controls ===== */
+static bool visconti_viif_isp_custom_ctrl_equal(const struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2)
+{
+ return !memcmp(ptr1.p_const, ptr2.p_const, ctrl->elem_size);
+}
+
+static void visconti_viif_isp_custom_ctrl_init(const struct v4l2_ctrl *ctrl, u32 idx,
+ union v4l2_ctrl_ptr ptr)
+{
+ if (ctrl->p_def.p_const)
+ memcpy(ptr.p, ctrl->p_def.p_const, ctrl->elem_size);
+ else
+ memset(ptr.p, 0, ctrl->elem_size);
+}
+
+static void visconti_viif_isp_custom_ctrl_log(const struct v4l2_ctrl *ctrl)
+{
+}
+
+static int visconti_viif_isp_custom_ctrl_validate(const struct v4l2_ctrl *ctrl,
+ union v4l2_ctrl_ptr ptr)
+{
+ pr_info("std_validate: %s", ctrl->name);
+ return 0;
+}
+
+static const struct v4l2_ctrl_type_ops custom_type_ops = {
+ .equal = visconti_viif_isp_custom_ctrl_equal,
+ .init = visconti_viif_isp_custom_ctrl_init,
+ .log = visconti_viif_isp_custom_ctrl_log,
+ .validate = visconti_viif_isp_custom_ctrl_validate,
+};
+
+static const struct v4l2_ctrl_ops visconti_viif_isp_ctrl_ops = {
+ .g_volatile_ctrl = visconti_viif_isp_get_ctrl,
+ .try_ctrl = visconti_viif_isp_try_ctrl,
+ .s_ctrl = visconti_viif_isp_set_ctrl,
+};
+
+/* ----- control handler ----- */
+#define CTRL_CONFIG_DEFAULT_ENTRY \
+ .ops = &visconti_viif_isp_ctrl_ops, .type_ops = &custom_type_ops, \
+ .type = COMPOUND_TYPE_SAMPLE01
+
+#define CTRL_CONFIG_VOLATILE_ENTRY \
+ .ops = &visconti_viif_isp_ctrl_ops, .type_ops = &custom_type_ops, \
+ .type = COMPOUND_TYPE_SAMPLE01, \
+ .flags = (V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY)
+
+#define CTRL_CONFIG_RDONLY_ENTRY \
+ .ops = &visconti_viif_isp_ctrl_ops, .type_ops = &custom_type_ops, \
+ .type = COMPOUND_TYPE_SAMPLE01, .flags = (V4L2_CTRL_FLAG_READ_ONLY)
+
+static const u32 defval_main_set_rawpack_mode = VIIF_RAWPACK_DISABLE;
+
+static const struct viif_l1_input_mode_config defval_l1_set_input_mode = {
+ .mode = VIIF_L1_INPUT_HDR,
+ .depth = 10,
+ .raw_color_filter = VIIF_L1_RAW_B_GB_GR_R,
+};
+
+static const struct viif_l1_rgb_to_y_coef_config defval_l1_set_rgb_to_y_coef = {
+ /* ITU-R BT.601 */
+ .coef_r = 0x4C8C,
+ .coef_g = 0x9644,
+ .coef_b = 0x1D30,
+};
+
+static const struct viif_l1_ag_mode_config defval_l1_set_ag_mode = { 0 };
+
+static const struct viif_l1_ag_config defval_l1_set_ag = { 0 };
+
+static const struct viif_l1_hdre_config defval_l1_set_hdre = {
+ .hdre_src_point[0] = 0x3FFF,
+ .hdre_dst_max_val = 0xFFFFFF,
+};
+
+static const struct viif_l1_img_extraction_config defval_l1_set_img_extraction = {
+ .input_black_gr = 256,
+ .input_black_r = 256,
+ .input_black_b = 256,
+ .input_black_gb = 256,
+};
+
+static const struct viif_l1_dpc_config defval_l1_set_dpc = { 0 };
+
+static const struct viif_l1_preset_white_balance_config defval_l1_set_preset_white_balance = {
+ .dstmaxval = 0x0FFF,
+ .param_h = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+ .param_m = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+ .param_l = {
+ .gain_gr = 0x4000,
+ .gain_r = 0x4000,
+ .gain_b = 0x4000,
+ .gain_gb = 0x4000,
+ },
+};
+
+static const
+struct viif_l1_raw_color_noise_reduction_config defval_l1_set_raw_color_noise_reduction = {
+ .param_h = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+ .param_m = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+ .param_l = {
+ .rcnr_cnf_clip_gain_r = 3,
+ .rcnr_cnf_clip_gain_g = 2,
+ .rcnr_cnf_clip_gain_b = 3,
+ .rcnr_merge_black = 0x20,
+ .rcnr_merge_mindiv = 4,
+ .rcnr_anf_blend_ag0 = 1,
+ .rcnr_anf_blend_ag1 = 2,
+ .rcnr_anf_blend_ag2 = 2,
+ .rcnr_lpf_threshold = 8,
+ },
+};
+
+static const struct viif_l1_hdrs_config defval_l1_set_hdrs = {
+ .hdrs_hdr_mode = 1,
+ .hdrs_hdr_ratio_m = 0x10000,
+ .hdrs_hdr_ratio_l = 0x400000,
+ .hdrs_hdr_ratio_e = 0x400,
+ .hdrs_dg_h = 0x400,
+ .hdrs_dg_m = 0x400,
+ .hdrs_dg_l = 0x400,
+ .hdrs_dg_e = 0x400,
+ .hdrs_blendend_h = 0xFA0,
+ .hdrs_blendend_m = 0xFA0,
+ .hdrs_blendend_e = 0xFA0,
+ .hdrs_blendbeg_h = 0x12C,
+ .hdrs_blendbeg_m = 0x12C,
+ .hdrs_blendbeg_e = 0x12C,
+ .hdrs_dst_max_val = 0xFFFFFF,
+};
+
+static const struct viif_l1_black_level_correction_config defval_l1_set_black_level_correction = {
+ .srcblacklevel_gr = 0x100,
+ .srcblacklevel_r = 0x100,
+ .srcblacklevel_b = 0x100,
+ .srcblacklevel_gb = 0x100,
+ .mulval_gr = 0x100,
+ .mulval_r = 0x100,
+ .mulval_b = 0x100,
+ .mulval_gb = 0x100,
+ .dstmaxval = 0xFFFFFF,
+};
+
+static const struct viif_l1_lsc_config defval_l1_set_lsc = { 0 };
+
+static const struct viif_l1_main_process_config defval_l1_set_main_process = {
+ .damp_lsbsel = 0x8,
+ .demosaic_mode = 1,
+ .colormat_enable = 0,
+ .dst_maxval = 0xFFFFFF,
+};
+
+static const struct viif_l1_awb_config defval_l1_set_awb = {
+ .enable = 0,
+ .awhb_wbmrg = 256,
+ .awhb_wbmgg = 256,
+ .awhb_wbmbg = 256,
+};
+
+static const u32 defval_l1_lock_awb_gain;
+
+static const struct viif_l1_hdrc_config
+ defval_l1_set_hdrc = { .enable = 1,
+ .param = {
+ .hdrc_ratio = 0x0E + VIIF_L1_HDRC_RATIO_OFFSET,
+ .hdrc_pt_ratio = 7,
+ .hdrc_pt_sat = 0xFFC0,
+ .hdrc_tn_type = 1,
+ } };
+
+static const struct viif_l1_hdrc_ltm_config defval_l1_set_hdrc_ltm = {
+ .tnp_max = 0x3FFFFF,
+ .tnp_mag = 0x40,
+ .tnp_fil = { 0x88, 0x84, 0x7A, 0x6A, 0x54 },
+};
+
+static const struct viif_l1_gamma_config defval_l1_set_gamma = {
+ .enable = 1,
+ .param = {
+ .gam_p = {
+ 0x02F, 0x01B, 0x02A, 0x023, 0x020, 0x037, 0x031, 0x057, 0x04D, 0x088,
+ 0x078, 0x0D6, 0x0BD, 0x14F, 0x12A, 0x20D, 0x1D3, 0x1AB, 0x18D, 0x2DC,
+ 0x29E, 0x271, 0x47C, 0x41B, 0x3D4, 0x70A, 0x672, 0x601, 0xB0C, 0xA1D,
+ 0x96C, 0x8E2, 0x874, 0xFDD, 0xEC9, 0xDF2, 0xD42, 0xCB1, 0xC35, 0xBC9,
+ 0xB6A, 0xB16, 0xACB, 0xA86},
+ .blkadj = 0x1000,
+ },
+};
+
+static const struct viif_l1_img_quality_adjustment_config defval_l1_set_img_quality_adjustment = {
+ .enable = 0,
+ .coef_cb = 0x9078,
+ .coef_cr = 0xB699,
+ .brightness = 0,
+ .linear_contrast = 128,
+};
+
+static const struct viif_l1_avg_lum_generation_config defval_l1_set_avg_lum_generation = {
+ .enable = 0
+};
+
+static const struct viif_l2_undist_config defval_l2_set_undist = { .param = {
+ .through_mode = 0,
+ .roi_mode = { 0, 0 },
+ .grid_node_num_h = 0x10,
+ .grid_node_num_v = 0x10,
+ } };
+
+static const struct viif_l2_roi_config defval_l2_set_roi = {
+ .roi_num = 1,
+ .roi_scale = { 65536, 65536 },
+ .roi_scale_inv = { 65536, 65536 },
+ .corrected_wo_scale_hsize = { 0x80, 0x80 },
+ .corrected_hsize = { 0x80, 0x80 },
+ .corrected_wo_scale_vsize = { 0x80, 0x80 },
+ .corrected_vsize = { 0x80, 0x80 },
+};
+
+static const struct viif_l2_gamma_config defval_l2_set_gamma = { 0 };
+
+static const struct v4l2_ctrl_config visconti_viif_isp_ctrl_config[] = {
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE,
+ .name = "Pack 2 Raw Datastreams",
+ .p_def = { .p_const = &defval_main_set_rawpack_mode },
+ .elem_size = sizeof(u32),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE,
+ .name = "L1:Input Mode",
+ .p_def = { .p_const = &defval_l1_set_input_mode },
+ .elem_size = sizeof(struct viif_l1_input_mode_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RGB_TO_Y_COEF,
+ .name = "Coef RGB to Y",
+ .p_def = { .p_const = &defval_l1_set_rgb_to_y_coef },
+ .elem_size = sizeof(struct viif_l1_rgb_to_y_coef_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG_MODE,
+ .name = "L1:Analog Gain Mode",
+ .p_def = { .p_const = &defval_l1_set_ag_mode },
+ .elem_size = sizeof(struct viif_l1_ag_mode_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AG,
+ .name = "L1:Analog Gain Value",
+ .p_def = { .p_const = &defval_l1_set_ag },
+ .elem_size = sizeof(struct viif_l1_ag_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRE,
+ .name = "L1:HDR Expansion",
+ .p_def = { .p_const = &defval_l1_set_hdre },
+ .elem_size = sizeof(struct viif_l1_hdre_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_EXTRACTION,
+ .name = "L1:BlackLevel to extract SDR images from HDR input",
+ .p_def = { .p_const = &defval_l1_set_img_extraction },
+ .elem_size = sizeof(struct viif_l1_img_extraction_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_DPC,
+ .name = "L1:Defect Pixel Correction",
+ .p_def = { .p_const = &defval_l1_set_dpc },
+ .elem_size = sizeof(struct viif_l1_dpc_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_PRESET_WHITE_BALANCE,
+ .name = "L1:Preset White Balance",
+ .p_def = { .p_const = &defval_l1_set_preset_white_balance },
+ .elem_size = sizeof(struct viif_l1_preset_white_balance_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_RAW_COLOR_NOISE_REDUCTION,
+ .name = "L1:Raw Color Noise Reduction",
+ .p_def = { .p_const = &defval_l1_set_raw_color_noise_reduction },
+ .elem_size = sizeof(struct viif_l1_raw_color_noise_reduction_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRS,
+ .name = "L1:HDR Synthesis",
+ .p_def = { .p_const = &defval_l1_set_hdrs },
+ .elem_size = sizeof(struct viif_l1_hdrs_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_BLACK_LEVEL_CORRECTION,
+ .name = "L1:Black Level Correction",
+ .p_def = { .p_const = &defval_l1_set_black_level_correction },
+ .elem_size = sizeof(struct viif_l1_black_level_correction_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_LSC,
+ .name = "L1:Lens Shading Correction",
+ .p_def = { .p_const = &defval_l1_set_lsc },
+ .elem_size = sizeof(struct viif_l1_lsc_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_MAIN_PROCESS,
+ .name = "L1:Main Process",
+ .p_def = { .p_const = &defval_l1_set_main_process },
+ .elem_size = sizeof(struct viif_l1_main_process_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AWB,
+ .name = "L1:Auto White Balance",
+ .p_def = { .p_const = &defval_l1_set_awb },
+ .elem_size = sizeof(struct viif_l1_awb_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_LOCK_AWB_GAIN,
+ .name = "L1:Lock Auto White Balance Gain",
+ .p_def = { .p_const = &defval_l1_lock_awb_gain },
+ .elem_size = sizeof(u32),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC,
+ .name = "L1:HDR Compression",
+ .p_def = { .p_const = &defval_l1_set_hdrc },
+ .elem_size = sizeof(struct viif_l1_hdrc_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_HDRC_LTM,
+ .name = "L1:HDR Compression Local Tone",
+ .p_def = { .p_const = &defval_l1_set_hdrc_ltm },
+ .elem_size = sizeof(struct viif_l1_hdrc_ltm_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_GAMMA,
+ .name = "L1:Gamma Correction",
+ .p_def = { .p_const = &defval_l1_set_gamma },
+ .elem_size = sizeof(struct viif_l1_gamma_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_IMG_QUALITY_ADJUSTMENT,
+ .name = "L1:Image Quality Adjustment",
+ .p_def = { .p_const = &defval_l1_set_img_quality_adjustment },
+ .elem_size = sizeof(struct viif_l1_img_quality_adjustment_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_AVG_LUM_GENERATION,
+ .name = "L1:Average Luminance",
+ .p_def = { .p_const = &defval_l1_set_avg_lum_generation },
+ .elem_size = sizeof(struct viif_l1_avg_lum_generation_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_UNDIST,
+ .name = "L2:Undistortion",
+ .p_def = { .p_const = &defval_l2_set_undist },
+ .elem_size = sizeof(struct viif_l2_undist_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_ROI,
+ .name = "L2:ROI",
+ .p_def = { .p_const = &defval_l2_set_roi },
+ .elem_size = sizeof(struct viif_l2_roi_config),
+ },
+ {
+ CTRL_CONFIG_DEFAULT_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_ISP_L2_SET_GAMMA,
+ .name = "L2:Gamma Correction",
+ .p_def = { .p_const = &defval_l2_set_gamma },
+ .elem_size = sizeof(struct viif_l2_gamma_config),
+ },
+ {
+ CTRL_CONFIG_VOLATILE_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_CALIBRATION_STATUS,
+ .name = "CSI2RX: Calibration Status",
+ .elem_size = sizeof(struct viif_csi2rx_dphy_calibration_status),
+ },
+ {
+ CTRL_CONFIG_VOLATILE_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_CSI2RX_GET_ERR_STATUS,
+ .name = "CSI2RX: Error Status",
+ .elem_size = sizeof(struct viif_csi2rx_err_status),
+ },
+ {
+ CTRL_CONFIG_RDONLY_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS,
+ .name = "Last Frame Capture Status",
+ .elem_size = sizeof(struct viif_isp_capture_status),
+ },
+ {
+ CTRL_CONFIG_VOLATILE_ENTRY,
+ .id = V4L2_CID_VISCONTI_VIIF_GET_REPORTED_ERRORS,
+ .name = "Accumerated Reported Errors",
+ .elem_size = sizeof(struct viif_reported_errors),
+ },
+};
+
+int visconti_viif_isp_init_controls(struct viif_device *viif_dev)
+{
+ struct v4l2_ctrl_handler *ctrl_handler = &viif_dev->isp_subdev.ctrl_handler;
+ int ret;
+ int i;
+
+ ret = v4l2_ctrl_handler_init(ctrl_handler, ARRAY_SIZE(visconti_viif_isp_ctrl_config));
+ if (ret) {
+ dev_err(viif_dev->dev, "failed on v4l2_ctrl_handler_init");
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(visconti_viif_isp_ctrl_config); i++) {
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = v4l2_ctrl_new_custom(ctrl_handler, &visconti_viif_isp_ctrl_config[i],
+ viif_dev);
+ if (!ctrl) {
+ dev_err(viif_dev->dev, "failed to add ctrl: %d", ctrl_handler->error);
+ return ctrl_handler->error;
+ }
+ /* controls to be evaluated before S_FMT */
+ if (visconti_viif_isp_ctrl_config[i].id ==
+ V4L2_CID_VISCONTI_VIIF_MAIN_SET_RAWPACK_MODE) {
+ viif_dev->isp_subdev.ctrl_rawpack_mode = ctrl;
+ }
+ if (visconti_viif_isp_ctrl_config[i].id ==
+ V4L2_CID_VISCONTI_VIIF_ISP_L1_SET_INPUT_MODE) {
+ viif_dev->isp_subdev.ctrl_input_mode = ctrl;
+ }
+ /* controls to be updated at HW interrupt */
+ if (visconti_viif_isp_ctrl_config[i].id ==
+ V4L2_CID_VISCONTI_VIIF_GET_LAST_CAPTURE_STATUS) {
+ viif_dev->isp_subdev.ctrl_last_capture_status = ctrl;
+ }
+ }
+
+ viif_dev->isp_subdev.sd.ctrl_handler = &viif_dev->isp_subdev.ctrl_handler;
+ return 0;
+}
diff --git a/drivers/media/platform/toshiba/visconti/viif_controls.h b/drivers/media/platform/toshiba/visconti/viif_controls.h
new file mode 100644
index 000000000..d7a044e1c
--- /dev/null
+++ b/drivers/media/platform/toshiba/visconti/viif_controls.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/* Toshiba Visconti Video Capture Support
+ *
+ * (C) Copyright 2023 TOSHIBA CORPORATION
+ * (C) Copyright 2023 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#ifndef VIIF_CONTROLS_H
+#define VIIF_CONTROLS_H
+
+struct viif_device;
+struct viif_l2_undist;
+
+int visconti_viif_l2_undist_through(struct viif_device *viif_dev);
+int visconti_viif_isp_init_controls(struct viif_device *viif_dev);
+void visconti_viif_save_l1_info(struct viif_device *viif_dev);
+
+#endif /* VIIF_CONTROLS_H */
diff --git a/drivers/media/platform/toshiba/visconti/viif_isp.c b/drivers/media/platform/toshiba/visconti/viif_isp.c
index 94e62e95c..7cf1b5656 100644
--- a/drivers/media/platform/toshiba/visconti/viif_isp.c
+++ b/drivers/media/platform/toshiba/visconti/viif_isp.c
@@ -12,6 +12,7 @@

#include "viif.h"
#include "viif_common.h"
+#include "viif_controls.h"
#include "viif_regs.h"

/* disable CSI2 capture at viif_mux_start() */
@@ -761,12 +762,9 @@ int visconti_viif_isp_main_set_unit(struct viif_device *viif_dev)
hwd_viif_isp_set_regbuf_auto_transmission(viif_dev);

/* L2 UNDIST Enable through mode as default */
- /* this function is implemented in the next patch */
- /*
- * ret = visconti_viif_l2_undist_through(viif_dev);
- * if (ret)
- * dev_err(viif_dev->dev, "l2_set_undist error. %d\n", ret);
- */
+ ret = visconti_viif_l2_undist_through(viif_dev);
+ if (ret)
+ dev_err(viif_dev->dev, "l2_set_undist error. %d\n", ret);
return ret;
}

@@ -1236,10 +1234,7 @@ int visconti_viif_isp_register(struct viif_device *viif_dev)

mutex_init(&viif_dev->isp_subdev.ops_lock);

- /* this function is implemented in the next patch */
-/*
- * visconti_viif_isp_init_controls(viif_dev);
- */
+ visconti_viif_isp_init_controls(viif_dev);

ret = media_entity_pads_init(&sd->entity, 4, pads);
if (ret) {
--
2.25.1