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

Commit f9f98b69 authored by Camera Software Integration's avatar Camera Software Integration Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: tfe: Drop first rdi frame in dual tfe scenario" into camera-kernel.lnx.4.0

parents 84df0f25 8f9d6997
Loading
Loading
Loading
Loading
+209 −7
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/iopoll.h>
@@ -203,6 +203,152 @@ static int cam_tfe_csid_get_format_ipp(
	return rc;
}

static void cam_tfe_csid_enable_path_for_init_frame_drop(
	struct cam_tfe_csid_hw *csid_hw,
	int res_id)
{
	struct cam_tfe_csid_path_cfg             *path_data;
	const struct cam_tfe_csid_pxl_reg_offset *pxl_reg = NULL;
	const struct cam_tfe_csid_rdi_reg_offset *rdi_reg = NULL;
	const struct cam_tfe_csid_reg_offset     *csid_reg;
	struct cam_hw_soc_info                   *soc_info;
	struct cam_isp_resource_node             *res;
	uint32_t val;

	if (!csid_hw) {
		CAM_WARN(CAM_ISP, "csid_hw cannot be NULL");
		return;
	}

	csid_reg  = csid_hw->csid_info->csid_reg;
	soc_info  = &csid_hw->hw_info->soc_info;

	if (res_id == CAM_TFE_CSID_PATH_RES_IPP) {
		res = &csid_hw->ipp_res;
		pxl_reg = csid_reg->ipp_reg;
	} else if (res_id >= CAM_TFE_CSID_PATH_RES_RDI_0 &&
			res_id <= CAM_TFE_CSID_PATH_RES_RDI_2) {
		res = &csid_hw->rdi_res[res_id];
		rdi_reg = csid_reg->rdi_reg[res_id];
	} else {
		CAM_ERR(CAM_ISP, "Invalid res_id");
		return;
	}

	path_data = (struct cam_tfe_csid_path_cfg *)res->res_priv;

	if (!path_data || !path_data->init_frame_drop)
		return;
	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING)
		return;

	path_data->res_sof_cnt++;
	if ((path_data->res_sof_cnt + 1) <
			path_data->res_sof_cnt) {
		CAM_WARN(CAM_ISP, "Res %d sof count overflow %d",
			res_id, path_data->res_sof_cnt);
		return;
	}

	CAM_DBG(CAM_ISP, "CSID:%d res_id %d SOF cnt:%d init_frame_drop:%d",
		csid_hw->hw_intf->hw_idx, res_id, path_data->res_sof_cnt,
		path_data->init_frame_drop);

	if ((path_data->res_sof_cnt ==
		path_data->init_frame_drop) &&
		pxl_reg) {
		CAM_DBG(CAM_ISP, "Enabling pixel IPP Path");
		if (path_data->sync_mode !=
			CAM_ISP_HW_SYNC_SLAVE) {
			val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
				pxl_reg->csid_pxl_ctrl_addr);
			val |= CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY;
			cam_io_w_mb(val,
				soc_info->reg_map[0].mem_base +
				pxl_reg->csid_pxl_ctrl_addr);
		}

		if (!(csid_hw->csid_debug &
				TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) {
			val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
				pxl_reg->csid_pxl_irq_mask_addr);
			val &= ~(TFE_CSID_PATH_INFO_INPUT_SOF);
			cam_io_w_mb(val,
				soc_info->reg_map[0].mem_base +
				pxl_reg->csid_pxl_irq_mask_addr);
		}
	} else if ((path_data->res_sof_cnt ==
		path_data->init_frame_drop) && rdi_reg) {
		CAM_DBG(CAM_ISP, "Enabling RDI %d Path", res_id);
		cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY,
			soc_info->reg_map[0].mem_base +
			rdi_reg->csid_rdi_ctrl_addr);
		if (!(csid_hw->csid_debug &
				TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) {
			val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
				rdi_reg->csid_rdi_irq_mask_addr);
			val &= ~(TFE_CSID_PATH_INFO_INPUT_SOF);
			cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
				rdi_reg->csid_rdi_irq_mask_addr);
		}
	}
}

