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

Commit d94f0c97 authored by Jeyaprakash Soundrapandian's avatar Jeyaprakash Soundrapandian Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: isp: Add active list request flush support" into dev/msm-4.14-camx

parents aac95e5c 68a68b27
Loading
Loading
Loading
Loading
+81 −10
Original line number Diff line number Diff line
@@ -1368,12 +1368,56 @@ static int __cam_isp_ctx_flush_req_in_top_state(
	struct cam_context *ctx,
	struct cam_req_mgr_flush_request *flush_req)
{
	struct cam_isp_context           *ctx_isp =
		(struct cam_isp_context *) ctx->ctx_priv;
	struct cam_isp_stop_args          stop_isp;
	struct cam_hw_stop_args           stop_args;
	struct cam_isp_start_args         start_isp;
	int rc = 0;

	CAM_DBG(CAM_ISP, "try to flush pending list");
	spin_lock_bh(&ctx->lock);
	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
	spin_unlock_bh(&ctx->lock);

	if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
		/* if active and wait list are empty, return */
		spin_lock_bh(&ctx->lock);
		if ((list_empty(&ctx->wait_req_list)) &&
			(list_empty(&ctx->active_req_list))) {
			spin_unlock_bh(&ctx->lock);
			CAM_DBG(CAM_ISP, "active and wait list are empty");
			goto end;
		}
		spin_unlock_bh(&ctx->lock);

		/* Stop hw first before active list flush */
		stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
		stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY;
		stop_isp.stop_only = true;
		stop_args.args = (void *)&stop_isp;
		ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
				&stop_args);

		spin_lock_bh(&ctx->lock);
		CAM_DBG(CAM_ISP, "try to flush wait list");
		rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list,
		flush_req);
		CAM_DBG(CAM_ISP, "try to flush active list");
		rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list,
		flush_req);
		spin_unlock_bh(&ctx->lock);

		/* Start hw */
		start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx;
		start_isp.start_only = true;
		start_isp.hw_config.priv = NULL;

		rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
			&start_isp);
	}

end:
	CAM_DBG(CAM_ISP, "Flush request in top state %d",
		 ctx->state);
	return rc;
@@ -2294,7 +2338,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
	struct cam_start_stop_dev_cmd *cmd)
{
	int rc = 0;
	struct cam_hw_config_args        arg;
	struct cam_isp_start_args        start_isp;
	struct cam_ctx_request          *req;
	struct cam_isp_ctx_req          *req_isp;
	struct cam_isp_context          *ctx_isp =
@@ -2323,12 +2367,13 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
		goto end;
	}

	arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
	arg.request_id = req->request_id;
	arg.hw_update_entries = req_isp->cfg;
	arg.num_hw_update_entries = req_isp->num_cfg;
	arg.priv  = &req_isp->hw_update_data;
	arg.init_packet = 1;
	start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx;
	start_isp.hw_config.request_id = req->request_id;
	start_isp.hw_config.hw_update_entries = req_isp->cfg;
	start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg;
	start_isp.hw_config.priv  = &req_isp->hw_update_data;
	start_isp.hw_config.init_packet = 1;
	start_isp.start_only = false;

	ctx_isp->frame_id = 0;
	ctx_isp->active_req_cnt = 0;
@@ -2345,7 +2390,8 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
	 */
	ctx->state = CAM_CTX_ACTIVATED;
	trace_cam_context_state("ISP", ctx);
	rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, &arg);
	rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
		&start_isp);
	if (rc) {
		/* HW failure. user need to clean up the resource */
		CAM_ERR(CAM_ISP, "Start HW failed");
@@ -2386,6 +2432,7 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
	struct cam_isp_ctx_req          *req_isp;
	struct cam_isp_context          *ctx_isp =
		(struct cam_isp_context *) ctx->ctx_priv;
	struct cam_isp_stop_args         stop_isp;

	/* Mask off all the incoming hardware events */
	spin_lock_bh(&ctx->lock);
@@ -2396,7 +2443,15 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
	/* stop hw first */
	if (ctx_isp->hw_ctx) {
		stop.ctxt_to_hw_map = ctx_isp->hw_ctx;
		stop.args = stop_cmd;

		if (stop_cmd)
			stop_isp.hw_stop_cmd =
				CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY;
		else
			stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY;

		stop_isp.stop_only = false;
		stop.args = (void *) &stop_isp;
		ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
			&stop);
	}
