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

Commit f3a1bc3d authored by Karthik Anantha Ram's avatar Karthik Anantha Ram Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: custom: Add support for immediate stop



Add support for immediate stop and reset during flush
for custom HW.

CRs-Fixed: 2585745
Change-Id: I542ac02f8d99c194efa498bc07dffae7879a6c8a
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
parent 85ef6928
Loading
Loading
Loading
Loading
+171 −56
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/debugfs.h>
@@ -24,6 +24,10 @@ static const char custom_dev_name[] = "cam-custom";
static int __cam_custom_ctx_handle_irq_in_activated(
	void *context, uint32_t evt_id, void *evt_data);

static int __cam_custom_ctx_start_dev_in_ready(
	struct cam_context *ctx, struct cam_start_stop_dev_cmd *cmd);


static int __cam_custom_ctx_enqueue_request_in_order(
	struct cam_context *ctx, struct cam_ctx_request *req)
{
@@ -131,22 +135,104 @@ static int __cam_custom_ctx_flush_req(struct cam_context *ctx,
	return 0;
}

static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	ctx->link_hdl = -1;
	ctx->ctx_crm_intf = NULL;

	return 0;
}

static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	ctx->link_hdl = -1;
	ctx->ctx_crm_intf = NULL;
	ctx->state = CAM_CTX_ACQUIRED;

	return 0;
}

static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx,
	struct cam_req_mgr_device_info *dev_info)
{
	dev_info->dev_hdl = ctx->dev_hdl;
	strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name));
	dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW;
	dev_info->p_delay = 1;
	dev_info->trigger = CAM_TRIGGER_POINT_SOF;

	return 0;
}

static int __cam_custom_ctx_flush_req_in_top_state(
	struct cam_context *ctx,
	struct cam_req_mgr_flush_request *flush_req)
{
	int rc = 0;
	struct cam_custom_context      *custom_ctx;
	struct cam_hw_reset_args        reset_args;
	struct cam_hw_stop_args         stop_args;
	struct cam_custom_stop_args     custom_stop;

	custom_ctx =
		(struct cam_custom_context *) ctx->ctx_priv;

	CAM_DBG(CAM_CUSTOM, "Flushing pending list");
	spin_lock_bh(&ctx->lock);
	__cam_custom_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 (ctx->state <= CAM_CTX_READY) {
			ctx->state = CAM_CTX_ACQUIRED;
			goto end;
		}

		spin_lock_bh(&ctx->lock);
		ctx->state = CAM_CTX_FLUSHED;
		spin_unlock_bh(&ctx->lock);

		CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld",
			flush_req->req_id);
		ctx->last_flush_req = flush_req->req_id;

		/* stop hw first */
		if (ctx->hw_mgr_intf->hw_stop) {
			custom_stop.stop_only = true;
			stop_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
			stop_args.args = (void *) &custom_stop;
			rc = ctx->hw_mgr_intf->hw_stop(
				ctx->hw_mgr_intf->hw_mgr_priv, &stop_args);
			if (rc)
				CAM_ERR(CAM_CUSTOM,
					"HW stop failed in flush rc %d", rc);
		}

		spin_lock_bh(&ctx->lock);
	rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
		if (!list_empty(&ctx->wait_req_list))
			__cam_custom_ctx_flush_req(ctx, &ctx->wait_req_list,
			flush_req);

		if (!list_empty(&ctx->active_req_list))
			__cam_custom_ctx_flush_req(ctx, &ctx->active_req_list,
			flush_req);

		custom_ctx->active_req_cnt = 0;
		spin_unlock_bh(&ctx->lock);

		reset_args.ctxt_to_hw_map = custom_ctx->hw_ctx;
		rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv,
			&reset_args);
		if (rc)
			CAM_ERR(CAM_CUSTOM,
				"Reset HW failed in flush rc %d", rc);

		custom_ctx->init_received = false;
	}