static bool cam_tfe_csid_check_path_active(struct cam_tfe_csid_hw   *csid_hw)
{
	const struct cam_tfe_csid_reg_offset  *csid_reg;
	struct cam_hw_soc_info                *soc_info;
	uint32_t i;
	uint32_t path_status = 1;

	csid_reg = csid_hw->csid_info->csid_reg;
	soc_info = &csid_hw->hw_info->soc_info;

	/* check the IPP path status */
	if (csid_reg->cmn_reg->num_pix) {
		path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
				csid_reg->ipp_reg->csid_pxl_status_addr);
		CAM_DBG(CAM_ISP, "CSID:%d IPP path status:%d",
			csid_hw->hw_intf->hw_idx, path_status);
		/* if status is 0 then it is active */
		if (!path_status)
			goto end;
	}

	/* Check the RDI path status */
	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
		path_status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
				csid_reg->rdi_reg[i]->csid_rdi_status_addr);
		CAM_DBG(CAM_ISP, "CSID:%d RDI:%d path status:%d",
			csid_hw->hw_intf->hw_idx, i,  path_status);
		/* if status is 0 then it is active */
		if (!path_status)
			goto end;
	}

end:
	/* if status is 0 then path is active */
	return path_status ? false : true;
}

static void cam_tfe_csid_reset_path_data(
	struct cam_tfe_csid_hw       *csid_hw,
	struct cam_isp_resource_node *res)
{
	struct cam_tfe_csid_path_cfg *path_data = NULL;

	if (!csid_hw || !res) {
		CAM_WARN(CAM_ISP, "csid_hw or res cannot be NULL");
		return;
	}
	path_data = res->res_priv;

	if (path_data) {
		path_data->init_frame_drop = 0;
		path_data->res_sof_cnt     = 0;
	}
}

static int cam_tfe_csid_cid_get(struct cam_tfe_csid_hw *csid_hw,
	int32_t vc, uint32_t dt, uint32_t *cid)
{
@@ -249,6 +395,7 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
{
	struct cam_hw_soc_info                *soc_info;
	const struct cam_tfe_csid_reg_offset  *csid_reg;
	struct cam_tfe_csid_path_cfg          *path_data = NULL;
	int rc = 0;
	uint32_t val = 0, i;
	uint32_t status;
@@ -348,6 +495,15 @@ static int cam_tfe_csid_global_reset(struct cam_tfe_csid_hw *csid_hw)
	csid_hw->error_irq_count = 0;
	csid_hw->prev_boot_timestamp = 0;

	path_data = (struct cam_tfe_csid_path_cfg *)csid_hw->ipp_res.res_priv;
	path_data->res_sof_cnt = 0;

	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
		path_data = (struct cam_tfe_csid_path_cfg  *)
			csid_hw->rdi_res[i].res_priv;
		path_data->res_sof_cnt = 0;
	}

	return rc;
}

@@ -675,6 +831,7 @@ static int cam_tfe_csid_path_reserve(struct cam_tfe_csid_hw *csid_hw,
	path_data->height  = reserve->in_port->height;
	path_data->start_line = reserve->in_port->line_start;
	path_data->end_line = reserve->in_port->line_end;
	path_data->usage_type = reserve->in_port->usage_type;

	csid_hw->event_cb = reserve->event_cb;
	csid_hw->event_cb_priv = reserve->event_cb_prv;
@@ -869,6 +1026,7 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw)
	int rc = 0;
	const struct cam_tfe_csid_reg_offset      *csid_reg;
	struct cam_hw_soc_info                    *soc_info;
	struct cam_tfe_csid_path_cfg              *path_data = NULL;
	uint32_t i, val, clk_lvl;
	unsigned long flags;

@@ -949,6 +1107,16 @@ static int cam_tfe_csid_enable_hw(struct cam_tfe_csid_hw *csid_hw)
	spin_unlock_irqrestore(&csid_hw->spin_lock, flags);
	cam_tasklet_start(csid_hw->tasklet);

	path_data = (struct cam_tfe_csid_path_cfg  *)csid_hw->ipp_res.res_priv;
	path_data->res_sof_cnt = 0;

	for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) {
		path_data = (struct cam_tfe_csid_path_cfg *)
						csid_hw->rdi_res[i].res_priv;
		path_data->res_sof_cnt = 0;
	}


	return rc;