@@ -2417,6 +2472,22 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock(
		list_add_tail(&req->list, &ctx->free_req_list);
	}

	while (!list_empty(&ctx->wait_req_list)) {
		req = list_first_entry(&ctx->wait_req_list,
				struct cam_ctx_request, list);
		list_del_init(&req->list);
		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
		CAM_DBG(CAM_ISP, "signal fence in wait list. fence num %d",
			 req_isp->num_fence_map_out);
		for (i = 0; i < req_isp->num_fence_map_out; i++)
			if (req_isp->fence_map_out[i].sync_id != -1) {
				cam_sync_signal(
					req_isp->fence_map_out[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
			}
		list_add_tail(&req->list, &ctx->free_req_list);
	}

	while (!list_empty(&ctx->active_req_list)) {
		req = list_first_entry(&ctx->active_req_list,
				struct cam_ctx_request, list);
+145 −86
Original line number Diff line number Diff line
@@ -284,6 +284,100 @@ static void cam_ife_hw_mgr_deinit_hw_res(
	}
}

static int cam_ife_hw_mgr_init_hw(
	struct cam_ife_hw_mgr_ctx *ctx)
{
	struct cam_ife_hw_mgr_res *hw_mgr_res;
	int rc = 0, i;

	CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d",
		ctx->ctx_index);
	/* INIT IFE CID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)",
				 hw_mgr_res->res_id);
			return rc;
		}
	}

	CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d",
		ctx->ctx_index);

	/* INIT IFE csid */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)",
				 hw_mgr_res->res_id);
			return rc;
		}
	}

	/* INIT IFE SRC */
	CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d",
		ctx->ctx_index);
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)",
				 hw_mgr_res->res_id);
			return rc;
		}
	}

	/* INIT IFE OUT */
	CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d",
		ctx->ctx_index);

	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
		rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)",
				 ctx->res_list_ife_out[i].res_id);
			return rc;
		}
	}

	return rc;
}

static void cam_ife_hw_mgr_deinit_hw(
	struct cam_ife_hw_mgr_ctx *ctx)
{
	struct cam_ife_hw_mgr_res *hw_mgr_res;
	int i = 0;

	if (!ctx->init_done) {
		CAM_WARN(CAM_ISP, "ctx is not in init state");
		return;
	}

	/* Deinit IFE CID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
		CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deinit IFE CSID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
		CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__);
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deint IFE MUX(SRC) */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deinit IFE OUT */
	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
		cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]);

	ctx->init_done = false;
}

static int cam_ife_hw_mgr_put_res(
	struct list_head                *src_list,
	struct cam_ife_hw_mgr_res      **res)
@@ -1917,6 +2011,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{
	int                               rc        = 0;
	struct cam_hw_stop_args          *stop_args = stop_hw_args;
	struct cam_isp_stop_args         *stop_isp;
	struct cam_ife_hw_mgr_res        *hw_mgr_res;
	struct cam_ife_hw_mgr_ctx        *ctx;
	enum cam_ife_csid_halt_cmd        csid_halt_type;
@@ -1926,6 +2021,7 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
		CAM_ERR(CAM_ISP, "Invalid arguments");
		return -EINVAL;
	}

	ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map;
	if (!ctx || !ctx->ctx_in_use) {
		CAM_ERR(CAM_ISP, "Invalid context is used");
@@ -1933,12 +2029,20 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
	}

	CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index);
	stop_isp = (struct cam_isp_stop_args    *)stop_args->args;

	if ((stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_IMMEDIATELY) &&
		(stop_isp->stop_only)) {
		CAM_ERR(CAM_ISP, "Invalid params hw_stop_cmd:%d stop_only:%d",
			stop_isp->hw_stop_cmd, stop_isp->stop_only);
		return -EPERM;
	}

	/* Set the csid halt command */
	if (!stop_args->args)
		csid_halt_type = CAM_CSID_HALT_IMMEDIATELY;
	else
	if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY)
		csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY;
	else
		csid_halt_type = CAM_CSID_HALT_IMMEDIATELY;

	/* Note:stop resource will remove the irq mask from the hardware */

@@ -2014,30 +2118,15 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
			ctx->base[i].idx, csid_halt_type);
	}

	/* Deinit IFE CID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
		CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deinit IFE CSID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
		CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__);
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deint IFE MUX(SRC) */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
		cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res);
	}

	/* Deinit IFE OUT */
	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++)
		cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]);
	if (stop_isp->stop_only)
		goto end;

	cam_ife_hw_mgr_deinit_hw(ctx);
	CAM_DBG(CAM_ISP,
		"Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc);

end:

	mutex_lock(&g_ife_hw_mgr.ctx_mutex);
	if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) {
		rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE);