end:
	return rc;
}

@@ -170,16 +256,6 @@ static int __cam_custom_ctx_flush_req_in_ready(
	return rc;
}

static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	ctx->link_hdl = -1;
	ctx->ctx_crm_intf = NULL;
	ctx->state = CAM_CTX_ACQUIRED;

	return 0;
}

static int __cam_custom_stop_dev_core(
	struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd)
{
@@ -190,14 +266,17 @@ static int __cam_custom_stop_dev_core(
	struct cam_ctx_request             *req;
	struct cam_custom_dev_ctx_req      *req_custom;
	struct cam_hw_stop_args             stop;
	struct cam_custom_stop_args         custom_stop;

	if (ctx_custom->hw_ctx) {
	if ((ctx->state != CAM_CTX_FLUSHED) && (ctx_custom->hw_ctx) &&
		(ctx->hw_mgr_intf->hw_stop)) {
		custom_stop.stop_only = false;
		stop.ctxt_to_hw_map = ctx_custom->hw_ctx;

		stop.args = NULL;
		if (ctx->hw_mgr_intf->hw_stop)
			ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
		stop.args = (void *) &custom_stop;
		rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
			&stop);
		if (rc)
			CAM_ERR(CAM_CUSTOM, "HW stop failed rc %d", rc);
	}

	while (!list_empty(&ctx->pending_req_list)) {
@@ -752,7 +831,9 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx,
			CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state");
		}
	} else {
		if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) {
		if ((ctx->state != CAM_CTX_FLUSHED) &&
			(ctx->state >= CAM_CTX_READY) &&
			(ctx->ctx_crm_intf->add_req)) {
			add_req.link_hdl = ctx->link_hdl;
			add_req.dev_hdl  = ctx->dev_hdl;
			add_req.req_id   = req->request_id;
@@ -796,6 +877,44 @@ static int __cam_custom_ctx_config_dev(struct cam_context *ctx,

}

static int __cam_custom_ctx_config_dev_in_flushed(struct cam_context *ctx,
	struct cam_config_dev_cmd *cmd)
{
	int rc = 0;
	struct cam_start_stop_dev_cmd start_cmd;
	struct cam_custom_context *custom_ctx =
		(struct cam_custom_context *) ctx->ctx_priv;

	if (!custom_ctx->hw_acquired) {
		CAM_ERR(CAM_CUSTOM, "HW is not acquired, reject packet");
		rc = -EINVAL;
		goto end;
	}

	rc = __cam_custom_ctx_config_dev(ctx, cmd);
	if (rc)
		goto end;

	if (!custom_ctx->init_received) {
		CAM_WARN(CAM_CUSTOM,
			"Received update packet in flushed state, skip start");
		goto end;
	}

	start_cmd.dev_handle = cmd->dev_handle;
	start_cmd.session_handle = cmd->session_handle;
	rc = __cam_custom_ctx_start_dev_in_ready(ctx, &start_cmd);
	if (rc)
		CAM_ERR(CAM_CUSTOM,
			"Failed to re-start HW after flush rc: %d", rc);
	else
		CAM_INFO(CAM_CUSTOM,
			"Received init after flush. Re-start HW complete.");

end:
	return rc;
}

static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx,
	struct cam_config_dev_cmd *cmd)
{
@@ -835,32 +954,11 @@ static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx,
	return 0;
}

static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx,
	struct cam_req_mgr_core_dev_link_setup *unlink)
{
	ctx->link_hdl = -1;
	ctx->ctx_crm_intf = NULL;

	return 0;
}

static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx,
	struct cam_req_mgr_device_info *dev_info)
{
	dev_info->dev_hdl = ctx->dev_hdl;
	strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name));
	dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW;
	dev_info->p_delay = 1;
	dev_info->trigger = CAM_TRIGGER_POINT_SOF;

	return 0;
}

