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

Commit 4a8052a6 authored by Abhishek Kondaveeti's avatar Abhishek Kondaveeti
Browse files

msm:camera: Add support for AV time stamp for VT call



For vt call we need to update the camera buffers with AVTimer
timestamp instead of normal kernel time stamp to prevent
AV sync issues

Change-Id: I4aecf03c45b7dc36c255b122385cee561c7ae40f
Signed-off-by: default avatarAbhishek Kondaveeti <akondave@codeaurora.org>
Signed-off-by: default avatarLokesh Kumar Aakulu <lkumar@codeaurora.org>
parent 61a09d4a
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/avtimer.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include <mach/msm_bus.h>
@@ -35,6 +36,10 @@
#define MAX_INIT_FRAME_DROP 31
#define ISP_Q2 (1 << 2)

#define AVTIMER_MSW_PHY_ADDR 0xFE05300C
#define AVTIMER_LSW_PHY_ADDR 0xFE053008
#define AVTIMER_ITERATION_CTR 16

#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0

@@ -69,6 +74,8 @@ enum msm_isp_camif_update_state {
struct msm_isp_timestamp {
	/*Monotonic clock for v4l2 buffer*/
	struct timeval buf_time;
	/*Monotonic clock for VT */
	struct timeval vt_time;
	/*Wall clock for userspace event*/
	struct timeval event_time;
};
@@ -264,7 +271,7 @@ struct msm_vfe_axi_stream {
	uint32_t stream_handle;
	uint8_t buf_divert;
	enum msm_vfe_axi_stream_type stream_type;

	uint32_t vt_enable;
	uint32_t frame_based;
	uint32_t framedrop_period;
	uint32_t framedrop_pattern;
@@ -437,6 +444,9 @@ struct vfe_device {
	int dump_reg;
	int vfe_clk_idx;
	uint32_t vfe_open_cnt;
	uint8_t vt_enable;
	void __iomem *p_avtimer_msw;
	void __iomem *p_avtimer_lsw;
};

#endif
+29 −4
Original line number Diff line number Diff line
@@ -485,6 +485,19 @@ void msm_isp_calculate_bandwidth(
	}
}

#ifdef CONFIG_MSM_AVTIMER
void msm_isp_start_avtimer(void)
{
	avcs_core_open();
	avcs_core_disable_power_collapse(1);
}
#else
void msm_isp_start_avtimer(void)
{
	pr_err("AV Timer is not supported\n");
}
#endif

int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
	int rc = 0, i;
@@ -528,7 +541,13 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
	}

	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);

	stream_info->vt_enable = stream_cfg_cmd->vt_enable;
	if (stream_info->vt_enable) {
		vfe_dev->vt_enable = stream_info->vt_enable;
		msm_isp_start_avtimer();
		vfe_dev->p_avtimer_lsw = ioremap(AVTIMER_LSW_PHY_ADDR, 4);
		vfe_dev->p_avtimer_msw = ioremap(AVTIMER_MSW_PHY_ADDR, 4);
	}
	if (stream_info->num_planes > 1) {
		msm_isp_axi_reserve_comp_mask(
			&vfe_dev->axi_data, stream_info);
@@ -787,16 +806,22 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
{
	int rc;
	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 = vfe_dev->axi_data.
		src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
	memset(&buf_event, 0, sizeof(buf_event));

	if (buf && ts) {
		if (vfe_dev->vt_enable) {
			time_stamp = &ts->vt_time;
		} else {
			time_stamp = &ts->buf_time;
		}
		if (stream_info->buf_divert) {
			rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
				buf->bufq_handle, buf->buf_idx,
				&ts->buf_time, frame_id);
				time_stamp, frame_id);
			/* Buf divert return value represent whether the buf
			 * can be diverted. A positive return value means
			 * other ISP hardware is still processing the frame.
@@ -805,7 +830,7 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
				buf_event.input_intf =
					SRC_TO_INTF(stream_info->stream_src);
				buf_event.frame_id = frame_id;
				buf_event.timestamp = ts->buf_time;
				buf_event.timestamp = *time_stamp;
				buf_event.u.buf_done.session_id =
					stream_info->session_id;
				buf_event.u.buf_done.stream_id =
@@ -834,7 +859,7 @@ static void msm_isp_process_done_buf(struct vfe_device *vfe_dev,
				ISP_EVENT_BUF_DONE, &buf_event);
			vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
				buf->bufq_handle, buf->buf_idx,
				&ts->buf_time, frame_id,
				time_stamp, frame_id,
				stream_info->runtime_output_format);
		}
	}
+47 −0
Original line number Diff line number Diff line
@@ -193,6 +193,30 @@ static inline void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp)
	do_gettimeofday(&(time_stamp->event_time));
}

static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev,
	struct msm_isp_timestamp *time_stamp)
{
	uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
	uint32_t avtimer_msw_2nd = 0;
	uint8_t iter = 0;
	if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) {
		pr_err("%s: ioremap failed\n", __func__);
		return;
	}
	do {
		avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw);
		avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw);
		avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw);
	} while ((avtimer_msw_1st != avtimer_msw_2nd)
		&& (iter++ < AVTIMER_ITERATION_CTR));
	if (iter >= AVTIMER_ITERATION_CTR) {
		pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__);
		return;
	}
	time_stamp->vt_time.tv_sec = avtimer_msw_1st;
	time_stamp->vt_time.tv_usec = avtimer_lsw;
}

int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
	struct v4l2_event_subscription *sub)
{
@@ -885,6 +909,8 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
	queue_cmd->vfeInterruptStatus0 = irq_status0;
	queue_cmd->vfeInterruptStatus1 = irq_status1;
	msm_isp_get_timestamp(&queue_cmd->ts);
	if (vfe_dev->vt_enable)
		msm_isp_get_vt_tstamp(vfe_dev, &queue_cmd->ts);
	queue_cmd->cmd_used = 1;
	vfe_dev->taskletq_idx =
		(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
@@ -998,11 +1024,26 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
	vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
	vfe_dev->vfe_open_cnt++;
	vfe_dev->taskletq_idx = 0;
	vfe_dev->vt_enable = 0;
	vfe_dev->p_avtimer_lsw = NULL;
	vfe_dev->p_avtimer_msw = NULL;
	mutex_unlock(&vfe_dev->core_mutex);
	mutex_unlock(&vfe_dev->realtime_mutex);
	return 0;
}

#ifdef CONFIG_MSM_AVTIMER
void msm_isp_end_avtimer(void)
{
	avcs_core_disable_power_collapse(0);
}
#else
void msm_isp_end_avtimer(void)
{
	pr_err("AV Timer is not supported\n");
}
#endif

int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	long rc;
@@ -1024,6 +1065,12 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
	vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
	vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
	vfe_dev->vfe_open_cnt--;
	if (vfe_dev->vt_enable) {
		iounmap(vfe_dev->p_avtimer_lsw);
		iounmap(vfe_dev->p_avtimer_msw);
		msm_isp_end_avtimer();
		vfe_dev->vt_enable = 0;
	}
	mutex_unlock(&vfe_dev->core_mutex);
	mutex_unlock(&vfe_dev->realtime_mutex);
	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ struct msm_vfe_axi_plane_cfg {
struct msm_vfe_axi_stream_request_cmd {
	uint32_t session_id;
	uint32_t stream_id;
	uint32_t vt_enable;
	uint32_t output_format;/*Planar/RAW/Misc*/
	enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/
	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];