Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01163df2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm:camera: isp: Support for sw frame skip added"

parents a7c5abc7 67ee904f
Loading
Loading
Loading
Loading
+51 −8
Original line number Diff line number Diff line
@@ -238,7 +238,8 @@ static int msm_isp_buf_prepare(struct msm_isp_buf_mgr *buf_mgr,

	bufq = msm_isp_get_bufq(buf_mgr, buf_info->bufq_handle);
	if (!bufq) {
		pr_err("%s: Invalid bufq\n", __func__);
		pr_err("%s: Invalid bufq\n",
			__func__);
		return rc;
	}

@@ -610,9 +611,8 @@ static int msm_isp_put_buf_unsafe(struct msm_isp_buf_mgr *buf_mgr,
	return rc;
}

static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle, uint32_t buf_index,
	struct timeval *tv, uint32_t frame_id, uint32_t output_format)
static int msm_isp_update_put_buf_cnt(struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle, uint32_t buf_index)
{
	int rc = -1;
	unsigned long flags;
@@ -647,6 +647,41 @@ static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
				return rc;
			}
		}
		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
	}

	return 0;
}

static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
	uint32_t bufq_handle, uint32_t buf_index,
	struct timeval *tv, uint32_t frame_id, uint32_t output_format)
{
	int rc = -1;
	unsigned long flags;
	struct msm_isp_bufq *bufq = NULL;
	struct msm_isp_buffer *buf_info = NULL;
	enum msm_isp_buffer_state state;

	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
	if (!bufq) {
		pr_err("Invalid bufq\n");
		return rc;
	}

	buf_info = msm_isp_get_buf_ptr(buf_mgr, bufq_handle, buf_index);
	if (!buf_info) {
		pr_err("%s: buf not found\n", __func__);
		return rc;
	}

	spin_lock_irqsave(&bufq->bufq_lock, flags);
	state = buf_info->state;
	spin_unlock_irqrestore(&bufq->bufq_lock, flags);