static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx,
	struct cam_start_stop_dev_cmd *cmd)
{
	int rc = 0;
	struct cam_hw_config_args        hw_config;
	struct cam_custom_start_args     custom_start;
	struct cam_ctx_request          *req;
	struct cam_custom_dev_ctx_req   *req_custom;
	struct cam_custom_context       *ctx_custom =
@@ -889,16 +987,20 @@ static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx,
		goto end;
	}

	hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx;
	hw_config.request_id = req->request_id;
	hw_config.hw_update_entries = req_custom->cfg;
	hw_config.num_hw_update_entries = req_custom->num_cfg;
	hw_config.priv  = &req_custom->hw_update_data;
	hw_config.init_packet = 1;
	custom_start.hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx;
	custom_start.hw_config.request_id = req->request_id;
	custom_start.hw_config.hw_update_entries = req_custom->cfg;
	custom_start.hw_config.num_hw_update_entries = req_custom->num_cfg;
	custom_start.hw_config.priv  = &req_custom->hw_update_data;
	custom_start.hw_config.init_packet = 1;
	if (ctx->state == CAM_CTX_FLUSHED)
		custom_start.start_only = true;
	else
		custom_start.start_only = false;

	ctx->state = CAM_CTX_ACTIVATED;
	rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
		&hw_config);
		&custom_start);
	if (rc) {
		/* HW failure. User need to clean up the resource */
		CAM_ERR(CAM_CUSTOM, "Start HW failed");
@@ -1064,7 +1166,20 @@ static struct cam_ctx_ops
		.pagefault_ops = NULL,
	},
	/* Flushed */
	{},
	{
		.ioctl_ops = {
			.stop_dev = __cam_custom_stop_dev_in_activated,
			.release_dev =
				__cam_custom_ctx_release_dev_in_activated,
			.config_dev = __cam_custom_ctx_config_dev_in_flushed,
			.release_hw =
				__cam_custom_ctx_release_hw_in_activated_state,
		},
		.crm_ops = {
			.unlink = __cam_custom_ctx_unlink_in_ready,
		},
		.irq_ops = NULL,
	},
	/* Activated */
	{
		.ioctl_ops = {
+97 −2
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -220,6 +220,7 @@ static int cam_custom_hw_mgr_stop_hw_res(
static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{
	int                               rc        = 0;
	struct cam_custom_stop_args      *custom_args;
	struct cam_hw_stop_args          *stop_args = stop_hw_args;
	struct cam_custom_hw_mgr_res     *hw_mgr_res;
	struct cam_custom_hw_mgr_ctx     *ctx;
@@ -229,6 +230,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
		return -EINVAL;
	}

	custom_args = (struct cam_custom_stop_args *)stop_args->args;
	ctx = (struct cam_custom_hw_mgr_ctx *)
		stop_args->ctxt_to_hw_map;

@@ -261,6 +263,9 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)

	/* stop custom hw here */

	if (custom_args->stop_only)
		goto end;

	/* Deinit custom cid here */
	list_for_each_entry(hw_mgr_res,
		&ctx->res_list_custom_cid, list) {
@@ -282,6 +287,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)

	/* deinit custom rsrc */

end:
	return rc;
}

@@ -357,13 +363,19 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,
	struct cam_hw_stop_args                  stop_args;
	struct cam_custom_hw_mgr_res            *hw_mgr_res;
	struct cam_custom_hw_mgr_ctx            *ctx;
	struct cam_custom_stop_args              custom_stop_args;
	struct cam_custom_start_args            *custom_args;

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

	hw_config = (struct cam_hw_config_args *)start_hw_args;
	custom_args =
		(struct cam_custom_start_args *)start_hw_args;

	hw_config = (struct cam_hw_config_args *)
		&custom_args->hw_config;

	ctx = (struct cam_custom_hw_mgr_ctx *)
		hw_config->ctxt_to_hw_map;
@@ -375,6 +387,9 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,
	CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d",
		ctx->ctx_index);

	if (custom_args->start_only)
		goto start_only;

	/* Init custom cid */
	list_for_each_entry(hw_mgr_res,
		&ctx->res_list_custom_cid, list) {
@@ -402,6 +417,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,

	/* Apply init config */

start_only:

	/* Start custom HW first */
	if (rc < 0)
		goto err;
@@ -432,6 +449,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,
	return 0;

err:
	custom_stop_args.stop_only = false;
	stop_args.args = (void *) &custom_stop_args;
	stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map;
	cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args);
