msm: isp: Make HALT independent from disable_camif

AXI should be halted whenever all HW streams are stopping. This will
improve KPI even for RDI streams. Currently halt is determined using
Disable_Camif which is only valid for PIX streams. Decouple the two to
improve KPI on RDI and avoid wait.
Also, cleanup after timeout in start_axi. Remove handling of SD_SHUTDOWN
to avoid multiple release.

Change-Id: I09db8adb766d2e7889443f779a716aaa2f6c09d1
Signed-off-by: Harsh Shah <harshs@codeaurora.org>
This commit is contained in:
Harsh Shah 2015-09-24 18:32:44 -07:00 committed by David Keitel
parent e29112a1f7
commit a2b1739e1e
3 changed files with 84 additions and 48 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -80,7 +80,7 @@ int msm_isp_axi_create_stream(struct vfe_device *vfe_dev,
stream_cfg_cmd->axi_stream_handle =
(++axi_data->stream_handle_cnt) << 8 | i;
ISP_DBG(" vfe %d handle %x\n", vfe_dev->pdev->id,
ISP_DBG("%s: vfe %d handle %x\n", __func__, vfe_dev->pdev->id,
stream_cfg_cmd->axi_stream_handle);
memset(&axi_data->stream_info[i], 0,
@ -720,8 +720,8 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
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 %d Slave time %d Master time %d delta %d\n",
__func__, vfe_dev->pdev->id,
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);
@ -740,6 +740,10 @@ void msm_isp_increment_frame_id(struct vfe_device *vfe_dev,
vfe_dev->axi_data.src_info[frame_src].frame_id +=
vfe_dev->axi_data.src_info[frame_src].
sof_counter_step;
ISP_DBG("%s: vfe %d sof_step %d\n", __func__,
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 &&
@ -1895,9 +1899,11 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev,
return 0;
}
static enum msm_isp_camif_update_state
msm_isp_get_camif_update_state(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd)
static void msm_isp_get_camif_update_state_and_halt(
struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd,
enum msm_isp_camif_update_state *camif_update,
int *halt)
{
int i;
struct msm_vfe_axi_stream *stream_info;
@ -1915,22 +1921,30 @@ static enum msm_isp_camif_update_state
}
if ((pix_stream_cnt) &&
(axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) {
(axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) {
if (cur_pix_stream_cnt == 0 && pix_stream_cnt &&
stream_cfg_cmd->cmd == START_STREAM)
return ENABLE_CAMIF;
*camif_update = ENABLE_CAMIF;
else if (cur_pix_stream_cnt &&
(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
stream_cfg_cmd->cmd == STOP_STREAM)
return DISABLE_CAMIF;
*camif_update = DISABLE_CAMIF;
else if (cur_pix_stream_cnt &&
(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
stream_cfg_cmd->cmd == STOP_IMMEDIATELY)
return DISABLE_CAMIF_IMMEDIATELY;
}
*camif_update = DISABLE_CAMIF_IMMEDIATELY;
else
*camif_update = NO_UPDATE;
} else
*camif_update = NO_UPDATE;
if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams
&& (stream_cfg_cmd->cmd == STOP_STREAM ||
stream_cfg_cmd->cmd == STOP_IMMEDIATELY))
*halt = 1;
else
*halt = 0;
return NO_UPDATE;
}
static void msm_isp_update_camif_output_count(
@ -2472,6 +2486,8 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
return -EINVAL;
if (camif_update == ENABLE_CAMIF) {
ISP_DBG("%s: vfe %d camif enable\n", __func__,
vfe_dev->pdev->id);
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id = 0;
}
@ -2505,8 +2521,12 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
spin_unlock_irqrestore(&stream_info->lock, flags);
stream_info->state = START_PENDING;
ISP_DBG("%s, Stream 0x%x src_state %d on vfe %d\n", __func__,
stream_info->stream_id, src_state, vfe_dev->pdev->id);
ISP_DBG("%s, Stream 0x%x src %d src_state %d on vfe %d\n",
__func__, stream_info->stream_id,
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i]),
src_state, vfe_dev->pdev->id);
if (src_state) {
src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src));
wait_for_complete = 1;
@ -2560,8 +2580,20 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
if (wait_for_complete) {
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update,
src_mask, 2);
if (rc < 0)
if (rc < 0) {
pr_err("%s: wait for config done failed\n", __func__);
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(
stream_cfg_cmd->stream_handle[i])];
stream_info->state = STOPPING;
msm_isp_axi_stream_enable_cfg(
vfe_dev, stream_info, 0);
stream_cfg_cmd->cmd = STOP_IMMEDIATELY;
msm_isp_update_camif_output_count(vfe_dev,
stream_cfg_cmd);
}
}
}
return rc;
@ -2569,7 +2601,8 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd,
enum msm_isp_camif_update_state camif_update)
enum msm_isp_camif_update_state camif_update,
int halt)
{
int i, rc = 0;
uint8_t wait_for_complete_for_this_stream = 0;
@ -2625,12 +2658,11 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
wait_for_complete_for_this_stream = 1;
} else {
if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) &&
(!ext_read))
!halt && (!ext_read))
wait_for_complete_for_this_stream = 1;
}
ISP_DBG("%s: vfe_dev %d camif_update %d wait %d\n", __func__,
vfe_dev->pdev->id,
camif_update,
ISP_DBG("%s: vfe_dev %d camif_update %d halt %d wait %d\n",
__func__, vfe_dev->pdev->id, camif_update, halt,
wait_for_complete_for_this_stream);
intf = SRC_TO_INTF(stream_info->stream_src);
if (!wait_for_complete_for_this_stream ||
@ -2674,12 +2706,14 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
SRC_TO_INTF(stream_info->stream_src));
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev,
camif_update, src_mask, 1);
if (rc < 0)
if (rc < 0) {
pr_err("%s: vfe%d cfg done failed\n",
__func__, vfe_dev->pdev->id);
else
stream_info->state = INACTIVE;
} else
pr_err("%s: vfe%d retry success! report err!\n",
__func__, vfe_dev->pdev->id);
rc = -EBUSY;
}
}
@ -2702,20 +2736,26 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
vfe_dev->axi_data.camif_state = CAMIF_DISABLE;
} else if ((camif_update == DISABLE_CAMIF_IMMEDIATELY) ||
(ext_read)) {
/*during stop immediately, stop output then stop input*/
vfe_dev->hw_info->vfe_ops.irq_ops.enable_camif_err(vfe_dev, 0);
vfe_dev->ignore_error = 1;
vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
if (!ext_read)
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev,
DISABLE_CAMIF_IMMEDIATELY);
vfe_dev->axi_data.camif_state = CAMIF_STOPPED;
vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1);
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
vfe_dev->hw_info->vfe_ops.irq_ops.enable_camif_err(vfe_dev, 1);
vfe_dev->ignore_error = 0;
}
if (halt) {
/*during stop immediately, stop output then stop input*/
vfe_dev->ignore_error = 1;
vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 1);
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
vfe_dev->ignore_error = 0;
}
msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
msm_isp_update_stream_bandwidth(vfe_dev);
@ -2751,6 +2791,7 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
struct msm_vfe_axi_stream_cfg_cmd *stream_cfg_cmd = arg;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
enum msm_isp_camif_update_state camif_update;
int halt = 0;
rc = msm_isp_axi_check_stream_state(vfe_dev, stream_cfg_cmd);
if (rc < 0) {
@ -2765,7 +2806,8 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
atomic_set(&vfe_dev->error_info.overflow_state,
NO_OVERFLOW);
}
camif_update = msm_isp_get_camif_update_state(vfe_dev, stream_cfg_cmd);
msm_isp_get_camif_update_state_and_halt(vfe_dev, stream_cfg_cmd,
&camif_update, &halt);
if (camif_update == DISABLE_CAMIF)
vfe_dev->axi_data.camif_state = CAMIF_STOPPING;
if (stream_cfg_cmd->cmd == START_STREAM) {
@ -2775,7 +2817,7 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
vfe_dev, stream_cfg_cmd, camif_update);
} else {
rc = msm_isp_stop_axi_stream(
vfe_dev, stream_cfg_cmd, camif_update);
vfe_dev, stream_cfg_cmd, camif_update, halt);
msm_isp_axi_update_cgc_override(vfe_dev, stream_cfg_cmd, 0);
if (axi_data->num_active_stream == 0) {
@ -2795,7 +2837,8 @@ int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg)
}
if (rc < 0)
pr_err("%s: start/stop stream failed\n", __func__);
pr_err("%s: start/stop %d stream failed\n", __func__,
stream_cfg_cmd->cmd);
return rc;
}