	if (state == MSM_ISP_BUFFER_STATE_DEQUEUED ||
		state == MSM_ISP_BUFFER_STATE_DIVERTED) {
		spin_lock_irqsave(&bufq->bufq_lock, flags);
		buf_info->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
		spin_unlock_irqrestore(&bufq->bufq_lock, flags);
		if (MSM_ISP_BUFFER_SRC_HAL == BUF_SRC(bufq->stream_id)) {
@@ -656,6 +691,8 @@ static int msm_isp_buf_done(struct msm_isp_buf_mgr *buf_mgr,
			buf_mgr->vb2_ops->buf_done(buf_info->vb2_buf,
				bufq->session_id, bufq->stream_id);
		} else {
			pr_err("%s: Error wrong buf done %d\n", __func__,
				state);
			rc = msm_isp_put_buf(buf_mgr, buf_info->bufq_handle,
						buf_info->buf_idx);
			if (rc < 0) {
@@ -785,7 +822,8 @@ static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr,
		} else {
			bufq = msm_isp_get_bufq(buf_mgr, info->handle);
			if (!bufq) {
				pr_err("%s: Invalid bufq\n", __func__);
				pr_err("%s: Invalid bufq\n",
					__func__);
				return rc;
			}
			if (BUF_SRC(bufq->stream_id))
@@ -806,7 +844,8 @@ static int msm_isp_buf_enqueue(struct msm_isp_buf_mgr *buf_mgr,
			rc = msm_isp_put_buf(buf_mgr,
					info->handle, info->buf_idx);
			if (rc < 0) {
				pr_err("%s: Buf put failed\n", __func__);
				pr_err("%s: Buf put failed stream %x\n",
					__func__, bufq->stream_id);
				return rc;
			}
		}
@@ -836,7 +875,8 @@ static int msm_isp_get_buf_src(struct msm_isp_buf_mgr *buf_mgr,

	bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
	if (!bufq) {
		pr_err("%s: Invalid bufq\n", __func__);
		pr_err("%s: Invalid bufq\n",
			__func__);
		return -EINVAL;
	}
	*buf_src = BUF_SRC(bufq->stream_id);
@@ -865,7 +905,9 @@ static int msm_isp_request_bufq(struct msm_isp_buf_mgr *buf_mgr,

	bufq = msm_isp_get_bufq(buf_mgr, buf_request->handle);
	if (!bufq) {
		pr_err("Invalid buffer queue\n");
		pr_err("%s: Invalid bufq stream_id %x\n",
			__func__, buf_request->stream_id);

		return rc;
	}

@@ -1194,6 +1236,7 @@ static struct msm_isp_buf_ops isp_buf_ops = {
	.buf_mgr_deinit = msm_isp_deinit_isp_buf_mgr,
	.buf_mgr_debug = msm_isp_buf_mgr_debug,
	.get_bufq = msm_isp_get_bufq,
	.update_put_buf_cnt = msm_isp_update_put_buf_cnt,
};

int msm_isp_create_isp_buf_mgr(
+2 −0
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ struct msm_isp_buf_ops {
	int (*buf_mgr_debug) (struct msm_isp_buf_mgr *buf_mgr);
	struct msm_isp_bufq * (*get_bufq)(struct msm_isp_buf_mgr *buf_mgr,
		uint32_t bufq_handle);
	int (*update_put_buf_cnt)(struct msm_isp_buf_mgr *buf_mgr,
		uint32_t bufq_handle, uint32_t buf_index);
};

struct msm_isp_buf_mgr {
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, 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
@@ -350,6 +350,7 @@ struct msm_vfe_axi_stream {
	uint8_t  runtime_framedrop_update_burst;
	uint32_t runtime_output_format;
	enum msm_stream_memory_input_t  memory_input;
	struct msm_isp_sw_framskip sw_skip;
};

struct msm_vfe_axi_composite_info {
@@ -434,6 +435,7 @@ struct msm_vfe_stats_stream {
	uint32_t framedrop_period;
	uint32_t irq_subsample_pattern;
	uint32_t init_stats_frame_drop;
	struct msm_isp_sw_framskip sw_skip;

	uint32_t buffer_offset;
	struct msm_isp_buffer *buf[2];
+81 −5
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, 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
@@ -1044,27 +1044,48 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
	struct msm_isp_timestamp *ts)
{
	int rc;
	unsigned long flags;
	struct msm_isp_event_data buf_event;
	struct timeval *time_stamp;
	uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
	uint32_t frame_id;
	uint32_t buf_src;
	uint8_t drop_frame = 0;
	memset(&buf_event, 0, sizeof(buf_event));

	frame_id = vfe_dev->axi_data.
		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;

	if (SRC_TO_INTF(stream_info->stream_src) >= VFE_SRC_MAX) {
		pr_err("%s: Invalid stream index, put buf back to vb2 queue\n",
			__func__);
		vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
		rc = vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
			buf->bufq_handle, buf->buf_idx);
		return;
	}

	if (stream_info->stream_type != BURST_STREAM &&
		(stream_info->sw_skip.stream_src_mask &
		(1 << stream_info->stream_src))) {
		/* Hw stream output of this src is requested for drop */
		if (stream_info->sw_skip.skip_mode == SKIP_ALL) {
			/* drop all buffers */
			drop_frame = 1;
		} else if (stream_info->sw_skip.skip_mode == SKIP_RANGE &&
			(stream_info->sw_skip.min_frame_id <= frame_id &&
			stream_info->sw_skip.max_frame_id >= frame_id)) {
			drop_frame = 1;
		} else if (frame_id > stream_info->sw_skip.max_frame_id) {
			spin_lock_irqsave(&stream_info->lock, flags);
			memset(&stream_info->sw_skip, 0,
					sizeof(struct msm_isp_sw_framskip));
			spin_unlock_irqrestore(&stream_info->lock, flags);
		}
	}

	if (!buf || !ts)
		return;

	frame_id = vfe_dev->axi_data.
		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;

	if (vfe_dev->vt_enable) {
		msm_isp_get_avtimer_ts(ts);
		time_stamp = &ts->vt_time;
@@ -1086,6 +1107,20 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
		if (rc)
			return;

		if (drop_frame) {
			/* Put but if dual vfe usecase and
			 * both vfe have done using buf
			 */
			rc = vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
				buf->bufq_handle, buf->buf_idx);
			if (!rc) {
				ISP_DBG("%s:%d] vfe_id %d Buffer dropped %d\n",
					__func__, __LINE__,
					vfe_dev->pdev->id, frame_id);
					return;
			}
		}

		buf_event.input_intf = SRC_TO_INTF(stream_info->stream_src);
		buf_event.frame_id = frame_id;
		buf_event.timestamp = *time_stamp;
@@ -1098,6 +1133,28 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
		msm_isp_send_event(vfe_dev, ISP_EVENT_BUF_DIVERT + stream_idx,
			&buf_event);
	} else {
		rc = vfe_dev->buf_mgr->ops->update_put_buf_cnt(vfe_dev->buf_mgr,
			buf->bufq_handle, buf->buf_idx);
		/* Buf done state return value represent whether the buf
		 * can be dispatched. A positive return value means
		 * other ISP hardware is still processing the frame.
		 */
		if (rc)
			return;

		if (drop_frame) {
			/* Put but if dual vfe usecase and
			 * both vfe have done using buf
			 */
			rc = vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
				buf->bufq_handle, buf->buf_idx);
			if (!rc) {
				ISP_DBG("%s:%d] vfe_id %d Buffer dropped %d\n",
					__func__, __LINE__,
					vfe_dev->pdev->id, frame_id);
					return;
			}
		}
		buf_event.input_intf = SRC_TO_INTF(stream_info->stream_src);
		buf_event.frame_id = frame_id;
		buf_event.timestamp = ts->buf_time;
@@ -1824,6 +1881,8 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
	struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
	struct msm_vfe_axi_stream_cfg_update_info *update_info;
	struct msm_isp_sw_framskip *sw_skip_info = NULL;
	unsigned long flags;

	/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
	if (update_cmd->num_streams > MAX_NUM_STREAM)
@@ -1889,6 +1948,23 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
			}
			break;
		}
		case UPDATE_STREAM_SW_FRAME_DROP: {
			sw_skip_info = &update_info->sw_skip_info;
			if (sw_skip_info->stream_src_mask != 0) {
				/* SW image buffer drop */
				pr_debug("%s:%x sw skip type %x mode %d min %d max %d\n",
					__func__, stream_info->stream_id,
					sw_skip_info->stats_type_mask,
					sw_skip_info->skip_mode,
					sw_skip_info->min_frame_id,
					sw_skip_info->max_frame_id);
				spin_lock_irqsave(&stream_info->lock, flags);
				stream_info->sw_skip = *sw_skip_info;
				spin_unlock_irqrestore(&stream_info->lock,
					flags);
			}
			break;
		}
		case UPDATE_STREAM_AXI_CONFIG: {
			for (j = 0; j < stream_info->num_planes; j++) {
				stream_info->plane_cfg[j] =
+50 −7
Original line number Diff line number Diff line
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2015, 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
@@ -73,8 +73,9 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
	struct msm_vfe_stats_stream *stream_info,
	uint32_t *comp_stats_type_mask)
{
	int32_t rc = 0;
	int32_t rc = 0, frame_id = 0, drop_buffer = 0;
	struct msm_isp_stats_event *stats_event = NULL;
	struct msm_isp_sw_framskip *sw_skip = NULL;

	if (!vfe_dev || !done_buf || !ts || !buf_event || !stream_info ||
		!comp_stats_type_mask) {
@@ -83,16 +84,40 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
			stream_info, comp_stats_type_mask);
		return -EINVAL;
	}

	frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
	sw_skip = &stream_info->sw_skip;
	stats_event = &buf_event->u.stats;

	if (sw_skip->stats_type_mask &
		(1 << stream_info->stats_type)) {
		/* Hw stream output of this src is requested
		   for drop */
		if (sw_skip->skip_mode == SKIP_ALL) {
			/* drop all buffers */
			drop_buffer = 1;
		} else if (sw_skip->skip_mode == SKIP_RANGE &&
		(sw_skip->min_frame_id <= frame_id &&
		sw_skip->max_frame_id >= frame_id)) {
			drop_buffer = 1;
		} else if (frame_id > sw_skip->max_frame_id) {
			memset(sw_skip, 0, sizeof
				(struct msm_isp_sw_framskip));
		}
	}

	rc = vfe_dev->buf_mgr->ops->buf_divert(
		vfe_dev->buf_mgr, done_buf->bufq_handle,
		done_buf->buf_idx, &ts->buf_time,
		vfe_dev->axi_data.
		src_info[VFE_PIX_0].frame_id);
		frame_id);
	if (rc != 0)
		return rc;

	if (drop_buffer) {
		vfe_dev->buf_mgr->ops->put_buf(
			vfe_dev->buf_mgr,
			done_buf->bufq_handle,
			done_buf->buf_idx);
		return rc;
	}
	stats_event->stats_buf_idxs
		[stream_info->stats_type] =
		done_buf->buf_idx;
@@ -135,7 +160,6 @@ static int32_t msm_isp_stats_configure(struct vfe_device *vfe_dev,
	for (i = 0; i < vfe_dev->hw_info->stats_hw_info->num_stats_type; i++) {
		if (!(stats_irq_mask & (1 << i)))
			continue;

		stream_info = &vfe_dev->stats_data.stream_info[i];
		done_buf = NULL;
		msm_isp_stats_cfg_ping_pong_address(vfe_dev,
@@ -673,6 +697,7 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
	struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
	struct msm_vfe_axi_stream_update_cmd *update_cmd = arg;
	struct msm_vfe_axi_stream_cfg_update_info *update_info = NULL;
	struct msm_isp_sw_framskip *sw_skip_info = NULL;

	/*validate request*/
	for (i = 0; i < update_cmd->num_streams; i++) {
@@ -713,6 +738,24 @@ int msm_isp_update_stats_stream(struct vfe_device *vfe_dev, void *arg)
					vfe_dev, stream_info);
			break;
		}
		case UPDATE_STREAM_SW_FRAME_DROP: {
			sw_skip_info = &update_info->sw_skip_info;
			if (!stream_info->sw_skip.stream_src_mask)
				stream_info->sw_skip = *sw_skip_info;

			if (sw_skip_info->stats_type_mask != 0) {
				/* No image buffer skip, only stats skip */
				pr_debug("%s:%x skip type %x mode %d min %d max %d\n",
					__func__, stream_info->stream_id,
					sw_skip_info->stats_type_mask,
					sw_skip_info->skip_mode,
					sw_skip_info->min_frame_id,
					sw_skip_info->max_frame_id);
				stream_info->sw_skip.stats_type_mask =
					sw_skip_info->stats_type_mask;
			}
			break;
		}

		default:
			pr_err("%s: Invalid update type\n", __func__);
Loading