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

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

Merge "msm: isp: Add support to multipass offline ISP"

parents 816587b4 47b144f8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -244,6 +244,8 @@ struct msm_vfe_core_ops {
	int (*ahb_clk_cfg)(struct vfe_device *vfe_dev,
			struct msm_isp_ahb_clk_cfg *ahb_cfg);
	void (*set_halt_restart_mask)(struct vfe_device *vfe_dev);
	int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev,
		void *arg);
};
struct msm_vfe_stats_ops {
	int (*get_stats_idx)(enum msm_isp_stats_type stats_type);
+80 −2
Original line number Diff line number Diff line
@@ -1060,11 +1060,71 @@ static int msm_vfe40_start_fetch_engine(struct vfe_device *vfe_dev,
	return 0;
}

static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
	void *arg)
{
	int rc = 0;
	uint32_t bufq_handle = 0;
	struct msm_isp_buffer *buf = NULL;
	struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
	struct msm_isp_buffer_mapped_info mapped_info;

	if (vfe_dev->fetch_engine_info.is_busy == 1) {
		pr_err("%s: fetch engine busy\n", __func__);
		return -EINVAL;
	}
	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
	/* There is other option of passing buffer address from user,
		in such case, driver needs to map the buffer and use it*/
	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;

	if (!fe_cfg->offline_mode) {
		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
				vfe_dev->buf_mgr, fe_cfg->session_id,
				fe_cfg->stream_id);
		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;

		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
		if (rc < 0 || !buf) {
			pr_err("%s: No fetch buffer rc= %d buf= %p\n",
				__func__, rc, buf);
			return -EINVAL;
		}
		mapped_info = buf->mapped_info[0];
		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
	} else {
		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
			&mapped_info, fe_cfg->fd);
		if (rc < 0) {
			pr_err("%s: can not map buffer\n", __func__);
			return -EINVAL;
		}
	}
	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
	vfe_dev->fetch_engine_info.is_busy = 1;

	msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
		vfe_dev->vfe_base + 0x228);

	msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378);

	msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
	msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);

	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
	return 0;
}

static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
	struct msm_vfe_pix_cfg *pix_cfg)
{
	uint32_t x_size_word;
	uint32_t temp = 0;
	uint32_t main_unpack_pattern = 0;
	struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;

	if (pix_cfg->input_mux != EXTERNAL_READ) {
@@ -1097,10 +1157,14 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
	/* need to update to use formulae to calculate X_SIZE_WORD*/
	x_size_word = msm_isp_cal_word_per_line(
		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
		fe_cfg->fetch_width);
		fe_cfg->buf_width);

	msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x23C);

	x_size_word = msm_isp_cal_word_per_line(
		vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
		fe_cfg->fetch_width);

	temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
	temp |= 2 << 16 | pix_cfg->pixel_pattern;
	msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C);
@@ -1126,7 +1190,19 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
	}

	/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
	msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x248);
	switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
	case V4L2_PIX_FMT_P16BGGR10:
	case V4L2_PIX_FMT_P16GBRG10:
	case V4L2_PIX_FMT_P16GRBG10:
	case V4L2_PIX_FMT_P16RGGB10:
		main_unpack_pattern = 0xB210;
		break;
	default:
		main_unpack_pattern = 0xF6543210;
		break;
	}
	msm_camera_io_w(main_unpack_pattern,
		vfe_dev->vfe_base + 0x248);
	msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264);

	return;
@@ -2254,6 +2330,8 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
			.ahb_clk_cfg = NULL,
			.set_halt_restart_mask =
				msm_vfe40_set_halt_restart_mask,
			.start_fetch_eng_multi_pass =
				msm_vfe40_start_fetch_engine_multi_pass,
		},
		.stats_ops = {
			.get_stats_idx = msm_vfe40_get_stats_idx,
+63 −1
Original line number Diff line number Diff line
@@ -1044,6 +1044,63 @@ int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
	return 0;
}

int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
	void *arg)
{
	int rc = 0;
	uint32_t bufq_handle = 0;
	struct msm_isp_buffer *buf = NULL;
	struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
	struct msm_isp_buffer_mapped_info mapped_info;

	if (vfe_dev->fetch_engine_info.is_busy == 1) {
		pr_err("%s: fetch engine busy\n", __func__);
		return -EINVAL;
	}

	memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));

	vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
	vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
	vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
	vfe_dev->fetch_engine_info.fd = fe_cfg->fd;

	if (!fe_cfg->offline_mode) {
		bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
			vfe_dev->buf_mgr, fe_cfg->session_id,
			fe_cfg->stream_id);
		vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;

		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
			vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
		if (rc < 0 || !buf) {
			pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
				__func__, rc, buf);
			return -EINVAL;
		}
		mapped_info = buf->mapped_info[0];
		buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
	} else {
		rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
			&mapped_info, fe_cfg->fd);
		if (rc < 0) {
			pr_err("%s: can not map buffer\n", __func__);
			return -EINVAL;
		}
	}

	vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
	vfe_dev->fetch_engine_info.is_busy = 1;

	msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
		vfe_dev->vfe_base + 0x2F4);
	msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
	msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);

	ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);

	return 0;
}
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
	struct msm_vfe_pix_cfg *pix_cfg)
{
@@ -1075,10 +1132,13 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,

		x_size_word = msm_isp_cal_word_per_line(
			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
			fe_cfg->fetch_width);
			fe_cfg->buf_width);
		msm_camera_io_w((x_size_word - 1) << 16,
			vfe_dev->vfe_base + 0x30c);

		x_size_word = msm_isp_cal_word_per_line(
			vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
			fe_cfg->fetch_width);
		msm_camera_io_w(x_size_word << 16 |
			(temp & 0x3FFF) << 2 | VFE47_FETCH_BURST_LEN,
			vfe_dev->vfe_base + 0x310);
