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 <kartanan@codeaurora.org>
This commit is contained in:
Karthik Anantha Ram
2020-01-08 19:04:51 -08:00
committed by Gerrit - the friendly Code Review server
parent b08e2b4099
commit 118b93f5dd
2 changed files with 267 additions and 57 deletions

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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> #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( static int __cam_custom_ctx_handle_irq_in_activated(
void *context, uint32_t evt_id, void *evt_data); 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( static int __cam_custom_ctx_enqueue_request_in_order(
struct cam_context *ctx, struct cam_ctx_request *req) 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; 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( static int __cam_custom_ctx_flush_req_in_top_state(
struct cam_context *ctx, struct cam_context *ctx,
struct cam_req_mgr_flush_request *flush_req) struct cam_req_mgr_flush_request *flush_req)
{ {
int rc = 0; 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 (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", CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld",
flush_req->req_id); flush_req->req_id);
ctx->last_flush_req = 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);
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;
} }
spin_lock_bh(&ctx->lock); end:
rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
spin_unlock_bh(&ctx->lock);
return rc; return rc;
} }
@@ -170,34 +256,27 @@ static int __cam_custom_ctx_flush_req_in_ready(
return rc; 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( static int __cam_custom_stop_dev_core(
struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd)
{ {
int rc = 0; int rc = 0;
uint32_t i; uint32_t i;
struct cam_custom_context *ctx_custom = struct cam_custom_context *ctx_custom =
(struct cam_custom_context *) ctx->ctx_priv; (struct cam_custom_context *) ctx->ctx_priv;
struct cam_ctx_request *req; struct cam_ctx_request *req;
struct cam_custom_dev_ctx_req *req_custom; struct cam_custom_dev_ctx_req *req_custom;
struct cam_hw_stop_args stop; 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.ctxt_to_hw_map = ctx_custom->hw_ctx;
stop.args = (void *) &custom_stop;
stop.args = NULL; rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
if (ctx->hw_mgr_intf->hw_stop)
ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
&stop); &stop);
if (rc)
CAM_ERR(CAM_CUSTOM, "HW stop failed rc %d", rc);
} }
while (!list_empty(&ctx->pending_req_list)) { 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"); CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state");
} }
} else { } 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.link_hdl = ctx->link_hdl;
add_req.dev_hdl = ctx->dev_hdl; add_req.dev_hdl = ctx->dev_hdl;
add_req.req_id = req->request_id; 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, static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx,
struct cam_config_dev_cmd *cmd) struct cam_config_dev_cmd *cmd)
{ {
@@ -835,32 +954,11 @@ static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx,
return 0; 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, static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd) struct cam_start_stop_dev_cmd *cmd)
{ {
int rc = 0; int rc = 0;
struct cam_hw_config_args hw_config; struct cam_custom_start_args custom_start;
struct cam_ctx_request *req; struct cam_ctx_request *req;
struct cam_custom_dev_ctx_req *req_custom; struct cam_custom_dev_ctx_req *req_custom;
struct cam_custom_context *ctx_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; goto end;
} }
hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; custom_start.hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx;
hw_config.request_id = req->request_id; custom_start.hw_config.request_id = req->request_id;
hw_config.hw_update_entries = req_custom->cfg; custom_start.hw_config.hw_update_entries = req_custom->cfg;
hw_config.num_hw_update_entries = req_custom->num_cfg; custom_start.hw_config.num_hw_update_entries = req_custom->num_cfg;
hw_config.priv = &req_custom->hw_update_data; custom_start.hw_config.priv = &req_custom->hw_update_data;
hw_config.init_packet = 1; 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; ctx->state = CAM_CTX_ACTIVATED;
rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv,
&hw_config); &custom_start);
if (rc) { if (rc) {
/* HW failure. User need to clean up the resource */ /* HW failure. User need to clean up the resource */
CAM_ERR(CAM_CUSTOM, "Start HW failed"); CAM_ERR(CAM_CUSTOM, "Start HW failed");
@@ -1064,7 +1166,20 @@ static struct cam_ctx_ops
.pagefault_ops = NULL, .pagefault_ops = NULL,
}, },
/* Flushed */ /* 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 */ /* Activated */
{ {
.ioctl_ops = { .ioctl_ops = {

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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> #include <linux/slab.h>
@@ -222,6 +222,7 @@ err:
static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args)
{ {
int rc = 0; int rc = 0;
struct cam_custom_stop_args *custom_args;
struct cam_hw_stop_args *stop_args = stop_hw_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_res *hw_mgr_res;
struct cam_custom_hw_mgr_ctx *ctx; 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; return -EINVAL;
} }
custom_args = (struct cam_custom_stop_args *)stop_args->args;
ctx = (struct cam_custom_hw_mgr_ctx *) ctx = (struct cam_custom_hw_mgr_ctx *)
stop_args->ctxt_to_hw_map; 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 */ /* stop custom hw here */
if (custom_args->stop_only)
goto end;
/* Deinit custom cid here */ /* Deinit custom cid here */
list_for_each_entry(hw_mgr_res, list_for_each_entry(hw_mgr_res,
&ctx->res_list_custom_cid, list) { &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 */ /* deinit custom rsrc */
end:
return rc; 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_hw_stop_args stop_args;
struct cam_custom_hw_mgr_res *hw_mgr_res; struct cam_custom_hw_mgr_res *hw_mgr_res;
struct cam_custom_hw_mgr_ctx *ctx; 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) { if (!hw_mgr_priv || !start_hw_args) {
CAM_ERR(CAM_CUSTOM, "Invalid arguments"); CAM_ERR(CAM_CUSTOM, "Invalid arguments");
return -EINVAL; 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 *) ctx = (struct cam_custom_hw_mgr_ctx *)
hw_config->ctxt_to_hw_map; 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", CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d",
ctx->ctx_index); ctx->ctx_index);
if (custom_args->start_only)
goto start_only;
/* Init custom cid */ /* Init custom cid */
list_for_each_entry(hw_mgr_res, list_for_each_entry(hw_mgr_res,
&ctx->res_list_custom_cid, list) { &ctx->res_list_custom_cid, list) {
@@ -404,6 +419,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,
/* Apply init config */ /* Apply init config */
start_only:
/* Start custom HW first */ /* Start custom HW first */
if (rc < 0) if (rc < 0)
goto err; goto err;
@@ -434,6 +451,8 @@ static int cam_custom_mgr_start_hw(void *hw_mgr_priv,
return 0; return 0;
err: 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; stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map;
cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args); cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args);
deinit_hw: deinit_hw:
@@ -1115,6 +1134,81 @@ static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv,
return 0; 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, static int cam_custom_mgr_config_hw(void *hw_mgr_priv,
void *hw_config_args) 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_release = cam_custom_mgr_release_hw;
hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update; 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_config = cam_custom_mgr_config_hw;
hw_mgr_intf->hw_reset = cam_custom_hw_mgr_reset;
if (iommu_hdl) if (iommu_hdl)
*iommu_hdl = g_custom_hw_mgr.img_iommu_hdl; *iommu_hdl = g_custom_hw_mgr.img_iommu_hdl;