disable_soc:
@@ -1512,11 +1680,14 @@ static int cam_tfe_csid_enable_rdi_path(
{
	const struct cam_tfe_csid_reg_offset      *csid_reg;
	struct cam_hw_soc_info                    *soc_info;
	struct cam_tfe_csid_path_cfg              *path_data;
	uint32_t id, val;
	bool path_active = false;

	csid_reg = csid_hw->csid_info->csid_reg;
	soc_info = &csid_hw->hw_info->soc_info;
	id = res->res_id;
	path_data = (struct cam_tfe_csid_path_cfg   *) res->res_priv;

	if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW ||
		res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2 ||
@@ -1528,17 +1699,38 @@ static int cam_tfe_csid_enable_rdi_path(
		return -EINVAL;
	}

	/*Drop one frame extra on RDI for dual TFE use case */
	if (path_data->usage_type == CAM_ISP_TFE_IN_RES_USAGE_DUAL)
		path_data->init_frame_drop = 1;

	/*resume at frame boundary */
	if (!path_data->init_frame_drop) {
		CAM_DBG(CAM_ISP, "Start RDI:%d path", id);
		/* resume at frame boundary */
		cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY,
				  soc_info->reg_map[0].mem_base +
				  csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);
	} else {
		path_active = cam_tfe_csid_check_path_active(csid_hw);
		if (path_active)
			cam_io_w_mb(CAM_TFE_CSID_RESUME_AT_FRAME_BOUNDARY,
					  soc_info->reg_map[0].mem_base +
					  csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);

			CAM_DBG(CAM_ISP,
				"CSID:%d  %s RDI:%d path frame drop %d",
				csid_hw->hw_intf->hw_idx,
				path_active ? "Starting" : "Not Starting", id,
				path_data->init_frame_drop);
	}

	/* Enable the required RDI interrupts */
	val = TFE_CSID_PATH_INFO_RST_DONE | TFE_CSID_PATH_ERROR_FIFO_OVERFLOW |
		TFE_CSID_PATH_RDI_ERROR_CCIF_VIOLATION |
		TFE_CSID_PATH_RDI_OVERFLOW_IRQ;

	if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)
	if ((csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ) ||
		(path_data->init_frame_drop && !path_active))
		val |= TFE_CSID_PATH_INFO_INPUT_SOF;
	if (csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_EOF_IRQ)
		val |= TFE_CSID_PATH_INFO_INPUT_EOF;
@@ -1560,10 +1752,12 @@ static int cam_tfe_csid_disable_rdi_path(
	uint32_t id, val = 0;
	const struct cam_tfe_csid_reg_offset       *csid_reg;
	struct cam_hw_soc_info                     *soc_info;
	struct cam_tfe_csid_path_cfg               *path_data;

	csid_reg = csid_hw->csid_info->csid_reg;
	soc_info = &csid_hw->hw_info->soc_info;
	id = res->res_id;
	path_data = (struct cam_tfe_csid_path_cfg   *) res->res_priv;

	if ((res->res_id > CAM_TFE_CSID_PATH_RES_RDI_2) ||
		(!csid_reg->rdi_reg[res->res_id])) {
@@ -1599,6 +1793,9 @@ static int cam_tfe_csid_disable_rdi_path(
	CAM_DBG(CAM_ISP, "CSID:%d res_id:%d",
		csid_hw->hw_intf->hw_idx, res->res_id);

	path_data->init_frame_drop = 0;
	path_data->res_sof_cnt     = 0;

	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
		csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);

@@ -1964,6 +2161,8 @@ static int cam_tfe_csid_release(void *hw_priv,

	res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;

	cam_tfe_csid_reset_path_data(csid_hw, res);

end:
	mutex_unlock(&csid_hw->hw_info->hw_mutex);
	return rc;
@@ -3276,6 +3475,9 @@ irqreturn_t cam_tfe_csid_irq(int irq_num, void *data)
			complete(&csid_hw->csid_rdin_complete[i]);
		}

		if (irq_status[i] & TFE_CSID_PATH_INFO_INPUT_SOF)
			cam_tfe_csid_enable_path_for_init_frame_drop(csid_hw, i);

		if ((irq_status[i] & TFE_CSID_PATH_INFO_INPUT_SOF) &&
			(csid_hw->csid_debug & TFE_CSID_DEBUG_ENABLE_SOF_IRQ)) {
			if (!csid_hw->sof_irq_triggered)
+10 −2
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
 */

#ifndef _CAM_TFE_CSID_HW_H_
@@ -332,7 +332,12 @@ struct cam_tfe_csid_cid_data {
 * @sensor_fps      Sensor fps
 * @sensor_hbi      Sensor horizontal blanking interval
 * @sensor_vbi      Sensor vertical blanking interval
 *
 * @usage_type:     dual or single tfe information
 * @init_frame_drop init frame drop value. In dual ife case rdi need to drop one
 *                  more frame than pix.
 * @res_sof_cnt     path resource sof count value. it used for initial
 *                  frame drop

 */
struct cam_tfe_csid_path_cfg {
	uint32_t                        vc;
@@ -355,6 +360,9 @@ struct cam_tfe_csid_path_cfg {
	uint32_t                        sensor_fps;
	uint32_t                        sensor_hbi;
	uint32_t                        sensor_vbi;
	uint32_t                        usage_type;
	uint32_t                        init_frame_drop;
	uint32_t                        res_sof_cnt;
};

/**