@@ -2149,19 +2238,20 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args)
static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
{
	int                               rc = -1;
	struct cam_hw_config_args        *start_args = start_hw_args;
	struct cam_isp_start_args        *start_isp = start_hw_args;
	struct cam_hw_stop_args           stop_args;
	struct cam_isp_stop_hw_method     stop_hw_method;
	struct cam_isp_stop_args          stop_isp;
	struct cam_ife_hw_mgr_ctx        *ctx;
	struct cam_ife_hw_mgr_res        *hw_mgr_res;
	uint32_t                          i;

	if (!hw_mgr_priv || !start_hw_args) {
	if (!hw_mgr_priv || !start_isp) {
		CAM_ERR(CAM_ISP, "Invalid arguments");
		return -EINVAL;
	}

	ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map;
	ctx = (struct cam_ife_hw_mgr_ctx *)
		start_isp->hw_config.ctxt_to_hw_map;
	if (!ctx || !ctx->ctx_in_use) {
		CAM_ERR(CAM_ISP, "Invalid context is used");
		return -EPERM;
@@ -2174,6 +2264,9 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)

	cam_tasklet_start(ctx->common.tasklet_info);

	if (ctx->init_done && start_isp->start_only)
		goto start_only;

	/* set current csid debug information to CSID HW */
	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
		if (g_ife_hw_mgr.csid_devices[i])
@@ -2184,58 +2277,13 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
				sizeof(g_ife_hw_mgr.debug_cfg.csid_debug));
	}

	/* INIT IFE Root: do nothing */

	CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d",
		ctx->ctx_index);
	/* INIT IFE CID */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)",
				 hw_mgr_res->res_id);
			goto err;
		}
	}


	CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d",
		ctx->ctx_index);

	/* INIT IFE csid */
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
	rc = cam_ife_hw_mgr_init_hw(ctx);
	if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)",
				 hw_mgr_res->res_id);
		CAM_ERR(CAM_ISP, "Init failed");
		goto err;
	}
	}

	/* INIT IFE SRC */
	CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d",
		ctx->ctx_index);
	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
		rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)",
				 hw_mgr_res->res_id);
			goto err;
		}
	}

	/* INIT IFE OUT */
	CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d",
		ctx->ctx_index);

	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
		rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]);
		if (rc) {
			CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)",
				 ctx->res_list_ife_out[i].res_id);
			goto err;
		}
	}
start_only:

	mutex_lock(&g_ife_hw_mgr.ctx_mutex);
	if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) {
@@ -2256,13 +2304,16 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
		goto err;
	}

	if (!start_isp->start_only) {
		/* Apply initial configuration */
		CAM_DBG(CAM_ISP, "Config HW");
	rc = cam_ife_mgr_config_hw(hw_mgr_priv, start_hw_args);
		rc = cam_ife_mgr_config_hw(hw_mgr_priv,
			&start_isp->hw_config);
		if (rc) {
			CAM_ERR(CAM_ISP, "Config HW failed");
			goto err;
		}
	}

	CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d",
		ctx->ctx_index);
@@ -2313,13 +2364,18 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
		}
	}

	ctx->init_done = true;
	/* Start IFE root node: do nothing */
	CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index);

	return 0;

err:
	stop_hw_method.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY;
	stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map;
	stop_args.args = (void *)(&stop_hw_method);
	stop_isp.stop_only = false;
	stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY;
	stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map;
	stop_args.args = (void *)(&stop_isp);

	cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args);
	CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
	return rc;
@@ -2358,6 +2414,9 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
	CAM_DBG(CAM_ISP, "Enter...ctx id:%d",
		ctx->ctx_index);

	if (ctx->init_done)
		cam_ife_hw_mgr_deinit_hw(ctx);

	/* we should called the stop hw before this already */
	cam_ife_hw_mgr_release_hw_for_ctx(ctx);

+2 −0
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ struct cam_ife_hw_mgr_debug {
 *                          context
 * @is_rdi_only_context     flag to specify the context has only rdi resource
 * @config_done_complete    indicator for configuration complete
 * @init_done               indicate whether init hw is done
 */
struct cam_ife_hw_mgr_ctx {
	struct list_head                list;
@@ -156,6 +157,7 @@ struct cam_ife_hw_mgr_ctx {
	atomic_t                        overflow_pending;
	uint32_t                        is_rdi_only_context;
	struct completion               config_done_complete;
	bool                            init_done;
};

/**
+18 −2
Original line number Diff line number Diff line
@@ -60,13 +60,29 @@ enum cam_isp_hw_stop_cmd {
};

/**
 * struct cam_isp_stop_hw_method - hardware stop method
 * struct cam_isp_stop_args - hardware stop arguments
 *
 * @hw_stop_cmd:               Hardware stop command type information
 * @stop_only                  Send stop only to hw drivers. No Deinit to be
 *                             done.
 *
 */
struct cam_isp_stop_hw_method {
struct cam_isp_stop_args {
	enum cam_isp_hw_stop_cmd      hw_stop_cmd;
	bool                          stop_only;
};

/**
 * struct cam_isp_start_args - isp hardware start arguments
 *
 * @config_args:               Hardware configuration commands.
 * @start_only                 Send start only to hw drivers. No init to
 *                             be done.
 *
 */
struct cam_isp_start_args {
	struct cam_hw_config_args     hw_config;
	bool                          start_only;
};

/**
+4 −1
Original line number Diff line number Diff line
@@ -1250,7 +1250,10 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res)
	struct cam_vfe_bus_ver2_common_data        *common_data =
		rsrc_data->common_data;

	/* disable WM */
	/* Disable WM */
	cam_io_w_mb(0x0,
		common_data->mem_base + rsrc_data->hw_regs->cfg);

	/* Disable all register access, reply on global reset */
	CAM_DBG(CAM_ISP, "WM res %d irq_enabled %d",
		rsrc_data->index, rsrc_data->irq_enabled);