diff --git a/drivers/cam_cust/cam_custom_context.c b/drivers/cam_cust/cam_custom_context.c index 3e69ebd151..25e092841c 100644 --- a/drivers/cam_cust/cam_custom_context.c +++ b/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 @@ -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); + 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); - rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); - spin_unlock_bh(&ctx->lock); - +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; + (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_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 @@ 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 = { diff --git a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c index 78226a5f32..7587e41aa6 100644 --- a/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c +++ b/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 @@ -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;