@@ -2677,6 +2737,8 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
			.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
			.set_halt_restart_mask =
				msm_vfe47_set_halt_restart_mask,
			.start_fetch_eng_multi_pass =
				msm_vfe47_start_fetch_engine_multi_pass,
		},
		.stats_ops = {
			.get_stats_idx = msm_vfe47_get_stats_idx,
+99 −3
Original line number Diff line number Diff line
@@ -1658,6 +1658,82 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer(
	return buf;
}

int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
	uint32_t buf_idx)
{
	int i, rc = 0;
	struct msm_isp_buffer *buf = NULL;
	uint32_t pingpong_bit;
	uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
	uint32_t buffer_size_byte = 0;
	int32_t word_per_line = 0;
	dma_addr_t paddr;
	uint32_t bufq_handle = 0;

	if (stream_idx >= VFE_AXI_SRC_MAX) {
		pr_err("%s: Invalid stream_idx", __func__);
		return -EINVAL;
	}

	bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT];

	if (!vfe_dev->is_split) {
		rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
			vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf);
		if (rc < 0 || !buf) {
			pr_err("%s: No fetch buffer rc= %d buf= %p\n",
				__func__, rc, buf);
			return -EINVAL;
		}

		if (buf->num_planes != stream_info->num_planes) {
			pr_err("%s: Invalid buffer\n", __func__);
			vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
				bufq_handle, buf->buf_idx);
			return -EINVAL;
		}

		pingpong_bit = ((pingpong_status >>
			stream_info->wm[0]) & 0x1);

		for (i = 0; i < stream_info->num_planes; i++) {
			word_per_line = msm_isp_cal_word_per_line(
				stream_info->output_format,
				stream_info->plane_cfg[i].
				output_stride);
			if (word_per_line < 0) {
				/* 0 means no prefetch*/
				word_per_line = 0;
				buffer_size_byte = 0;
			} else {
				buffer_size_byte = (word_per_line * 8 *
					stream_info->plane_cfg[i].
					output_scan_lines) -
					stream_info->
					plane_cfg[i].plane_addr_offset;
			}
			paddr = buf->mapped_info[i].paddr;

			vfe_dev->hw_info->vfe_ops.axi_ops.
				update_ping_pong_addr(
				vfe_dev->vfe_base, stream_info->wm[i],
				pingpong_bit, paddr +
				stream_info->
				plane_cfg[i].plane_addr_offset,
				buffer_size_byte);

			if (0 == i) {
				stream_info->buf[!pingpong_bit] = buf;
				buf->pingpong_bit = !pingpong_bit;
			}
			buf->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
		}
	}
	return rc;

}

static int msm_isp_cfg_ping_pong_address(struct vfe_device *vfe_dev,
	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
	int scratch)
@@ -1915,6 +1991,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev,
	buf_event.u.buf_done.buf_idx = buf->buf_idx;
	buf_event.u.buf_done.output_format =
		stream_info->runtime_output_format;
	if (vfe_dev->fetch_engine_info.is_busy &&
		SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) {
		vfe_dev->fetch_engine_info.is_busy = 0;
	}

	if (stream_info->buf_divert &&
		buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) {

@@ -2768,7 +2849,6 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
		}
		stream_info = &axi_data->stream_info[
			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];

		/* set ping pong address to scratch before stream stop */
		spin_lock_irqsave(&stream_info->lock, flags);
		msm_isp_cfg_stream_scratch(vfe_dev, stream_info, VFE_PING_FLAG);
@@ -3148,7 +3228,6 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
	stream_cfg_cmd.frame_skip_pattern = NO_SKIP;
	stream_cfg_cmd.init_frame_drop = 0;
	stream_cfg_cmd.burst_count = stream_info->request_q_cnt;

	if (stream_info->undelivered_request_cnt == 1) {
		rc = msm_isp_cfg_ping_pong_address(vfe_dev, stream_info,
			VFE_PING_FLAG, 0);
@@ -3518,6 +3597,24 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
		}
		break;
	}
	case UPDATE_STREAM_OFFLINE_AXI_CONFIG: {
		for (i = 0; i < update_cmd->num_streams; i++) {
			update_info =
				(struct msm_vfe_axi_stream_cfg_update_info *)
				&update_cmd->update_info[i];
			stream_info = &axi_data->stream_info[HANDLE_TO_IDX(
				update_info->stream_handle)];
			for (j = 0; j < stream_info->num_planes; j++) {
				stream_info->plane_cfg[j] =
					update_info->plane_cfg[j];
			}
			for (j = 0; j < stream_info->num_planes; j++) {
				vfe_dev->hw_info->vfe_ops.axi_ops.
					cfg_wm_reg(vfe_dev, stream_info, j);
			}
		}
		break;
	}
	default:
		pr_err("%s: Invalid update type\n", __func__);
		return -EINVAL;
@@ -3735,7 +3832,6 @@ void msm_isp_process_axi_irq(struct vfe_device *vfe_dev,
			}
			stream_idx = HANDLE_TO_IDX(comp_info->stream_handle);
			stream_info = &axi_data->stream_info[stream_idx];

			msm_isp_process_axi_irq_stream(vfe_dev, stream_info,
						pingpong_status, ts);

+3 −0
Original line number Diff line number Diff line
@@ -117,4 +117,7 @@ static inline void msm_isp_cfg_stream_scratch(struct vfe_device *vfe_dev,
	stream_info->buf[pingpong_bit] = NULL;
}

int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
	struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
	uint32_t buf_idx);
#endif /* __MSM_ISP_AXI_UTIL_H__ */
Loading