瀏覽代碼

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: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 5 年之前
父節點
當前提交
118b93f5dd
共有 2 個文件被更改,包括 268 次插入58 次删除
  1. 171 56
      drivers/cam_cust/cam_custom_context.c
  2. 97 2
      drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c

+ 171 - 56
drivers/cam_cust/cam_custom_context.c

@@ -1,6 +1,6 @@
 // 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;
-	}
 
-	spin_lock_bh(&ctx->lock);
-	rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
-	spin_unlock_bh(&ctx->lock);
+		/* 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);
+		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,34 +256,27 @@ 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)
 {
 	int rc = 0;
 	uint32_t i;
 	struct cam_custom_context          *ctx_custom =
-		(struct cam_custom_context *) ctx->ctx_priv;
-	struct cam_ctx_request          *req;
-	struct cam_custom_dev_ctx_req       *req_custom;
-	struct cam_hw_stop_args          stop;
-
-	if (ctx_custom->hw_ctx) {
+		(struct cam_custom_context *)   ctx->ctx_priv;
+	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->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 @@ free_req:
 
 }
 
+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
drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c

@@ -1,6 +1,6 @@
 // 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>
@@ -222,6 +222,7 @@ err:
 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;
@@ -231,6 +232,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;
 
@@ -263,6 +265,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) {
@@ -284,6 +289,7 @@ static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
 
 	/* deinit custom rsrc */
 
+end:
 	return rc;
 }
 
@@ -359,13 +365,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;
@@ -377,6 +389,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) {
@@ -404,6 +419,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;
@@ -434,6 +451,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:
@@ -1115,6 +1134,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)
 {
@@ -1281,6 +1375,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;