msm: camera: isp: Dual camera sync feature

Add ioctl to swicth dual camera mode from sync to
unsync mode and vise versa. Also, change the logic
of frame id sync to support unsync mode.

CRs-Fixed: 1070296
Change-Id: I58e27c9ea66f1788d640bf523e7c6569cde162f7
Signed-off-by: Shubhraprakash Das <sadas@codeaurora.org>
Signed-off-by: Junzhe Zou <jnzhezou@codeaurora.org>
This commit is contained in:
Shubhraprakash Das 2016-12-01 23:52:31 -08:00
parent c30b1bc021
commit 2527a06cae
4 changed files with 269 additions and 324 deletions

View file

@ -95,11 +95,9 @@ struct msm_vfe_sof_info {
struct msm_vfe_dual_hw_ms_info {
/* type is Master/Slave */
enum msm_vfe_dual_hw_ms_type dual_hw_ms_type;
/* sof_info is resource from common_data. If NULL, then this INTF
* sof does not need to be saved */
struct msm_vfe_sof_info *sof_info;
/* slave_id is index in common_data sof_info array for slaves */
uint8_t slave_id;
enum msm_vfe_dual_cam_sync_mode sync_state;
struct msm_vfe_sof_info sof_info;
int index;
};
struct vfe_subscribe_info {
@ -680,13 +678,14 @@ struct dual_vfe_resource {
struct master_slave_resource_info {
enum msm_vfe_dual_hw_type dual_hw_type;
struct msm_vfe_sof_info master_sof_info;
uint8_t master_active;
uint32_t sof_delta_threshold; /* Updated by Master */
uint32_t num_slave;
uint32_t reserved_slave_mask;
uint32_t slave_active_mask;
struct msm_vfe_sof_info slave_sof_info[MS_NUM_SLAVE_MAX];
uint32_t active_src_mask;
uint32_t src_sof_mask;
int master_index;
int primary_slv_idx;
struct msm_vfe_src_info *src_info[MAX_VFE * VFE_SRC_MAX];
uint32_t num_src;
enum msm_vfe_dual_cam_sync_mode dual_sync_mode;
};
struct msm_vfe_common_dev_data {

View file

@ -19,10 +19,6 @@
#define HANDLE_TO_IDX(handle) (handle & 0xFF)
#define ISP_SOF_DEBUG_COUNT 0
static int msm_isp_update_dual_HW_ms_info_at_start(
struct vfe_device *vfe_dev,
enum msm_vfe_input_src stream_src);
static void msm_isp_reload_ping_pong_offset(
struct msm_vfe_axi_stream *stream_info);
@ -761,6 +757,71 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
}
}
static void msm_isp_sync_dual_cam_frame_id(
struct vfe_device *vfe_dev,
struct master_slave_resource_info *ms_res,
enum msm_vfe_input_src frame_src,
struct msm_isp_timestamp *ts)
{
struct msm_vfe_src_info *src_info =
&vfe_dev->axi_data.src_info[frame_src];
int i;
uint32_t frame_id = src_info->frame_id;
uint32_t master_time = 0, current_time;
if (src_info->dual_hw_ms_info.sync_state ==
ms_res->dual_sync_mode) {
(frame_src == VFE_PIX_0) ? src_info->frame_id +=
vfe_dev->axi_data.src_info[frame_src].
sof_counter_step :
src_info->frame_id++;
return;
}
WARN_ON(ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC);
/* find highest frame id */
for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
if (ms_res->src_info[i] == NULL)
continue;
if (src_info == ms_res->src_info[i] ||
ms_res->src_info[i]->active == 0)
continue;
if (frame_id >= ms_res->src_info[i]->frame_id)
continue;
frame_id = ms_res->src_info[i]->frame_id;
master_time = ms_res->src_info[i]->
dual_hw_ms_info.sof_info.mono_timestamp_ms;
}
/* copy highest frame id to the intf based on sof delta */
current_time = ts->buf_time.tv_sec * 1000 +
ts->buf_time.tv_usec / 1000;
if (current_time > master_time &&
(current_time - master_time) > ms_res->sof_delta_threshold) {
if (frame_src == VFE_PIX_0)
frame_id += vfe_dev->axi_data.src_info[frame_src].
sof_counter_step;
else
frame_id += 1;
} else {
for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
if (ms_res->src_info[i] == NULL)
continue;
if (src_info == ms_res->src_info[i] ||
((1 << ms_res->src_info[i]->
dual_hw_ms_info.index) &
ms_res->active_src_mask) == 0)
continue;
if (ms_res->src_info[i]->frame_id == frame_id)
ms_res->src_sof_mask |= (1 <<
ms_res->src_info[i]->dual_hw_ms_info.index);
}
}
ms_res->active_src_mask |= (1 << src_info->dual_hw_ms_info.index);
src_info->frame_id = frame_id;
src_info->dual_hw_ms_info.sync_state = MSM_ISP_DUAL_CAM_SYNC;
}
void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src, struct msm_isp_timestamp *ts)
{
@ -768,13 +829,9 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
struct msm_vfe_sof_info *sof_info = NULL;
enum msm_vfe_dual_hw_type dual_hw_type;
enum msm_vfe_dual_hw_ms_type ms_type;
struct msm_vfe_sof_info *master_sof_info = NULL;
int32_t time, master_time, delta;
uint32_t sof_incr = 0;
unsigned long flags;
if (vfe_dev->axi_data.src_info[frame_src].frame_id == 0)
msm_isp_update_dual_HW_ms_info_at_start(vfe_dev, frame_src);
struct master_slave_resource_info *ms_res =
&vfe_dev->common_data->ms_resource;
spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags);
dual_hw_type =
@ -782,43 +839,41 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
ms_type =
vfe_dev->axi_data.src_info[frame_src].
dual_hw_ms_info.dual_hw_ms_type;
/*
* Increment frame_id if
* 1. Not Master Slave
* 2. Master
* 3. Slave and Master is Inactive
*
* OR
* (in other words)
* If SLAVE and Master active, don't increment slave frame_id.
* Instead use Master frame_id for Slave.
*/
if ((dual_hw_type == DUAL_HW_MASTER_SLAVE) &&
(ms_type == MS_TYPE_SLAVE) &&
(vfe_dev->common_data->ms_resource.master_active == 1)) {
/* DUAL_HW_MS_SLAVE && MASTER active */
time = ts->buf_time.tv_sec * 1000 +
src_info = &vfe_dev->axi_data.src_info[frame_src];
if (dual_hw_type == DUAL_HW_MASTER_SLAVE) {
msm_isp_sync_dual_cam_frame_id(vfe_dev, ms_res, frame_src, ts);
if (src_info->dual_hw_ms_info.sync_state ==
MSM_ISP_DUAL_CAM_SYNC) {
/*
* for dual hw check that we recv sof from all
* linked intf
*/
if (ms_res->src_sof_mask & (1 <<
src_info->dual_hw_ms_info.index)) {
pr_err("Frame out of sync on vfe %d\n",
vfe_dev->pdev->id);
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_BUF_FATAL_ERROR);
}
ms_res->src_sof_mask |= (1 <<
src_info->dual_hw_ms_info.index);
if (ms_res->active_src_mask == ms_res->src_sof_mask)
ms_res->src_sof_mask = 0;
}
sof_info = &vfe_dev->axi_data.src_info[frame_src].
dual_hw_ms_info.sof_info;
sof_info->frame_id = vfe_dev->axi_data.src_info[frame_src].
frame_id;
sof_info->timestamp_ms = ts->event_time.tv_sec * 1000 +
ts->event_time.tv_usec / 1000;
sof_info->mono_timestamp_ms = ts->buf_time.tv_sec * 1000 +
ts->buf_time.tv_usec / 1000;
master_sof_info = &vfe_dev->common_data->ms_resource.
master_sof_info;
master_time = master_sof_info->mono_timestamp_ms;
delta = vfe_dev->common_data->ms_resource.sof_delta_threshold;
ISP_DBG("%s: vfe %d frame_src %d frame %d Slave time %d Master time %d delta %d\n",
__func__, vfe_dev->pdev->id, frame_src,
vfe_dev->axi_data.src_info[frame_src].frame_id,
time, master_time, time - master_time);
if (time - master_time > delta)
sof_incr = 1;
/*
* If delta < 5ms, slave frame_id = master frame_id
* If delta > 5ms, slave frame_id = master frame_id + 1
* CANNOT support Batch Mode with this logic currently.
*/
vfe_dev->axi_data.src_info[frame_src].frame_id =
master_sof_info->frame_id + sof_incr;
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
} else {
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
if (frame_src == VFE_PIX_0) {
vfe_dev->axi_data.src_info[frame_src].frame_id +=
vfe_dev->axi_data.src_info[frame_src].
@ -827,40 +882,27 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
vfe_dev->pdev->id,
vfe_dev->axi_data.src_info[frame_src].
sof_counter_step);
src_info = &vfe_dev->axi_data.src_info[frame_src];
if (!src_info->frame_id &&
!src_info->reg_update_frame_id &&
((src_info->frame_id -
src_info->reg_update_frame_id) >
(MAX_REG_UPDATE_THRESHOLD *
src_info->sof_counter_step))) {
pr_err("%s:%d reg_update not received for %d frames\n",
__func__, __LINE__,
src_info->frame_id -
src_info->reg_update_frame_id);
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_REG_UPDATE_MISSING);
}
} else
} else {
vfe_dev->axi_data.src_info[frame_src].frame_id++;
}
}
sof_info = vfe_dev->axi_data.src_info[frame_src].
dual_hw_ms_info.sof_info;
if (dual_hw_type == DUAL_HW_MASTER_SLAVE &&
sof_info != NULL) {
sof_info->frame_id = vfe_dev->axi_data.src_info[frame_src].
frame_id;
sof_info->timestamp_ms = ts->event_time.tv_sec * 1000 +
ts->event_time.tv_usec / 1000;
sof_info->mono_timestamp_ms = ts->buf_time.tv_sec * 1000 +
ts->buf_time.tv_usec / 1000;
if (frame_src == VFE_PIX_0) {
if (!src_info->frame_id &&
!src_info->reg_update_frame_id &&
((src_info->frame_id -
src_info->reg_update_frame_id) >
(MAX_REG_UPDATE_THRESHOLD *
src_info->sof_counter_step))) {
pr_err("%s:%d reg_update not received for %d frames\n",
__func__, __LINE__,
src_info->frame_id -
src_info->reg_update_frame_id);
msm_isp_halt_send_error(vfe_dev,
ISP_EVENT_REG_UPDATE_MISSING);
}
}
spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock,
flags);
}
void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
@ -869,7 +911,6 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
struct msm_isp_event_data event_data;
struct msm_vfe_sof_info *sof_info = NULL, *self_sof = NULL;
enum msm_vfe_dual_hw_ms_type ms_type;
int i, j;
unsigned long flags;
memset(&event_data, 0, sizeof(event_data));
@ -907,51 +948,43 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type,
* If need to support framedrop as well, move delta calculation
* to userspace
*/
if (vfe_dev->axi_data.src_info[frame_src].dual_hw_type ==
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
if (vfe_dev->common_data->ms_resource.dual_sync_mode ==
MSM_ISP_DUAL_CAM_SYNC &&
vfe_dev->axi_data.src_info[frame_src].dual_hw_type ==
DUAL_HW_MASTER_SLAVE) {
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
self_sof = vfe_dev->axi_data.src_info[frame_src].
struct master_slave_resource_info *ms_res =
&vfe_dev->common_data->ms_resource;
self_sof = &vfe_dev->axi_data.src_info[frame_src].
dual_hw_ms_info.sof_info;
if (!self_sof) {
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
break;
}
ms_type = vfe_dev->axi_data.src_info[frame_src].
dual_hw_ms_info.dual_hw_ms_type;
if (ms_type == MS_TYPE_MASTER) {
for (i = 0, j = 0; i < MS_NUM_SLAVE_MAX; i++) {
if (!(vfe_dev->common_data->
ms_resource.slave_active_mask
& (1 << i)))
continue;
sof_info = &vfe_dev->common_data->
ms_resource.slave_sof_info[i];
event_data.u.sof_info.ms_delta_info.
delta[j] =
self_sof->mono_timestamp_ms -
sof_info->mono_timestamp_ms;
j++;
if (j == vfe_dev->common_data->
ms_resource.num_slave)
break;
}
/* only send back time delta for primatry intf */
if (ms_res->primary_slv_idx > 0 &&
ms_type == MS_TYPE_MASTER)
sof_info = &ms_res->src_info[
ms_res->primary_slv_idx]->
dual_hw_ms_info.sof_info;
if (ms_type != MS_TYPE_MASTER &&
ms_res->master_index > 0)
sof_info = &ms_res->src_info[
ms_res->master_index]->
dual_hw_ms_info.sof_info;
if (sof_info) {
event_data.u.sof_info.ms_delta_info.
num_delta_info = j;
} else {
sof_info = &vfe_dev->common_data->ms_resource.
master_sof_info;
event_data.u.sof_info.ms_delta_info.
num_delta_info = 1;
event_data.u.sof_info.ms_delta_info.delta[0] =
delta[0] =
self_sof->mono_timestamp_ms -
sof_info->mono_timestamp_ms;
event_data.u.sof_info.ms_delta_info.
num_delta_info = 1;
}
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
} else {
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
if (frame_src <= VFE_RAW_2) {
msm_isp_check_for_output_error(vfe_dev, ts,
&event_data.u.sof_info);
@ -2089,6 +2122,7 @@ static void msm_isp_input_disable(struct vfe_device *vfe_dev)
int stream_count;
int total_stream_count = 0;
int i;
struct msm_vfe_src_info *src_info;
for (i = 0; i < VFE_SRC_MAX; i++)
total_stream_count += axi_data->src_info[i].stream_count +
@ -2103,6 +2137,37 @@ static void msm_isp_input_disable(struct vfe_device *vfe_dev)
continue;
/* deactivate the input line */
axi_data->src_info[i].active = 0;
src_info = &axi_data->src_info[i];
if (src_info->dual_hw_type == DUAL_HW_MASTER_SLAVE) {
struct master_slave_resource_info *ms_res =
&vfe_dev->common_data->ms_resource;
unsigned long flags;
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
if (src_info->dual_hw_ms_info.index ==
ms_res->master_index)
ms_res->master_index = -1;
if (src_info->dual_hw_ms_info.index ==
ms_res->primary_slv_idx)
ms_res->primary_slv_idx = -1;
ms_res->active_src_mask &= ~(1 <<
src_info->dual_hw_ms_info.index);
ms_res->src_sof_mask &= ~(1 <<
src_info->dual_hw_ms_info.index);
ms_res->src_info[src_info->dual_hw_ms_info.index] =
NULL;
ms_res->num_src--;
src_info->dual_hw_ms_info.sync_state =
MSM_ISP_DUAL_CAM_ASYNC;
src_info->dual_hw_type = DUAL_NONE;
src_info->dual_hw_ms_info.index = -1;
spin_unlock_irqrestore(
&vfe_dev->common_data->common_dev_data_lock,
flags);
}
if (i != VFE_PIX_0 || ext_read)
continue;
@ -2520,152 +2585,6 @@ static int msm_isp_axi_update_cgc_override(struct vfe_device *vfe_dev_ioctl,
return 0;
}
static int msm_isp_update_dual_HW_ms_info_at_start(
struct vfe_device *vfe_dev,
enum msm_vfe_input_src stream_src)
{
int rc = 0;
uint32_t j, k, max_sof = 0;
uint8_t slave_id;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
struct msm_vfe_src_info *src_info = NULL;
uint32_t vfe_id = 0;
unsigned long flags;
if (stream_src >= VFE_SRC_MAX) {
pr_err("%s: Error! Invalid src %u\n", __func__, stream_src);
return -EINVAL;
}
src_info = &axi_data->src_info[stream_src];
if (src_info->dual_hw_type != DUAL_HW_MASTER_SLAVE)
return rc;
spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags);
if (src_info->dual_hw_ms_info.dual_hw_ms_type ==
MS_TYPE_MASTER) {
if (vfe_dev->common_data->ms_resource.master_active == 1) {
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
return rc;
}
vfe_dev->common_data->ms_resource.master_active = 1;
/*
* If any slaves are active, then find the max slave
* frame_id and set it to Master, so master will start
* higher and then the slave can copy master frame_id
* without repeating.
*/
if (!vfe_dev->common_data->ms_resource.slave_active_mask) {
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
return rc;
}
for (j = 0, k = 0; k < MS_NUM_SLAVE_MAX; k++) {
if (!(vfe_dev->common_data->ms_resource.
reserved_slave_mask & (1 << k)))
continue;
if (vfe_dev->common_data->ms_resource.slave_active_mask
& (1 << k) &&
(vfe_dev->common_data->ms_resource.
slave_sof_info[k].frame_id > max_sof)) {
max_sof = vfe_dev->common_data->ms_resource.
slave_sof_info[k].frame_id;
}
j++;
if (j == vfe_dev->common_data->ms_resource.num_slave)
break;
}
vfe_dev->axi_data.src_info[stream_src].frame_id =
max_sof + 1;
if (vfe_dev->is_split) {
vfe_id = vfe_dev->pdev->id;
vfe_id = (vfe_id == 0) ? 1 : 0;
vfe_dev->common_data->dual_vfe_res->axi_data[vfe_id]->
src_info[stream_src].frame_id = max_sof + 1;
}
ISP_DBG("%s: Setting Master frame_id to %u\n", __func__,
max_sof + 1);
} else {
if (src_info->dual_hw_ms_info.sof_info != NULL) {
slave_id = src_info->dual_hw_ms_info.slave_id;
vfe_dev->common_data->ms_resource.slave_active_mask |=
(1 << slave_id);
}
}
spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock,
flags);
return rc;
}
static int msm_isp_update_dual_HW_ms_info_at_stop(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
{
int i, rc = 0;
uint8_t slave_id;
struct msm_vfe_axi_stream *stream_info = NULL;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
enum msm_vfe_input_src stream_src = VFE_SRC_MAX;
struct msm_vfe_src_info *src_info = NULL;
unsigned long flags;
if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM ||
stream_cfg_cmd->num_streams == 0)
return -EINVAL;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
if (HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]) >=
VFE_AXI_SRC_MAX) {
return -EINVAL;
}
stream_info = msm_isp_get_stream_common_data(vfe_dev,
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]));
stream_src = SRC_TO_INTF(stream_info->stream_src);
/* Remove PIX if DISABLE CAMIF */
if (stream_src == VFE_PIX_0 &&
axi_data->src_info[VFE_PIX_0].active)
continue;
src_info = &axi_data->src_info[stream_src];
if (src_info->dual_hw_type != DUAL_HW_MASTER_SLAVE)
continue;
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
if (src_info->dual_hw_ms_info.dual_hw_ms_type ==
MS_TYPE_MASTER) {
/*
* Once Master is inactive, slave will increment
* its own frame_id
*/
vfe_dev->common_data->ms_resource.master_active = 0;
} else {
slave_id = src_info->dual_hw_ms_info.slave_id;
vfe_dev->common_data->ms_resource.reserved_slave_mask &=
~(1 << slave_id);
vfe_dev->common_data->ms_resource.slave_active_mask &=
~(1 << slave_id);
vfe_dev->common_data->ms_resource.num_slave--;
}
src_info->dual_hw_ms_info.sof_info = NULL;
spin_unlock_irqrestore(
&vfe_dev->common_data->common_dev_data_lock,
flags);
vfe_dev->vfe_ub_policy = 0;
}
return rc;
}
/**
* msm_isp_axi_wait_for_stream_cfg_done() - Wait for a stream completion
* @stream_info: The stream to wait on
@ -3126,7 +3045,7 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev_ioctl,
int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
int rc = 0, ret;
int rc = 0;
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
uint32_t stream_idx[MAX_NUM_STREAM];
int i;
@ -3175,11 +3094,6 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
* Use different ret value to not overwrite the error from
* msm_isp_stop_axi_stream
*/
ret = msm_isp_update_dual_HW_ms_info_at_stop(
vfe_dev, stream_cfg_cmd);
if (ret < 0)
pr_warn("%s: Warning! Update dual_cam failed\n",
__func__);
if (vfe_dev->axi_data.num_active_stream == 0)
vfe_dev->hvx_cmd = HVX_DISABLE;
if (vfe_dev->is_split) {

View file

@ -202,17 +202,17 @@ void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp,
struct vfe_device *vfe_dev)
{
struct timespec ts;
do_gettimeofday(&(time_stamp->event_time));
if (vfe_dev->vt_enable) {
msm_isp_get_avtimer_ts(time_stamp);
time_stamp->buf_time.tv_sec = time_stamp->vt_time.tv_sec;
time_stamp->buf_time.tv_usec = time_stamp->vt_time.tv_usec;
} else {
} else {
get_monotonic_boottime(&ts);
time_stamp->buf_time.tv_sec = ts.tv_sec;
time_stamp->buf_time.tv_usec = ts.tv_nsec/1000;
}
}
static inline u32 msm_isp_evt_mask_to_isp_event(u32 evt_mask)
@ -548,18 +548,53 @@ int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
return rc;
}
static int msm_isp_dual_hw_master_slave_sync(struct vfe_device *vfe_dev,
void *arg)
{
int rc = 0;
struct msm_isp_dual_hw_master_slave_sync *link = arg;
unsigned long flags;
struct master_slave_resource_info *ms_res =
&vfe_dev->common_data->ms_resource;
int i;
struct msm_vfe_src_info *src_info = NULL;
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
ms_res->dual_sync_mode = link->sync_mode;
if (ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC) {
for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
if (ms_res->src_info[i] == NULL)
continue;
src_info = ms_res->src_info[i];
if (src_info->dual_hw_ms_info.sync_state ==
MSM_ISP_DUAL_CAM_ASYNC)
continue;
ms_res->active_src_mask &= ~(1 <<
src_info->dual_hw_ms_info.index);
ms_res->src_sof_mask &= ~(1 <<
src_info->dual_hw_ms_info.index);
src_info->dual_hw_ms_info.sync_state =
MSM_ISP_DUAL_CAM_ASYNC;
}
}
spin_unlock_irqrestore(
&vfe_dev->common_data->common_dev_data_lock,
flags);
return rc;
}
static int msm_isp_set_dual_HW_master_slave_mode(
struct vfe_device *vfe_dev, void *arg)
{
/*
* This method assumes no 2 processes are accessing it simultaneously.
* Currently this is guaranteed by mutex lock in ioctl.
* If that changes, need to revisit this
*/
int rc = 0, i, j;
int rc = 0, i;
struct msm_isp_set_dual_hw_ms_cmd *dual_hw_ms_cmd = NULL;
struct msm_vfe_src_info *src_info = NULL;
unsigned long flags;
struct master_slave_resource_info *ms_res =
&vfe_dev->common_data->ms_resource;
if (!vfe_dev || !arg) {
pr_err("%s: Error! Invalid input vfe_dev %pK arg %pK\n",
@ -567,6 +602,7 @@ static int msm_isp_set_dual_HW_master_slave_mode(
return -EINVAL;
}
spin_lock_irqsave(&vfe_dev->common_data->common_dev_data_lock, flags);
dual_hw_ms_cmd = (struct msm_isp_set_dual_hw_ms_cmd *)arg;
vfe_dev->common_data->ms_resource.dual_hw_type = DUAL_HW_MASTER_SLAVE;
vfe_dev->vfe_ub_policy = MSM_WM_UB_EQUAL_SLICING;
@ -575,50 +611,20 @@ static int msm_isp_set_dual_HW_master_slave_mode(
vfe_dev->pdev->id, dual_hw_ms_cmd->primary_intf);
src_info = &vfe_dev->axi_data.
src_info[dual_hw_ms_cmd->primary_intf];
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
src_info->dual_hw_ms_info.dual_hw_ms_type =
dual_hw_ms_cmd->dual_hw_ms_type;
}
/* No lock needed here since ioctl lock protects 2 session from race */
if (src_info != NULL &&
dual_hw_ms_cmd->dual_hw_ms_type == MS_TYPE_MASTER) {
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
ISP_DBG("%s: vfe %d Master\n", __func__, vfe_dev->pdev->id);
src_info->dual_hw_ms_info.sof_info =
&vfe_dev->common_data->ms_resource.master_sof_info;
vfe_dev->common_data->ms_resource.sof_delta_threshold =
dual_hw_ms_cmd->sof_delta_threshold;
} else if (src_info != NULL) {
spin_lock_irqsave(
&vfe_dev->common_data->common_dev_data_lock,
flags);
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
ISP_DBG("%s: vfe %d Slave\n", __func__, vfe_dev->pdev->id);
for (j = 0; j < MS_NUM_SLAVE_MAX; j++) {
if (vfe_dev->common_data->ms_resource.
reserved_slave_mask & (1 << j))
continue;
vfe_dev->common_data->ms_resource.reserved_slave_mask |=
(1 << j);
vfe_dev->common_data->ms_resource.num_slave++;
src_info->dual_hw_ms_info.sof_info =
&vfe_dev->common_data->ms_resource.
slave_sof_info[j];
src_info->dual_hw_ms_info.slave_id = j;
ISP_DBG("%s: Slave id %d\n", __func__, j);
break;
}
spin_unlock_irqrestore(
&vfe_dev->common_data->common_dev_data_lock,
flags);
if (j == MS_NUM_SLAVE_MAX) {
pr_err("%s: Error! Cannot find free aux resource\n",
__func__);
return -EBUSY;
src_info->dual_hw_ms_info.index = dual_hw_ms_cmd->
primary_intf + VFE_SRC_MAX * vfe_dev->pdev->id;
ms_res->src_info[src_info->dual_hw_ms_info.index] = src_info;
ms_res->num_src++;
if (dual_hw_ms_cmd->dual_hw_ms_type == MS_TYPE_MASTER) {
ms_res->master_index = src_info->dual_hw_ms_info.index;
ms_res->sof_delta_threshold =
dual_hw_ms_cmd->sof_delta_threshold;
} else {
ms_res->primary_slv_idx =
src_info->dual_hw_ms_info.index;
}
}
ISP_DBG("%s: vfe %d num_src %d\n", __func__, vfe_dev->pdev->id,
@ -630,6 +636,8 @@ static int msm_isp_set_dual_HW_master_slave_mode(
if (dual_hw_ms_cmd->input_src[i] >= VFE_SRC_MAX) {
pr_err("%s: Error! Invalid SRC param %d\n", __func__,
dual_hw_ms_cmd->input_src[i]);
spin_unlock_irqrestore(&vfe_dev->common_data->
common_dev_data_lock, flags);
return -EINVAL;
}
ISP_DBG("%s: vfe %d src %d type %d\n", __func__,
@ -640,8 +648,13 @@ static int msm_isp_set_dual_HW_master_slave_mode(
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
src_info->dual_hw_ms_info.dual_hw_ms_type =
dual_hw_ms_cmd->dual_hw_ms_type;
src_info->dual_hw_ms_info.index = dual_hw_ms_cmd->
input_src[i] + VFE_SRC_MAX * vfe_dev->pdev->id;
ms_res->src_info[src_info->dual_hw_ms_info.index] = src_info;
ms_res->num_src++;
}
spin_unlock_irqrestore(&vfe_dev->common_data->common_dev_data_lock,
flags);
return rc;
}
@ -909,6 +922,11 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd,
rc = msm_isp_set_dual_HW_master_slave_mode(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC:
mutex_lock(&vfe_dev->core_mutex);
rc = msm_isp_dual_hw_master_slave_sync(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
case VIDIOC_MSM_ISP_FETCH_ENG_START:
case VIDIOC_MSM_ISP_MAP_BUF_START_FE:
mutex_lock(&vfe_dev->core_mutex);

View file

@ -819,6 +819,16 @@ struct msm_isp_ahb_clk_cfg {
uint32_t reserved[2];
};
enum msm_vfe_dual_cam_sync_mode {
MSM_ISP_DUAL_CAM_ASYNC,
MSM_ISP_DUAL_CAM_SYNC,
};
struct msm_isp_dual_hw_master_slave_sync {
uint32_t sync_mode;
uint32_t reserved[2];
};
#define V4L2_PIX_FMT_QBGGR8 v4l2_fourcc('Q', 'B', 'G', '8')
#define V4L2_PIX_FMT_QGBRG8 v4l2_fourcc('Q', 'G', 'B', '8')
#define V4L2_PIX_FMT_QGRBG8 v4l2_fourcc('Q', 'G', 'R', '8')
@ -981,6 +991,10 @@ enum msm_isp_ioctl_cmd_code {
#define VIDIOC_MSM_ISP_AHB_CLK_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE+25, struct msm_isp_ahb_clk_cfg)
#define VIDIOC_MSM_ISP_DUAL_HW_MASTER_SLAVE_SYNC \
_IOWR('V', BASE_VIDIOC_PRIVATE+26, \
struct msm_isp_dual_hw_master_slave_sync)
#define VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START \
_IOWR('V', MSM_ISP_FETCH_ENG_MULTI_PASS_START, \
struct msm_vfe_fetch_eng_multi_pass_start)