View file

@ -739,6 +739,8 @@ static int msm_isp_set_dual_HW_master_slave_mode(
vfe_dev->common_data->ms_resource.dual_hw_type = DUAL_HW_MASTER_SLAVE;
vfe_dev->vfe_ub_policy = MSM_WM_UB_EQUAL_SLICING;
if (dual_hw_ms_cmd->primary_intf < VFE_SRC_MAX) {
ISP_DBG("%s: vfe %d primary_intf %d\n", __func__,
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_ms_info.dual_hw_ms_type =
@ -749,7 +751,7 @@ static int msm_isp_set_dual_HW_master_slave_mode(
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: Master\n", __func__);
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;
@ -760,7 +762,7 @@ static int msm_isp_set_dual_HW_master_slave_mode(
&vfe_dev->common_data->common_dev_data_lock,
flags);
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;
ISP_DBG("%s: Slave\n", __func__);
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.
@ -787,7 +789,8 @@ static int msm_isp_set_dual_HW_master_slave_mode(
return -EBUSY;
}
}
ISP_DBG("%s: num_src %d\n", __func__, dual_hw_ms_cmd->num_src);
ISP_DBG("%s: vfe %d num_src %d\n", __func__, vfe_dev->pdev->id,
dual_hw_ms_cmd->num_src);
/* This for loop is for non-primary intf to be marked with Master/Slave
* in order for frame id sync. But their timestamp is not saved.
* So no sof_info resource is allocated */
@ -797,7 +800,9 @@ static int msm_isp_set_dual_HW_master_slave_mode(
dual_hw_ms_cmd->input_src[i]);
return -EINVAL;
}
ISP_DBG("%s: src %d\n", __func__, dual_hw_ms_cmd->input_src[i]);
ISP_DBG("%s: vfe %d src %d type %d\n", __func__,
vfe_dev->pdev->id, dual_hw_ms_cmd->input_src[i],
dual_hw_ms_cmd->dual_hw_ms_type);
src_info = &vfe_dev->axi_data.
src_info[dual_hw_ms_cmd->input_src[i]];
src_info->dual_hw_type = DUAL_HW_MASTER_SLAVE;

View file

@ -1490,20 +1490,8 @@ static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd,
ispif->ispif_rdi2_debug = 0;
return 0;
}
case MSM_SD_SHUTDOWN: {
struct ispif_device *ispif =
(struct ispif_device *)v4l2_get_subdevdata(sd);
if (ispif && ispif->base) {
while (ispif->open_cnt != 0)
ispif_close_node(sd, NULL);
} else {
pr_debug("%s:SD SHUTDOWN fail, ispif%s %p\n", __func__,
ispif ? "_base" : "",
ispif ? ispif->base : NULL);
}
case MSM_SD_SHUTDOWN:
return 0;
}
default:
pr_err_ratelimited("%s: invalid cmd 0x%x received\n",
__func__, cmd);