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

Commit 1f0cf54f authored by Jing Zhou's avatar Jing Zhou Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: isp: Fix the framedrop setting issue



This change fixes a framedrop issue due to unsynced epoch signal.
In dual vfe case, the epoch signal from each VFE might arrived in any
order. Since reset the framedrop pattern for both VFE is done in the
epocch signal, we need to align this action with the last vfe epoch
signal. The current implementation is to do the reset always on the
vfe1 signal, this has led to incorrect framedrop pattern reset which
cause the framedrop pattern out of sync between two VFEs.
This change aligns this action with the latest epoch signal so split
will not happen.

CRs-fixed: 991080
Change-Id: I20a911fd8cec9e36e6867fa19428513f36054a8a
Signed-off-by: default avatarJing Zhou <jzhou70@codeaurora.org>
parent 96091a5d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -616,6 +616,7 @@ struct dual_vfe_resource {
	struct msm_vfe_stats_shared_data *stats_data[MAX_VFE];
	struct msm_vfe_axi_shared_data *axi_data[MAX_VFE];
	uint32_t wm_reload_mask[MAX_VFE];
	uint32_t epoch_sync_mask;
};

struct master_slave_resource_info {
+90 −1
Original line number Diff line number Diff line
@@ -527,6 +527,89 @@ static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev,
	}
}

/**
 * msm_isp_check_epoch_status() -  check the epock signal for framedrop
 *
 * @vfe_dev: The h/w on which the epoch signel is reveived
 * @frame_src: The source of the epoch signal for this frame
 *
 * For dual vfe case and pixel stream, if both vfe's epoch signal is
 * received, this function will return success.
 * It will also return the vfe1 for further process
 * For none dual VFE stream or none pixl source, this
 * funciton will just return success.
 *
 * Returns  1 - epoch received is complete.
 *          0 - epoch reveived is not complete.
 */
static int msm_isp_check_epoch_status(struct vfe_device **vfe_dev,
	enum msm_vfe_input_src frame_src)
{
	struct vfe_device *vfe_dev_cur = *vfe_dev;
	struct vfe_device *vfe_dev_other = NULL;
	uint32_t vfe_id_other = 0;
	uint32_t vfe_id_cur = 0;
	uint32_t epoch_mask = 0;
	unsigned long flags;
	int completed = 0;

	spin_lock_irqsave(
		&vfe_dev_cur->common_data->common_dev_data_lock, flags);

	if (vfe_dev_cur->is_split &&
		frame_src == VFE_PIX_0) {
		if (vfe_dev_cur->pdev->id == ISP_VFE0) {
			vfe_id_cur = ISP_VFE0;
			vfe_id_other = ISP_VFE1;
		} else {
			vfe_id_cur = ISP_VFE1;
			vfe_id_other = ISP_VFE0;
		}
		vfe_dev_other = vfe_dev_cur->common_data->dual_vfe_res->
			vfe_dev[vfe_id_other];

		if (vfe_dev_cur->common_data->dual_vfe_res->
			epoch_sync_mask & (1 << vfe_id_cur)) {
			/* serious scheduling delay */
			pr_err("Missing epoch: vfe %d, epoch mask 0x%x\n",
				vfe_dev_cur->pdev->id,
				vfe_dev_cur->common_data->dual_vfe_res->
					epoch_sync_mask);
			goto fatal;
		}

		vfe_dev_cur->common_data->dual_vfe_res->
			epoch_sync_mask |= (1 << vfe_id_cur);

		epoch_mask = (1 << vfe_id_cur) | (1 << vfe_id_other);
		if ((vfe_dev_cur->common_data->dual_vfe_res->
			epoch_sync_mask & epoch_mask) == epoch_mask) {

			if (vfe_id_other == ISP_VFE0)
				*vfe_dev = vfe_dev_cur;
			else
				*vfe_dev = vfe_dev_other;

			vfe_dev_cur->common_data->dual_vfe_res->
				epoch_sync_mask &= ~epoch_mask;
			completed = 1;
		}
	} else
		completed = 1;

	spin_unlock_irqrestore(
		&vfe_dev_cur->common_data->common_dev_data_lock, flags);

	return completed;
fatal:
	spin_unlock_irqrestore(
		&vfe_dev_cur->common_data->common_dev_data_lock, flags);
	/* new error event code will be added later */
	msm_isp_halt_send_error(vfe_dev_cur, ISP_EVENT_PING_PONG_MISMATCH);
	return 0;
}


/**
 * msm_isp_update_framedrop_reg() - Update frame period pattern on h/w
 * @vfe_dev: The h/w on which the perion pattern is updated.
@@ -542,10 +625,15 @@ void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev,
	enum msm_vfe_input_src frame_src)
{
	int i;
	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
	struct msm_vfe_axi_shared_data *axi_data = NULL;
	struct msm_vfe_axi_stream *stream_info;
	unsigned long flags;

	if (msm_isp_check_epoch_status(&vfe_dev, frame_src) != 1)
		return;

	axi_data = &vfe_dev->axi_data;

	for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
		if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) !=
			frame_src) {
@@ -2549,6 +2637,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
		vfe_dev->hw_info->vfe_ops.core_ops.
			update_camif_state(vfe_dev, camif_update);
		vfe_dev->axi_data.camif_state = CAMIF_ENABLE;
		vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0;
	}

	if (wait_for_complete) {
+7 −2
Original line number Diff line number Diff line
@@ -2131,11 +2131,16 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)

	ISP_DBG("%s open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt);

	if (vfe_dev->common_data == NULL) {
		pr_err("%s: Error in probe. No common_data\n", __func__);
	if (vfe_dev->common_data == NULL ||
		vfe_dev->common_data->dual_vfe_res == NULL) {
		pr_err("%s: Error in probe. No common_data or dual vfe res\n",
			__func__);
		return -EINVAL;
	}

	if (vfe_dev->pdev->id == ISP_VFE0)
		vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0;

	mutex_lock(&vfe_dev->realtime_mutex);
	mutex_lock(&vfe_dev->core_mutex);