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

Commit 6b530bb2 authored by Vikram Sharma's avatar Vikram Sharma
Browse files

msm: camera: isp: Change csid stop sequence during flush



This change takes care of a race which we see when we halt master
csid immediately and slave csid halt to follow. In some scenarios
after master csid halt, slave gives violation errors.
With this change we are first changing the mode of slave to master
then issue halt commands to both master and slave.

CRs-Fixed: 2662825
Change-Id: Id5cd7e1bdf469f43da23af151b99c9f481830cfa
Signed-off-by: default avatarVikram Sharma <vikramsa@codeaurora.org>
parent 1e731569
Loading
Loading
Loading
Loading
+54 −1
Original line number Diff line number Diff line
@@ -824,6 +824,47 @@ static void cam_ife_hw_mgr_dump_acq_data(
	}
}

static int cam_ife_mgr_csid_change_halt_mode(struct list_head  *halt_list,
	uint32_t  base_idx, enum cam_ife_csid_halt_mode halt_mode)
{
	struct cam_ife_hw_mgr_res      *hw_mgr_res;
	struct cam_isp_resource_node   *isp_res;
	struct cam_csid_hw_halt_args    halt;
	struct cam_hw_intf             *hw_intf;
	uint32_t i;
	int rc = 0;

	list_for_each_entry(hw_mgr_res, halt_list, list) {
		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
			if (!hw_mgr_res->hw_res[i] ||
				(hw_mgr_res->hw_res[i]->res_state !=
				CAM_ISP_RESOURCE_STATE_STREAMING))
				continue;

			isp_res = hw_mgr_res->hw_res[i];
			if (isp_res->hw_intf->hw_idx != base_idx)
				continue;

			if ((isp_res->res_type == CAM_ISP_RESOURCE_PIX_PATH) &&
				(isp_res->res_id == CAM_IFE_PIX_PATH_RES_IPP)) {
				hw_intf         = isp_res->hw_intf;
				halt.node_res   = isp_res;
				halt.halt_mode  = halt_mode;
				rc = hw_intf->hw_ops.process_cmd(
					hw_intf->hw_priv,
					CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
					&halt,
					sizeof(struct cam_csid_hw_halt_args));
				if (rc)
					CAM_ERR(CAM_ISP, "Halt update failed");
				break;
			}
		}
	}

	return rc;
}

static int cam_ife_mgr_csid_stop_hw(
	struct cam_ife_hw_mgr_ctx *ctx, struct list_head  *stop_list,
		uint32_t  base_idx, uint32_t stop_cmd)
@@ -3864,6 +3905,19 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
	 */
	if (i == ctx->num_base)
		master_base_idx = ctx->base[0].idx;

	/*Change slave mode*/
	if (csid_halt_type == CAM_CSID_HALT_IMMEDIATELY) {
		for (i = 0; i < ctx->num_base; i++) {
			if (ctx->base[i].idx == master_base_idx)
				continue;
			cam_ife_mgr_csid_change_halt_mode(
				&ctx->res_list_ife_csid,
				ctx->base[i].idx,
				CAM_CSID_HALT_MODE_INTERNAL);
		}
	}

	CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);

	/* Stop the master CSID path first */
@@ -6954,7 +7008,6 @@ static int cam_ife_hw_mgr_handle_hw_rup(

	CAM_DBG(CAM_ISP, "RUP done for VFE:%d source %d", event_info->hw_idx,
		event_info->res_id);

	return 0;
}

+96 −0
Original line number Diff line number Diff line
@@ -2127,6 +2127,64 @@ static int cam_ife_csid_enable_pxl_path(
	return 0;
}


static void cam_ife_csid_change_pxl_halt_mode(
	struct cam_ife_csid_hw          *csid_hw,
	struct cam_isp_resource_node    *res,
	enum cam_ife_csid_halt_mode      halt_mode)
{
	uint32_t val = 0;
	const struct cam_ife_csid_reg_offset       *csid_reg;
	struct cam_hw_soc_info                     *soc_info;
	struct cam_ife_csid_path_cfg               *path_data;
	const struct cam_ife_csid_pxl_reg_offset   *pxl_reg;
	bool                                        is_ipp;

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

