/*
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
*/
#include <stdio.h>
#include <math.h>
#include "ot_mpi_isp.h"
#include "ot_mpi_ae.h"
#include "ot_mpi_awb.h"
#include "securec.h"
#include "imx678_cmos_ex.h"
#include "imx678_cmos.h"
#define IMX678_ID 678
#define SENSOR_IMX678_WIDTH 3840
#define SENSOR_IMX678_HEIGHT 2160
#define higher_4bits(x) (((x) & 0xf0000) >> 16)
#define high_8bits(x) (((x) & 0xff00) >> 8)
#define low_8bits(x) ((x) & 0x00ff)
#ifndef max
#define max(a, b) (((a) < (b)) ? (b) : (a))
#endif
#ifndef min
#define min(a, b) (((a) > (b)) ? (b) : (a))
#endif
/****************************************************************************
* global variables *
****************************************************************************/
#define imx678_sensor_set_ctx(pipe, ctx) ((g_imx678_sns_state[pipe]) = (ctx))
#define imx678_sensor_reset_ctx(pipe) (g_imx678_sns_state[pipe] = TD_NULL)
static ot_isp_fswdr_mode g_fswdr_mode[OT_ISP_MAX_PIPE_NUM] = {
[0 ... OT_ISP_MAX_PIPE_NUM - 1] = OT_ISP_FSWDR_NORMAL_MODE
};
static td_u8 g_ae_stat_pos[OT_ISP_MAX_PIPE_NUM] = {0};
static td_u32 g_max_time_get_cnt[OT_ISP_MAX_PIPE_NUM] = {0};
static td_u32 g_init_exposure[OT_ISP_MAX_PIPE_NUM] = {0};
static td_u32 g_lines_per500ms[OT_ISP_MAX_PIPE_NUM] = {0};
static td_u16 g_init_wb_gain[OT_ISP_MAX_PIPE_NUM][OT_ISP_RGB_CHN_NUM] = {{0}};
static td_u16 g_sample_r_gain[OT_ISP_MAX_PIPE_NUM] = {0};
static td_u16 g_sample_b_gain[OT_ISP_MAX_PIPE_NUM] = {0};
static td_bool g_quick_start_en[OT_ISP_MAX_PIPE_NUM] = {TD_FALSE};
static td_bool g_ae_route_ex_valid[OT_ISP_MAX_PIPE_NUM] = {0};
static ot_isp_ae_route g_init_ae_route[OT_ISP_MAX_PIPE_NUM] = {{0}};
static ot_isp_ae_route_ex g_init_ae_route_ex[OT_ISP_MAX_PIPE_NUM] = {{0}};
static ot_isp_ae_route g_init_ae_route_sf[OT_ISP_MAX_PIPE_NUM] = {{0}};
static ot_isp_ae_route_ex g_init_ae_route_sf_ex[OT_ISP_MAX_PIPE_NUM] = {{0}};
typedef struct {
td_u8 hcg;
td_u32 brl;
td_u32 rhs1_max;
td_u32 rhs2_max;
} imx678_state;
imx678_state g_imx678_state[OT_ISP_MAX_PIPE_NUM] = {{0}};
ot_isp_sns_commbus g_imx678_bus_info[OT_ISP_MAX_PIPE_NUM] = {
[0] = { .i2c_dev = 0},
[1 ... OT_ISP_MAX_PIPE_NUM - 1] = { .i2c_dev = -1}
};
ot_isp_sns_state *g_imx678_sns_state[OT_ISP_MAX_PIPE_NUM] = {TD_NULL};
static td_bool blc_clamp_info[OT_ISP_MAX_PIPE_NUM] = {[0 ...(OT_ISP_MAX_PIPE_NUM - 1)] = TD_TRUE};
ot_isp_sns_commbus *imx678_get_bus_info(ot_vi_pipe vi_pipe)
{
return &g_imx678_bus_info[vi_pipe];
}
ot_isp_sns_state *imx678_get_ctx(ot_vi_pipe vi_pipe)
{
return g_imx678_sns_state[vi_pipe];
}
td_void imx678_set_blc_clamp_value(ot_vi_pipe vi_pipe, td_bool clamp_en)
{
blc_clamp_info[vi_pipe] = clamp_en;
}
const imx678_video_mode_tbl g_imx678_mode_tbl[IMX678_MODE_BUTT] = {
{IMX678_VMAX_4K2K_LINEAR, IMX678_FULL_LINES_MAX, 30, 0.07,
3840, 2160, 0, OT_WDR_MODE_NONE, "IMX678_SENSOR_8M_30FPS_LINEAR_MODE"},
{IMX678_VMAX_4K2K_LINEAR, IMX678_FULL_LINES_MAX, 60, 2.0,
3840, 2160, 0, OT_WDR_MODE_NONE, "IMX678_SENSOR_8M_60FPS_LINEAR_MODE"},
};
/****************************************************************************
* local variables *
****************************************************************************/
/* Imx678 Register Address */
#define IMX678_VMAX_ADDR_L 0x3028
#define IMX678_VMAX_ADDR_M 0x3029
#define IMX678_VMAX_ADDR_H 0x302A
#define IMX678_SHR0_L 0x3050
#define IMX678_SHR0_M 0x3051
#define IMX678_SHR0_H 0x3052
#define IMX678_GAIN_PGC_L 0x3070
#define IMX678_GAIN_PGC_H 0x3071
#define IMX678_HCG 0x3030
// sensor gain
#define IMX678_AGAIN_MIN 1024
#define IMX678_AGAIN_MAX 182096
#define IMX678_DGAIN_MIN 1024
#define IMX678_DGAIN_MAX 128914
#define IMX678_EXP_TIME_LMT 8
#define imx678_err_mode_print(sns_image_mode, sns_state) \
do { \
isp_err_trace("Not support! Width:%u, Height:%u, Fps:%f, WDRMode:%d\n", \
(sns_image_mode)->width, \
(sns_image_mode)->height, \
(sns_image_mode)->fps, \
(sns_state)->wdr_mode); \
} while (0)
static td_void cmos_get_ae_comm_default(ot_vi_pipe vi_pipe, ot_isp_ae_sensor_default *ae_sns_dft,
const ot_isp_sns_state *sns_state)
{
ae_sns_dft->full_lines_std = sns_state->fl_std;
ae_sns_dft->flicker_freq = 50 * 256; /* light flicker freq: 50Hz, accuracy: 256 */
ae_sns_dft->full_lines_max = IMX678_FULL_LINES_MAX;
ae_sns_dft->hmax_times = (1000000000) / (sns_state->fl_std * 30); /* 1000000000ns, 30fps */
ae_sns_dft->int_time_accu.accu_type = OT_ISP_AE_ACCURACY_LINEAR;
ae_sns_dft->int_time_accu.accuracy = 1;
ae_sns_dft->int_time_accu.offset = 0;
ae_sns_dft->again_accu.accu_type = OT_ISP_AE_ACCURACY_TABLE;
ae_sns_dft->again_accu.accuracy = 1;
ae_sns_dft->dgain_accu.accu_type = OT_ISP_AE_ACCURACY_TABLE;
ae_sns_dft->dgain_accu.accuracy = 1;
ae_sns_dft->isp_dgain_shift = 8; /* accuracy: 8 */
ae_sns_dft->min_isp_dgain_target = 1 << ae_sns_dft->isp_dgain_shift;
ae_sns_dft->max_isp_dgain_target = 2 << ae_sns_dft->isp_dgain_shift; /* max 2 */
if (g_lines_per500ms[vi_pipe] == 0) {
ae_sns_dft->lines_per500ms = sns_state->fl_std * 30 / 2; /* 30fps, div 2 */
} else {
ae_sns_dft->lines_per500ms = g_lines_per500ms[vi_pipe];
}
ae_sns_dft->max_iris_fno = OT_ISP_IRIS_F_NO_1_0;
ae_sns_dft->min_iris_fno = OT_ISP_IRIS_F_NO_32_0;
ae_sns_dft->ae_route_ex_valid = TD_FALSE;
ae_sns_dft->ae_route_attr.total_num = 0;
ae_sns_dft->ae_route_attr_ex.total_num = 0;
ae_sns_dft->quick_start.quick_start_enable = g_quick_start_en[vi_pipe];
ae_sns_dft->quick_start.black_frame_num = 0;
ae_sns_dft->ae_stat_pos = g_ae_stat_pos[vi_pipe]; /* 1 use be stat to AE */
return;
}
static td_void cmos_get_ae_linear_default(ot_vi_pipe vi_pipe, ot_isp_ae_sensor_default *ae_sns_dft,
const ot_isp_sns_state *sns_state)
{
ae_sns_dft->max_again = IMX678_AGAIN_MAX;
ae_sns_dft->min_again = IMX678_AGAIN_MIN;
ae_sns_dft->max_again_target = ae_sns_dft->max_again;
ae_sns_dft->min_again_target = ae_sns_dft->min_again;
ae_sns_dft->max_dgain = IMX678_DGAIN_MAX;
ae_sns_dft->min_dgain = IMX678_DGAIN_MIN;
ae_sns_dft->max_dgain_target = ae_sns_dft->max_dgain;
ae_sns_dft->min_dgain_target = ae_sns_dft->min_dgain;
ae_sns_dft->ae_compensation = 0x38;
ae_sns_dft->ae_exp_mode = OT_ISP_AE_EXP_HIGHLIGHT_PRIOR;
ae_sns_dft->init_exposure = g_init_exposure[vi_pipe] ? g_init_exposure[vi_pipe] : 76151; /* init 76151 */
ae_sns_dft->max_int_time = sns_state->fl_std - 2; /* sub 2 */
ae_sns_dft->min_int_time = 9; /* min 9 */
ae_sns_dft->max_int_time_target = 65535; /* max 65535 */
ae_sns_dft->min_int_time_target = 9; /* min 9 */
ae_sns_dft->ae_route_ex_valid = g_ae_route_ex_valid[vi_pipe];
(td_void)memcpy_s(&ae_sns_dft->ae_route_attr, sizeof(ot_isp_ae_route),
&g_init_ae_route[vi_pipe], sizeof(ot_isp_ae_route));
(td_void)memcpy_s(&ae_sns_dft->ae_route_attr_ex, sizeof(ot_isp_ae_route_ex),
&g_init_ae_route_ex[vi_pipe], sizeof(ot_isp_ae_route_ex));
return;
}
static td_s32 cmos_get_ae_default(ot_vi_pipe vi_pipe, ot_isp_ae_sensor_default *ae_sns_dft)
{
ot_isp_sns_state *sns_state = TD_NULL;
sns_check_pointer_return(ae_sns_dft);
imx678_sensor_get_ctx(vi_pipe, sns_state);
sns_check_pointer_return(sns_state);
(td_void)memset_s(&ae_sns_dft->ae_route_attr, si