kernel-brax3-ubuntu-touch/drivers/misc/mediatek/imgsensor/src-v4l2/frame-sync/frame_sync.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

3739 lines
97 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#if !defined(FS_UT)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#endif // FS_UT
#include "frame_sync.h"
#include "frame_sync_camsys.h"
#include "frame_sync_algo.h"
#include "frame_monitor.h"
#include "hw_sensor_sync_algo.h"
#if !defined(FS_UT)
#include "frame_sync_console.h"
#endif // FS_UT
/******************************************************************************/
// Log message
/******************************************************************************/
#include "frame_sync_log.h"
#define REDUCE_FS_DRV_LOG
#define PFX "FrameSync"
/******************************************************************************/
/******************************************************************************/
// Frame Sync Mgr Structure (private structure)
/******************************************************************************/
//------------------------ fs preset perframe st -----------------------------//
struct fs_preset_perframe_st {
unsigned int is_valid;
unsigned int is_streaming;
struct fs_perframe_st preset_pf_ctrl;
};
//----------------------------------------------------------------------------//
//----------------------- fs seamless perframe st ----------------------------//
struct fs_seamless_ctrl_st {
FS_Atomic_T wait_for_processing;
unsigned int seamless_sof_cnt;
struct fs_seamless_st seamless_info;
};
//----------------------------------------------------------------------------//
//---------------------------- frame recorder --------------------------------//
struct FrameRecord {
unsigned int shutter_lc;
unsigned int framelength_lc;
};
struct FrameRecorder {
/* init: 0 => recorder need input default framelength. */
unsigned int init;
unsigned int depthIdx;
struct FrameRecord frame_recs[RECORDER_DEPTH];
};
//----------------------------------------------------------------------------//
//------------------------ fs mgr register sensor-----------------------------//
struct SensorInfo {
unsigned int sensor_id; // imx586 -> 0x0586; s5k3m5sx -> 0x30D5
unsigned int sensor_idx; // main1 -> 0; sub1 -> 1;
// main2 -> 2; sub2 -> 3; main3 -> 4;
};
struct SensorTable {
FS_Atomic_T reg_cnt;
struct SensorInfo sensors[SENSOR_MAX_NUM];
};
//----------------------------------------------------------------------------//
//------------------------ call back function data ---------------------------//
struct callback_st {
void *p_ctx;
unsigned int cmd_id;
callback_set_framelength func_ptr;
};
//----------------------------------------------------------------------------//
//-------------------------------- fs mgr ------------------------------------//
struct FrameSyncMgr {
/* Sensor Register Table */
struct SensorTable reg_table;
/* Frame Sync Status information */
unsigned int user_counter; // also fs_init() cnt
FS_Atomic_T fs_status;
FS_Atomic_T streaming_bits;
FS_Atomic_T enSync_bits;
FS_Atomic_T validSync_bits;
FS_Atomic_T pf_ctrl_bits;
FS_Atomic_T setup_complete_bits;
FS_Atomic_T seamless_bits; // notify which sensor is doing seamless switch
unsigned int last_pf_ctrl_bits;
unsigned int last_setup_complete_bits;
unsigned int trigger_ctrl_bits;
/* For support HW sync */
unsigned int hw_sync_group_id[SENSOR_MAX_NUM];
FS_Atomic_T hw_sync_bits;
FS_Atomic_T hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_MAX];
FS_Atomic_T hw_sync_non_valid_group_bits;
FS_Atomic_T setup_complete_hw_group_bits[FS_HW_SYNC_GROUP_ID_MAX];
/* --- fs act cnt (for ctrl pair trigger) --- */
unsigned int act_cnt[FS_HW_SYNC_GROUP_ID_MAX];
/* For keeping things before register/streaming on */
FS_Atomic_T set_sync_sidx_table[SENSOR_MAX_NUM];
#ifdef USING_CCU
FS_Atomic_T power_on_ccu_bits;
#endif // USING_CCU
/* for different fps sync sensor sync together */
/* e.g. fps: (60 vs 30) */
/* => frame_cell_size: 2 */
/* => frame_tag: 0, 1, 0, 1, 0, ... */
enum FS_HDR_FT_MODE hdr_ft_mode[SENSOR_MAX_NUM];
unsigned int frame_cell_size[SENSOR_MAX_NUM];
unsigned int frame_tag[SENSOR_MAX_NUM];
/* keep for supporting trigger by ext vsync */
struct fs_perframe_st pf_ctrl[SENSOR_MAX_NUM];
/* for set ae ctrl before streaming on */
struct fs_preset_perframe_st preset_ctrl[SENSOR_MAX_NUM];
/* for seamless switch */
struct fs_seamless_ctrl_st seamless_ctrl[SENSOR_MAX_NUM];
/* Frame Settings Recorder */
struct FrameRecorder frm_recorder[SENSOR_MAX_NUM];
/* call back */
struct callback_st cb_data[SENSOR_MAX_NUM];
#ifdef SUPPORT_FS_NEW_METHOD
unsigned int user_set_sa:1; // user config using SA
FS_Atomic_T user_async_master_sidx; // user config async master sidx
FS_Atomic_T using_sa_ver; // flag - using standalone ver
FS_Atomic_T sa_bits; // for needing standalone ver
FS_Atomic_T sa_method; // 0:adaptive switch
FS_Atomic_T master_idx; // SA master idx
FS_Atomic_T async_mode_bits; // SA async mode bits
FS_Atomic_T async_master_idx; // SA async mode m_idx
#endif // SUPPORT_FS_NEW_METHOD
unsigned int sof_cnt_arr[SENSOR_MAX_NUM]; // debug, from p1 sof cnt
};
static struct FrameSyncMgr fs_mgr;
//----------------------------------------------------------------------------//
#ifdef FS_SENSOR_CCU_IT
/* (IT using) Set FL regularly to observe the sensor's response */
#define FL_TABLE_SIZE 8
static unsigned int fl_table[FL_TABLE_SIZE] = {
40000, 45000, 50000, 55000, 60000, 65000, 70000, 75000};
static unsigned int fl_table_idxs[SENSOR_MAX_NUM] = {0, 1, 2, 3, 4};
#endif // FS_SENSOR_CCU_IT
/******************************************************************************/
/******************************************************************************/
// Operate & Basic & utility function
/******************************************************************************/
static inline void change_fs_status(const enum FS_STATUS status)
{
FS_ATOMIC_SET((int)status, &fs_mgr.fs_status);
}
/*
* return: enum FS_STATUS value
* FS_STATUS_UNKNOWN:
* when reading atomic value with
* the value is out of valid range.
*/
static enum FS_STATUS get_fs_status(void)
{
enum FS_STATUS status;
int val = FS_ATOMIC_READ(&fs_mgr.fs_status);
/* check if value valid for enum */
if (unlikely(!(val >= FS_NONE && val < FS_STATUS_UNKNOWN))) {
LOG_INF(
"ERROR: get status val:%d, treat as FS_STATUS_UNKNOWN\n",
val);
return FS_STATUS_UNKNOWN;
}
status = (enum FS_STATUS)val;
return status;
}
/*
* return: (0/1) for (non-valid/valid)
*/
static inline unsigned int check_idx_valid(const unsigned int sensor_idx)
{
return (likely(sensor_idx < SENSOR_MAX_NUM)) ? 1 : 0;
}
#if defined(SUPPORT_FS_NEW_METHOD)
/*
* return: (0/1) or 0xFFFFFFFF
* 0xFFFFFFFF: when check_idx_valid() return error
*/
static unsigned int check_bit_atomic(const unsigned int idx,
const FS_Atomic_T *p_fs_atomic_val)
{
unsigned int ret = check_idx_valid(idx);
unsigned int result = 0;
if (unlikely(ret == 0))
return 0xFFFFFFFF;
result = FS_ATOMIC_READ(p_fs_atomic_val);
result = ((result >> idx) & 1UL);
return result;
}
/*
* return: 1 or 0xFFFFFFFF
* 0xFFFFFFFF: when check_idx_valid() return error
*/
static unsigned int write_bit_atomic(const unsigned int idx,
const unsigned int en, FS_Atomic_T *p_fs_atomic_val)
{
unsigned int ret = check_idx_valid(idx);
if (unlikely(ret == 0))
return 0xFFFFFFFF;
/* en > 0 => set ; en == 0 => clear */
if (en > 0)
FS_ATOMIC_FETCH_OR((1UL << idx), p_fs_atomic_val);
else
FS_ATOMIC_FETCH_AND((~(1UL << idx)), p_fs_atomic_val);
return ret;
}
static inline void clear_all_bit_atomic(FS_Atomic_T *p_fs_atomic_val)
{
FS_ATOMIC_SET(0, p_fs_atomic_val);
}
static inline unsigned int fs_user_sa_config(void)
{
#ifdef FORCE_USING_SA_MODE
return 1;
#else
return fs_mgr.user_set_sa;
#endif // FORCE_USING_SA_MODE
}
#endif // SUPPORT_FS_NEW_METHOD
/******************************************************************************/
/******************************************************************************/
// Dump & Debug function
/******************************************************************************/
static void fs_dump_status(const int idx, const int flag, const char *caller,
const char *msg)
{
const enum FS_STATUS status = get_fs_status();
const unsigned int cnt =
FS_POPCOUNT(FS_ATOMIC_READ(&fs_mgr.validSync_bits));
char *log_buf = NULL;
int ret = 0;
log_buf = FS_CALLOC(LOG_BUF_STR_LEN, sizeof(char));
if (unlikely(log_buf == NULL)) {
LOG_MUST(
"[%s]: ERROR: [%u] flag:%u, log_buf allocate memory failed\n",
caller, idx, flag);
return;
}
log_buf[0] = '\0';
ret = snprintf(log_buf + strlen(log_buf),
LOG_BUF_STR_LEN - strlen(log_buf),
"[%s:%d/%d %s]: stat:%u, ready:%u, stream:%d, enSync:%d(%d/%d/%d/%d/%d/%d), valid:%d, hw_sync:%d(%d)(%d/%d/%d/%d/%d/%d), trigger:%u, pf_ctrl:%d(%u), complete:%d(%u)(hw:%d/%d/%d/%d/%d/%d), act(%u/%u/%u/%u/%u/%u), hdr_ft_mode(%u/%u/%u/%u/%u/%u), seamless:%#x, SA(%d/%d/%d, %d, async(%d, m_sidx:%d(%d)))",
caller, idx, flag, msg,
status,
cnt,
FS_ATOMIC_READ(&fs_mgr.streaming_bits),
FS_ATOMIC_READ(&fs_mgr.enSync_bits),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[0]),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[1]),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[2]),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[3]),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[4]),
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[5]),
FS_ATOMIC_READ(&fs_mgr.validSync_bits),
FS_ATOMIC_READ(&fs_mgr.hw_sync_bits),
FS_ATOMIC_READ(&fs_mgr.hw_sync_non_valid_group_bits),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_0]),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_1]),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_2]),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_3]),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_4]),
FS_ATOMIC_READ(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_5]),
fs_mgr.trigger_ctrl_bits,
FS_ATOMIC_READ(&fs_mgr.pf_ctrl_bits),
fs_mgr.last_pf_ctrl_bits,
FS_ATOMIC_READ(&fs_mgr.setup_complete_bits),
fs_mgr.last_setup_complete_bits,
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_0]),
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_1]),
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_2]),
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_3]),
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_4]),
FS_ATOMIC_READ(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_5]),
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_0],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_1],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_2],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_3],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_4],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_5],
fs_mgr.hdr_ft_mode[0],
fs_mgr.hdr_ft_mode[1],
fs_mgr.hdr_ft_mode[2],
fs_mgr.hdr_ft_mode[3],
fs_mgr.hdr_ft_mode[4],
fs_mgr.hdr_ft_mode[5],
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
FS_ATOMIC_READ(&fs_mgr.using_sa_ver),
fs_user_sa_config(),
FS_ATOMIC_READ(&fs_mgr.sa_bits),
FS_ATOMIC_READ(&fs_mgr.master_idx),
FS_ATOMIC_READ(&fs_mgr.async_mode_bits),
FS_ATOMIC_READ(&fs_mgr.user_async_master_sidx),
FS_ATOMIC_READ(&fs_mgr.async_master_idx));
if (unlikely(ret < 0))
LOG_MUST("ERROR: LOG encoding error, ret:%d\n", ret);
#if defined(USING_CCU)
ret = snprintf(log_buf + strlen(log_buf),
LOG_BUF_STR_LEN - strlen(log_buf),
", pw_ccu:%d(cnt:%d)",
FS_ATOMIC_READ(&fs_mgr.power_on_ccu_bits),
frm_get_ccu_pwn_cnt());
if (unlikely(ret < 0)) {
LOG_MUST(
"ERROR: LOG encoding error (add USING_CCU part), ret:%d\n",
ret);
}
#endif // USING_CCU
LOG_MUST("%s\n", log_buf);
FS_FREE(log_buf);
}
/******************************************************************************/
/******************************************************************************/
// Register Sensor function / SensorInfo & SensorTable
//
// PS: The method register "BY_SENSOR_IDX" is't been tested in this SW flow.
/******************************************************************************/
static inline unsigned int compare_sensor_id(
const unsigned int id1, const unsigned int id2)
{
return (id1 == id2 && id1 != 0) ? 1 : 0;
}
static inline unsigned int compare_sensor_idx(
const unsigned int idx1, const unsigned int idx2)
{
return (idx1 == idx2) ? 1 : 0;
}
static unsigned int check_sensor_info(
const struct SensorInfo (*info1),
const struct SensorInfo (*info2),
const enum CHECK_SENSOR_INFO_METHOD method)
{
switch (method) {
case BY_SENSOR_ID:
return compare_sensor_id(info1->sensor_id, info2->sensor_id);
case BY_SENSOR_IDX:
return compare_sensor_idx(info1->sensor_idx, info2->sensor_idx);
default:
return compare_sensor_idx(info1->sensor_idx, info2->sensor_idx);
}
}
static inline unsigned int fs_get_reg_sensor_id(const unsigned int idx)
{
return fs_mgr.reg_table.sensors[idx].sensor_id;
}
static inline unsigned int fs_get_reg_sensor_idx(const unsigned int idx)
{
return fs_mgr.reg_table.sensors[idx].sensor_idx;
}
/*
* return: uint_t or 0xffffffff
* uint_t: array position for the registered sensor save in.
* 0xffffffff: not found this sensor ID in "SensorTable".
*/
static unsigned int fs_search_reg_sensors(
const struct SensorInfo (*sensor_info),
const enum CHECK_SENSOR_INFO_METHOD method)
{
unsigned int i = 0;
int reg_cnt = FS_ATOMIC_READ(&fs_mgr.reg_table.reg_cnt);
for (i = 0; i < reg_cnt; ++i) {
const struct SensorInfo *pInfo = &fs_mgr.reg_table.sensors[i];
if (check_sensor_info(pInfo, sensor_info, method))
return i;
}
return 0xffffffff;
}
/*
* return: uint_t or 0xffffffff
* uint_t: array position for the registered sensor save in.
* 0xffffffff: reach maximum register capacity, couldn't register it.
*
* !!! You have check the return idx before using it. !!!
*/
static unsigned int fs_push_sensor(const struct SensorInfo (*sensor_info))
{
struct SensorTable (*pSensorTable) = &fs_mgr.reg_table;
FS_Atomic_T *p_fs_atomic_val = &fs_mgr.reg_table.reg_cnt;
int cnt_now = 0, cnt_new = 0;
do {
cnt_now = FS_ATOMIC_READ(p_fs_atomic_val);
cnt_new = cnt_now + 1;
/* boundary check and check if reach maximum capacity */
if (!((cnt_now >= 0) && (cnt_now < SENSOR_MAX_NUM)))
return 0xFFFFFFFF;
#ifdef FS_UT
} while (!atomic_compare_exchange_weak(
p_fs_atomic_val, &cnt_now, cnt_new));
#else
} while (atomic_cmpxchg(p_fs_atomic_val, cnt_now, cnt_new) != cnt_now);
#endif // FS_UT
/* => cnt_now is correct and avalible */
pSensorTable->sensors[(unsigned int)cnt_now] = *sensor_info;
return cnt_now;
}
/*
* return: uint_t or 0xffffffff
* uint_t: array position for the registered sensor save in.
* 0xffffffff: couldn't register sensor.
* (reach maximum capacity or sensor ID is 0)
*
* !!! You have better to check the return idx before using it. !!!
*/
static unsigned int fs_register_sensor(const struct SensorInfo (*sensor_info),
const enum CHECK_SENSOR_INFO_METHOD method)
{
unsigned int idx = 0;
/* 1. check error sensor id */
if (unlikely(method == BY_SENSOR_ID && sensor_info->sensor_id == 0)) {
LOG_PR_WARN("ERROR: sensor ID is %#x\n", sensor_info->sensor_id);
return 0xffffffff;
}
/* 2. search registered sensors */
idx = fs_search_reg_sensors(sensor_info, method);
if (idx == 0xffffffff) {
/* 2-1. add / push this sensor, regitser it */
/* two results: */
/* 1. register successfully; */
/* 2. can't register */
idx = fs_push_sensor(sensor_info);
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_PR_WARN("ERROR: Reach max sensor capacity\n");
return idx;
}
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"ID:%#x(sidx:%u), register it (idx:%u), method:%s\n",
sensor_info->sensor_id,
sensor_info->sensor_idx,
idx,
REG_INFO);
#endif // REDUCE_FS_DRV_LOG
} else {
/* 2-2. this sensor has been registered, do nothing */
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("ID:%#x(sidx:%u), idx:%u, method:%s, already registered\n",
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
idx,
REG_INFO);
#endif // REDUCE_FS_DRV_LOG
if (method == BY_SENSOR_IDX) {
if (fs_mgr.reg_table.sensors[idx].sensor_id !=
sensor_info->sensor_id) {
LOG_INF(
"Overwrite to... [%u] ID:%#x(sidx:%u), method:%s\n",
idx,
sensor_info->sensor_id,
sensor_info->sensor_idx,
REG_INFO);
fs_mgr.reg_table.sensors[idx].sensor_id =
sensor_info->sensor_id;
}
}
}
return idx;
}
/*
* return: uint_t or 0xffffffff
* uint_t: array position for the registered sensor save in.
* 0xffffffff: not found this sensor idx in "SensorTable".
*
* input:
* ident: sensor ID / sensor idx
*/
static unsigned int fs_get_reg_sensor_pos(const unsigned int ident)
{
struct SensorInfo info = {0};
unsigned int idx = 0;
switch (REGISTER_METHOD) {
case BY_SENSOR_ID:
info.sensor_id = ident;
break;
case BY_SENSOR_IDX:
info.sensor_idx = ident;
break;
default:
info.sensor_idx = ident;
break;
}
idx = fs_search_reg_sensors(&info, REGISTER_METHOD);
return idx;
}
static inline unsigned int fs_get_reg_sensor_ident(
const unsigned int sid, const unsigned int sidx)
{
unsigned int ident = 0;
switch (REGISTER_METHOD) {
case BY_SENSOR_ID:
ident = sid;
break;
case BY_SENSOR_IDX:
ident = sidx;
break;
default:
ident = sidx;
break;
}
return ident;
}
/******************************************************************************/
/******************************************************************************/
// call back struct data operation
/******************************************************************************/
static inline void fs_reset_cb_data(const unsigned int idx)
{
fs_mgr.cb_data[idx].func_ptr = NULL;
fs_mgr.cb_data[idx].p_ctx = NULL;
fs_mgr.cb_data[idx].cmd_id = 0;
}
static inline void fs_init_cb_data(const unsigned int idx,
void *p_ctx, const callback_set_framelength func_ptr)
{
fs_mgr.cb_data[idx].func_ptr = func_ptr;
fs_mgr.cb_data[idx].p_ctx = p_ctx;
fs_mgr.cb_data[idx].cmd_id = 0;
}
static inline void fs_set_cb_cmd_id(const unsigned int idx,
const unsigned int cmd_id)
{
fs_mgr.cb_data[idx].cmd_id = cmd_id;
}
/******************************************************************************/
/******************************************************************************/
// Frame Recorder function
/******************************************************************************/
static inline unsigned int frec_chk_depthIdx_valid(const unsigned int depthIdx)
{
return (likely(depthIdx < RECORDER_DEPTH)) ? 1 : 0;
}
static void frec_dump_recorder(const unsigned int idx, const char *caller)
{
struct FrameRecorder (*pFrameRecord) = &fs_mgr.frm_recorder[idx];
LOG_MUST(
"[%s]: [%u] ID:%#x(sidx:%u), recs:(ref at:%u) (0:%u/%u), (1:%u/%u), (2:%u/%u), (3:%u/%u) (fl_lc/shut_lc), init:%u, depthIdx:%u\n",
caller,
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
/* ring back */
(pFrameRecord->depthIdx + (RECORDER_DEPTH-1)) % RECORDER_DEPTH,
pFrameRecord->frame_recs[0].framelength_lc,
pFrameRecord->frame_recs[0].shutter_lc,
pFrameRecord->frame_recs[1].framelength_lc,
pFrameRecord->frame_recs[1].shutter_lc,
pFrameRecord->frame_recs[2].framelength_lc,
pFrameRecord->frame_recs[2].shutter_lc,
pFrameRecord->frame_recs[3].framelength_lc,
pFrameRecord->frame_recs[3].shutter_lc,
pFrameRecord->init,
pFrameRecord->depthIdx);
}
static void frec_reset_recorder(const unsigned int idx)
{
unsigned int i = 0;
struct FrameRecord clear_st = {0};
struct FrameRecorder (*pFrameRecord) = &fs_mgr.frm_recorder[idx];
/* all FrameRecorder member variables set to 0 */
pFrameRecord->init = 0;
pFrameRecord->depthIdx = 0;
for (i = 0; i < RECORDER_DEPTH; ++i)
pFrameRecord->frame_recs[i] = clear_st;
#if defined(TRACE_FS_FREC_LOG)
frec_dump_recorder(idx, __func__);
#endif
}
/*
* Notify fs algo and frame monitor the data in the frame recorder have been
* updated
*
* This function should be call after having any frame recorder operation
*
*
* description:
* fs algo will use these information to predict current and
* next framelength when calculating vsync diff.
*/
static void frec_notify_setting_frame_record_st_data(const unsigned int idx)
{
struct frame_record_st recs[RECORDER_DEPTH];
struct FrameRecorder *pFrameRecord = &fs_mgr.frm_recorder[idx];
unsigned int depthIdx = pFrameRecord->depthIdx;
unsigned int i = 0;
/* 1. prepare frame settings in the recorder */
/* => 0:newest, 1:second, 2:third */
for (i = 0; i < RECORDER_DEPTH; ++i) {
/* 1-1. ring back depthIdx */
depthIdx = (depthIdx + (RECORDER_DEPTH-1)) % (RECORDER_DEPTH);
/* 1-2. map the settings to frame record structure */
recs[i].framelength_lc =
&pFrameRecord->frame_recs[depthIdx].framelength_lc;
recs[i].shutter_lc =
&pFrameRecord->frame_recs[depthIdx].shutter_lc;
}
/* 2. call fs alg set frame record data */
fs_alg_set_frame_record_st_data(idx, recs);
}
static void frec_push_def_shutter_fl_lc(const unsigned int idx,
const unsigned int shutter_lc, const unsigned int fl_lc)
{
struct FrameRecorder *pFrameRecord = &fs_mgr.frm_recorder[idx];
unsigned int i = 0;
/* case handling */
if (unlikely(pFrameRecord->init)) {
LOG_MUST(
"NOTICE: [%u] frec was initialized:%u, auto return [get %u/%u (fl_lc/shut_lc)]\n",
idx,
pFrameRecord->init,
fl_lc, shutter_lc);
frec_dump_recorder(idx, __func__);
return;
}
/* init all frec value to default shutter and framelength */
pFrameRecord->init = 1;
for (i = 0; i < RECORDER_DEPTH; ++i) {
pFrameRecord->frame_recs[i].shutter_lc = shutter_lc;
pFrameRecord->frame_recs[i].framelength_lc = fl_lc;
}
#if defined(TRACE_FS_FREC_LOG)
frec_dump_recorder(idx, __func__);
#endif
/* set the results to fs algo and frame monitor */
frec_notify_setting_frame_record_st_data(idx);
}
/*
* description:
* update / frec data for next calculation/calibration
*
* input:
* idx: sensor register position in sensor table.
* shutter_lc: shutter lc you want to update to frec (> 0 will update)
* fl_lc: frame length lc you want to update to frec (> 0 will update)
*/
static void frec_update_shutter_fl_lc(const unsigned int idx,
const unsigned int shutter_lc, const unsigned int fl_lc)
{
struct FrameRecorder *pFrameRecord = &fs_mgr.frm_recorder[idx];
unsigned int curr_depth = pFrameRecord->depthIdx;
/* ring back to point to current data records */
curr_depth = ((curr_depth + (RECORDER_DEPTH-1)) % (RECORDER_DEPTH));
/* set / update shutter/framelength lc */
if (shutter_lc > 0)
pFrameRecord->frame_recs[curr_depth].shutter_lc = shutter_lc;
if (fl_lc > 0)
pFrameRecord->frame_recs[curr_depth].framelength_lc = fl_lc;
if (unlikely((shutter_lc == 0) && (fl_lc == 0))) {
LOG_MUST(
"WARNING: [%u] ID:%#x(sidx:%u) get: %u/%u => recs[*%u] = *%u/%u (fl_lc/shut_lc), don't update frec data\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fl_lc,
shutter_lc,
curr_depth,
pFrameRecord->frame_recs[curr_depth].framelength_lc,
pFrameRecord->frame_recs[curr_depth].shutter_lc);
frec_dump_recorder(idx, __func__);
}
#if defined(TRACE_FS_FREC_LOG)
LOG_MUST(
"[%u] ID:%#x(sidx:%u) get:(%u/%u) => curr at recs[%u]=(%u/%u) [recs:(at %u) (0:%u/%u), (1:%u/%u), (2:%u/%u), (3:%u/%u)] (fl_lc/shut_lc)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fl_lc,
shutter_lc,
curr_depth,
pFrameRecord->frame_recs[curr_depth].framelength_lc,
pFrameRecord->frame_recs[curr_depth].shutter_lc,
(pFrameRecord->depthIdx + (RECORDER_DEPTH-1)) % (RECORDER_DEPTH),
pFrameRecord->frame_recs[0].framelength_lc,
pFrameRecord->frame_recs[0].shutter_lc,
pFrameRecord->frame_recs[1].framelength_lc,
pFrameRecord->frame_recs[1].shutter_lc,
pFrameRecord->frame_recs[2].framelength_lc,
pFrameRecord->frame_recs[2].shutter_lc,
pFrameRecord->frame_recs[3].framelength_lc,
pFrameRecord->frame_recs[3].shutter_lc);
#endif
/* set the results to fs algo and frame monitor */
frec_notify_setting_frame_record_st_data(idx);
}
static void frec_push_shutter_fl_lc(const unsigned int idx,
const unsigned int shutter_lc, const unsigned int fl_lc)
{
struct FrameRecorder *pFrameRecord = &fs_mgr.frm_recorder[idx];
unsigned int *pDepthIdx = &pFrameRecord->depthIdx;
#if defined(TRACE_FS_FREC_LOG)
unsigned int bufDepthIdx = *pDepthIdx;
#endif
/* case handling */
if (unlikely(!frec_chk_depthIdx_valid(*pDepthIdx))) {
LOG_MUST(
"ERROR: detect invalid frec depthIdx:%u (RECORDER_DEPTH:%u), return\n",
*pDepthIdx, RECORDER_DEPTH);
return;
}
/* push shutter_lc and framelength_lc if are not equal to 0 */
if (shutter_lc > 0)
pFrameRecord->frame_recs[*pDepthIdx].shutter_lc = shutter_lc;
if (fl_lc > 0)
pFrameRecord->frame_recs[*pDepthIdx].framelength_lc = fl_lc;
/* depth idx ring forward */
(*pDepthIdx) = (((*pDepthIdx) + 1) % RECORDER_DEPTH);
#if defined(TRACE_FS_FREC_LOG)
LOG_MUST(
"[%u] ID:%#x(sidx:%u) get:(%u/%u) => curr at recs[%u]=(%u/%u), depthIdx update to %u [recs:(at %u) (0:%u/%u), (1:%u/%u), (2:%u/%u), (3:%u/%u)] (fl_lc/shut_lc)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fl_lc, shutter_lc,
bufDepthIdx,
pFrameRecord->frame_recs[bufDepthIdx].framelength_lc,
pFrameRecord->frame_recs[bufDepthIdx].shutter_lc,
(*pDepthIdx),
(pFrameRecord->depthIdx + (RECORDER_DEPTH-1)) % (RECORDER_DEPTH),
pFrameRecord->frame_recs[0].framelength_lc,
pFrameRecord->frame_recs[0].shutter_lc,
pFrameRecord->frame_recs[1].framelength_lc,
pFrameRecord->frame_recs[1].shutter_lc,
pFrameRecord->frame_recs[2].framelength_lc,
pFrameRecord->frame_recs[2].shutter_lc,
pFrameRecord->frame_recs[3].framelength_lc,
pFrameRecord->frame_recs[3].shutter_lc);
#endif
/* set the results to fs algo and frame monitor */
frec_notify_setting_frame_record_st_data(idx);
}
static void frec_push_record(const unsigned int idx,
const unsigned int shutter_lc, const unsigned int framelength_lc)
{
/* unexpected case handling */
if (unlikely(fs_mgr.frm_recorder[idx].init == 0)) {
// TODO : add error handle ?
LOG_INF(
"NOTICE: [%u] ID:%#x(sidx:%u) push shutter, fl before initialized recorder\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx));
}
frec_push_shutter_fl_lc(idx, shutter_lc, framelength_lc);
}
#if defined(QUERY_CCU_TS_AT_SOF)
/*
* be careful:
* only call this API after all frame settings/info are be done!
* owning to this API will push a frame settings into recorder.
*
* e.g. call this API after doing bellow processing
* setup frame monitor frame measurement,
* dump fs algo info, ..., etc
*/
static void frec_notify_vsync(const unsigned int idx)
{
/* push previous frame settings into frame recorder */
frec_push_record(idx,
fs_mgr.pf_ctrl[idx].shutter_lc,
fs_mgr.pf_ctrl[idx].out_fl_lc);
}
#endif // QUERY_CCU_TS_AT_SOF
/******************************************************************************/
/******************************************************************************/
// preset perframe structure functions
/******************************************************************************/
static void fs_reset_preset_perframe_data(const unsigned int sidx)
{
struct fs_perframe_st clear_st = {0};
/* unexpected case */
if (unlikely(check_idx_valid(sidx) == 0)) {
LOG_MUST(
"ERROR: get invalid sidx:%u, return\n",
sidx);
return;
}
/* reset/clear data */
fs_mgr.preset_ctrl[sidx].is_valid = 0;
fs_mgr.preset_ctrl[sidx].is_streaming = 0;
fs_mgr.preset_ctrl[sidx].preset_pf_ctrl = clear_st;
}
static void fs_set_preset_perframe_data(const unsigned int sidx,
const struct fs_perframe_st *p_pf_ctrl)
{
/* unexpected case */
if (unlikely(check_idx_valid(sidx) == 0)) {
LOG_MUST(
"ERROR: get invalid sidx:%u, return\n",
sidx);
return;
}
/* only copy pf_ctrl data when sensor is streaming OFF */
if (fs_mgr.preset_ctrl[sidx].is_streaming)
return;
/* keep preset pf_ctrl data */
fs_mgr.preset_ctrl[sidx].is_valid = 1;
fs_mgr.preset_ctrl[sidx].preset_pf_ctrl = *p_pf_ctrl;
}
static unsigned int fs_get_preset_perframe_data(const unsigned int sidx,
struct fs_perframe_st *p_pf_ctrl)
{
unsigned int ret = 0;
/* unexpected case */
if (unlikely(check_idx_valid(sidx) == 0)) {
LOG_MUST(
"ERROR: get invalid sidx:%u, return\n",
sidx);
return 0;
}
/* notify streaming ON */
fs_mgr.preset_ctrl[sidx].is_streaming = 1;
if (fs_mgr.preset_ctrl[sidx].is_valid) {
/* copy preset pf_ctrl data */
*p_pf_ctrl = fs_mgr.preset_ctrl[sidx].preset_pf_ctrl;
ret = 1;
}
return ret;
}
/******************************************************************************/
/******************************************************************************/
// Frame Sync Mgr function
/******************************************************************************/
#ifdef SUPPORT_FS_NEW_METHOD
static void fs_init_members(void)
{
unsigned int i = 0;
FS_ATOMIC_INIT(0, &fs_mgr.reg_table.reg_cnt);
FS_ATOMIC_INIT(0, &fs_mgr.fs_status);
FS_ATOMIC_INIT(0, &fs_mgr.streaming_bits);
FS_ATOMIC_INIT(0, &fs_mgr.enSync_bits);
FS_ATOMIC_INIT(0, &fs_mgr.validSync_bits);
FS_ATOMIC_INIT(0, &fs_mgr.pf_ctrl_bits);
FS_ATOMIC_INIT(0, &fs_mgr.setup_complete_bits);
FS_ATOMIC_INIT(0, &fs_mgr.seamless_bits);
FS_ATOMIC_INIT(0, &fs_mgr.hw_sync_bits);
for (i = 0; i < FS_HW_SYNC_GROUP_ID_MAX; ++i) {
FS_ATOMIC_INIT(0, &fs_mgr.hw_sync_group_bits[i]);
FS_ATOMIC_INIT(0, &fs_mgr.setup_complete_hw_group_bits[i]);
}
FS_ATOMIC_INIT(0, &fs_mgr.hw_sync_non_valid_group_bits);
for (i = 0; i < SENSOR_MAX_NUM; ++i) {
FS_ATOMIC_INIT(0, &fs_mgr.set_sync_sidx_table[i]);
FS_ATOMIC_INIT(0, &fs_mgr.seamless_ctrl[i].wait_for_processing);
}
#if defined(USING_CCU)
FS_ATOMIC_INIT(0, &fs_mgr.power_on_ccu_bits);
#endif // USING_CCU
FS_ATOMIC_INIT(0, &fs_mgr.using_sa_ver);
FS_ATOMIC_INIT(0, &fs_mgr.sa_bits);
FS_ATOMIC_INIT(0, &fs_mgr.sa_method);
FS_ATOMIC_INIT(MASTER_IDX_NONE, &fs_mgr.master_idx);
FS_ATOMIC_INIT(0, &fs_mgr.async_mode_bits);
FS_ATOMIC_INIT(MASTER_IDX_NONE, &fs_mgr.user_async_master_sidx);
FS_ATOMIC_INIT(MASTER_IDX_NONE, &fs_mgr.async_master_idx);
}
#endif // SUPPORT_FS_NEW_METHOD
static void fs_init(void)
{
enum FS_STATUS status = get_fs_status();
fs_mgr.user_counter++;
if (status == FS_NONE) {
#ifdef SUPPORT_FS_NEW_METHOD
fs_init_members();
#endif // SUPPORT_FS_NEW_METHOD
change_fs_status(FS_INITIALIZED);
LOG_MUST("FrameSync init. (User:%u)\n", fs_mgr.user_counter);
} else if (status == FS_INITIALIZED)
LOG_MUST("Initialized. (User:%u)\n", fs_mgr.user_counter);
// else if () => for re-init.
}
#ifdef SUPPORT_FS_NEW_METHOD
/*
* Support user/custom setting for using FrameSync StandAlone(SA) mode
*/
void fs_set_using_sa_mode(const unsigned int en)
{
fs_mgr.user_set_sa = (en > 0) ? 1 : 0;
}
unsigned int fs_is_hw_sync(const unsigned int ident)
{
unsigned int idx = 0, result = 0;
idx = fs_get_reg_sensor_pos(ident);
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"WARNING: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return 0;
}
result = FS_CHECK_BIT(idx, &fs_mgr.hw_sync_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("%u [%u] ID:%#x(sidx:%u) [hw_sync_bits:%d]\n",
result,
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.hw_sync_bits));
#endif // REDUCE_FS_DRV_LOG
return result;
}
static void fs_set_hw_sync_info(
const unsigned int idx,
const unsigned int flag,
const unsigned int hw_sync_mode,
const unsigned int hw_sync_group_id)
{
/* means no using HW solution */
/* hw sync mode equal to 0 (means using SW solution) */
/* will be retruned at the start of this function, */
/* so exclude that case should all using hw sync solution */
if (hw_sync_mode == 0)
return;
/* error handling */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"ERROR: [idx:%u] is not valid (MIN:0/MAX:%u), return\n",
idx, SENSOR_MAX_NUM);
return;
}
/* set(stream ON)/clear(stream OFF) hw sync bits */
if (flag)
FS_WRITE_BIT(idx, 1, &fs_mgr.hw_sync_bits);
else
FS_WRITE_BIT(idx, 0, &fs_mgr.hw_sync_bits);
/* set hw sync group bits */
fs_mgr.hw_sync_group_id[idx] = hw_sync_group_id;
if (hw_sync_group_id >= FS_HW_SYNC_GROUP_ID_MAX) {
/* error handling (de-reference non-valid address) */
if (flag) {
FS_WRITE_BIT(idx, 1,
&fs_mgr.hw_sync_non_valid_group_bits);
} else {
FS_WRITE_BIT(idx, 0,
&fs_mgr.hw_sync_non_valid_group_bits);
}
LOG_MUST(
"ERROR: [%u] ID:%#x(sidx:%u) Non-valid value of hw_sync_group_id:%d (MIN:%d/MAX:%d), no apply(curr:%u), non_valid_group_bits:%d [en:%u]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
hw_sync_group_id,
FS_HW_SYNC_GROUP_ID_MIN,
FS_HW_SYNC_GROUP_ID_MAX,
fs_mgr.hw_sync_group_id[idx],
FS_READ_BITS(&fs_mgr.hw_sync_non_valid_group_bits),
flag);
return;
}
if (flag) {
FS_WRITE_BIT(idx, 1,
&fs_mgr.hw_sync_group_bits[hw_sync_group_id]);
} else {
FS_WRITE_BIT(idx, 0,
&fs_mgr.hw_sync_group_bits[hw_sync_group_id]);
}
/* clear/reset ctrls setup complete hw group bit */
FS_WRITE_BIT(idx, 0,
&fs_mgr.setup_complete_hw_group_bits[hw_sync_group_id]);
/* clear/reset frame-sync act cnt */
fs_mgr.act_cnt[hw_sync_group_id] = 0;
LOG_MUST(
"[%u] ID:%#x(sidx:%u) en:%u, hw_sync(mode:%u(N:0/M:1/S:2), group_id:%u) [hw_sync(bits:%u, group_bits(%d/%d/%d/%d/%d/%d), setup_complete(%d/%d/%d/%d/%d/%d), act_cnt(%u/%u/%u/%u/%u/%u)), non_valid_group_bits:%d]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
flag,
hw_sync_mode,
fs_mgr.hw_sync_group_id[idx],
FS_READ_BITS(&fs_mgr.hw_sync_bits),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_0]),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_1]),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_2]),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_3]),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_4]),
FS_READ_BITS(
&fs_mgr.hw_sync_group_bits[FS_HW_SYNC_GROUP_ID_5]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_0]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_1]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_2]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_3]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_4]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_5]),
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_0],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_1],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_2],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_3],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_4],
fs_mgr.act_cnt[FS_HW_SYNC_GROUP_ID_5],
FS_READ_BITS(&fs_mgr.hw_sync_non_valid_group_bits));
}
#endif // SUPPORT_FS_NEW_METHOD
static int fs_update_valid_sync_bit(void)
{
int streaming = 0, en_sync = 0;
streaming = FS_ATOMIC_READ(&fs_mgr.streaming_bits);
en_sync = FS_ATOMIC_READ(&fs_mgr.enSync_bits);
FS_ATOMIC_SET((streaming & en_sync), &fs_mgr.validSync_bits);
return (streaming & en_sync);
}
static void fs_update_status(const unsigned int idx,
const unsigned int flag, const char *caller)
{
unsigned int cnt = 0;
int valid_sync = 0;
/* update validSync_bits value */
valid_sync = fs_update_valid_sync_bit();
/* change status or not by counting the number of valid sync sensors */
cnt = FS_POPCOUNT(valid_sync);
if (cnt > 1 && cnt <= SENSOR_MAX_NUM)
change_fs_status(FS_WAIT_FOR_SYNCFRAME_START);
else
change_fs_status(FS_INITIALIZED);
fs_dump_status(idx, flag, caller, "");
}
static inline void fs_set_status_bits(const unsigned int idx,
const unsigned int flag, FS_Atomic_T *bits)
{
if (flag > 0)
write_bit_atomic(idx, 1, bits);
else
write_bit_atomic(idx, 0, bits);
}
static inline void fs_set_stream(unsigned int idx, unsigned int flag)
{
fs_set_status_bits(idx, flag, &fs_mgr.streaming_bits);
}
static inline void fs_reset_ft_mode_data(unsigned int idx, unsigned int flag)
{
if (flag > 0)
return;
fs_mgr.hdr_ft_mode[idx] = 0;
fs_mgr.frame_cell_size[idx] = 0;
fs_mgr.frame_tag[idx] = 0;
}
static void fs_reset_perframe_stage_data(
const unsigned int idx, const unsigned int flag)
{
struct fs_perframe_st clear_st = {0};
if (flag > 0)
return;
fs_mgr.pf_ctrl[idx] = clear_st;
fs_alg_reset_vsync_data(idx);
}
/*---------------------------------------------------------------------------*/
// seamless switch functions
/*---------------------------------------------------------------------------*/
static unsigned int fs_chk_seamless_switch_status(const unsigned int idx)
{
return FS_CHECK_BIT(idx, &fs_mgr.seamless_bits);
}
static void fs_clr_seamless_switch_info(const unsigned int idx)
{
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, return\n",
idx, REG_INFO);
return;
}
fs_set_status_bits(idx, 0, &fs_mgr.seamless_bits);
memset(&fs_mgr.seamless_ctrl[idx], 0, sizeof(fs_mgr.seamless_ctrl[idx]));
LOG_MUST(
"[%u] ID:%#x(sidx:%u), seamless:%#x, seamless_sof_cnt:%u (cleared), SA(m_idx:%d)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
fs_mgr.seamless_ctrl->seamless_sof_cnt,
FS_ATOMIC_READ(&fs_mgr.master_idx));
}
static void fs_set_seamless_switch_info(const unsigned int idx,
struct fs_seamless_st *p_seamless_info,
const unsigned int seamless_sof_cnt)
{
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, return\n",
idx, REG_INFO);
return;
}
if (unlikely(p_seamless_info == NULL)) {
LOG_MUST(
"ERROR: [%u] ID:%#x(sidx:%u), get p_seamless_info:%p, return\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
p_seamless_info);
return;
}
fs_set_status_bits(idx, 1, &fs_mgr.seamless_bits);
/* !!! setup fs_seamless_ctrl_st data !!! */
/* keep seamless switch ctrl information */
/* keep here & check for clear data when exit seamless frame */
FS_ATOMIC_SET(1, &fs_mgr.seamless_ctrl[idx].wait_for_processing);
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt = seamless_sof_cnt;
fs_mgr.seamless_ctrl[idx].seamless_info = *p_seamless_info;
/* change SA alg master to this sensor */
/* before keepping seamless ctrl */
fs_sa_request_switch_master(idx);
LOG_INF(
"[%u] ID:%#x(sidx:%u), seamless:%#x, seamless_sof_cnt:%u, wait_for_processing:%d, SA(m_idx:%d), orig_readout_time_us:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt,
FS_ATOMIC_READ(&fs_mgr.seamless_ctrl[idx].wait_for_processing),
FS_ATOMIC_READ(&fs_mgr.master_idx),
fs_mgr.seamless_ctrl[idx].seamless_info.orig_readout_time_us);
}
static void fs_do_seamless_switch_proc(const unsigned int idx,
const struct fs_sa_cfg *p_sa_cfg)
{
struct fs_seamless_st *p_seamless_info = NULL;
struct fs_perframe_st *p_seamless_ctrl = NULL;
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, return\n",
idx, REG_INFO);
return;
}
if (unlikely(p_sa_cfg == NULL)) {
LOG_MUST(
"ERROR: [%u] ID:%#x(sidx:%u), get p_sa_cfg:%p, return\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
p_sa_cfg);
return;
}
/* read back/get seamless ctrl that keep last time */
/* and prevent any issue overwriting last pf ctrl exp and fl */
p_seamless_info = &fs_mgr.seamless_ctrl[idx].seamless_info;
p_seamless_ctrl = &fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl;
frec_reset_recorder(idx);
frec_push_def_shutter_fl_lc(idx,
p_seamless_ctrl->shutter_lc, p_seamless_ctrl->out_fl_lc);
// frec_dump_recorder(idx, __func__);
fs_alg_seamless_switch(idx, p_seamless_info, p_sa_cfg);
}
/*---------------------------------------------------------------------------*/
#ifdef SUPPORT_FS_NEW_METHOD
static inline void fs_check_sync_need_sa_mode(
unsigned int idx, enum FS_HDR_FT_MODE flag)
{
/* NOT FS_HDR_FT_MODE_NORMAL => using SA mode */
if (flag != FS_HDR_FT_MODE_NORMAL) {
write_bit_atomic(idx, 1, &fs_mgr.sa_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"[%u] ID:%#x(sidx:%u), hdr_ft_mode:%u(need SA mode, except 0 for normal) [sa_bits:%d]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
flag,
FS_ATOMIC_READ(&fs_mgr.sa_bits));
#endif // REDUCE_FS_DRV_LOG
}
}
static void fs_decision_maker(unsigned int idx)
{
int sa_bits_now = 0;
int need_sa_ver = 0;
int user_sa_en = 0;
/* 1. check sync tag of the sensor need use SA mode or not */
fs_check_sync_need_sa_mode(idx, fs_mgr.hdr_ft_mode[idx]);
/* 2. check all sensor for using SA mode or not */
do {
sa_bits_now = FS_ATOMIC_READ(&fs_mgr.sa_bits);
need_sa_ver = (FS_POPCOUNT(sa_bits_now) > 0) ? 1 : 0;
#ifdef FS_UT
} while (!atomic_compare_exchange_weak(&fs_mgr.sa_bits,
&sa_bits_now, sa_bits_now));
#else
} while (atomic_cmpxchg(&fs_mgr.sa_bits,
sa_bits_now, sa_bits_now) != sa_bits_now);
#endif // FS_UT
/* 3. check user/custom SA config EN */
user_sa_en = fs_user_sa_config();
/* X. setup result of using SA mode or not */
if (need_sa_ver > 0 || user_sa_en > 0)
FS_ATOMIC_SET(1, &fs_mgr.using_sa_ver);
else
FS_ATOMIC_SET(0, &fs_mgr.using_sa_ver);
#if !defined(FORCE_USING_SA_MODE) || !defined(REDUCE_FS_DRV_LOG)
LOG_MUST(
"using_sa:%d (user_sa_en:%u), hdr_ft_mode:%u, sa_bits:%d [idx:%u]\n",
FS_ATOMIC_READ(&fs_mgr.using_sa_ver),
user_sa_en,
fs_mgr.hdr_ft_mode[idx],
FS_ATOMIC_READ(&fs_mgr.sa_bits),
idx);
#endif
}
/*
* if the input, idx, un-set FrameSync set sync, and is SA master idx,
* => true: reset SA master idx to MASTER_IDX_NONE
* => false: do nothing.
*/
static void fs_sa_try_reset_master_idx(const unsigned int idx,
const unsigned int flag)
{
int master_idx = MASTER_IDX_NONE;
/* The sensor status is already set sync => do nothing */
if (flag > 0)
return;
/* check situation for needing reset SA master idx */
do {
master_idx = FS_ATOMIC_READ(&fs_mgr.master_idx);
#ifdef FS_UT
} while (!atomic_compare_exchange_weak(&fs_mgr.master_idx,
&master_idx,
((idx == master_idx)
? MASTER_IDX_NONE : master_idx)));
#else
} while (atomic_cmpxchg(&fs_mgr.master_idx,
master_idx,
((idx == master_idx)
? MASTER_IDX_NONE : master_idx))
!= master_idx);
#endif // FS_UT
}
/*
* This function will change async_master_idx value immediately!
* Only call this function when you confirmed that
* this instance idx of sensor is valid for doing frame-sync!
*/
static void fs_sa_update_async_master_idx(const unsigned int idx,
const unsigned int flag)
{
const unsigned int sidx = fs_get_reg_sensor_idx(idx);
const int async_m_idx = FS_ATOMIC_READ(&fs_mgr.async_master_idx);
int user_async_m_sidx = FS_ATOMIC_READ(&fs_mgr.user_async_master_sidx);
#if !defined(FS_UT)
int ret = fs_con_chk_usr_async_m_sidx();
/* user cmd overwrite set sync flag */
if (unlikely(ret != MASTER_IDX_NONE)) {
user_async_m_sidx = ret;
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), USER set async master sidx:%u => user_async_m_sidx:%d\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
ret,
user_async_m_sidx);
}
#endif // FS_UT
/* case handling */
/* --- check user input value is valid or not */
if (unlikely((user_async_m_sidx != MASTER_IDX_NONE)
&& (user_async_m_sidx < 0
|| user_async_m_sidx >= SENSOR_MAX_NUM))) {
LOG_MUST(
"[%u] ERROR: ID:%#x(sidx:%u), invalid user_async_master_sidx:%d value, return\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
user_async_m_sidx);
return;
}
if (flag > 0) {
if (sidx != user_async_m_sidx)
return;
/* set to this instance idx for using */
FS_ATOMIC_SET(idx, &fs_mgr.async_master_idx);
} else {
if (idx != async_m_idx)
return;
FS_ATOMIC_SET(MASTER_IDX_NONE, &fs_mgr.async_master_idx);
}
LOG_MUST(
"[%u] ID:%#x(sidx:%u), flag:%u, async_master(user_sidx:%d/curr_idx:%d->%d) [streaming:%d/enSync:%d/validSync:%d]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
flag,
user_async_m_sidx,
async_m_idx,
FS_ATOMIC_READ(&fs_mgr.async_master_idx),
FS_ATOMIC_READ(&fs_mgr.streaming_bits),
FS_ATOMIC_READ(&fs_mgr.enSync_bits),
FS_ATOMIC_READ(&fs_mgr.validSync_bits));
}
void fs_sa_set_user_async_master(const unsigned int sidx,
const unsigned int flag)
{
unsigned int idx = fs_get_reg_sensor_pos(sidx);
if (flag > 0)
FS_ATOMIC_SET(sidx, &fs_mgr.user_async_master_sidx);
else
FS_ATOMIC_SET(MASTER_IDX_NONE, &fs_mgr.user_async_master_sidx);
/* if sensor is registered and valid for doing frame-sync, */
/* (streaming ON + set sync) update async master idx simultaneously */
if (check_idx_valid(idx)
&& FS_CHECK_BIT(idx, &fs_mgr.validSync_bits)) {
fs_sa_update_async_master_idx(idx, flag);
/* log info can be see by above function */
return;
}
LOG_MUST(
"[%d] sidx:%u, flag:%u, user_async_master_sidx:%d, streaming:%d, enSync:%d, validSync:%d, async_master_idx:%u\n",
(int)idx, sidx, flag,
FS_ATOMIC_READ(&fs_mgr.user_async_master_sidx),
FS_ATOMIC_READ(&fs_mgr.streaming_bits),
FS_ATOMIC_READ(&fs_mgr.enSync_bits),
FS_ATOMIC_READ(&fs_mgr.validSync_bits),
FS_ATOMIC_READ(&fs_mgr.async_master_idx));
}
static inline void fs_sa_set_async_info(const unsigned int idx,
const unsigned int flag)
{
const unsigned int async_en = (flag & FS_SYNC_TYPE_ASYNC_MODE);
FS_WRITE_BIT(idx, async_en, &fs_mgr.async_mode_bits);
}
#endif // SUPPORT_FS_NEW_METHOD
static void fs_set_sync_status(unsigned int idx, unsigned int flag)
{
/* unset sync => reset pf_ctrl_bits data of this idx */
/* TODO: add a API for doing this */
if (flag == 0) {
FS_WRITE_BIT(idx, 0, &fs_mgr.pf_ctrl_bits);
FS_WRITE_BIT(idx, 0, &fs_mgr.setup_complete_bits);
#if defined(USING_CCU) && defined(DELAY_CCU_OP)
if (FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits) == 1) {
FS_WRITE_BIT(idx, 0, &fs_mgr.power_on_ccu_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("[%u] ID:%#x(sidx:%u), pw_ccu:%d (OFF)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.power_on_ccu_bits));
#endif // REDUCE_FS_DRV_LOG
frm_reset_ccu_vsync_timestamp(idx, 0);
/* power off CCU */
frm_power_on_ccu(0);
fs_alg_reset_vsync_data(idx);
}
#endif // USING_CCU && DELAY_CCU_OP
}
#if defined(USING_CCU) && defined(DELAY_CCU_OP)
if (flag > 0 && FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits) == 0) {
FS_WRITE_BIT(idx, 1, &fs_mgr.power_on_ccu_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("[%u] ID:%#x(sidx:%u), pw_ccu:%d (ON)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.power_on_ccu_bits));
#endif // REDUCE_FS_DRV_LOG
fs_alg_reset_vsync_data(idx);
/* power on CCU and get device handle */
frm_power_on_ccu(1);
frm_reset_ccu_vsync_timestamp(idx, 1);
}
#endif // USING_CCU && DELAY_CCU_OP
fs_set_status_bits(idx, flag, &fs_mgr.enSync_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("en:%u [%u] ID:%#x(sidx:%u) [enSync_bits:%d]\n",
flag,
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.enSync_bits));
#endif // REDUCE_FS_DRV_LOG
}
static void fs_update_set_sync_sidx_table(const unsigned int sidx,
const unsigned int flag)
{
if (unlikely(check_idx_valid(sidx) == 0)) {
LOG_MUST(
"ERROR: get invalid sidx:%u, return\n",
sidx);
return;
}
FS_ATOMIC_SET(flag, &fs_mgr.set_sync_sidx_table[sidx]);
LOG_INF(
"sidx:%u, flag:%u, => set_sync_sidx_table[%u]:%d\n",
sidx, flag, sidx,
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[sidx]));
}
static int fs_check_set_sync_sidx_table(const unsigned int sidx)
{
int ret = -1;
if (unlikely(check_idx_valid(sidx) == 0)) {
LOG_MUST(
"ERROR: get invalid sidx:%u, return (-1)\n",
sidx);
return -1;
}
ret = FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[sidx]);
LOG_INF(
"sidx:%u, set_sync_sidx_table[%u]:%d, => ret:%d\n",
sidx, sidx,
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[sidx]),
ret);
return ret;
}
static void fs_set_sync_idx(unsigned int idx, unsigned int flag)
{
fs_set_sync_status(idx, flag);
fs_alg_set_sync_type(idx, flag);
fs_sa_set_async_info(idx, flag);
#if defined(FS_UT)
fs_reset_ft_mode_data(idx, flag);
#endif // FS_UT
fs_sa_try_reset_master_idx(idx, flag);
fs_sa_update_async_master_idx(idx, flag);
fs_decision_maker(idx);
fs_update_status(idx, flag, __func__);
}
void fs_set_sync(unsigned int ident, unsigned int flag)
{
unsigned int idx = fs_get_reg_sensor_pos(ident);
#if !defined(FS_UT)
unsigned int owr_flag = flag;
/* user cmd force disable frame-sync set_sync */
if (unlikely(fs_con_chk_force_to_ignore_set_sync())) {
LOG_MUST(
"WARNING: [%u] ident:%u(%s), USER set frame-sync force to ignore set sync, return\n",
idx, ident, REG_INFO);
return;
}
/* user cmd overwrite set sync flag */
if (unlikely(fs_con_chk_en_overwrite_set_sync(ident, &owr_flag))) {
LOG_MUST(
"NOTICE: [%u] ident:%u(%s), USER set overwrite set sync value:(%u -> %u)\n",
idx, ident, REG_INFO,
flag, owr_flag);
flag = owr_flag;
}
#endif // FS_UT
fs_update_set_sync_sidx_table(ident, flag);
if (check_idx_valid(idx) == 0) {
LOG_MUST(
"NOTICE: [%u] ident:%u(%s) is not register, only update set_sync_sidx_table[%u]:%d\n value",
idx, ident, REG_INFO, ident,
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[ident]));
return;
}
fs_set_sync_idx(idx, flag);
}
unsigned int fs_is_set_sync(unsigned int ident)
{
unsigned int idx = 0, result = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return 0;
}
result = FS_CHECK_BIT(idx, &fs_mgr.enSync_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF("%u [%u] ID:%#x(sidx:%u) [enSync_bits:%d]\n",
result,
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.enSync_bits));
#endif // REDUCE_FS_DRV_LOG
return result;
}
static void fs_set_sensor_driver_framelength_lc(
unsigned int idx, unsigned int fl_lc)
{
int ret = 0;
struct callback_st *p_cb = &fs_mgr.cb_data[idx];
callback_set_framelength cb_func = p_cb->func_ptr;
/* callback sensor driver to set framelength lc */
if (p_cb->func_ptr != NULL) {
if (fl_lc != 0)
ret = cb_func(p_cb->p_ctx, p_cb->cmd_id, fl_lc);
if (ret != 0) {
LOG_PR_WARN(
"ERROR: [%u] ID:%#x(sidx:%u), set fl_lc:%u failed, p_ctx:%p\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fl_lc,
fs_mgr.cb_data[idx].p_ctx);
}
} else
LOG_PR_WARN("ERROR: [%u] ID:%#x(sidx:%u), func_ptr is NULL\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx));
}
/*
* all framelength operation must use this API
*/
static inline void fs_set_framelength_lc(unsigned int idx, unsigned int fl_lc)
{
#if !defined(TWO_STAGE_FS) //|| defined(QUERY_CCU_TS_AT_SOF)
/* 0. update frame recorder data */
frec_update_shutter_fl_lc(idx, 0, fl_lc);
/* after all settings are updated, */
/* setup frame monitor fmeas data before calling fs_alg_get_vsync_data */
fs_alg_setup_frame_monitor_fmeas_data(idx);
#endif // TWO_STAGE_FS
#ifndef REDUCE_FS_DRV_LOG
frec_dump_recorder(idx, __func__);
#endif //REDUCE_FS_DRV_LOG
/* 1. using callback function to set framelength */
fs_set_sensor_driver_framelength_lc(idx, fl_lc);
/* 2. set the results to fs algo and frame monitor */
// frec_notify_setting_frame_record_st_data(idx);
}
#ifdef SUPPORT_FS_NEW_METHOD
static inline unsigned int fs_check_n_1_status_ctrl(
unsigned int idx, unsigned int en)
{
enum FS_HDR_FT_MODE mode_status = fs_mgr.hdr_ft_mode[idx];
if (en) {
/* only normal mode can turn ON N:1 mode */
return (mode_status == 0) ? 1 : 0;
}
/* only FRAME_TAG and N_1_KEEP can turn OFF N:1 mode */
return (mode_status
& (FS_HDR_FT_MODE_FRAME_TAG | FS_HDR_FT_MODE_N_1_KEEP))
? 1 : 0;
}
static inline void fs_check_n_1_status_extra_ctrl(unsigned int idx)
{
enum FS_HDR_FT_MODE old_ft_status;
old_ft_status = fs_mgr.hdr_ft_mode[idx];
if (fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_ON) {
fs_mgr.hdr_ft_mode[idx] &= ~(FS_HDR_FT_MODE_N_1_ON);
fs_mgr.hdr_ft_mode[idx] |= FS_HDR_FT_MODE_N_1_KEEP;
LOG_MUST(
"[%u] ID:%#x(sidx:%u), feature mode status change (%u->%u), ON:%u/KEEP:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
old_ft_status,
fs_mgr.hdr_ft_mode[idx],
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_ON,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_KEEP
);
/* turn off FS algo n_1_on_off flag */
/* for calculating FL normally */
fs_alg_set_n_1_on_off_flag(idx, 0);
} else if (fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_OFF) {
fs_mgr.hdr_ft_mode[idx] &= ~(FS_HDR_FT_MODE_N_1_OFF);
fs_mgr.hdr_ft_mode[idx] &= ~(FS_HDR_FT_MODE_FRAME_TAG);
fs_mgr.hdr_ft_mode[idx] |= FS_HDR_FT_MODE_NORMAL;
LOG_MUST(
"[%u] ID:%#x(sidx:%u), feature mode status change (%u->%u), OFF:%u/FRAME_TAG:%u/NORMAL:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
old_ft_status,
fs_mgr.hdr_ft_mode[idx],
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_OFF,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_FRAME_TAG,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_NORMAL
);
/* turn off FS algo n_1_on_off flag */
/* for calculating FL normally */
fs_alg_set_n_1_on_off_flag(idx, 0);
}
}
static inline void fs_feature_status_extra_ctrl(unsigned int idx)
{
fs_check_n_1_status_extra_ctrl(idx);
}
void fs_sa_request_switch_master(unsigned int idx)
{
int sa_method = -1;
sa_method = FS_ATOMIC_READ(&fs_mgr.sa_method);
if (sa_method != FS_SA_ADAPTIVE_MASTER) {
LOG_MUST(
"ERROR: SA method:%d, but request (from idx:%u) switch master sensor, vdiff will not be adjusted\n",
sa_method,
idx);
return;
}
FS_ATOMIC_SET(idx, &fs_mgr.master_idx);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"switch master instance idx to %d (from idx:%u)\n",
FS_ATOMIC_READ(&fs_mgr.master_idx),
idx);
#endif // REDUCE_FS_DRV_LOG
}
static int fs_get_valid_master_instance_idx(const unsigned int idx)
{
const int async_mode_bits = FS_ATOMIC_READ(&fs_mgr.async_mode_bits);
const int valid_bits = FS_ATOMIC_READ(&fs_mgr.validSync_bits);
const int m_idx = FS_ATOMIC_READ(&fs_mgr.master_idx);
int i = 0;
/* check case */
/* --- user not config master sensor */
/* or config a invalid sensor as master */
/* invalid: (not set sync || uses async mode) */
if (m_idx == MASTER_IDX_NONE
|| (((valid_bits >> m_idx) & 0x01) == 0)
|| (((async_mode_bits >> m_idx) & 0x01) == 1)) {
/* auto select a master sensor */
i = 0;
while ((i < SENSOR_MAX_NUM)
&& ((((valid_bits >> i) & 0x01) != 1)
|| ((async_mode_bits >> i) & 0x01) == 1))
i++;
/* no match => set to itself & preventing OOB */
if (i >= SENSOR_MAX_NUM) {
i = idx;
/* unexpected case */
if (async_mode_bits == 0) {
LOG_MUST(
"[%u] NOTICE: can't auto select SA master idx, force set to itself, m_idx:%d [validSync:%u/Async_Mode_bits:%d]\n",
idx, i, valid_bits, async_mode_bits);
}
}
FS_ATOMIC_SET(i, &fs_mgr.master_idx);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_MUST(
"NOTICE: current master_idx:%d is not valid for doing frame-sync, validSync_bits:%d, Async_Mode_bits:%d, auto set to idx:%d\n",
m_idx, valid_bits, async_mode_bits, i);
#endif
return i;
}
return m_idx;
}
static int fs_get_valid_async_master_instance_idx(const unsigned int idx)
{
const int async_mode_bits = FS_READ_BITS(&fs_mgr.async_mode_bits);
const int valid_bits = FS_ATOMIC_READ(&fs_mgr.validSync_bits);
const int async_m_idx = FS_ATOMIC_READ(&fs_mgr.async_master_idx);
/* check async master idx */
/* --- no sensor uses async mode => it's fine */
if (async_mode_bits == 0)
return MASTER_IDX_NONE;
/* --- has async_mode sensor => check async_m_idx is valid */
if ((async_mode_bits != 0) && ((async_m_idx != MASTER_IDX_NONE)
&& ((valid_bits >> async_m_idx) & 0x01)))
return async_m_idx;
/* un-wish case handling */
/* --- async master idx is not valid */
if ((async_mode_bits != 0) && ((async_m_idx == MASTER_IDX_NONE)
|| (((valid_bits >> async_m_idx) & 0x01) == 0))) {
fs_dump_status(idx, -1, __func__,
"WARNING: async_m_sidx is invalid for using, auto assign to itself");
return idx;
}
LOG_MUST(
"[%u] WARNING: undefined case, return async_m_idx:%u (itself) for using\n",
idx, idx);
return idx;
}
static inline void fs_sa_setup_perframe_cfg_info(const unsigned int idx,
struct fs_sa_cfg *p_sa_cfg)
{
p_sa_cfg->idx = idx;
p_sa_cfg->sa_method = FS_ATOMIC_READ(&fs_mgr.sa_method);
p_sa_cfg->m_idx = fs_get_valid_master_instance_idx(idx);
p_sa_cfg->valid_sync_bits = FS_READ_BITS(&fs_mgr.validSync_bits);
p_sa_cfg->async_m_idx = fs_get_valid_async_master_instance_idx(idx);
p_sa_cfg->async_s_bits = FS_READ_BITS(&fs_mgr.async_mode_bits);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_MUST(
"[%u] idx:%u, sa_mthod:%u, m_idx:%d, valid_sync_bits:%#x, async_m_idx:%d, async_s_bits:%#x\n",
idx,
p_sa_cfg->idx,
p_sa_cfg->sa_method,
p_sa_cfg->m_idx,
p_sa_cfg->valid_sync_bits,
p_sa_cfg->async_m_idx,
p_sa_cfg->async_s_bits);
#endif
}
static void fs_try_trigger_frame_sync_sa(const unsigned int idx)
{
struct fs_sa_cfg sa_cfg = {0};
unsigned int fl_lc = 0;
unsigned int ret = 0;
/* unexpected case check (but it should be detect in previous caller) */
if (unlikely(
(FS_CHECK_BIT(idx, &fs_mgr.validSync_bits) == 0)
|| (FS_CHECK_BIT(idx, &fs_mgr.pf_ctrl_bits) == 0)
|| (FS_CHECK_BIT(idx, &fs_mgr.setup_complete_bits) == 0))) {
/* call dump all info for seeing what's happened */
fs_dump_status(idx, -1, __func__,
"ERROR: invalid for doing frame-sync, check validSync/pf_ctrl/setup_complete");
return;
}
/* clear status bit */
/* --- because it's valid for trigger FL calculation */
FS_WRITE_BIT(idx, 0, &fs_mgr.pf_ctrl_bits);
FS_WRITE_BIT(idx, 0, &fs_mgr.setup_complete_bits);
/* trigger FS-SA for calculating frame length, */
/* but only set FL to sensor driver if return with no error */
fs_sa_setup_perframe_cfg_info(idx, &sa_cfg);
ret = fs_alg_solve_frame_length_sa(&sa_cfg, &fl_lc);
if (ret != 0) { // !0 => had error
LOG_INF(
"ERROR: [%u] ID:%#x(sidx:%u), fs_alg_solve_frame_length_sa return error:%u, auto set fl_lc:%u to min_fl_lc for sensor driver",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
ret,
fl_lc);
}
/* set framelength (all FL operation must use this API) */
fs_set_framelength_lc(idx, fl_lc);
/* check/change feature mode status */
fs_feature_status_extra_ctrl(idx);
}
static void fs_reset_frame_tag(unsigned int idx)
{
fs_mgr.frame_tag[idx] = 0;
fs_alg_set_frame_tag(idx, fs_mgr.frame_tag[idx]);
}
static inline void fs_try_set_auto_frame_tag(unsigned int idx)
{
unsigned int f_tag = 0, f_cell = 0;
if (((fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_ASSIGN_FRAME_TAG) == 0)
&& (fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_FRAME_TAG)) {
/* N:1 case */
if (fs_mgr.frame_cell_size[idx] == 0) {
LOG_MUST(
"NOTICE: [%u] call set auto frame_tag, feature_mode:%u, but frame_cell_size:%u not valid, return\n",
idx,
fs_mgr.hdr_ft_mode[idx],
fs_mgr.frame_cell_size[idx]
);
return;
}
fs_alg_set_frame_tag(idx, fs_mgr.frame_tag[idx]);
/* update new frame tag */
f_tag = (fs_mgr.frame_tag[idx] + 1);
f_cell = (fs_mgr.frame_cell_size[idx]);
fs_mgr.frame_tag[idx] = f_tag % f_cell;
}
}
void fs_set_frame_tag(unsigned int ident, unsigned int f_tag)
{
#if defined(TWO_STAGE_FS) && !defined(QUERY_CCU_TS_AT_SOF)
unsigned int f_cell;
#endif // TWO_STAGE_FS && !QUERY_CCU_TS_AT_SOF
unsigned int idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, f_tag:%u, return\n",
idx, REG_INFO, ident, f_tag);
return;
}
if ((fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_ASSIGN_FRAME_TAG)
&& (fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_FRAME_TAG)) {
/* M-Stream case */
#if !defined(TWO_STAGE_FS) || defined(QUERY_CCU_TS_AT_SOF)
fs_mgr.frame_tag[idx] = f_tag;
#else // TWO_STAGE_FS
f_cell = fs_mgr.frame_cell_size[idx];
if (f_cell != 0)
fs_mgr.frame_tag[idx] = (f_tag + 1) % f_cell;
else {
fs_mgr.frame_tag[idx] = 0;
LOG_MUST(
"WARNING: [%u] input f_tag:%u, re-set to %u, because f_cell:%u (TWO_STAGE_FS)\n",
idx, f_tag, fs_mgr.frame_tag[idx], f_cell);
}
#endif // !TWO_STAGE_FS || QUERY_CCU_TS_AT_SOF
fs_alg_set_frame_tag(idx, fs_mgr.frame_tag[idx]);
} else {
LOG_MUST(
"WARNING: [%u] call set frame_tag:%u, but feature_mode:%u not allow\n",
idx,
f_tag,
fs_mgr.hdr_ft_mode[idx]
);
}
}
void fs_n_1_en(unsigned int ident, unsigned int n, unsigned int en)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, n:%u, en:%u, return\n",
idx, REG_INFO, ident, n, en);
return;
}
if (fs_check_n_1_status_ctrl(idx, en) == 0) {
/* feature mode status is non valid for this ctrl */
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), set N:%u, but ft ctrl non valid, feature_mode:%u (FRAME_TAG:%u/ON:%u/KEEP:%u/OFF:%u), return [en:%u]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
n,
fs_mgr.hdr_ft_mode[idx],
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_FRAME_TAG,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_ON,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_KEEP,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_OFF,
en);
return;
}
if (en) {
fs_mgr.frame_cell_size[idx] = n;
fs_mgr.hdr_ft_mode[idx] =
(FS_HDR_FT_MODE_FRAME_TAG | FS_HDR_FT_MODE_N_1_ON);
} else {
fs_mgr.frame_cell_size[idx] = 0;
fs_mgr.hdr_ft_mode[idx] =
(FS_HDR_FT_MODE_FRAME_TAG | FS_HDR_FT_MODE_N_1_OFF);
}
fs_alg_set_frame_cell_size(idx, fs_mgr.frame_cell_size[idx]);
/* reset frame tag cnt */
// fs_set_frame_tag(idx, 0);
fs_reset_frame_tag(idx);
/* notify frame-sync algo at ON/OFF case for setting correct FL */
/* this will be turn off when FL be calculated done */
fs_alg_set_n_1_on_off_flag(idx, 1);
LOG_MUST(
"[%u] ID:%#x(sidx:%u), N:%u, feature_mode:%u (FRAME_TAG:%u/ON:%u/OFF:%u) [en:%u]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
n,
fs_mgr.hdr_ft_mode[idx],
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_FRAME_TAG,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_ON,
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_N_1_OFF,
en);
}
void fs_mstream_en(unsigned int ident, unsigned int en)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, en:%u, return\n",
idx, REG_INFO, ident, en);
return;
}
fs_n_1_en(ident, 2, en);
if (en) {
/* set M-Stream mode */
fs_mgr.hdr_ft_mode[idx] |= FS_HDR_FT_MODE_ASSIGN_FRAME_TAG;
} else {
/* unset M-Stream mode */
fs_mgr.hdr_ft_mode[idx] &= ~(FS_HDR_FT_MODE_ASSIGN_FRAME_TAG);
}
LOG_MUST(
"[%u] ID:%#x(sidx:%u), N:2, feature_mode:%u (ASSIGN_FRAME_TAG:%u) [en:%u]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fs_mgr.hdr_ft_mode[idx],
fs_mgr.hdr_ft_mode[idx] & FS_HDR_FT_MODE_ASSIGN_FRAME_TAG,
en);
}
#endif // SUPPORT_FS_NEW_METHOD
void fs_set_extend_framelength(
unsigned int ident, unsigned int ext_fl_lc, unsigned int ext_fl_us)
{
unsigned int idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, ext_fl(lc:%u/us:%u), return\n",
idx, REG_INFO, ident, ext_fl_lc, ext_fl_us);
return;
}
fs_alg_set_extend_framelength(idx, ext_fl_lc, ext_fl_us);
}
void fs_chk_exit_seamless_switch_frame(const unsigned int ident)
{
const unsigned int idx = fs_get_reg_sensor_pos(ident);
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
/* check if new vsync sof cnt been updated and is NOT match to seamless sof cnt */
/* because it is the next frame that after seamless switch frame */
/* if yes, clear/reset seamless ctrl data */
if (fs_chk_seamless_switch_status(idx)) {
if (fs_mgr.seamless_ctrl[idx].seamless_sof_cnt != fs_mgr.sof_cnt_arr[idx]
|| (FS_ATOMIC_READ(&fs_mgr.seamless_ctrl[idx].wait_for_processing) == 0)) {
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), wait_for_processing:%d or (current sof cnt:%u)/(seamelss sof cnt:%u) is different => It is NOT seamless switch frame => enter to NORMAL frame => clear seamless ctrl that keep before\n",
idx,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_id,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_idx,
FS_ATOMIC_READ(&fs_mgr.seamless_ctrl[idx].wait_for_processing),
fs_mgr.sof_cnt_arr[idx],
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt);
fs_clr_seamless_switch_info(idx);
}
}
}
void fs_chk_valid_for_doing_seamless_switch(const unsigned int ident)
{
struct fs_sa_cfg sa_cfg = {0};
const unsigned int idx = fs_get_reg_sensor_pos(ident);
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
/* check if new vsync sof cnt been updated and is match to seamless sof cnt */
/* if not, keep seamless ctrl for vsync notify using. */
if (fs_chk_seamless_switch_status(idx)) {
if (fs_mgr.seamless_ctrl[idx].seamless_sof_cnt != fs_mgr.sof_cnt_arr[idx]) {
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), seamless:%#x, wait_for_processing:%d, (current sof cnt:%u)/(seamelss sof cnt:%u) is different, SA(m_idx:%d), keep this seamless ctrl\n",
idx,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_id,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_idx,
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
FS_ATOMIC_READ(&fs_mgr.seamless_ctrl[idx].wait_for_processing),
fs_mgr.sof_cnt_arr[idx],
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt,
FS_ATOMIC_READ(&fs_mgr.master_idx));
return;
}
/* !!! can do seamless frame-sync flow !!! */
fs_sa_setup_perframe_cfg_info(idx, &sa_cfg);
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), seamless_bits:%#x, wait_for_processing:%d, (current sof cnt:%u)/(seamelss sof cnt:%u) is same, SA(idx:%u/m_idx:%d/async_m_idx:%u/async_s:%#x/valid_sync:%#x/method:%u) => do seamless switch process\n",
idx,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_id,
fs_mgr.seamless_ctrl[idx].seamless_info.seamless_pf_ctrl.sensor_idx,
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
FS_ATOMIC_READ(&fs_mgr.seamless_ctrl[idx].wait_for_processing),
fs_mgr.sof_cnt_arr[idx],
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt,
sa_cfg.idx,
sa_cfg.m_idx,
sa_cfg.async_m_idx,
sa_cfg.async_s_bits,
sa_cfg.valid_sync_bits,
sa_cfg.sa_method);
FS_ATOMIC_SET(0, &fs_mgr.seamless_ctrl[idx].wait_for_processing);
fs_do_seamless_switch_proc(idx, &sa_cfg);
}
}
void fs_seamless_switch(const unsigned int ident,
struct fs_seamless_st *p_seamless_info,
const unsigned int seamless_sof_cnt)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
fs_set_seamless_switch_info(idx, p_seamless_info, seamless_sof_cnt);
fs_chk_valid_for_doing_seamless_switch(ident);
}
/*
* update fs_streaming_st data
* (for cam_mux switch & sensor stream on before cam mux setup)
*/
void fs_update_tg(unsigned int ident, unsigned int tg)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
#ifdef USING_CCU
/* 0. check ccu pwr ON, and disable INT(previous tg) */
if (FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits))
frm_reset_ccu_vsync_timestamp(idx, 0);
#endif // USING_CCU
/* 0-1 convert cammux id to ccu tg id */
// tg = frm_convert_cammux_tg_to_ccu_tg(tg);
tg = frm_convert_cammux_id_to_ccu_tg_id(tg);
/* 1. update the fs_streaming_st data */
fs_alg_update_tg(idx, tg);
frm_update_tg(idx, tg);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_MUST(
"[%u] ID:%#x(sidx:%u), updated tg:%u (fs_alg, frm)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
tg
);
#endif // REDUCE_FS_DRV_LOG
#ifdef USING_CCU
/* 2. on the fly change cam_mux/tg */
/* => reset/re-init frame info data for after using */
if (FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits)) {
// frm_reset_frame_info(idx);
// frm_init_frame_info_st_data(idx,
// info.sensor_id, info.sensor_idx,
// tg);
frm_reset_ccu_vsync_timestamp(idx, 1);
}
#endif // USING_CCU
}
/*
* update fs_streaming_st data
* (for cam_mux switch & sensor stream on before cam mux setup)
* ISP7s HW change, seninf assign target tg ID (direct map to CCU tg ID)
*/
void fs_update_target_tg(const unsigned int ident,
const unsigned int target_tg)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
#ifdef USING_CCU
/* 0. check ccu pwr ON, and disable INT(previous tg) */
if (FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits))
frm_reset_ccu_vsync_timestamp(idx, 0);
#endif
/* 1. update the fs_streaming_st data */
fs_alg_update_tg(idx, target_tg);
frm_update_tg(idx, target_tg);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_MUST(
"[%u] ID:%#x(sidx:%u), updated target_tg:%u (fs_alg, frm)\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
target_tg);
#endif
#ifdef USING_CCU
/* 2. on the fly change cam_mux/tg */
/* => reset/re-init frame info data for after using */
if (FS_CHECK_BIT(idx, &fs_mgr.power_on_ccu_bits)) {
// frm_reset_frame_info(idx);
// frm_init_frame_info_st_data(idx,
// info.sensor_id, info.sensor_idx,
// tg);
frm_reset_ccu_vsync_timestamp(idx, 1);
}
#endif
}
static unsigned int fs_chk_and_get_tg_value(
const unsigned int cammux_id, const unsigned int target_tg)
{
unsigned int tg = CAMMUX_ID_INVALID;
if ((cammux_id != 0) && (cammux_id != CAMMUX_ID_INVALID))
tg = frm_convert_cammux_id_to_ccu_tg_id(cammux_id);
if ((target_tg != 0) && (target_tg != CAMMUX_ID_INVALID))
tg = target_tg;
LOG_MUST(
"get cammux_id:%u, target_tg:%u, => ret tg:%u\n",
cammux_id,
target_tg,
tg);
return tg;
}
static inline void fs_reset_idx_ctx(unsigned int idx)
{
/* unset sync */
fs_set_sync_idx(idx, 0);
/* reset frm frame info data */
frm_reset_frame_info(idx);
/* reset fs instance data (algo -> fs_inst[idx]) */
fs_alg_reset_fs_inst(idx);
/* reset frame recorder data */
frec_reset_recorder(idx);
/* clear/reset perframe stage data */
fs_reset_perframe_stage_data(idx, 0);
/* unset stream (stream off) */
fs_set_stream(idx, 0);
/* clear/reset callback function pointer */
fs_reset_cb_data(idx);
}
/*
* return: (0/uint_t) for (no error/error)
* P.S: 1 -> register failed
*
* input:
* flag: "non 0" -> stream on; "0" -> stream off;
* sensor_info: struct fs_streaming_st*
*/
unsigned int fs_streaming(const unsigned int flag,
struct fs_streaming_st (*sensor_info))
{
struct fs_perframe_st preset_pf_ctrl = {0};
struct SensorInfo info = {
.sensor_id = sensor_info->sensor_id,
.sensor_idx = sensor_info->sensor_idx,
};
unsigned int idx = 0;
int ret = 0;
#if !defined(FS_UT)
unsigned int owr_flag = 1;
/* streaming with enable set sync if user set it */
if (unlikely(fs_con_chk_default_en_set_sync())) {
/* user cmd overwrite set sync flag */
if (fs_con_chk_en_overwrite_set_sync(sensor_info->sensor_idx,
&owr_flag)) {
LOG_MUST(
"NOTICE: ID:%#x(sidx:%u), USER set overwrite set sync value:(1 -> %u)\n",
sensor_info->sensor_id,
sensor_info->sensor_idx,
owr_flag);
}
fs_update_set_sync_sidx_table(sensor_info->sensor_idx, owr_flag);
LOG_MUST(
"NOTICE: ID:%#x(sidx:%u), USER set frame-sync force enable set sync, set_sync_sidx_table[%u]:%d\n",
sensor_info->sensor_id,
sensor_info->sensor_idx,
sensor_info->sensor_idx,
FS_ATOMIC_READ(&fs_mgr.set_sync_sidx_table[
sensor_info->sensor_idx]));
}
#endif // !FS_UT
/* 1. register this sensor and check return idx/position value */
idx = fs_register_sensor(&info, REGISTER_METHOD);
if (check_idx_valid(idx) == 0) {
LOG_PR_WARN("ERROR: [idx:%u] ID:%#x(sidx:%u)\n",
idx, info.sensor_id, info.sensor_idx);
/* TODO: return a special error number ? */
return 1;
}
/* 2. reset this idx item and reset CCU vsync timestamp */
fs_reset_idx_ctx(idx);
/* set/clear hw sensor sync info */
fs_set_hw_sync_info(
idx, flag,
sensor_info->sync_mode,
sensor_info->hw_sync_group_id);
/* 3. if fs_streaming on, set information of this idx correctlly */
if (flag > 0) {
/* get tg by check cammux_id and target_tg value */
sensor_info->tg = fs_chk_and_get_tg_value(
sensor_info->cammux_id, sensor_info->target_tg);
/* set data to frm, fs algo, and frame recorder */
frm_init_frame_info_st_data(idx,
sensor_info->sensor_id, sensor_info->sensor_idx,
sensor_info->tg);
ret = fs_get_preset_perframe_data(sensor_info->sensor_idx,
&preset_pf_ctrl);
if (ret)
fs_alg_set_preset_perframe_streaming_st_data(idx,
sensor_info, &preset_pf_ctrl);
else
fs_alg_set_streaming_st_data(idx, sensor_info);
hw_fs_alg_set_streaming_st_data(idx, sensor_info);
frec_push_def_shutter_fl_lc(idx,
sensor_info->def_shutter_lc,
sensor_info->def_fl_lc);
fs_set_stream(idx, 1);
/* set/init callback data */
fs_init_cb_data(idx, sensor_info->p_ctx, sensor_info->func_ptr);
/* check if set sync before streaming on */
ret = fs_check_set_sync_sidx_table(sensor_info->sensor_idx);
if (ret > 0) {
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), apply set sync procedure, due to set_sync_sidx_table[%u]:%d\n",
idx,
sensor_info->sensor_id,
sensor_info->sensor_idx,
sensor_info->sensor_idx,
ret);
fs_set_sync_idx(idx, ret);
}
} else {
fs_reset_ft_mode_data(idx, flag);
/* reset/clear set sync sidx table value */
fs_update_set_sync_sidx_table(sensor_info->sensor_idx, 0);
fs_reset_preset_perframe_data(sensor_info->sensor_idx);
}
LOG_INF(
"[%u] ID:%#x(sidx:%u), flag:%u(ON:1/OFF:0) [streaming_bits:%d]\n",
idx,
info.sensor_id,
info.sensor_idx,
flag,
FS_READ_BITS(&fs_mgr.streaming_bits));
return 0;
}
static void fs_notify_sensor_ctrl_setup_complete(unsigned int idx)
{
unsigned int hw_sync_group_id = FS_HW_SYNC_GROUP_ID_MIN;
if (FS_CHECK_BIT(idx, &fs_mgr.validSync_bits) == 0) {
/* no start frame sync, return */
return;
}
/* set setup complete */
FS_WRITE_BIT(idx, 1, &fs_mgr.setup_complete_bits);
/* checking for hw sync method */
if (FS_CHECK_BIT(idx, &fs_mgr.hw_sync_bits)) {
hw_sync_group_id = fs_mgr.hw_sync_group_id[idx];
if (hw_sync_group_id < FS_HW_SYNC_GROUP_ID_MAX) {
/* hw group id is a valid value */
FS_WRITE_BIT(idx, 1,
&fs_mgr.setup_complete_hw_group_bits[
hw_sync_group_id]);
}
}
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"[%u] ID:%#x(sidx:%u), hw_sync(bits:%d, group_id:%u) [setup_complete(%d, hw_group(%d/%d/%d/%d/%d/%d))]\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
FS_READ_BITS(&fs_mgr.hw_sync_bits),
fs_mgr.hw_sync_group_id[idx],
FS_READ_BITS(&fs_mgr.setup_complete_bits),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_0]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_1]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_2]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_3]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_4]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_5]));
#endif
#ifdef SUPPORT_FS_NEW_METHOD
/* setup compeleted => tirgger FS standalone method */
if (FS_ATOMIC_READ(&fs_mgr.using_sa_ver)
&& !FS_CHECK_BIT(idx, &fs_mgr.hw_sync_bits))
fs_try_trigger_frame_sync_sa(idx);
#endif // SUPPORT_FS_NEW_METHOD
}
/*
* update fs_perframe_st data
* (for v4l2_ctrl_request_setup order)
* (set_framelength is called after set_anti_flicker)
*/
void fs_update_auto_flicker_mode(unsigned int ident, unsigned int en)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, en:%u, return\n",
idx, REG_INFO, ident, en);
return;
}
/* update the fs_perframe_st data in fs algo */
fs_alg_set_anti_flicker(idx, en);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"[%u] ID:%#x(sidx:%u), updated flicker_en:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
en
);
#endif // REDUCE_FS_DRV_LOG
}
/*
* update fs_perframe_st data
* (for v4l2_ctrl_request_setup order)
* (set_max_framerate_by_scenario is called after set_shutter)
*/
void fs_update_min_framelength_lc(unsigned int ident, unsigned int min_fl_lc)
{
unsigned int idx = 0;
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF(
"NOTICE: [%u] %s is not register, ident:%u, min_fl_lc:%u, return\n",
idx, REG_INFO, ident, min_fl_lc);
return;
}
/* update the fs_perframe_st data in fs algo */
fs_alg_update_min_fl_lc(idx, min_fl_lc);
hw_fs_alg_update_min_fl_lc(idx, min_fl_lc);
#if !defined(REDUCE_FS_DRV_LOG)
LOG_INF(
"[%u] ID:%#x(sidx:%u), updated min_fl_lc:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
min_fl_lc);
#endif // REDUCE_FS_DRV_LOG
#ifndef USING_V4L2_CTRL_REQUEST_SETUP
/* if this is the last ctrl needed by FrameSync, notify setup complete */
fs_notify_sensor_ctrl_setup_complete(idx);
#endif // USING_V4L2_CTRL_REQUEST_SETUP
}
/*
* Run Frame Sync Method (for pair ctrl trigger)
*
* ex:
* 1. hardware sensor frame sync
* => call hw fs algo API to solve framelength
*
* 2. software frame sync
* => call fs algo API to solve framelength
*/
static inline unsigned int fs_run_frame_sync_proc(
unsigned int solveIdxs[], unsigned int framelength[], unsigned int len)
{
unsigned int ret = 0;
if (handle_by_hw_sensor_sync(solveIdxs, len))
ret = hw_fs_alg_solve_frame_length(solveIdxs, framelength, len);
else
ret = fs_alg_solve_frame_length(solveIdxs, framelength, len);
return ret;
}
unsigned int fs_try_trigger_frame_sync(void)
{
unsigned int i = 0, ret = 0;
unsigned int fs_act = 0;
unsigned int len = 0; /* how many sensors wait for doing frame sync */
unsigned int solveIdxs[SENSOR_MAX_NUM] = {0};
unsigned int fl_lc[SENSOR_MAX_NUM] = {0};
/* if validSync_bits == pf_ctrl_bits => "DO" FrameSync */
fs_act = (
FS_READ_BITS(&fs_mgr.validSync_bits) ==
FS_READ_BITS(&fs_mgr.pf_ctrl_bits))
? 1 : 0;
/* add for checking all ctrl needed by FrameSync have been setup */
if (fs_act == 1) {
fs_act = (
FS_READ_BITS(&fs_mgr.pf_ctrl_bits) ==
FS_READ_BITS(&fs_mgr.setup_complete_bits))
? 1 : 0;
if (fs_act == 0) {
LOG_MUST(
"WARNING: sensor ctrl has not been setup yet, validSync:%2d, pf_ctrl:%2d, setup_complete:%2d\n",
FS_READ_BITS(&fs_mgr.validSync_bits),
FS_READ_BITS(&fs_mgr.pf_ctrl_bits),
FS_READ_BITS(&fs_mgr.setup_complete_bits));
}
}
if (fs_act == 1) {
// LOG_INF("fs_activate:%u, validSync:%2d, pf_ctrl:%2d, cnt:%u\n",
LOG_INF("fs_activate:%u, validSync:%2d, pf_ctrl:%2d\n",
fs_act,
FS_READ_BITS(&fs_mgr.validSync_bits),
FS_READ_BITS(&fs_mgr.pf_ctrl_bits));
// ++fs_mgr.act_cnt);
/* 1 pick up validSync sensor information correctlly */
for (i = 0; i < SENSOR_MAX_NUM; ++i) {
if (FS_CHECK_BIT(i, &fs_mgr.validSync_bits) == 1) {
/* pick up sensor registered location */
solveIdxs[len++] = i;
}
}
/* 2 run frame sync proc to solve frame length */
/* if no error */
/* update framelength to frame recorder and then */
/* use callback function to set framelength to sensor */
ret = fs_run_frame_sync_proc(solveIdxs, fl_lc, len);
if (ret == 0) { // 0 => No error
for (i = 0; i < len; ++i) {
unsigned int idx = solveIdxs[i];
/* set framelength */
/* all framelength operation must use this API */
fs_set_framelength_lc(idx, fl_lc[idx]);
}
}
} else {
LOG_MUST(
"wait for other pf_ctrl setup, validSync:%2d, pf_ctrl:%2d, setup_complete:%2d\n",
FS_READ_BITS(&fs_mgr.validSync_bits),
FS_READ_BITS(&fs_mgr.pf_ctrl_bits),
FS_READ_BITS(&fs_mgr.setup_complete_bits));
}
return fs_act;
}
/*
* For trigger HW sync Frame-Sync solution
*
* return:
* pf ctrl that be triggered successfully by Frame-Sync
*/
int fs_try_trigger_hw_frame_sync(void)
{
int pf_ctrl_bits = 0, trigger_ctrl_bits = 0;
int setup_complete_hw_group_bits = 0;
unsigned int i = 0, j = 0, ret = 1;
unsigned int len = 0; /* how many sensors wait for doing frame sync */
unsigned int solveIdxs[SENSOR_MAX_NUM] = {0};
unsigned int fl_lc[SENSOR_MAX_NUM] = {0};
/* trigger Frame-Sync proc by group (find out 1 group) */
for (i = FS_HW_SYNC_GROUP_ID_MIN; i < FS_HW_SYNC_GROUP_ID_MAX; ++i) {
if (FS_READ_BITS(&fs_mgr.hw_sync_group_bits[i]) == 0)
continue;
do {
ret = 1;
/* reset/clear tmp data for current run */
len = 0;
for (j = 0; j < SENSOR_MAX_NUM; ++j) {
solveIdxs[j] = 0;
fl_lc[j] = 0;
}
setup_complete_hw_group_bits =
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[i]);
pf_ctrl_bits =
FS_READ_BITS(&fs_mgr.pf_ctrl_bits) &
FS_READ_BITS(&fs_mgr.validSync_bits);
/* do NOT expect */
if (pf_ctrl_bits == 0) {
LOG_MUST(
"WARNING: try trigger, but validSync:%d, pf_ctrl:%d, setup_complete:%d(%d/%d/%d/%d/%d/%d), abort\n",
FS_READ_BITS(&fs_mgr.validSync_bits),
FS_READ_BITS(&fs_mgr.pf_ctrl_bits),
FS_READ_BITS(
&fs_mgr.setup_complete_bits),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_0]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_1]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_2]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_3]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_4]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_5]));
ret = 1;
break;
}
/* check group match for triggering pf ctrl */
trigger_ctrl_bits =
(pf_ctrl_bits
& FS_READ_BITS(&fs_mgr.hw_sync_group_bits[i]));
if (trigger_ctrl_bits ==
(FS_READ_BITS(&fs_mgr.hw_sync_group_bits[i])
& FS_READ_BITS(&fs_mgr.validSync_bits))) {
LOG_PF_INF(
"Trigger group id:%u, cnt:%u, valid_sync:%d, trigger_ctrl:%u/%u, pf_ctrl:%d, setup_complete:%d(%d/%d/%d/%d/%d/%d)\n",
i,
fs_mgr.act_cnt[i] + 1,
FS_READ_BITS(&fs_mgr.validSync_bits),
trigger_ctrl_bits,
setup_complete_hw_group_bits,
FS_READ_BITS(&fs_mgr.pf_ctrl_bits),
FS_READ_BITS(
&fs_mgr.setup_complete_bits),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_0]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_1]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_2]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_3]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_4]),
FS_READ_BITS(
&fs_mgr.setup_complete_hw_group_bits[
FS_HW_SYNC_GROUP_ID_5]));
/* pick up sensor information */
for (j = 0; j < SENSOR_MAX_NUM; ++j) {
if ((FS_CHECK_BIT(j,
&fs_mgr.hw_sync_group_bits[i])
& FS_CHECK_BIT(j,
&fs_mgr.validSync_bits))
== 1) {
/* pick up sensor registered location */
solveIdxs[len++] = j;
}
}
/* run frame sync proc (hw) to solve frame length */
ret = hw_fs_alg_solve_frame_length(
solveIdxs, fl_lc, len);
}
#ifdef FS_UT
} while (
!atomic_compare_exchange_weak(
&fs_mgr.setup_complete_hw_group_bits[i],
&setup_complete_hw_group_bits, 0));
#else
} while (
atomic_cmpxchg(
&fs_mgr.setup_complete_hw_group_bits[i],
setup_complete_hw_group_bits, 0)
!= setup_complete_hw_group_bits);
#endif // FS_UT
/* if this group proc. has some error occurred, */
/* move on to next group for preventing */
/* each time entering this function jump out at this group */
if (ret == 0) { // 0 => no error
/* increase frame-sync act cnt */
fs_mgr.act_cnt[i]++;
break;
}
}
/* clear pf ctrl & setup complete bits */
/* that those ctrls are been triggered */
/* and update framelength to frame recorder and then */
/* use callback function to set framelength to sensor */
if (ret == 0) { // 0 => No error
FS_ATOMIC_FETCH_AND(
(~(trigger_ctrl_bits)), &fs_mgr.pf_ctrl_bits);
FS_ATOMIC_FETCH_AND(
(~(trigger_ctrl_bits)), &fs_mgr.setup_complete_bits);
for (j = 0; j < len; ++j) {
unsigned int idx = solveIdxs[j];
/* set framelength */
fs_set_framelength_lc(idx, fl_lc[j]);
}
}
return (ret == 0) ? trigger_ctrl_bits : 0;
}
static void fs_check_frame_sync_ctrl(
unsigned int idx, struct fs_perframe_st (*pf_ctrl))
{
/* before doing frame sync, check some situation */
unsigned int ret = 0;
/* 1. check this sensor is valid for sync or not */
ret = FS_CHECK_BIT(idx, &fs_mgr.validSync_bits);
if (ret == 0) {
#ifndef REDUCE_FS_DRV_LOG
LOG_PR_WARN(
"WARNING: Not valid for doing sync. [%u] ID:%#x\n",
idx,
pf_ctrl->sensor_id);
#endif // REDUCE_FS_DRV_LOG
return;
}
/* 2. check this perframe ctrl is valid or not */
ret = FS_CHECK_BIT(idx, &fs_mgr.pf_ctrl_bits);
if (ret == 1) {
LOG_PR_WARN(
"WARNING: Set same sensor, return. [%u] ID:%#x [pf_ctrl_bits:%d]\n",
idx,
pf_ctrl->sensor_id,
FS_READ_BITS(&fs_mgr.pf_ctrl_bits));
return;
} else {
FS_WRITE_BIT(idx, 1, &fs_mgr.pf_ctrl_bits);
fs_set_cb_cmd_id(idx, pf_ctrl->cmd_id);
#ifdef FS_SENSOR_CCU_IT
/* for frame-sync single cam IT */
fs_single_cam_IT(idx, pf_ctrl->lineTimeInNs);
#endif // FS_SENSOR_CCU_IT
}
/* trigger framesync at ::fs_sync_frame(0) */
/* 3. check for running frame sync processing or not */
// fs_try_trigger_frame_sync();
}
/*
* description:
* call by sensor driver,
* fs_perframe_st is a settings for a certain sensor.
*
* input:
* pf_ctrl: struct fs_perframe_st*
*/
void fs_set_shutter(struct fs_perframe_st (*pf_ctrl))
{
unsigned int idx = 0;
unsigned int ident = 0;
ident = fs_get_reg_sensor_ident(pf_ctrl->sensor_id, pf_ctrl->sensor_idx);
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF("NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
if (FS_CHECK_BIT(idx, &fs_mgr.validSync_bits) == 0) {
/* not start frame sync, return */
return;
}
/* check streaming status, due to maybe calling by non-sync flow */
if (FS_CHECK_BIT(idx, &fs_mgr.streaming_bits) == 0) {
LOG_INF("NOTICE: [%u] ID:%#x(sidx:%u) is NOT stream ON, return\n",
idx,
pf_ctrl->sensor_id,
pf_ctrl->sensor_idx);
return;
}
if (fs_chk_seamless_switch_status(idx)) {
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), (%d/%u), in seamless frame, seamless(%#x, sof_cnt:%u), skip/return\n",
idx,
pf_ctrl->sensor_id,
pf_ctrl->sensor_idx,
pf_ctrl->req_id,
fs_mgr.sof_cnt_arr[idx],
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt);
return;
}
fs_mgr.pf_ctrl[idx] = *pf_ctrl;
#if !defined(FORCE_USING_SA_MODE)
#if defined(SUPPORT_AUTO_EN_SA_MODE) && !defined(FS_UT)
/* check needed SA */
if (pf_ctrl->hdr_exp.mode_exp_cnt > 0)
fs_mgr.hdr_ft_mode[idx] |= FS_HDR_FT_MODE_STG_HDR;
else
fs_mgr.hdr_ft_mode[idx] &= ~FS_HDR_FT_MODE_STG_HDR;
fs_decision_maker(idx);
#endif
#endif // FORCE_USING_SA_MODE
/* for FPS non 1-1 frame-sync case */
fs_try_set_auto_frame_tag(idx);
/* 1. set perframe ctrl data to fs algo */
fs_alg_set_perframe_st_data(idx, pf_ctrl);
hw_fs_alg_set_perframe_st_data(idx, pf_ctrl);
#ifdef FS_UT
pf_ctrl->out_fl_lc = fs_alg_write_shutter(idx);
#endif // FS_UT
#if !defined(QUERY_CCU_TS_AT_SOF)
/* 3. push frame settings into frame recorder */
frec_push_record(idx, pf_ctrl->shutter_lc, pf_ctrl->out_fl_lc);
#else
/* 3. update frame recorder data */
frec_update_shutter_fl_lc(idx,
pf_ctrl->shutter_lc, pf_ctrl->out_fl_lc);
#endif // QUERY_CCU_TS_AT_SOF
/* 4. frame sync ctrl */
fs_check_frame_sync_ctrl(idx, pf_ctrl);
#ifdef USING_V4L2_CTRL_REQUEST_SETUP
/* if this is the last ctrl needed by FrameSync, notify setup complete */
fs_notify_sensor_ctrl_setup_complete(idx);
#endif // USING_V4L2_CTRL_REQUEST_SETUP
}
void fs_update_shutter(struct fs_perframe_st (*pf_ctrl))
{
unsigned int idx = 0;
unsigned int ident = 0;
fs_set_preset_perframe_data(pf_ctrl->sensor_idx, pf_ctrl);
ident = fs_get_reg_sensor_ident(pf_ctrl->sensor_id, pf_ctrl->sensor_idx);
idx = fs_get_reg_sensor_pos(ident);
if (check_idx_valid(idx) == 0) {
LOG_INF("NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
if (FS_CHECK_BIT(idx, &fs_mgr.validSync_bits) == 0) {
/* not start frame sync, return */
return;
}
/* check streaming status, due to maybe calling by non-sync flow */
if (FS_CHECK_BIT(idx, &fs_mgr.streaming_bits) == 0) {
LOG_INF("NOTICE: [%u] ID:%#x(sidx:%u) is NOT stream ON, return\n",
idx,
pf_ctrl->sensor_id,
pf_ctrl->sensor_idx);
return;
}
if (fs_chk_seamless_switch_status(idx)) {
LOG_MUST(
"NOTICE: [%u] ID:%#x(sidx:%u), (%d/%u), in seamless frame, seamless(%#x, sof_cnt:%u), skip/return\n",
idx,
pf_ctrl->sensor_id,
pf_ctrl->sensor_idx,
pf_ctrl->req_id,
fs_mgr.sof_cnt_arr[idx],
FS_ATOMIC_READ(&fs_mgr.seamless_bits),
fs_mgr.seamless_ctrl[idx].seamless_sof_cnt);
return;
}
// fs_mgr.pf_ctrl[idx] = *pf_ctrl;
/* ONLY update frame length value (we care this value) */
/* Not modify other data that getting from set shutter API */
/* (HW sync flow will pass in data that almost 0, except FL) */
fs_mgr.pf_ctrl[idx].out_fl_lc = pf_ctrl->out_fl_lc;
/* update frame recorder data */
frec_update_shutter_fl_lc(idx, 0, pf_ctrl->out_fl_lc);
}
void fs_get_fl_record_info(const unsigned int ident,
unsigned int *p_target_min_fl_us, unsigned int *p_out_fl_us)
{
const unsigned int idx = fs_get_reg_sensor_pos(ident);
/* error handling (unexpected case) */
if (check_idx_valid(idx) == 0) {
LOG_MUST(
"NOTICE: [%u] %s is not register, ident:%u, return\n",
idx, REG_INFO, ident);
return;
}
fs_alg_get_fl_rec_st_info(idx, p_target_min_fl_us, p_out_fl_us);
}
#if !defined(FS_UT)
static void fs_debug_hw_sync(unsigned int idx)
{
unsigned int arr[1] = {idx};
fs_alg_setup_frame_monitor_fmeas_data(idx);
frec_notify_vsync(idx);
fs_alg_get_vsync_data(arr, 1);
// fs_alg_sa_notify_vsync(idx);
hw_fs_dump_dynamic_para(idx);
}
#endif // !FS_UT
void fs_set_debug_info_sof_cnt(const unsigned int ident,
const unsigned int sof_cnt)
{
unsigned int idx = fs_get_reg_sensor_pos(ident);
/* error handling (unexpected case) */
if (unlikely(check_idx_valid(idx) == 0)) {
LOG_MUST(
"NOTICE: [%u] %s is not register, return\n",
idx, REG_INFO);
return;
}
/* update debug info */
fs_mgr.sof_cnt_arr[idx] = sof_cnt;
fs_alg_set_debug_info_sof_cnt(idx, sof_cnt);
}
void fs_notify_vsync(const unsigned int ident, const unsigned int sof_cnt)
{
#if !defined(FS_UT)
unsigned int listen_vsync_usr = fs_con_get_usr_listen_ext_vsync();
unsigned int listen_vsync_alg = fs_con_get_listen_vsync_alg_cfg();
unsigned int idx = fs_get_reg_sensor_pos(ident);
if (unlikely(check_idx_valid(idx) == 0)) {
/* not register/streaming on */
return;
}
if (FS_CHECK_BIT(idx, &fs_mgr.validSync_bits) == 0) {
/* no start frame sync, return */
return;
}
if (FS_CHECK_BIT(idx, &fs_mgr.hw_sync_bits)) {
/* using hw sensor sync, not doing sw sync flow */
fs_debug_hw_sync(idx);
return;
}
/* check listen to ext vysnc or not */
if (!(listen_vsync_usr || listen_vsync_alg))
return;
#if !defined(QUERY_CCU_TS_AT_SOF)
fs_set_shutter(&fs_mgr.pf_ctrl[idx]);
#else
fs_alg_sa_notify_setup_all_frame_info(idx);
frec_notify_vsync(idx);
fs_alg_sa_notify_vsync(idx);
#endif // QUERY_CCU_TS_AT_SOF
/* update debug info --- sof cnt */
fs_set_debug_info_sof_cnt(ident, sof_cnt);
/* check special ctrl (e.g., seamless switch) */
fs_chk_valid_for_doing_seamless_switch(ident);
fs_chk_exit_seamless_switch_frame(ident);
#endif // !FS_UT
}
/*
* return:
* 0 for error,
* non 0 for (Start -> cnt of validSync_bits;
* End -> cnt of pf_ctrl_bits)
*
* input:
* flag: "non 0" -> Start sync frame; "0" -> End sync frame;
*
* header file:
* frame_sync_camsys.h
*
* descriptions:
* By default, SW Frame-Sync Algo is using SA algo,
* so this function now is only for HW Frame-Sync Algo using.
*/
unsigned int fs_sync_frame(unsigned int flag)
{
#if defined(FS_UT)
unsigned int pf_log_tracer = 1;
#endif
enum FS_STATUS status = get_fs_status();
int valid_sync = FS_ATOMIC_READ(&fs_mgr.validSync_bits);
#if !defined(FS_UT)
/* user cmd force disable frame-sync set_sync */
if (fs_con_chk_force_to_ignore_set_sync())
return 0;
#endif // FS_UT
#ifdef SUPPORT_FS_NEW_METHOD
if (FS_READ_BITS(&fs_mgr.hw_sync_bits) == 0
&& (FS_ATOMIC_READ(&fs_mgr.using_sa_ver) != 0
|| fs_user_sa_config())) {
/* Only using SW soltuion and using SA algo for Frame-Sync */
return 0;
}
#endif // SUPPORT_FS_NEW_METHOD
/* check sync frame start/end */
/* flag > 0 : cam-sys call - start sync frame */
/* flag = 0 : cam-sys call - end sync frame */
if (flag > 0) {
/* check status is ready for starting sync frame or not */
if (status < FS_WAIT_FOR_SYNCFRAME_START) {
fs_dump_status(-1, flag, __func__, "Start:1 Notice");
return 0;
}
if (unlikely(pf_log_tracer))
fs_dump_status(-1, flag, __func__, "Start:1");
/* return the number of valid sync sensors */
return FS_POPCOUNT(valid_sync);
} else {
/* fs_sync_frame(0) flow */
fs_mgr.last_pf_ctrl_bits =
FS_READ_BITS(&fs_mgr.pf_ctrl_bits);
fs_mgr.last_setup_complete_bits =
FS_READ_BITS(&fs_mgr.setup_complete_bits);
/* try to trigger frame sync processing */
fs_mgr.trigger_ctrl_bits =
// fs_try_trigger_frame_sync();
fs_try_trigger_hw_frame_sync();
if (likely(fs_mgr.trigger_ctrl_bits)) {
/* framesync trigger DONE */
if (pf_log_tracer)
fs_dump_status(-1, flag, __func__, "Start:0 DONE");
} else {
/* framesync trigger FAIL */
fs_dump_status(-1, flag, __func__, "Start:0 WARNING: FAIL");
}
/* return the number of perframe ctrl sensors */
return FS_POPCOUNT(fs_mgr.trigger_ctrl_bits);
}
}
#if !defined(FS_UT)
EXPORT_SYMBOL(fs_sync_frame);
#endif // FS_UT
/******************************************************************************/
#ifdef FS_SENSOR_CCU_IT
/******************************************************************************/
// Frame Sync IT (FS_Drv + FRM + Adaptor + Sensor Driver + CCU) function
/******************************************************************************/
static void fs_single_cam_IT(unsigned int idx, unsigned int line_time_ns)
{
unsigned int idxs[TG_MAX_NUM] = {0};
unsigned int fl_lc = 0;
/* 1. query timestamp from CCU */
idxs[0] = idx;
/* get Vsync data by calling fs_algo func to call Frame Monitor */
if (fs_alg_get_vsync_data(idxs, 1))
LOG_INF("[FS IT] ERROR: Get Vsync data ERROR\n");
/* 2. set FL regularly for testing */
fl_lc = fl_table[fl_table_idxs[idx]];
fl_lc = convert2LineCount(line_time_ns, fl_lc);
/* log print info */
LOG_INF("[FS IT] [%u] ID:%#x(sidx:%u) set FL:%u(%u), lineTimeInNs:%u\n",
idx,
fs_get_reg_sensor_id(idx),
fs_get_reg_sensor_idx(idx),
fl_table[fl_table_idxs[idx]],
fl_lc,
line_time_ns);
fl_table_idxs[idx] = (fl_table_idxs[idx] + 1) % FL_TABLE_SIZE;
/* all framelength operation must use this API */
fs_set_framelength_lc(idx, fl_lc);
/* 3. clear pf_ctrl_bits data of this idx */
fs_set_status_bits(idx, 0, &fs_mgr.pf_ctrl_bits);
}
#endif // FS_SENSOR_CCU_IT
/******************************************************************************/
/******************************************************************************/
// Frame Sync entry function
/******************************************************************************/
// export some Frame Sync member function.
static struct FrameSync frameSync = {
fs_streaming,
fs_set_sync,
fs_sa_set_user_async_master,
fs_sync_frame,
fs_set_shutter,
fs_update_shutter,
fs_update_tg,
fs_update_target_tg,
fs_update_auto_flicker_mode,
fs_update_min_framelength_lc,
fs_set_extend_framelength,
fs_chk_exit_seamless_switch_frame,
fs_chk_valid_for_doing_seamless_switch,
fs_seamless_switch,
fs_set_using_sa_mode,
fs_set_frame_tag,
fs_n_1_en,
fs_mstream_en,
fs_set_debug_info_sof_cnt,
fs_notify_vsync,
fs_is_set_sync,
fs_is_hw_sync,
fs_get_fl_record_info
};
/*
* Frame Sync init function.
*
* init FrameSync object.
* get FrameSync function for operation.
*
* return: (0 / 1) => (no error / error)
*/
#if !defined(FS_UT)
unsigned int FrameSyncInit(struct FrameSync **pframeSync, struct device *dev)
#else // FS_UT
unsigned int FrameSyncInit(struct FrameSync (**pframeSync))
#endif // FS_UT
{
int ret = 0;
/* check NULL pointer */
if (pframeSync == NULL) {
LOG_MUST(
"ERROR: pframeSync is NULL, return");
ret = 1;
return ret;
}
fs_init();
*pframeSync = &frameSync;
#if !defined(FS_UT)
ret = fs_con_create_sysfs_file(dev);
#endif // FS_UT
return ret;
}
#if !defined(FS_UT)
void FrameSyncUnInit(struct device *dev)
{
fs_con_remove_sysfs_file(dev);
}
#endif // FS_UT
/******************************************************************************/