deinit_hw:
@@ -1113,6 +1132,81 @@ static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv,
	return 0;
}

static int cam_custom_hw_mgr_reset_csid_res(
	struct cam_custom_hw_mgr_res *hw_mgr_res)
{
	int rc = -1;
	struct cam_csid_reset_cfg_args  csid_reset_args;
	struct cam_isp_resource_node *custom_rsrc_node = NULL;
	struct cam_hw_intf *hw_intf = NULL;

	custom_rsrc_node =
		(struct cam_isp_resource_node *)hw_mgr_res->rsrc_node;
	if (!custom_rsrc_node) {
		CAM_ERR(CAM_CUSTOM, "Invalid args");
		return -EINVAL;
	}

	csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH;
	csid_reset_args.node_res = custom_rsrc_node;
	hw_intf = custom_rsrc_node->hw_intf;
	if (hw_intf->hw_ops.reset) {
		CAM_DBG(CAM_CUSTOM, "RESET HW for res_id:%u",
			hw_mgr_res->res_id);
		rc = hw_intf->hw_ops.reset(hw_intf->hw_priv,
			&csid_reset_args,
			sizeof(struct cam_csid_reset_cfg_args));
		if (rc)
			goto err;
	}

	return 0;

err:
	CAM_ERR(CAM_CUSTOM,
		"RESET HW failed for res_id:%u",
		hw_mgr_res->res_id);
	return rc;
}

static int cam_custom_hw_mgr_reset(
	void *hw_mgr_priv, void *hw_reset_args)
{
	struct cam_hw_reset_args         *reset_args =
		hw_reset_args;
	struct cam_custom_hw_mgr_ctx     *ctx;
	struct cam_custom_hw_mgr_res     *hw_mgr_res;
	int                               rc = 0;

	if (!hw_mgr_priv || !hw_reset_args) {
		CAM_ERR(CAM_CUSTOM, "Invalid arguments");
		return -EINVAL;
	}

	ctx = (struct cam_custom_hw_mgr_ctx *)
		reset_args->ctxt_to_hw_map;
	if (!ctx || !ctx->ctx_in_use) {
		CAM_ERR(CAM_CUSTOM, "Invalid context is used");
		return -EPERM;
	}

	CAM_DBG(CAM_CUSTOM, "Reset SBI CSID and SBI core");
	list_for_each_entry(hw_mgr_res, &ctx->res_list_custom_csid, list) {
		rc = cam_custom_hw_mgr_reset_csid_res(hw_mgr_res);
		if (rc) {
			CAM_ERR(CAM_CUSTOM,
				"Failed to reset CSID:%d rc: %d",
				hw_mgr_res->res_id, rc);
			goto end;
		}
	}

	/* Reset SBI HW */

end:
	return rc;
}

static int cam_custom_mgr_config_hw(void *hw_mgr_priv,
	void *hw_config_args)
{
@@ -1279,6 +1373,7 @@ int cam_custom_hw_mgr_init(struct device_node *of_node,
	hw_mgr_intf->hw_release = cam_custom_mgr_release_hw;
	hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update;
	hw_mgr_intf->hw_config = cam_custom_mgr_config_hw;
	hw_mgr_intf->hw_reset = cam_custom_hw_mgr_reset;

	if (iommu_hdl)
		*iommu_hdl = g_custom_hw_mgr.img_iommu_hdl;