summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c136
2 files changed, 105 insertions, 35 deletions
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
index 21fab0590b55..34cac9daea89 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, 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
@@ -98,6 +98,8 @@ struct msm_isp_buffer {
struct timeval *tv;
/* Indicates whether buffer is used as ping ot pong buffer */
uint32_t pingpong_bit;
+ /* Indicates buffer is reconfig due to drop frame */
+ uint32_t is_drop_reconfig;
/*Native buffer*/
struct list_head list;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 7bb36d9d4855..15f8061b9919 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -719,13 +719,7 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
sof_info->stream_get_buf_fail_mask = 0;
axi_data = &vfe_dev->axi_data;
- /* report that registers are not updated and return empty buffer for
- * controllable outputs
- */
- if (!vfe_dev->reg_updated) {
- sof_info->regs_not_updated =
- vfe_dev->reg_update_requested;
- }
+
for (i = 0; i < RDI_INTF_0; i++) {
stream_info = msm_isp_get_stream_common_data(vfe_dev,
i);
@@ -747,6 +741,12 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
if (stream_info->controllable_output &&
!vfe_dev->reg_updated) {
if (stream_info->undelivered_request_cnt) {
+ /*report that registers are not updated
+ * and return empty buffer for controllable
+ * outputs
+ */
+ sof_info->regs_not_updated =
+ !vfe_dev->reg_updated;
pr_err("Drop frame no reg update\n");
if (msm_isp_drop_frame(vfe_dev, stream_info, ts,
sof_info)) {
@@ -1648,23 +1648,30 @@ static void msm_isp_reload_ping_pong_offset(
}
static int msm_isp_update_deliver_count(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit)
+ struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_bit,
+ struct msm_isp_buffer *done_buf)
{
int rc = 0;
if (!stream_info->controllable_output)
goto done;
- if (!stream_info->undelivered_request_cnt) {
+ if (!stream_info->undelivered_request_cnt ||
+ (done_buf == NULL)) {
pr_err_ratelimited("%s:%d error undelivered_request_cnt 0\n",
__func__, __LINE__);
rc = -EINVAL;
goto done;
} else {
+ if ((done_buf->is_drop_reconfig == 1) &&
+ (stream_info->sw_ping_pong_bit == -1)) {
+ goto done;
+ }
/*After wm reload, we get bufdone for ping buffer*/
if (stream_info->sw_ping_pong_bit == -1)
stream_info->sw_ping_pong_bit = 0;
- stream_info->undelivered_request_cnt--;
+ if (done_buf->is_drop_reconfig != 1)
+ stream_info->undelivered_request_cnt--;
if (pingpong_bit != stream_info->sw_ping_pong_bit) {
pr_err("%s:%d ping pong bit actual %d sw %d\n",
__func__, __LINE__, pingpong_bit,
@@ -1910,7 +1917,8 @@ int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
}
static int msm_isp_cfg_ping_pong_address(
- struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status)
+ struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+ struct msm_isp_buffer *buf)
{
int i;
int j;
@@ -1919,7 +1927,6 @@ static int msm_isp_cfg_ping_pong_address(
uint32_t buffer_size_byte = 0;
int32_t word_per_line = 0;
dma_addr_t paddr;
- struct msm_isp_buffer *buf = NULL;
/* Isolate pingpong_bit from pingpong_status */
@@ -1930,10 +1937,11 @@ static int msm_isp_cfg_ping_pong_address(
if (stream_info->buf[!pingpong_bit]) {
pr_err("stream %x buffer already set for pingpong %d\n",
stream_info->stream_src, !pingpong_bit);
- return 0;
+ return 1;
}
- buf = msm_isp_get_stream_buffer(vfe_dev, stream_info);
+ if (buf == NULL)
+ buf = msm_isp_get_stream_buffer(vfe_dev, stream_info);
if (!buf) {
msm_isp_cfg_stream_scratch(stream_info, pingpong_status);
@@ -2167,6 +2175,7 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev,
struct msm_isp_bufq *bufq = NULL;
uint32_t pingpong_bit;
int vfe_idx;
+ int rc = -1;
if (!vfe_dev || !stream_info || !ts || !sof_info) {
pr_err("%s %d vfe_dev %pK stream_info %pK ts %pK op_info %pK\n",
@@ -2183,17 +2192,42 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev,
pingpong_bit =
(~(pingpong_status >> stream_info->wm[vfe_idx][0]) & 0x1);
done_buf = stream_info->buf[pingpong_bit];
- if (done_buf) {
- bufq = vfe_dev->buf_mgr->ops->get_bufq(vfe_dev->buf_mgr,
- done_buf->bufq_handle);
- if (!bufq) {
- spin_unlock_irqrestore(&stream_info->lock, flags);
- pr_err("%s: Invalid bufq buf_handle %x\n",
- __func__, done_buf->bufq_handle);
- return -EINVAL;
+ if (done_buf &&
+ (stream_info->composite_irq[MSM_ISP_COMP_IRQ_EPOCH] == 0)) {
+ if ((stream_info->sw_ping_pong_bit != -1) &&
+ !vfe_dev->reg_updated) {
+ rc = msm_isp_cfg_ping_pong_address(
+ stream_info, ~pingpong_status, done_buf);
+ if (rc < 0) {
+ ISP_DBG("%s: Error configuring ping_pong\n",
+ __func__);
+ bufq = vfe_dev->buf_mgr->ops->get_bufq(
+ vfe_dev->buf_mgr,
+ done_buf->bufq_handle);
+ if (!bufq) {
+ spin_unlock_irqrestore(
+ &stream_info->lock,
+ flags);
+ pr_err("%s: Invalid bufq buf_handle %x\n",
+ __func__,
+ done_buf->bufq_handle);
+ return -EINVAL;
+ }
+ sof_info->reg_update_fail_mask_ext |=
+ (bufq->bufq_handle & 0xFF);
+ }
+ }
+ /*Avoid Drop Frame and re-issue pingpong cfg*/
+ /*this notify is per ping and pong buffer*/
+ done_buf->is_drop_reconfig = 1;
+ stream_info->current_framedrop_period = 1;
+ /*Avoid Multiple request frames for single SOF*/
+ vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false;
+
+ if (stream_info->current_framedrop_period !=
+ stream_info->requested_framedrop_period) {
+ msm_isp_cfg_framedrop_reg(stream_info);
}
- sof_info->reg_update_fail_mask_ext |=
- (bufq->bufq_handle & 0xFF);
}
spin_unlock_irqrestore(&stream_info->lock, flags);
@@ -2203,6 +2237,8 @@ int msm_isp_drop_frame(struct vfe_device *vfe_dev,
/* no buf done come */
msm_isp_process_axi_irq_stream(vfe_dev, stream_info,
pingpong_status, ts);
+ if (done_buf)
+ done_buf->is_drop_reconfig = 0;
}
return 0;
}
@@ -2507,7 +2543,7 @@ static int msm_isp_init_stream_ping_pong_reg(
/* Set address for both PING & PO NG register */
rc = msm_isp_cfg_ping_pong_address(
- stream_info, VFE_PING_FLAG);
+ stream_info, VFE_PING_FLAG, NULL);
/* No buffer available on start is not error */
if (rc == -ENOMEM && stream_info->stream_type != BURST_STREAM)
return 0;
@@ -2519,7 +2555,7 @@ static int msm_isp_init_stream_ping_pong_reg(
if (stream_info->stream_type != BURST_STREAM ||
stream_info->runtime_num_burst_capture > 1) {
rc = msm_isp_cfg_ping_pong_address(
- stream_info, VFE_PONG_FLAG);
+ stream_info, VFE_PONG_FLAG, NULL);
/* No buffer available on start is not error */
if (rc == -ENOMEM)
return 0;
@@ -3518,7 +3554,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
if (stream_info->undelivered_request_cnt == 1) {
rc = msm_isp_cfg_ping_pong_address(stream_info,
- VFE_PING_FLAG);
+ VFE_PING_FLAG, NULL);
if (rc) {
spin_unlock_irqrestore(&stream_info->lock, flags);
stream_info->undelivered_request_cnt--;
@@ -3551,10 +3587,10 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
* now.
*/
rc = msm_isp_cfg_ping_pong_address(stream_info,
- VFE_PONG_FLAG);
+ VFE_PONG_FLAG, NULL);
} else {
rc = msm_isp_cfg_ping_pong_address(
- stream_info, pingpong_status);
+ stream_info, pingpong_status, NULL);
}
if (rc) {
stream_info->undelivered_request_cnt--;
@@ -3576,6 +3612,9 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
if (0 == rc)
msm_isp_reset_framedrop(vfe_dev, stream_info);
+ /*Avoid Multiple request frames for single SOF*/
+ vfe_dev->axi_data.src_info[frame_src].accept_frame = false;
+
spin_unlock_irqrestore(&stream_info->lock, flags);
return rc;
@@ -4059,6 +4098,10 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
done_buf = stream_info->buf[pingpong_bit];
if (vfe_dev->buf_mgr->frameId_mismatch_recovery == 1) {
+ if (done_buf) {
+ if (done_buf->is_drop_reconfig == 1)
+ done_buf->is_drop_reconfig = 0;
+ }
pr_err_ratelimited("%s: Mismatch Recovery in progress, drop frame!\n",
__func__);
spin_unlock_irqrestore(&stream_info->lock, flags);
@@ -4078,14 +4121,26 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
stream_info->frame_id++;
stream_info->buf[pingpong_bit] = NULL;
+ if (stream_info->controllable_output &&
+ (done_buf != NULL) &&
+ (stream_info->sw_ping_pong_bit == -1) &&
+ (done_buf->is_drop_reconfig == 1)) {
+ /*When wm reloaded and corresponding reg_update fail
+ * then buffer is reconfig as PING buffer. so, avoid
+ * NULL assignment to PING buffer and eventually
+ * next AXI_DONE or buf_done can be successful
+ */
+ stream_info->buf[pingpong_bit] = done_buf;
+ }
+
if (stream_info->stream_type == CONTINUOUS_STREAM ||
stream_info->runtime_num_burst_capture > 1) {
rc = msm_isp_cfg_ping_pong_address(
- stream_info, pingpong_status);
+ stream_info, pingpong_status, NULL);
if (rc < 0)
ISP_DBG("%s: Error configuring ping_pong\n",
__func__);
- } else if (done_buf) {
+ } else if (done_buf && (done_buf->is_drop_reconfig != 1)) {
msm_isp_cfg_stream_scratch(stream_info, pingpong_status);
}
@@ -4109,8 +4164,10 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
}
rc = msm_isp_update_deliver_count(vfe_dev, stream_info,
- pingpong_bit);
+ pingpong_bit, done_buf);
if (rc) {
+ if (done_buf->is_drop_reconfig == 1)
+ done_buf->is_drop_reconfig = 0;
spin_unlock_irqrestore(&stream_info->lock, flags);
pr_err_ratelimited("%s:VFE%d get done buf fail\n",
__func__, vfe_dev->pdev->id);
@@ -4119,17 +4176,28 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev,
return;
}
- spin_unlock_irqrestore(&stream_info->lock, flags);
if ((done_buf->frame_id != frame_id) &&
vfe_dev->axi_data.enable_frameid_recovery) {
+ if (done_buf->is_drop_reconfig == 1)
+ done_buf->is_drop_reconfig = 0;
+ spin_unlock_irqrestore(&stream_info->lock, flags);
msm_isp_handle_done_buf_frame_id_mismatch(vfe_dev,
stream_info, done_buf, time_stamp, frame_id);
return;
}
- msm_isp_process_done_buf(vfe_dev, stream_info,
+ if (done_buf->is_drop_reconfig == 1) {
+ /*When ping/pong buf is already reconfigured
+ * then dont issue buf-done for current buffer
+ */
+ done_buf->is_drop_reconfig = 0;
+ spin_unlock_irqrestore(&stream_info->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&stream_info->lock, flags);
+ msm_isp_process_done_buf(vfe_dev, stream_info,
done_buf, time_stamp, frame_id);
+ }
}
void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,