1057 lines
26 KiB
C
1057 lines
26 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
#include "kd_imgsensor_define_v4l2.h"
|
|
#include "imgsensor-user.h"
|
|
|
|
#include "adaptor.h"
|
|
#include "adaptor-def.h"
|
|
#include "adaptor-common-ctrl.h"
|
|
#include "adaptor-fsync-ctrls.h"
|
|
|
|
|
|
#define REDUCE_FSYNC_CTRLS_LOG
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* fsync mgr variables
|
|
******************************************************************************/
|
|
/* for checking if any sensor enter long exposure mode */
|
|
static atomic_t long_exp_mode_bits = ATOMIC_INIT(0);
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
* sensor driver feature ctrls
|
|
******************************************************************************/
|
|
static u32 fsync_mgr_g_sensor_hw_sync_mode(struct adaptor_ctx *ctx)
|
|
{
|
|
union feature_para para;
|
|
u32 sync_mode = 0;
|
|
u32 len;
|
|
|
|
para.u32[0] = 0;
|
|
|
|
subdrv_call(ctx, feature_control,
|
|
SENSOR_FEATURE_GET_SENSOR_SYNC_MODE,
|
|
para.u8, &len);
|
|
|
|
sync_mode = para.u32[0];
|
|
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, get hw sync mode:%u(N:0/M:1/S:2)\n",
|
|
__func__,
|
|
ctx->idx,
|
|
sync_mode);
|
|
#endif
|
|
|
|
|
|
return sync_mode;
|
|
}
|
|
|
|
static void fsync_mgr_s_frame_length(struct adaptor_ctx *ctx)
|
|
{
|
|
union feature_para para;
|
|
u32 len;
|
|
|
|
// para.u64[0] = ctx->subctx.frame_length;
|
|
para.u64[0] = ctx->fsync_out_fl;
|
|
|
|
subdrv_call(ctx, feature_control,
|
|
SENSOR_FEATURE_SET_FRAMELENGTH,
|
|
para.u8, &len);
|
|
}
|
|
|
|
#if defined(TWO_STAGE_FS)
|
|
static void fsync_mgr_s_multi_shutter_frame_length(
|
|
struct adaptor_ctx *ctx,
|
|
u32 *ae_exp_arr, u32 ae_exp_cnt)
|
|
{
|
|
union feature_para para;
|
|
u32 fsync_exp[IMGSENSOR_STAGGER_EXPOSURE_CNT] = {0};
|
|
u32 len = 0;
|
|
int i;
|
|
|
|
if (likely(ae_exp_arr != NULL)) {
|
|
for (i = 0;
|
|
(i < ae_exp_cnt) && (i < IMGSENSOR_STAGGER_EXPOSURE_CNT);
|
|
++i)
|
|
fsync_exp[i] = (u32)(*(ae_exp_arr + i));
|
|
}
|
|
|
|
para.u64[0] = (u64)fsync_exp;
|
|
para.u64[1] = min_t(u32, ae_exp_cnt, (u32)IMGSENSOR_STAGGER_EXPOSURE_CNT);
|
|
para.u64[2] = ctx->fsync_out_fl;
|
|
|
|
subdrv_call(ctx, feature_control,
|
|
SENSOR_FEATURE_SET_MULTI_SHUTTER_FRAME_TIME,
|
|
para.u8, &len);
|
|
}
|
|
#endif // TWO_STAGE_FS
|
|
|
|
|
|
/*******************************************************************************
|
|
* fsync mgr static functions
|
|
******************************************************************************/
|
|
static void fsync_mgr_chk_long_exposure(struct adaptor_ctx *ctx,
|
|
const u32 *ae_exp_arr, const u32 ae_exp_cnt)
|
|
{
|
|
unsigned int i = 0;
|
|
int has_long_exp = 0;
|
|
u32 fine_integ_line = 0;
|
|
|
|
fine_integ_line =
|
|
g_sensor_fine_integ_line(ctx, ctx->subctx.current_scenario_id);
|
|
|
|
for (i = 0; i < ae_exp_cnt; ++i) {
|
|
u32 exp_lc =
|
|
FINE_INTEG_CONVERT(ae_exp_arr[i], fine_integ_line);
|
|
|
|
/* check if any exp will enter long exposure mode */
|
|
if ((exp_lc + ctx->subctx.margin) >=
|
|
ctx->subctx.max_frame_length) {
|
|
has_long_exp = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* has_long_exp > 0 => set bits ; has_long_exp == 0 => clear bits */
|
|
if (has_long_exp != 0)
|
|
atomic_fetch_or((1UL << ctx->idx), &long_exp_mode_bits);
|
|
else
|
|
atomic_fetch_and((~(1UL << ctx->idx)), &long_exp_mode_bits);
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: detected long exp:%d, long_exp_mode_bits:%#x\n",
|
|
__func__, ctx->idx,
|
|
has_long_exp, atomic_read(&long_exp_mode_bits));
|
|
#endif
|
|
}
|
|
|
|
|
|
static void fsync_mgr_set_hdr_exp_data(struct adaptor_ctx *ctx,
|
|
struct fs_hdr_exp_st *p_hdr_exp,
|
|
u32 *ae_exp_arr, u32 ae_exp_cnt,
|
|
u32 fine_integ_line, const u32 mode_id)
|
|
{
|
|
struct mtk_stagger_info info = {0};
|
|
unsigned int i = 0;
|
|
int ret = 0;
|
|
|
|
/* error handle */
|
|
if (unlikely(ae_exp_cnt == 0
|
|
/*|| ae_exp_cnt > MAX_NUM_OF_EXPOSURE*/
|
|
|| ae_exp_arr == NULL)) {
|
|
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, ERROR: get ae_exp_cnt:%u (min:1, max:), *ae_exp_arr:%p, return\n",
|
|
__func__, ctx->idx,
|
|
ae_exp_cnt/*, MAX_NUM_OF_EXPOSURE*/,
|
|
ae_exp_arr);
|
|
|
|
return;
|
|
}
|
|
|
|
if (unlikely(p_hdr_exp == NULL)) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, ERROR: get p_hdr_exp is NULL, return\n",
|
|
__func__, ctx->idx);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
info.scenario_id = SENSOR_SCENARIO_ID_NONE;
|
|
|
|
/* for hdr-exp settings, e.g. STG sensor */
|
|
// ret = g_stagger_info(ctx, ctx->cur_mode->id, &info);
|
|
ret = g_stagger_info(ctx, mode_id, &info);
|
|
if (!ret) {
|
|
p_hdr_exp->mode_exp_cnt = info.count;
|
|
p_hdr_exp->ae_exp_cnt = ae_exp_cnt;
|
|
p_hdr_exp->readout_len_lc = ctx->subctx.readout_length;
|
|
p_hdr_exp->read_margin_lc = ctx->subctx.read_margin;
|
|
|
|
for (i = 0; i < ae_exp_cnt; ++i) {
|
|
int idx = hdr_exp_idx_map[ae_exp_cnt][i];
|
|
|
|
if (idx >= 0) {
|
|
p_hdr_exp->exp_lc[idx] = ae_exp_arr[i];
|
|
if (fine_integ_line) {
|
|
p_hdr_exp->exp_lc[idx] =
|
|
FINE_INTEG_CONVERT(p_hdr_exp->exp_lc[idx],
|
|
fine_integ_line);
|
|
}
|
|
|
|
#ifndef REDUCE_FSYNC_CTRLS_LOG
|
|
adaptor_logi(ctx,
|
|
"ae_exp_arr[%u]:%u, fine_integ_line:%u, p_hdr_exp->exp_lc[%d]:%u\n",
|
|
i, ae_exp_arr[i], fine_integ_line,
|
|
idx, p_hdr_exp->exp_lc[idx]);
|
|
#endif // !REDUCE_FSYNC_CTRLS_LOG
|
|
|
|
} else {
|
|
adaptor_logi(ctx,
|
|
"ERROR: idx:%d (< 0) = hdr_exp_idx_map[%u][%u]\n",
|
|
idx, ae_exp_cnt, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fsync_mgr_set_exp_data(struct adaptor_ctx *ctx,
|
|
struct fs_perframe_st *p_pf_ctrl,
|
|
u32 *ae_exp_arr, u32 ae_exp_cnt, const u32 mode_id)
|
|
{
|
|
u32 fine_integ_line = 0;
|
|
|
|
/* error handle */
|
|
if (unlikely(ae_exp_arr == NULL || ae_exp_cnt == 0)) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, ERROR: get ae_exp_arr is NULL, ae_exp_cnt:%u, return\n",
|
|
__func__, ctx->idx,
|
|
ae_exp_cnt);
|
|
|
|
return;
|
|
}
|
|
|
|
if (unlikely(p_pf_ctrl == NULL)) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, ERROR: get p_pf_ctrl is NULL, return\n",
|
|
__func__, ctx->idx);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
fine_integ_line = g_sensor_fine_integ_line(ctx, mode_id);
|
|
p_pf_ctrl->shutter_lc = (ae_exp_cnt == 1) ? *(ae_exp_arr + 0) : 0;
|
|
if (fine_integ_line) {
|
|
p_pf_ctrl->shutter_lc =
|
|
FINE_INTEG_CONVERT(p_pf_ctrl->shutter_lc, fine_integ_line);
|
|
}
|
|
|
|
fsync_mgr_set_hdr_exp_data(ctx,
|
|
&p_pf_ctrl->hdr_exp,
|
|
ae_exp_arr, ae_exp_cnt,
|
|
fine_integ_line, mode_id);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* call back function for Frame-Sync set frame length using
|
|
******************************************************************************/
|
|
/* return: 0 => No-Error ; non-0 => Error */
|
|
int cb_fsync_mgr_set_framelength(void *p_ctx,
|
|
unsigned int cmd_id, unsigned int framelength)
|
|
{
|
|
struct adaptor_ctx *ctx = NULL;
|
|
struct fs_perframe_st pf_ctrl = {0};
|
|
enum ACDK_SENSOR_FEATURE_ENUM cmd = 0;
|
|
int ret = 0;
|
|
|
|
/* error handle */
|
|
if (unlikely(p_ctx == NULL)) {
|
|
ret = 1;
|
|
pr_info(
|
|
"%s: ERROR: p_ctx is NULL (cmd_id:%u, fl:%u), return:%d\n",
|
|
__func__,
|
|
cmd_id, framelength, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
ctx = (struct adaptor_ctx *)p_ctx;
|
|
cmd = (enum ACDK_SENSOR_FEATURE_ENUM)cmd_id;
|
|
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
ret = 2;
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: ctx->fsync_mgr is NULL (cmd_id:%u, fl:%u), return:%d\n",
|
|
__func__, ctx->idx,
|
|
cmd_id, framelength, ret);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
// ctx->subctx.frame_length = framelength;
|
|
ctx->fsync_out_fl = framelength;
|
|
|
|
|
|
switch (cmd) {
|
|
#if defined(TWO_STAGE_FS)
|
|
case SENSOR_FEATURE_SET_MULTI_SHUTTER_FRAME_TIME:
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, CMD:SET_MULTI_SHUTTER_FRAME_TIME, update ctx->fsync_out_fl:%u, return to notify set shutter\n",
|
|
__func__, ctx->idx,
|
|
ctx->fsync_out_fl);
|
|
#endif
|
|
|
|
break;
|
|
#endif
|
|
case SENSOR_FEATURE_SET_FRAMELENGTH:
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, CMD:SET_FRAMELENGTH, set ctx->fsync_out_fl:%u to sensor drv\n",
|
|
__func__, ctx->idx,
|
|
ctx->fsync_out_fl);
|
|
#endif
|
|
|
|
/* set frame length */
|
|
fsync_mgr_s_frame_length(ctx);
|
|
|
|
/* update sensor current fl_lc to Frame-Sync */
|
|
pf_ctrl.sensor_id = ctx->subdrv->id;
|
|
pf_ctrl.sensor_idx = ctx->idx;
|
|
pf_ctrl.out_fl_lc = ctx->subctx.frame_length;
|
|
ctx->fsync_mgr->fs_update_shutter(&pf_ctrl);
|
|
|
|
break;
|
|
|
|
default:
|
|
dev_info(ctx->dev, "unknown CMD type, do nothing\n");
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* streaming ctrls
|
|
******************************************************************************/
|
|
void notify_fsync_mgr_streaming(struct adaptor_ctx *ctx, unsigned int flag)
|
|
{
|
|
struct fs_streaming_st s_info = {0};
|
|
unsigned int ret = 0;
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
s_info.sensor_id = ctx->subdrv->id;
|
|
s_info.sensor_idx = ctx->idx;
|
|
|
|
/* fsync_map_id is cam_mux no */
|
|
s_info.cammux_id = (ctx->fsync_map_id->val > 0)
|
|
? (ctx->fsync_map_id->val + 1) : 0;
|
|
/* 7s use fsync_listen_target to update ccu tg id, so init from this */
|
|
s_info.target_tg = ctx->fsync_listen_target->val;
|
|
|
|
s_info.fl_active_delay = ctx->subctx.frame_time_delay_frame;
|
|
|
|
/* using ctx->subctx.frame_length instead of ctx->cur_mode->fll */
|
|
/* for any settings before streaming on */
|
|
s_info.def_fl_lc = ctx->subctx.frame_length;
|
|
s_info.max_fl_lc = ctx->subctx.max_frame_length;
|
|
|
|
/* frame sync sensor operate mode. none/master/slave */
|
|
s_info.sync_mode = fsync_mgr_g_sensor_hw_sync_mode(ctx);
|
|
|
|
|
|
/* using ctx->subctx.shutter instead of ctx->subctx.exposure_def */
|
|
/* for any settings before streaming on */
|
|
s_info.def_shutter_lc = ctx->subctx.shutter;
|
|
s_info.margin_lc = g_sensor_margin(ctx, ctx->subctx.current_scenario_id);
|
|
|
|
|
|
/* sensor mode info */
|
|
s_info.pclk = ctx->subctx.pclk;
|
|
s_info.linelength = ctx->subctx.line_length;
|
|
s_info.lineTimeInNs =
|
|
CALC_LINE_TIME_IN_NS(s_info.pclk, s_info.linelength);
|
|
|
|
|
|
/* callback data */
|
|
s_info.func_ptr = cb_fsync_mgr_set_framelength;
|
|
s_info.p_ctx = ctx;
|
|
|
|
|
|
/* call frame-sync streaming ON/OFF */
|
|
ret = ctx->fsync_mgr->fs_streaming(flag, &s_info);
|
|
if (unlikely(ret != 0)) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: frame-sync streaming ERROR!\n",
|
|
__func__, ctx->idx);
|
|
}
|
|
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, cammux_id:%u/target_tg:%u, fl_delay:%u(must be 3 or 2), fl(def/max):%u/%u, def_exp:%u, lineTime:%u(pclk:%u/linelength:%u), hw_sync_mode:%u(N:0/M:1/S:2)\n",
|
|
__func__, ctx->idx,
|
|
s_info.cammux_id,
|
|
s_info.target_tg,
|
|
s_info.fl_active_delay,
|
|
s_info.def_fl_lc,
|
|
s_info.max_fl_lc,
|
|
s_info.def_shutter_lc,
|
|
s_info.lineTimeInNs,
|
|
s_info.pclk,
|
|
s_info.linelength,
|
|
s_info.sync_mode);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* per-frame ctrls
|
|
******************************************************************************/
|
|
int chk_s_exp_with_fl_by_fsync_mgr(struct adaptor_ctx *ctx,
|
|
u32 *ae_exp_arr, u32 ae_exp_cnt)
|
|
{
|
|
int ret = 0;
|
|
int en_fsync = 0;
|
|
|
|
#if defined(TWO_STAGE_FS)
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: ctx->fsync_mgr is NULL, return 0\n",
|
|
__func__, ctx->idx);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* check situation */
|
|
en_fsync = (ctx->fsync_mgr->fs_is_set_sync(ctx->idx));
|
|
|
|
if (en_fsync) {
|
|
fsync_mgr_chk_long_exposure(ctx, ae_exp_arr, ae_exp_cnt);
|
|
if (atomic_read(&long_exp_mode_bits) != 0) {
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: detected any en_sync sensor in long exp mode, long_exp_mode_bits:%#x => CTRL by sensor drv, return:0\n",
|
|
__func__, ctx->idx,
|
|
atomic_read(&long_exp_mode_bits));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/* get result from above situation check */
|
|
ret = en_fsync;
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR) && !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev, "%s: sidx:%d, ret:%d(en_fsync:%u)\n",
|
|
__func__, ctx->idx,
|
|
ret, en_fsync);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
void notify_fsync_mgr_update_tg(struct adaptor_ctx *ctx, u64 val)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set update tg:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
val);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_update_tg(ctx->idx, val + 1);
|
|
}
|
|
|
|
/* ISP7S new add */
|
|
void notify_fsync_mgr_update_target_tg(struct adaptor_ctx *ctx, u64 val)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set update tg:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
val);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_update_target_tg(ctx->idx, val);
|
|
}
|
|
|
|
void notify_fsync_mgr_set_sync(struct adaptor_ctx *ctx, u64 en)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set sync:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
en);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_set_sync(ctx->idx, en);
|
|
|
|
if (en == 0) {
|
|
ctx->fsync_out_fl = 0;
|
|
atomic_fetch_and((~(1UL << ctx->idx)), &long_exp_mode_bits);
|
|
}
|
|
}
|
|
|
|
void notify_fsync_mgr_set_async_master(struct adaptor_ctx *ctx, const u64 en)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set async master:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
en);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_sa_set_user_async_master(ctx->idx, en);
|
|
}
|
|
|
|
void notify_fsync_mgr_update_auto_flicker_mode(struct adaptor_ctx *ctx, u64 en)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set flicker en:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
en);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_update_auto_flicker_mode(ctx->idx, en);
|
|
}
|
|
|
|
void notify_fsync_mgr_update_min_fl(struct adaptor_ctx *ctx)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set min fl:%u, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
ctx->subctx.min_frame_length);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_update_min_framelength_lc(ctx->idx,
|
|
ctx->subctx.min_frame_length);
|
|
}
|
|
|
|
void notify_fsync_mgr_set_extend_framelength(
|
|
struct adaptor_ctx *ctx, u64 ext_fl)
|
|
{
|
|
unsigned int ext_fl_us = 0;
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set extend FL:%u(ns), but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
ext_fl);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
/* ext_fl (input) is ns */
|
|
ext_fl_us = ext_fl / 1000;
|
|
|
|
/* args:(ident / ext_fl_lc / ext_fl_us) */
|
|
ctx->fsync_mgr->fs_set_extend_framelength(ctx->idx, 0, ext_fl_us);
|
|
}
|
|
|
|
void notify_fsync_mgr_seamless_switch(struct adaptor_ctx *ctx,
|
|
u32 *ae_exp_arr, u32 ae_exp_max_cnt,
|
|
u32 orig_readout_time_us, u32 target_scenario_id)
|
|
{
|
|
struct fs_seamless_st seamless_info = {0};
|
|
unsigned int ae_exp_cnt = 0;
|
|
unsigned int mode_crop_height = 0;
|
|
unsigned int mode_linetime_readout_ns = 0;
|
|
unsigned int i = 0;
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
adaptor_logi(ctx,
|
|
"sidx:%d, NOTICE: seamless switch, but ctx->fsync_mgr is NULL, return\n",
|
|
ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if (unlikely(ae_exp_arr == NULL || ae_exp_max_cnt == 0)) {
|
|
adaptor_logi(ctx,
|
|
"sidx:%d, ERROR: get ae_exp_arr:%p, ae_exp_cnt:%u, return\n",
|
|
ctx->idx,
|
|
ae_exp_arr,
|
|
ae_exp_max_cnt);
|
|
return;
|
|
}
|
|
|
|
if (unlikely(target_scenario_id >= MODE_MAXCNT)) {
|
|
/* not expected case */
|
|
mode_crop_height = 0;
|
|
mode_linetime_readout_ns = 0;
|
|
|
|
adaptor_logi(ctx,
|
|
"sidx:%d, ERROR target_scenario_id:%u >= MODE_MAXCNT:%u, auto set mode_crop_height:%u, mode_linetime_readout_ns:%u\n",
|
|
target_scenario_id,
|
|
MODE_MAXCNT,
|
|
mode_crop_height,
|
|
mode_linetime_readout_ns);
|
|
} else {
|
|
mode_crop_height = ctx->mode[target_scenario_id].height;
|
|
mode_linetime_readout_ns =
|
|
ctx->mode[target_scenario_id].linetime_in_ns_readout;
|
|
}
|
|
|
|
|
|
seamless_info.seamless_pf_ctrl.req_id = ctx->req_id;
|
|
|
|
seamless_info.seamless_pf_ctrl.sensor_id = ctx->subdrv->id;
|
|
seamless_info.seamless_pf_ctrl.sensor_idx = ctx->idx;
|
|
|
|
seamless_info.seamless_pf_ctrl.min_fl_lc = ctx->subctx.min_frame_length;
|
|
seamless_info.seamless_pf_ctrl.margin_lc =
|
|
g_sensor_margin(ctx, target_scenario_id);
|
|
seamless_info.seamless_pf_ctrl.flicker_en = ctx->subctx.autoflicker_en;
|
|
seamless_info.seamless_pf_ctrl.out_fl_lc = ctx->subctx.frame_length;
|
|
|
|
/* preventing issue (seamless switch not update ctx->cur_mode data) */
|
|
seamless_info.seamless_pf_ctrl.pclk = ctx->subctx.pclk;
|
|
seamless_info.seamless_pf_ctrl.linelength = ctx->subctx.line_length;
|
|
seamless_info.seamless_pf_ctrl.lineTimeInNs =
|
|
CALC_LINE_TIME_IN_NS(
|
|
seamless_info.seamless_pf_ctrl.pclk,
|
|
seamless_info.seamless_pf_ctrl.linelength);
|
|
seamless_info.seamless_pf_ctrl.readout_time_us =
|
|
(mode_crop_height * mode_linetime_readout_ns / 1000);
|
|
|
|
/* calculate ae exp cnt manually */
|
|
for (i = 0; i < ae_exp_max_cnt; ++i) {
|
|
/* check how many non zero exp setting */
|
|
if (*(ae_exp_arr + i) != 0)
|
|
ae_exp_cnt++;
|
|
}
|
|
|
|
/* set exposure data */
|
|
fsync_mgr_set_exp_data(ctx, &seamless_info.seamless_pf_ctrl,
|
|
ae_exp_arr, ae_exp_cnt, target_scenario_id);
|
|
|
|
/* set orig readout time */
|
|
seamless_info.orig_readout_time_us = orig_readout_time_us;
|
|
|
|
|
|
ctx->fsync_mgr->fs_seamless_switch(ctx->idx, &seamless_info, ctx->sof_cnt);
|
|
|
|
|
|
adaptor_logd(ctx,
|
|
"sidx:%d, exp(%u, %u/%u/%u/%u/%u, cnt(mode:%u/ae:%u), max:%u, readout_len:%u, read_margin:%u), margin:%u, min_fl:%u, flk:%u, line_time:%u(ns), readout_time_us:%u(height:%u/linetime_readout_ns:%u), orig_readout_time_us:%u, fl(fsync:%u/subctx:%u), req_id:%d, sof_cnt:%u\n",
|
|
ctx->idx,
|
|
seamless_info.seamless_pf_ctrl.shutter_lc,
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.exp_lc[0],
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.exp_lc[1],
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.exp_lc[2],
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.exp_lc[3],
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.exp_lc[4],
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.mode_exp_cnt,
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.ae_exp_cnt,
|
|
ae_exp_max_cnt,
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.readout_len_lc,
|
|
seamless_info.seamless_pf_ctrl.hdr_exp.read_margin_lc,
|
|
seamless_info.seamless_pf_ctrl.margin_lc,
|
|
seamless_info.seamless_pf_ctrl.min_fl_lc,
|
|
seamless_info.seamless_pf_ctrl.flicker_en,
|
|
seamless_info.seamless_pf_ctrl.lineTimeInNs,
|
|
seamless_info.seamless_pf_ctrl.readout_time_us,
|
|
mode_crop_height,
|
|
mode_linetime_readout_ns,
|
|
seamless_info.orig_readout_time_us,
|
|
ctx->fsync_out_fl,
|
|
ctx->subctx.frame_length,
|
|
ctx->req_id,
|
|
ctx->sof_cnt);
|
|
}
|
|
|
|
void notify_fsync_mgr_n_1_en(struct adaptor_ctx *ctx, u64 n, u64 en)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set N(%llu):1 en(%llu), but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
n, en);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_n_1_en(ctx->idx, n, en);
|
|
}
|
|
|
|
void notify_fsync_mgr_mstream_en(struct adaptor_ctx *ctx, u64 en)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set mstream en:%llu, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
en);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_mstream_en(ctx->idx, en);
|
|
}
|
|
|
|
void notify_fsync_mgr_subsample_tag(struct adaptor_ctx *ctx, u64 sub_tag)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: set subsample tag:%u, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx,
|
|
sub_tag);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if (unlikely(sub_tag < 1)) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: sub_tag:%llu should larger than 1, return\n",
|
|
__func__, ctx->idx,
|
|
sub_tag);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#if !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, sub_tag %u\n",
|
|
__func__, ctx->idx,
|
|
sub_tag);
|
|
#endif
|
|
|
|
|
|
ctx->fsync_mgr->fs_set_frame_tag(ctx->idx, sub_tag - 1);
|
|
}
|
|
|
|
void notify_fsync_mgr_set_shutter(struct adaptor_ctx *ctx,
|
|
u32 *ae_exp_arr, u32 ae_exp_cnt,
|
|
int do_set_exp_with_fl)
|
|
{
|
|
struct fs_perframe_st pf_ctrl = {0};
|
|
const unsigned int mode_id = ctx->subctx.current_scenario_id;
|
|
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: notify set shutter, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
if (atomic_read(&long_exp_mode_bits) != 0) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: detected any sensor in long exp mode, long_exp_mode_bits:%#x => return [do_set_exp_with_fl:%d]\n",
|
|
__func__, ctx->idx,
|
|
atomic_read(&long_exp_mode_bits), do_set_exp_with_fl);
|
|
return;
|
|
}
|
|
|
|
|
|
pf_ctrl.req_id = ctx->req_id;
|
|
|
|
pf_ctrl.sensor_id = ctx->subdrv->id;
|
|
pf_ctrl.sensor_idx = ctx->idx;
|
|
|
|
pf_ctrl.min_fl_lc = ctx->subctx.min_frame_length;
|
|
pf_ctrl.margin_lc = g_sensor_margin(ctx, mode_id);
|
|
pf_ctrl.flicker_en = ctx->subctx.autoflicker_en;
|
|
pf_ctrl.out_fl_lc = ctx->subctx.frame_length; // sensor current fl_lc
|
|
|
|
/* preventing issue (seamless switch not update ctx->cur_mode data) */
|
|
pf_ctrl.pclk = ctx->subctx.pclk;
|
|
pf_ctrl.linelength = ctx->subctx.line_length;
|
|
pf_ctrl.lineTimeInNs =
|
|
CALC_LINE_TIME_IN_NS(pf_ctrl.pclk, pf_ctrl.linelength);
|
|
pf_ctrl.readout_time_us =
|
|
(ctx->mode[mode_id].height * ctx->mode[mode_id].linetime_in_ns_readout / 1000);
|
|
|
|
/* set exposure data */
|
|
fsync_mgr_set_exp_data(ctx, &pf_ctrl, ae_exp_arr, ae_exp_cnt, mode_id);
|
|
|
|
|
|
#if defined(TWO_STAGE_FS)
|
|
pf_ctrl.cmd_id = (do_set_exp_with_fl)
|
|
? (unsigned int)SENSOR_FEATURE_SET_MULTI_SHUTTER_FRAME_TIME
|
|
: (unsigned int)SENSOR_FEATURE_SET_FRAMELENGTH;
|
|
#else
|
|
pf_ctrl.cmd_id = (unsigned int)SENSOR_FEATURE_SET_FRAMELENGTH;
|
|
#endif
|
|
|
|
|
|
/* call frame-sync fs set shutter */
|
|
ctx->fsync_mgr->fs_set_shutter(&pf_ctrl);
|
|
|
|
|
|
#if defined(TWO_STAGE_FS)
|
|
if (do_set_exp_with_fl) {
|
|
/* Enable frame-sync && using SW sync (SA algo) solution */
|
|
/* set exp with fl (ctx->fsync_out_fl) */
|
|
fsync_mgr_s_multi_shutter_frame_length(ctx,
|
|
ae_exp_arr, ae_exp_cnt);
|
|
|
|
/* update sensor current fl_lc */
|
|
pf_ctrl.out_fl_lc = ctx->subctx.frame_length;
|
|
}
|
|
|
|
|
|
/* update sensor current fl_lc to Frame-Sync */
|
|
ctx->fsync_mgr->fs_update_shutter(&pf_ctrl);
|
|
#endif
|
|
|
|
|
|
adaptor_logd(ctx,
|
|
"sidx:%d, exp(%u, %u/%u/%u/%u/%u, cnt(mode:%u/ae:%u), readout_len:%u, read_margin:%u), margin:%u, min_fl:%u, flk:%u, line_time:%u(ns), readout_time_us:%u(mode_id:%u/height:%u/linetime_readout_ns:%u), set_exp_with_fl(%u, %u/%u), req_id:%d, sof_cnt:%u\n",
|
|
ctx->idx,
|
|
pf_ctrl.shutter_lc,
|
|
pf_ctrl.hdr_exp.exp_lc[0],
|
|
pf_ctrl.hdr_exp.exp_lc[1],
|
|
pf_ctrl.hdr_exp.exp_lc[2],
|
|
pf_ctrl.hdr_exp.exp_lc[3],
|
|
pf_ctrl.hdr_exp.exp_lc[4],
|
|
pf_ctrl.hdr_exp.mode_exp_cnt,
|
|
pf_ctrl.hdr_exp.ae_exp_cnt,
|
|
pf_ctrl.hdr_exp.readout_len_lc,
|
|
pf_ctrl.hdr_exp.read_margin_lc,
|
|
pf_ctrl.margin_lc,
|
|
pf_ctrl.min_fl_lc,
|
|
pf_ctrl.flicker_en,
|
|
pf_ctrl.lineTimeInNs,
|
|
pf_ctrl.readout_time_us,
|
|
mode_id,
|
|
ctx->mode[mode_id].height,
|
|
ctx->mode[mode_id].linetime_in_ns_readout,
|
|
do_set_exp_with_fl,
|
|
ctx->fsync_out_fl,
|
|
ctx->subctx.frame_length,
|
|
ctx->req_id,
|
|
ctx->sof_cnt);
|
|
}
|
|
|
|
|
|
void notify_fsync_mgr_sync_frame(struct adaptor_ctx *ctx,
|
|
const unsigned int flag)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
adaptor_logi(ctx,
|
|
"sidx:%d, NOTICE: notify fsync sync frame, but ctx->fsync_mgr is NULL, return\n",
|
|
ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
adaptor_logd(ctx, "sidx:%d, flag:%u\n", ctx->idx, flag);
|
|
|
|
ctx->fsync_mgr->fs_sync_frame(flag);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* ext ctrls
|
|
******************************************************************************/
|
|
void notify_fsync_mgr_vsync(struct adaptor_ctx *ctx)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR) && !defined(REDUCE_FSYNC_CTRLS_LOG)
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, NOTICE: notify vsync, but ctx->fsync_mgr is NULL, return\n",
|
|
__func__, ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_notify_vsync(ctx->idx, ctx->sof_cnt);
|
|
}
|
|
|
|
|
|
void notify_fsync_mgr_g_fl_record_info(struct adaptor_ctx *ctx,
|
|
struct mtk_fs_frame_length_info *p_fl_info)
|
|
{
|
|
/* not expected case */
|
|
if (unlikely(ctx->fsync_mgr == NULL)) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
adaptor_logi(ctx,
|
|
"sidx:%d, NOTICE: notify fsync sync frame, but ctx->fsync_mgr is NULL, return\n",
|
|
ctx->idx);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
ctx->fsync_mgr->fs_get_fl_record_info(ctx->idx,
|
|
&p_fl_info->target_min_fl_us, &p_fl_info->out_fl_us);
|
|
|
|
adaptor_logd(ctx,
|
|
"sidx:%d, p_fl_info(target_min_fl_us:%u, out_fl_us:%u)\n",
|
|
ctx->idx,
|
|
p_fl_info->target_min_fl_us,
|
|
p_fl_info->out_fl_us);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* init Frame-Sync Mgr / get all function calls
|
|
******************************************************************************/
|
|
int notify_fsync_mgr(struct adaptor_ctx *ctx, int on)
|
|
{
|
|
int ret, seninf_idx = 0;
|
|
const char *seninf_port = NULL;
|
|
char c_ab;
|
|
struct device_node *seninf_np;
|
|
struct device *dev = ctx->dev;
|
|
|
|
if (!on) {
|
|
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
/* imgsensor remove => for remove sysfs file */
|
|
FrameSyncUnInit(ctx->dev);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
seninf_np = of_graph_get_remote_node(dev->of_node, 0, 0);
|
|
if (!seninf_np) {
|
|
dev_info(dev, "no remote device node\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = of_property_read_string(seninf_np, "csi-port", &seninf_port);
|
|
|
|
of_node_put(seninf_np);
|
|
|
|
if (ret || !seninf_port) {
|
|
dev_info(dev, "no seninf csi-port\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* convert seninf-port to seninf-idx */
|
|
ret = sscanf(seninf_port, "%d%c", &seninf_idx, &c_ab);
|
|
seninf_idx <<= 1;
|
|
seninf_idx += (ret == 2 && (c_ab == 'b' || c_ab == 'B'));
|
|
|
|
dev_info(dev, "sensor_idx %d seninf_port %s seninf_idx %d\n",
|
|
ctx->idx, seninf_port, seninf_idx);
|
|
|
|
/* notify frame-sync mgr of sensor-idx and seninf-idx */
|
|
#if !defined(FORCE_DISABLE_FSYNC_MGR)
|
|
/* frame-sync init */
|
|
ret = FrameSyncInit(&ctx->fsync_mgr, ctx->dev);
|
|
if (ret != 0) {
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, WARNING: ctx->fsync_mgr init failed!\n",
|
|
__func__, ctx->idx);
|
|
|
|
ctx->fsync_mgr = NULL;
|
|
} else {
|
|
dev_info(dev,
|
|
"%s: sidx:%d, ctx->fsync_mgr init done, ret:%d",
|
|
__func__, ctx->idx,
|
|
ret);
|
|
}
|
|
#else
|
|
ctx->fsync_mgr = NULL;
|
|
dev_info(ctx->dev,
|
|
"%s: sidx:%d, WARNING: ctx->fsync_mgr is NULL(set FORCE_DISABLE_FSYNC_MGR compile flag)\n",
|
|
__func__, ctx->idx);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|