	if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) {
		CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d",
			csid_hw->hw_intf->hw_idx, res->res_id);
		goto end;
	}

	if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
		res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
		CAM_ERR(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
			csid_hw->hw_intf->hw_idx, res->res_id, res->res_state);
		goto end;
	}

	if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) {
		is_ipp = true;
		pxl_reg = csid_reg->ipp_reg;
	} else {
		goto end;
	}

	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
		CAM_ERR(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d",
			csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP",
			res->res_id, res->res_state);
		goto end;
	}

	cam_io_w_mb(0, soc_info->reg_map[0].mem_base +
		pxl_reg->csid_pxl_irq_mask_addr);

	/* configure Halt for slave */
	val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
		pxl_reg->csid_pxl_ctrl_addr);
	val &= ~0xC;
	val |= (halt_mode << 2);
	cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
		pxl_reg->csid_pxl_ctrl_addr);
end:
	return;
}

static int cam_ife_csid_disable_pxl_path(
	struct cam_ife_csid_hw          *csid_hw,
	struct cam_isp_resource_node    *res,
@@ -3692,6 +3750,41 @@ int cam_ife_csid_start(void *hw_priv, void *start_args,
	return rc;
}

int cam_ife_csid_halt(struct cam_ife_csid_hw *csid_hw,
		void *halt_args)
{
	struct cam_isp_resource_node         *res;
	struct cam_csid_hw_halt_args         *csid_halt;

	if (!csid_hw || !halt_args) {
		CAM_ERR(CAM_ISP, "CSID: Invalid args");
		return -EINVAL;
	}

	csid_halt = (struct cam_csid_hw_halt_args *)halt_args;

	/* Change the halt mode */
	res = csid_halt->node_res;
	CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d",
		csid_hw->hw_intf->hw_idx,
		res->res_type, res->res_id);

	switch (res->res_type) {
	case CAM_ISP_RESOURCE_PIX_PATH:
		if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP)
			cam_ife_csid_change_pxl_halt_mode(csid_hw, res,
				csid_halt->halt_mode);
		break;
	default:
		CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d",
			csid_hw->hw_intf->hw_idx,
			res->res_type);
		break;
	}

	return 0;
}

int cam_ife_csid_stop(void *hw_priv,
	void *stop_args, uint32_t arg_size)
{
@@ -4089,6 +4182,9 @@ static int cam_ife_csid_process_cmd(void *hw_priv,
	case CAM_IFE_CSID_SET_SENSOR_DIMENSION_CFG:
		rc = cam_ife_csid_set_sensor_dimension(csid_hw, cmd_args);
		break;
	case CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE:
		rc = cam_ife_csid_halt(csid_hw, cmd_args);
		break;
	default:
		CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d",
			csid_hw->hw_intf->hw_idx, cmd_type);
+27 −0
Original line number Diff line number Diff line
@@ -153,6 +153,33 @@ enum cam_ife_csid_halt_cmd {
	CAM_CSID_HALT_MAX,
};

/**
 *  enum cam_ife_csid_halt_mode_cmd - Specify the halt command type
 */
enum cam_ife_csid_halt_mode {
	CAM_CSID_HALT_MODE_INTERNAL,
	CAM_CSID_HALT_MODE_GLOBAL,
	CAM_CSID_HALT_MODE_MASTER,
	CAM_CSID_HALT_MODE_SLAVE,
	CAM_CSID_HALT_MODE_MAX,
};

/**
 * struct cam_csid_hw_halt_args
 * @halt_mode : Applicable only for PATH resources
 * 0 Internal : The CSID responds to the HALT_CMD
 * 1 Global : The CSID responds to the GLOBAL_HALT_CMD
 * 2 Master : The CSID responds to the HALT_CMD
 * 3 Slave : The CSID responds to the external halt command
 * and not the HALT_CMD register
 * @node_res : reource pointer array( ie cid or CSID)
 *
 */
struct cam_csid_hw_halt_args {
	enum cam_ife_csid_halt_mode   halt_mode;
	struct cam_isp_resource_node *node_res;
};

/**
 * struct cam_csid_hw_stop- stop all resources
 * @stop_cmd : Applicable only for PATH resources
+1 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ enum cam_isp_hw_cmd_type {
	CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA,
	CAM_ISP_HW_CMD_DUMP_HW,
	CAM_ISP_HW_CMD_FE_TRIGGER_CMD,
	CAM_ISP_HW_CMD_CSID_CHANGE_HALT_MODE,
	CAM_ISP_HW_CMD_MAX,
};